Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lld-linked FreeBSD/amd64 rtld segfaults after lld r288107 #30569

Closed
emaste opened this issue Dec 1, 2016 · 15 comments
Closed

lld-linked FreeBSD/amd64 rtld segfaults after lld r288107 #30569

emaste opened this issue Dec 1, 2016 · 15 comments
Labels
bugzilla Issues migrated from bugzilla lld:ELF

Comments

@emaste
Copy link
Member

emaste commented Dec 1, 2016

Bugzilla Link 31221
Resolution FIXED
Resolved on Jan 16, 2017 08:53
Version unspecified
OS FreeBSD
Blocks #23588

Extended Description

I built a FreeBSD installation using lld @ r288228 as the linker, and almost all userland binaries segfaulted when starting up, in rtld.

Bisecting identified r288107 as the culprit. The problem is not reproducible after switching back to a rtld linked with lld built at r288102.

The difference is that rtld built with post-r288107 lld has an entirely zeroed .got:

% diffoscope old-lld/ld-elf.so.1 new-lld/ld-elf.so.1
--- old-lld/ld-elf.so.1
+++ new-lld/ld-elf.so.1
├── readelf --wide --hex-dump=.got {}
│ @@ -1,16 +1,16 @@

│ Hex dump of section '.got':
│ - 0x00020410 20900000 00000000 70100200 00000000 .......p.......
│ - 0x00020420 e0230200 00000000 e8230200 00000000 .#.......#......
│ - 0x00020430 10030200 00000000 d0b60000 00000000 ................
│ - 0x00020440 18240200 00000000 18230200 00000000 .$.......#......
│ - 0x00020450 68240200 00000000 6c240200 00000000 h$......l$......
│ - 0x00020460 70240200 00000000 74240200 00000000 p$......t$......
│ - 0x00020470 80100200 00000000 18060000 00000000 ................
│ - 0x00020480 00000200 00000000 7c240200 00000000 ........|$......
│ - 0x00020490 10240200 00000000 0010020 00000000 .$..............
│ - 0x000204a0 04100200 00000000 10100200 00000000 ................
│ - 0x000204b0 30160200 00000000 981b0200 00000000 0...............
│ - 0x000204c0 b0100200 00000000 00240200 00000000 .........$......
│ - 0x000204d0 60240200 00000000 84240200 00000000 `$.......$......
│ - 0x000204e0 f8230200 00000000 .#......
│ + 0x00020410 00000000 00000000 00000000 00000000 ................
│ + 0x00020420 00000000 00000000 00000000 00000000 ................
│ + 0x00020430 00000000 00000000 00000000 00000000 ................
│ + 0x00020440 00000000 00000000 00000000 00000000 ................
│ + 0x00020450 00000000 00000000 00000000 00000000 ................
│ + 0x00020460 00000000 00000000 00000000 00000000 ................
│ + 0x00020470 00000000 00000000 00000000 00000000 ................
│ + 0x00020480 00000000 00000000 00000000 00000000 ................
│ + 0x00020490 00000000 00000000 00000000 00000000 ................
│ + 0x000204a0 00000000 00000000 00000000 00000000 ................
│ + 0x000204b0 00000000 00000000 00000000 00000000 ................
│ + 0x000204c0 00000000 00000000 00000000 00000000 ................
│ + 0x000204d0 00000000 00000000 00000000 00000000 ................
│ + 0x000204e0 00000000 00000000 ........
├── readelf --wide --string-dump=.comment {}
│ @@ -1,6 +1,6 @@

│ String dump of section '.comment':
│ [ 1] FreeBSD clang version 3.9.0 (tags/RELEASE_390/final 280324) (based on LLVM 3.9.0)
│ [ 53] $FreeBSD$
│ - [ 5d] Linker: LLD 4.0.0 (http://llvm.org/git/lld 01db8cc)
│ + [ 5d] Linker: LLD 4.0.0 (http://llvm.org/git/lld 326233f)

├── readelf --wide --hex-dump=.gnu_debuglink {}
│ @@ -1,4 +1,4 @@

│ Hex dump of section '.gnu_debuglink':
│ 0x00000000 6c642d65 6c662e73 6f2e312e 64656275 ld-elf.so.1.debu
│ - 0x00000010 6700000 a26ecfb2 g....n..
│ + 0x00000010 6700000 c1a333a6 g.....3.

rtld has code to determine if it needs to relocate itself or not, which defaults to

#ifndef RTLD_IS_DYNAMIC
#define RTLD_IS_DYNAMIC() (&_DYNAMIC != NULL)
#endif

RTLD_IS_DYNAMIC is false when linked with lld >= r288107, so rtld does not apply its own relocations at startup and crashes.

This is arguably a FreeBSD rtld bug (and we could address it there). I'm submitting this LLD ticket for tracking the issue as it may affect other projects.

@llvmbot
Copy link
Collaborator

llvmbot commented Dec 2, 2016

Can you attach the cpio?

@llvmbot
Copy link
Collaborator

llvmbot commented Dec 2, 2016

testcase

@llvmbot
Copy link
Collaborator

llvmbot commented Dec 2, 2016

I can reproduce it. Debugging.

@emaste
Copy link
Member Author

emaste commented Dec 2, 2016

I have a patch in review to address part of what broke after r288107: https://reviews.freebsd.org/D8687 The code removed by that change has never been used as far as I can tell, and should probably be done differently if we want to bring the functionality back in FreeBSD anyhow.

However, we'd still need to change rtld to access _DYNAMIC not via the GOT.

@llvmbot
Copy link
Collaborator

llvmbot commented Dec 2, 2016

This reduces to just

cmpq $0, _DYNAMIC@GOTPCREL(%rip)

The old code was creating both a relocation with an addend and putting the value in the .got position. That is the same issue the loader had.

It is not a hard fix if we really have to do it. I will also take a quick look at musl to see how it handles that.

@llvmbot
Copy link
Collaborator

llvmbot commented Dec 2, 2016

It is not a hard fix if we really have to do it. I will also take a quick
look at musl to see how it handles that.

What musl does is to have a tiny bit of assembly in arch/x86_64/crt_arch.h that includes

lea _DYNAMIC(%rip),%rsi

which avoids needing relocations to find the value of _DYNAMIC.

Could freebsd do the same?

@emaste
Copy link
Member Author

emaste commented Dec 2, 2016

The old code was creating both a relocation with an addend and putting the
value in the .got position. That is the same issue the loader had.

Right, although rtld has been working for some time, while the loader hasn't. Did LLD previously store the value only in the rela addend for non-GOT relocations, but in both the addend and .got slot for GOT ones? Or it could be that there are multiple issues affecting the EFI loader.

It is not a hard fix if we really have to do it. I will also take a quick
look at musl to see how it handles that.

I'd rather FreeBSD not rely on it if there's no ABI requirement that it be populated, so I'd like to incorporate something like that. But I worry about the variety of other software that has less of an incentive to work with LLD.

@llvmbot
Copy link
Collaborator

llvmbot commented Dec 2, 2016

It is not a hard fix if we really have to do it. I will also take a quick
look at musl to see how it handles that.

What musl does is to have a tiny bit of assembly in arch/x86_64/crt_arch.h
that includes

lea _DYNAMIC(%rip),%rsi

which avoids needing relocations to find the value of _DYNAMIC.

Could freebsd do the same?

I fixed the Elf_Rel case in r288451. It should be trivial now to hack it to always write the addend if we really must.

@llvmbot
Copy link
Collaborator

llvmbot commented Dec 2, 2016

The old code was creating both a relocation with an addend and putting the
value in the .got position. That is the same issue the loader had.

Right, although rtld has been working for some time, while the loader
hasn't. Did LLD previously store the value only in the rela addend for
non-GOT relocations, but in both the addend and .got slot for GOT ones? Or
it could be that there are multiple issues affecting the EFI loader.

lld was writing the addend only in got entries before I think.

@emaste
Copy link
Member Author

emaste commented Dec 2, 2016

I fixed the Elf_Rel case in r288451. It should be trivial now to hack it to
always write the addend if we really must.

Thanks, rtld again works. I still intend to rework it to avoid relying on this if it's not an ABI requirement.

@emaste
Copy link
Member Author

emaste commented Dec 2, 2016

I think this can be resolved as of r288451 now that the GOT entries are populated?

The FreeBSD PR for this is https://bugs.freebsd.org/214972. I expect that I'll be able to use an approach like what musl does.

@llvmbot
Copy link
Collaborator

llvmbot commented Dec 3, 2016

Closing for now

@emaste
Copy link
Member Author

emaste commented Jan 15, 2017

Current versions of LLD are no longer writing the addend into the GOT entries. I've posted a FreeBSD rtld patch to handle this at https://reviews.freebsd.org/D9180.

@emaste
Copy link
Member Author

emaste commented Jan 16, 2017

FreeBSD rtld no longer relies on a populated GOT as of r312288
https://svnweb.freebsd.org/changeset/base/312288

@llvmbot
Copy link
Collaborator

llvmbot commented Jan 16, 2017

FreeBSD rtld no longer relies on a populated GOT as of r312288
https://svnweb.freebsd.org/changeset/base/312288

Thanks!

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 10, 2021
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla lld:ELF
Projects
None yet
Development

No branches or pull requests

2 participants