Bug 19030 - ld generates .so/x86 with bad phdr so the Android linker won't dlopen
Summary: ld generates .so/x86 with bad phdr so the Android linker won't dlopen
Status: RESOLVED INVALID
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.25
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL: https://code.google.com/p/android/iss...
Keywords:
Depends on:
Blocks:
 
Reported: 2015-09-30 06:40 UTC by winter-gcc
Modified: 2015-10-02 08:15 UTC (History)
2 users (show)

See Also:
Host: x86
Target: x86
Build:
Last reconfirmed:


Attachments
.so with supposedly broken structure (7.19 KB, application/octet-stream)
2015-09-30 06:40 UTC, winter-gcc
Details

Note You need to log in before you can comment on or make changes to this bug.
Description winter-gcc 2015-09-30 06:40:12 UTC
Created attachment 8651 [details]
.so with supposedly broken structure

I originally reported the Bug to Android since a generated .so file could not by loaded by their linker/loader but they claim ld is a fault for generating a flawed ELF structure.

To quote:
"The so file in question is a strange one. Android linker assumes that phdr table is part of loadable segment but looking at the bad.so the load segment has the offset > sizeof(ehdr) + sizeof(phdr), so it ends up not being mapped into the memory - hence inaccessible after the library is loaded.

I think the ld is broken (or very old). What does ld --version say?

There are some other irregularities like one load segment for data and executable with RWE permission. And p_vaddr which might assume fixed load-address despite the fact that the object type is set to ET_DYN."

For my minimal test case I linked an object file (generated from a C file with an empty function) like this:
$ ld -L /usr/lib/android-ndk/x86/usr/lib -o client-ndk-x86.so -shared -nostdlib -lc obj-client-ndk-x86/test.o

As mentioned in the original bug report, ld.gold generates an ELF structure which works for the Android loader.
Comment 1 Alan Modra 2015-10-01 05:37:20 UTC
-nostdlib is a gcc option, not a ld option.  It looks to me like your version of ld is treating the option as if it were -n.
Comment 2 winter-gcc 2015-10-01 06:27:23 UTC
Your analysis is correct, thank you.

While "-nostdlib" actually is a ld option (at least in my ld according to --help and man page), I rechecked and noticed I passed another gcc parameter "-no-enum-size-warning" to ld which seems to behave like "-n" as you suggested hence you can label this as user error but I keep wondering how this parameter handling could be useful/intended.

The man page says "For options whose names are a single letter, option arguments must either follow the option letter without intervening whitespace, or be given as separate arguments immediately following the option that requires them." so "-no-enum-size-warning" would be taken as "-n" with value "o-enum-size-warning". Yet according to the man page "-n" does not take a value, so it seems the trailing characters will be silently discarded.

Is this parameter-handling behavior intended this way? (Should one open a new bug to discuss that?)
Comment 3 winter-gcc 2015-10-01 06:55:53 UTC
Even worse, the actual error is the missing dash in the beginning. "--no-enum-size-warning" *is* a ld parameter but without the first dash it behaves like "-n".
Comment 4 Ian Lance Taylor 2015-10-01 13:36:55 UTC
The option -no-enum-size-warning is handled as -n -o -enum-size-warning.  In other words, the -n option, followed by the -o option, setting the name of the output file to -enum-size-warning.  Perhaps in your case you had a subsequent -o option setting a different output file name--that last -o option on the command line takes precedence.

Yes, one dash or two makes a difference.
Comment 5 winter-gcc 2015-10-02 08:15:29 UTC
> Yes, one dash or two makes a difference.

Using single-dash arguments can then be considered pretty dangerous in ld since any small typo (or using a parameter that might only exist in some other ld version) in the argument results in ld looking for single letter arguments (even in concatenation) which it almost always find.

$ ld -nostdlib # correct
$ ld -nostdllib # incorrect, results in -n -o stdllib

Much safer is double dash:

$ ld --nostdlib # correct
$ ld --nostdllib
ld: unrecognized option '--nostdllib'

I figure a lot of people and application rely on single letter concatenation like this, but probably also a lot of people suffer from incorrectly applied settings without even knowing.