-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Invalid relocation in ubsan_signals_standalone.cpp on FreeBSD/aarch64 #63418
Invalid relocation in ubsan_signals_standalone.cpp on FreeBSD/aarch64 #63418
Comments
This failure was introduced by commit 74b0ac5. |
But it's using |
For changes see: https://discourse.llvm.org/t/llvm-17-0-0-rc2-released/72658 COMPILER_RT is currently disabled for aarch64 as it is broken due to llvm/llvm-project#63418. Hopefully a fix will be found before the full release or I'll attempt use a smaller hammer that only disables ubsan.
Is this something that still should be fixed for 17.x? |
Ideally, if it's still broken, but it's not clear from the error what's broken, because it doesn't make sense... |
Reproducible with |
The problem is a result of dodginess in the AArch64 assembler, shared with GNU as (either overfitting LLVM IAS to GNU as or both repeating the same mistake). The short summary is that:
will use a section symbol for the GOT relocations against sym if sym is a local symbol. But this doesn't work if the addend is non-zero when linking with LLD, and from skimming GNU ld I don't think it works there either. Rather than being G(GDAT(S+A)) (as specified by aaelf64, but differing from aaelf32 where it's GOT(S)+A-GOT) LLD gives G(GDAT(S))+A and so end up trying to offset from the GOT slot in question. Sometimes that happens to land you at a multiple of 8 (if the offset is), and you'll end up reading some garbage from wherever you happen to point, and sometimes that will not be a multiple of 8 (as seen here where the addend is 4) and give you a linker error. GNU ld instead seems to just ignore the addend in my testing. This situation seems like a complete mess in the AArch64 ABI; technically the assembler isn't at fault, since it's requesting something that the ABI says should work, but neither toolchain's linker implementation of that ABI does that. I'd be inclined to say that the AArch64 ABI should be amended to document the actual linker behaviour, possibly reserving a non-zero addend completely rather than specifying it as either behaviour (that way linkers can give an error on this kind of input), and altering both assemblers to not exploit this part of the ABI and instead always use actual symbols for GOT relocations. https://godbolt.org/z/Goh4farKf shows the relocation produced. For a simple test program to run and examine the linker behaviour compile the following as a PIE:
This models what's going on in compiler-rt, and shows that y's address is always the start of the section with GNU ld, but doesn't link with LLD, unless you make OFFSET a multiple of 8, at which point it reads garbage (for non-zero OFFSET). For example, binutils 2.41 on Debian sid as of today-ish gives:
whilst LLD 15.0.7 on FreeBSD 13.2-STABLE gives:
TL;DR: Everything is broken in different ways, nothing agrees and it all goes pear-shaped when symbol-declaring assembly is mixed with C. Someone from Arm needs to decide what they want to do about it. For compiler-rt, the workaround would be to make these symbols global or something that means the assembler can't turn them into being section-relative. Attempting to actually use this on Linux with GNU ld should be totally hosed, too, you just silently get a garbage binary out of GNU ld. |
Tagging @smithp35 for the broken ABI implementations and/or unintended spec |
@llvm/issue-subscribers-lld-elf |
@llvm/issue-subscribers-backend-aarch64 |
Ah, no, FreeBSD and NetBSD are uniquely affected because __ASM_WEAK_WRAPPER is a no-op there but expands to |
Indeed: diff --git a/compiler-rt/lib/interception/interception.h b/compiler-rt/lib/interception/interception.h
index 078d33b61..069f73d27 100644
--- a/compiler-rt/lib/interception/interception.h
+++ b/compiler-rt/lib/interception/interception.h
@@ -181,7 +181,7 @@ const interpose_substitution substitution_##func_name[] \
// FreeBSD's dynamic linker (incompliantly) gives non-weak symbols higher
// priority than weak ones so weak aliases won't work for indirect calls
// in position-independent (-fPIC / -fPIE) mode.
-# define __ASM_WEAK_WRAPPER(func)
+# define __ASM_WEAK_WRAPPER(func) ".globl " #func "\n"
# else
# define __ASM_WEAK_WRAPPER(func) ".weak " #func "\n"
# endif // SANITIZER_FREEBSD || SANITIZER_NETBSD works, and is probably the right thing to be doing anyway regardless of this toolchain/spec bug. |
@jrtc27 thanks for the tag. I've raised an ABI issue ARM-software/abi-aa#217 , feel free to add any additional comments/clarifications to that. It may be that this turns out to be a pair of toolchain bugs, but will need to discuss with the GNU folks to see what is possible in GNU ld. |
FreeBSD hasn't migrated to the compliant behavior (post glibc 2.2) Once it does, we can change
This change looks good to me. GNU assembler and LLVM integrated assembler don't convert a GOT generating relocation against non-local symbol to the section symbol.
Thanks for filing ARM-software/abi-aa#217 .
Then, the ABI difference largely doesn't affect the code above. In the integrated assembler, (
|
/cherry-pick 7e1afab |
/branch llvm/llvm-project-release-prs/issue63418 |
On FreeBSD and NetBSD we don't use .weak due to differing semantics. Currently we end up using no directive, which gives a local symbol, whereas the closer thing to a weak symbol would be a global one. In particular, both GNU and LLVM toolchains cannot handle a GOT-indirect reference to a local symbol at a non-zero offset within a section on AArch64 (see ARM-software/abi-aa#217), and so interceptors do not work on FreeBSD/arm64, failing to link with LLD. Switching to .globl both works around this bug and more closely aligns such non-weak platforms with weak ones. Fixes llvm/llvm-project#63418 Reviewed By: MaskRay Differential Revision: https://reviews.llvm.org/D158552 (cherry picked from commit 7e1afab1b1821550c5f8d0d6a50636236fa02e2c)
/pull-request llvm/llvm-project-release-prs#632 |
…relocations Assemblers change certain relocations referencing a local symbol to reference the section symbol instead. This conversion is disabled for many conditions (`shouldRelocateWithSymbol`), e.g. TLS symbol, for most targets (including AArch32, x86, PowerPC, and RISC-V) GOT-generating relocations. However, AArch64 encodes the GOT-generating intent in MCValue::RefKind instead of MCSymbolRef::Kind (see commit 0999cbd (2014)), therefore not affected by the code `case MCSymbolRefExpr::VK_GOT:`. Therefore, GOT relocations referencing two local symbols may share the same GOT entry after linking (GNU ld, ld.lld), which is not expected: ``` ldr x1, [x1, :got_lo12:x] // converted to .data+0 ldr x1, [x1, :got_lo12:y] // converted to .data+4 .data // .globl x, y would suppress STT_SECTION conversion x: .zero 4 y: .long 42 ``` This patch changes AArch64 to suppress local symbol to STT_SECTION conversion for GOT relocations, matching most other targets. x and y will use different GOT entries, which IMO is the most sensable behavior. With this change, the ABI decision on ARM-software/abi-aa#217 will only affect relocations explicitly referencing STT_SECTION symbols, e.g. ``` ldr x1, [x1, :got_lo12:(.data+0)] ldr x1, [x1, :got_lo12:(.data+4)] // I consider this unreasonable uses ``` IMO all reasonable use cases are unaffected. Link: llvm#63418 GNU assembler PR: https://sourceware.org/bugzilla/show_bug.cgi?id=30788 Differential Revision: https://reviews.llvm.org/D158577
On FreeBSD and NetBSD we don't use .weak due to differing semantics. Currently we end up using no directive, which gives a local symbol, whereas the closer thing to a weak symbol would be a global one. In particular, both GNU and LLVM toolchains cannot handle a GOT-indirect reference to a local symbol at a non-zero offset within a section on AArch64 (see ARM-software/abi-aa#217), and so interceptors do not work on FreeBSD/arm64, failing to link with LLD. Switching to .globl both works around this bug and more closely aligns such non-weak platforms with weak ones. Fixes llvm/llvm-project#63418 Reviewed By: MaskRay Differential Revision: https://reviews.llvm.org/D158552 (cherry picked from commit 7e1afab1b1821550c5f8d0d6a50636236fa02e2c)
…relocations Assemblers change certain relocations referencing a local symbol to reference the section symbol instead. This conversion is disabled for many conditions (`shouldRelocateWithSymbol`), e.g. TLS symbol, for most targets (including AArch32, x86, PowerPC, and RISC-V) GOT-generating relocations. However, AArch64 encodes the GOT-generating intent in MCValue::RefKind instead of MCSymbolRef::Kind (see commit 0999cbd (2014)), therefore not affected by the code `case MCSymbolRefExpr::VK_GOT:`. As GNU ld and ld.lld create GOT entries based on the symbol, ignoring addend, the two ldr instructions will share the same GOT entry, which is not expected: ``` ldr x1, [x1, :got_lo12:x] // converted to .data+0 ldr x1, [x1, :got_lo12:y] // converted to .data+4 .data // .globl x, y would suppress STT_SECTION conversion x: .zero 4 y: .long 42 ``` This patch changes AArch64 to suppress local symbol to STT_SECTION conversion for GOT relocations, matching most other targets. x and y will use different GOT entries, which IMO is the most sensable behavior. With this change, the ABI decision on ARM-software/abi-aa#217 will only affect relocations explicitly referencing STT_SECTION symbols, e.g. ``` ldr x1, [x1, :got_lo12:(.data+0)] ldr x1, [x1, :got_lo12:(.data+4)] // I consider this unreasonable uses ``` IMO all reasonable use cases are unaffected. Link: #63418 GNU assembler PR: https://sourceware.org/bugzilla/show_bug.cgi?id=30788 Reviewed By: peter.smith Differential Revision: https://reviews.llvm.org/D158577
On FreeBSD and NetBSD we don't use .weak due to differing semantics. Currently we end up using no directive, which gives a local symbol, whereas the closer thing to a weak symbol would be a global one. In particular, both GNU and LLVM toolchains cannot handle a GOT-indirect reference to a local symbol at a non-zero offset within a section on AArch64 (see ARM-software/abi-aa#217), and so interceptors do not work on FreeBSD/arm64, failing to link with LLD. Switching to .globl both works around this bug and more closely aligns such non-weak platforms with weak ones. Fixes llvm#63418 Reviewed By: MaskRay Differential Revision: https://reviews.llvm.org/D158552
On FreeBSD and NetBSD we don't use .weak due to differing semantics. Currently we end up using no directive, which gives a local symbol, whereas the closer thing to a weak symbol would be a global one. In particular, both GNU and LLVM toolchains cannot handle a GOT-indirect reference to a local symbol at a non-zero offset within a section on AArch64 (see ARM-software/abi-aa#217), and so interceptors do not work on FreeBSD/arm64, failing to link with LLD. Switching to .globl both works around this bug and more closely aligns such non-weak platforms with weak ones. Fixes llvm#63418 Reviewed By: MaskRay Differential Revision: https://reviews.llvm.org/D158552
On FreeBSD and NetBSD we don't use .weak due to differing semantics. Currently we end up using no directive, which gives a local symbol, whereas the closer thing to a weak symbol would be a global one. In particular, both GNU and LLVM toolchains cannot handle a GOT-indirect reference to a local symbol at a non-zero offset within a section on AArch64 (see ARM-software/abi-aa#217), and so interceptors do not work on FreeBSD/arm64, failing to link with LLD. Switching to .globl both works around this bug and more closely aligns such non-weak platforms with weak ones. Fixes llvm#63418 Reviewed By: MaskRay Differential Revision: https://reviews.llvm.org/D158552
On FreeBSD and NetBSD we don't use .weak due to differing semantics. Currently we end up using no directive, which gives a local symbol, whereas the closer thing to a weak symbol would be a global one. In particular, both GNU and LLVM toolchains cannot handle a GOT-indirect reference to a local symbol at a non-zero offset within a section on AArch64 (see ARM-software/abi-aa#217), and so interceptors do not work on FreeBSD/arm64, failing to link with LLD. Switching to .globl both works around this bug and more closely aligns such non-weak platforms with weak ones. Fixes llvm#63418 Reviewed By: MaskRay Differential Revision: https://reviews.llvm.org/D158552
On FreeBSD and NetBSD we don't use .weak due to differing semantics. Currently we end up using no directive, which gives a local symbol, whereas the closer thing to a weak symbol would be a global one. In particular, both GNU and LLVM toolchains cannot handle a GOT-indirect reference to a local symbol at a non-zero offset within a section on AArch64 (see ARM-software/abi-aa#217), and so interceptors do not work on FreeBSD/arm64, failing to link with LLD. Switching to .globl both works around this bug and more closely aligns such non-weak platforms with weak ones. Fixes llvm#63418 Reviewed By: MaskRay Differential Revision: https://reviews.llvm.org/D158552
On FreeBSD and NetBSD we don't use .weak due to differing semantics. Currently we end up using no directive, which gives a local symbol, whereas the closer thing to a weak symbol would be a global one. In particular, both GNU and LLVM toolchains cannot handle a GOT-indirect reference to a local symbol at a non-zero offset within a section on AArch64 (see ARM-software/abi-aa#217), and so interceptors do not work on FreeBSD/arm64, failing to link with LLD. Switching to .globl both works around this bug and more closely aligns such non-weak platforms with weak ones. Fixes llvm#63418 Reviewed By: MaskRay Differential Revision: https://reviews.llvm.org/D158552
On FreeBSD and NetBSD we don't use .weak due to differing semantics. Currently we end up using no directive, which gives a local symbol, whereas the closer thing to a weak symbol would be a global one. In particular, both GNU and LLVM toolchains cannot handle a GOT-indirect reference to a local symbol at a non-zero offset within a section on AArch64 (see ARM-software/abi-aa#217), and so interceptors do not work on FreeBSD/arm64, failing to link with LLD. Switching to .globl both works around this bug and more closely aligns such non-weak platforms with weak ones. Fixes llvm#63418 Reviewed By: MaskRay Differential Revision: https://reviews.llvm.org/D158552
My build of LLVM main on FreeBSD AArch64 fails:
The problem is apparently this line of assembly:
This is an 8 byte load and the relocation expects it to be aligned to 8 bytes. Earlier in the file I see in the
.text
segmentThere is no explicit alignment and the function happens to land at an odd multiple of 4 bytes.
Compile the attached file with
ubsan_signals_standalone.txt
The text was updated successfully, but these errors were encountered: