Page MenuHomePhabricator

[lld] Avoid defining reserved symbols from depndent DSOs
Needs RevisionPublic

Authored by thomasanderson on Apr 30 2020, 5:29 PM.

Details

Summary

Issue: save this empty program to main.c:

int main() { return 0; }

And build with:

clang main.c -fuse-ld=lld -o main1

and

clang main.c -fuse-ld=lld -o main2 -lX11

main1 will not have _end or _edata, but main2 will because
libX11.so.6 defines _end and _edata.

With this change, lld only defines _end and _edata if
they're actually used.

Diff Detail

Event Timeline

thomasanderson created this revision.Apr 30 2020, 5:29 PM

I'll punt this to Fangrui, he's a lot more familiar with this area :)

MaskRay added a comment.EditedApr 30 2020, 7:07 PM

I am not sure we want to make this change. I believe lld's current behavior is consistent with GNU ld and gold.

% clang -fuse-ld=bfd a.c -lX11 -o a && readelf -W --dyn-syms a
...
     3: 0000000000404028     0 NOTYPE  GLOBAL DEFAULT   21 _edata
     4: 0000000000404030     0 NOTYPE  GLOBAL DEFAULT   22 _end

GNU ld's internal linker script includes:

_edata = .; PROVIDE (edata = .);

So _edata is always available (in .symtab). It will end up in .dynsym if it can preempt _edata in a shared object (libX11.so.6) or is exported via other mechanisms.

lld's current behavior matches GNU ld w.r.t. .dynsym, but the .symtab entry is optional.

It may be useful to understand why libX11.so.6 exports _edata and _end. References within libX11.so.6 will get bound to _edata and _end defined in the main executable (preempted), which may be non-intuitive to many users.

It's definitely odd that some (possibly indirect) dependency's exports has an effect on our own exports. But since bfd and gold have this behavior I guess changing it would have the potential to break things.

It's probably a bug in libX11 that they export _edata, _end, and __bss_start

MaskRay requested changes to this revision.Jul 28 2020, 11:48 AM
This revision now requires changes to proceed.Jul 28 2020, 11:48 AM