You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[ELF][AArch64][PAC] Weak undefined symbols treated as symbol with value 0 and signed #173296
For a relocation that involves signing a pointer, if the target symbol is an undefined weak reference, the result of the relocation is 0 (nullptr) regardless of the signing schema.
However, this is not what's implemented. isStaticLinkTimeConstant has an early false return for RE_AARCH64_AUTH that ignores this case, and so will treat it like a defined non-preemptible symbol, emitting R_AARCH64_AUTH_RELATIVE with an addend of the symbol's VA (+ original addend), 0. See this failing test (FileCheck assertions derived from the output when dropping the @AUTH(da,42), which is what the output should be the same as):
We have a similar case in CHERI LLVM for capabilities, as those need run-time initialisation like PAuth signing, and use the following instead:
if (e == R_ABS_CAP)
return !sym.isPreemptible && sym.isUndefWeak();
However, we're currently based on an older version of LLD, and there's been a little refactoring here (we predate moving !config->isPic && sym.isUndefWeak() from processAux into isStaticLinkTimeConstant), so that might not be quite the right change, and AArch64::relocate will need to know to write the full 64 bits to zero out the signing schema from the input (or replace it with the upper bits of the addend, especially if negative), so that's insufficient.
> For a relocation that involves signing a pointer, if the target symbol is an undefined weak reference, the result of the relocation is 0 (nullptr) regardless of the signing schema.
However, this is not what's implemented. isStaticLinkTimeConstant has an early false return for RE_AARCH64_AUTH that ignores this case, and so will treat it like a defined non-preemptible symbol, emitting R_AARCH64_AUTH_RELATIVE with an addend of the symbol's VA (+ original addend), 0. See this failing test (FileCheck assertions derived from the output when dropping the @<!-- -->AUTH(da,42), which is what the output should be the same as):
We have a similar case in CHERI LLVM for capabilities, as those need run-time initialisation like PAuth signing, and use the following instead:
if (e == R_ABS_CAP)
return !sym.isPreemptible && sym.isUndefWeak();
However, we're currently based on an older version of LLD, and there's been a little refactoring here (we predate moving !config->isPic && sym.isUndefWeak() from processAux into isStaticLinkTimeConstant), so that might not be quite the right change, and AArch64::relocate will need to know to write the full 64 bits to zero out the signing schema from the input (or replace it with the upper bits of the addend, especially if negative), so that's insufficient.
@jrtc27 Thanks for your issue report and interest to PAuth! I see that the reproducer you've provided tests static linking. While the documentation has a section regarding static linking, it only provides a high-level view of how this could be implemented: https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#static-linking. And I'm not aware of anyone using that - it requires additional runtime support, which does not seem to be implemented by anyone.
We've never actually tested that static linking works as expected for AUTH relocs at all (and I'm kinda surprised if this was working as expected for other cases with non-undef-weak symbols).
@asl Would it make sense to just explicitly unsupport (e.g. emit an error message) static linking (at least as for now) if we have AUTH relocs? It would at least be less misleading because right now I suppose that we just get invalid binaries which make no sense (and unless runtime support for AUTH relocs in static binaries is present, there is no reason to use static linking with PAuth).
Also, I wonder if we have any test cases for dynamic linking which violate the rule mentioned in the issue description:
For a relocation that involves signing a pointer, if the target symbol is an undefined weak reference, the result of the relocation is 0 (nullptr) regardless of the signing schema.
As far as I remember, when we have an undefined weak symbol and an AUTH reloc against that, we end up with a dynamic relocation against this symbol. This seems to work properly given that we have our own runtime pauth-testsuite involving tests with undef weak symbols and we also run regular llvm-test-suite which I believe should also include smth like that.
@jrtc27 Were you facing similar issues with dynamic linking? If yes, could you please provide a reproducer for that as well? If no, could you please tell if this is "no, we were testing smth with dynamic linking and everything was OK" or "no, we were not testing dynamic linking at all"? Thanks in advance for your collaboration!
I think currently it is indeed reasonable to explicitly error out on static linking when pauth is involved. If any downstream platform would rely on it, then likely some private changes wrt emission of pauth relocs would be needed in any case
No, it's not specific to static linking, I just wrote the test using that because it's the simplest to think about. Here's the same test tweaked to use a PIE:
@asl Would it make sense to just explicitly unsupport (e.g. emit an error message) static linking (at least as for now) if we have AUTH relocs? It would at least be less misleading because right now I suppose that we just get invalid binaries which make no sense (and unless runtime support for AUTH relocs in static binaries is present, there is no reason to use static linking with PAuth).
As far as I can tell static linking is generally fine, the dynamic relocs end up in .rela.dyn and encapsulated by __rel[a]_iplt_start/end just like IRELATIVE relocations (and how static PIE works for platforms that support that). Your runtime may not support that, but I don't see any reason why a runtime that did wouldn't work. That is, I don't see anything making the binaries "invalid", they look how I'd expect them to.
Were you facing similar issues with dynamic linking? If yes, could you please provide a reproducer for that as well? If no, could you please tell if this is "no, we were testing smth with dynamic linking and everything was OK" or "no, we were not testing dynamic linking at all"? Thanks in advance for your collaboration!
Just to be clear, I'm not actually using PAuth in any way. I have just been working to clean up upstream LLD in various ways, in particular around relative relocation handling, as I've spent a lot of time thinking about and refining our implementation downstream for CHERI/Morello, and there's a lot of overlap conceptually, so I've been aligning the two. My experience also means that, as I've been reading and refactoring the upstream code, ways to break it have popped into my head (sometimes aligned with bugs we've had in the past that I've fixed), and I've either submitted fixes for them or filed issues. So I don't actually care about PAuth specifically, but it's convenient that what it needs LLD to do overlaps with CHERI in some respects.
@jrtc27 Thanks for additional test cases and for investing your time into this (especially given that pauth is not your main field of interest)! I'll dive into this deeper and report the results.
@jrtc27 Sorry for a delay, @smithp35 thanks for updating the docs!
I've prepared a draft PR which partially resolves the issue #194636, but we still have an unresolved case with AUTH TLSDESC for undefined weak non-preemptible symbols.
As discussed on the previous PAuth meeting, it would be nice to allow link-time relaxation for such cases. See the following ticket for details: ARM-software/abi-aa#393. I would be happy to discuss any details regarding that.
I suppose that it's worth making such a relaxation mandatory in lld, since similar non-auth relaxations are already mandatory.
So, as soon as we have a clear understanding of how things would look like in the docs, I'll submit a PR against AArch64 AsmPrinter (LLVM) and update the PR #194636 correspondingly.
For the slightly more general case, absolute symbols are also mis-handled (something we accidentally missed for CHERI until last week1...); for both data and GOT auth relocations they will end up with relative relocations, which is rather unhelpful when you want an absolute address. In CHERI land we made them behave the same as undef weak, i.e. link-time constants that look like you cast a plain integer to a pointer, which would translate to an unsigned integer value for PAuth. That may not be what makes most sense for you, though, in which case I guess you'd have to translate them to AUTH_ABS64 relocations against a null symbol instead as a special PAuth-specific class of handling? Test below that demonstrates the wrong behaviour, adapted from the PIE test in #194636 (notably, drops the TLSDESC case; absolute+TLS is just so utterly nonsensical I don't even want to think about how you might interpret it in some twisted manner that makes any semblance of being valid input):
Activity
jrtc27 commentedon Dec 22, 2025
Cc @asl @kovdan01
llvmbot commentedon Dec 22, 2025
@llvm/issue-subscribers-lld-elf
Author: Jessica Clarke (jrtc27)
Details
The PAuthABI spec says the following:> For a relocation that involves signing a pointer, if the target symbol is an undefined weak reference, the result of the relocation is 0 (nullptr) regardless of the signing schema.
However, this is not what's implemented. isStaticLinkTimeConstant has an early false return for RE_AARCH64_AUTH that ignores this case, and so will treat it like a defined non-preemptible symbol, emitting R_AARCH64_AUTH_RELATIVE with an addend of the symbol's VA (+ original addend), 0. See this failing test (FileCheck assertions derived from the output when dropping the
@<!-- -->AUTH(da,42), which is what the output should be the same as):We have a similar case in CHERI LLVM for capabilities, as those need run-time initialisation like PAuth signing, and use the following instead:
However, we're currently based on an older version of LLD, and there's been a little refactoring here (we predate moving
!config->isPic && sym.isUndefWeak()from processAux into isStaticLinkTimeConstant), so that might not be quite the right change, and AArch64::relocate will need to know to write the full 64 bits to zero out the signing schema from the input (or replace it with the upper bits of the addend, especially if negative), so that's insufficient.asl commentedon Dec 22, 2025
Also tagging @atrosinenko
kovdan01 commentedon Dec 23, 2025
@jrtc27 Thanks for your issue report and interest to PAuth! I see that the reproducer you've provided tests static linking. While the documentation has a section regarding static linking, it only provides a high-level view of how this could be implemented: https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#static-linking. And I'm not aware of anyone using that - it requires additional runtime support, which does not seem to be implemented by anyone.
We've never actually tested that static linking works as expected for AUTH relocs at all (and I'm kinda surprised if this was working as expected for other cases with non-undef-weak symbols).
@asl Would it make sense to just explicitly unsupport (e.g. emit an error message) static linking (at least as for now) if we have AUTH relocs? It would at least be less misleading because right now I suppose that we just get invalid binaries which make no sense (and unless runtime support for AUTH relocs in static binaries is present, there is no reason to use static linking with PAuth).
Also, I wonder if we have any test cases for dynamic linking which violate the rule mentioned in the issue description:
As far as I remember, when we have an undefined weak symbol and an AUTH reloc against that, we end up with a dynamic relocation against this symbol. This seems to work properly given that we have our own runtime pauth-testsuite involving tests with undef weak symbols and we also run regular llvm-test-suite which I believe should also include smth like that.
@jrtc27 Were you facing similar issues with dynamic linking? If yes, could you please provide a reproducer for that as well? If no, could you please tell if this is "no, we were testing smth with dynamic linking and everything was OK" or "no, we were not testing dynamic linking at all"? Thanks in advance for your collaboration!
asl commentedon Dec 23, 2025
I think currently it is indeed reasonable to explicitly error out on static linking when pauth is involved. If any downstream platform would rely on it, then likely some private changes wrt emission of pauth relocs would be needed in any case
jrtc27 commentedon Dec 23, 2025
No, it's not specific to static linking, I just wrote the test using that because it's the simplest to think about. Here's the same test tweaked to use a PIE:
Or for a DSO (need to try a bit harder to make symbols non-preemptible):
jrtc27 commentedon Dec 23, 2025
As far as I can tell static linking is generally fine, the dynamic relocs end up in .rela.dyn and encapsulated by __rel[a]_iplt_start/end just like IRELATIVE relocations (and how static PIE works for platforms that support that). Your runtime may not support that, but I don't see any reason why a runtime that did wouldn't work. That is, I don't see anything making the binaries "invalid", they look how I'd expect them to.
jrtc27 commentedon Dec 23, 2025
Just to be clear, I'm not actually using PAuth in any way. I have just been working to clean up upstream LLD in various ways, in particular around relative relocation handling, as I've spent a lot of time thinking about and refining our implementation downstream for CHERI/Morello, and there's a lot of overlap conceptually, so I've been aligning the two. My experience also means that, as I've been reading and refactoring the upstream code, ways to break it have popped into my head (sometimes aligned with bugs we've had in the past that I've fixed), and I've either submitted fixes for them or filed issues. So I don't actually care about PAuth specifically, but it's convenient that what it needs LLD to do overlaps with CHERI in some respects.
kovdan01 commentedon Dec 24, 2025
@jrtc27 Thanks for additional test cases and for investing your time into this (especially given that pauth is not your main field of interest)! I'll dive into this deeper and report the results.
jrtc27 commentedon Feb 1, 2026
NB this also applies to GOT entries, which follow a separate path (and would be easier to fix since there isn't a signing schema to replace).
PDE test:
PIE test:
DSO test:
kovdan01 commentedon Feb 5, 2026
Thanks @jrtc27 for providing additional context! I'll try to allocate some time to look into this during the next week
16 remaining items
kovdan01 commentedon May 11, 2026
@jrtc27 Sorry for a delay, @smithp35 thanks for updating the docs!
I've prepared a draft PR which partially resolves the issue #194636, but we still have an unresolved case with AUTH TLSDESC for undefined weak non-preemptible symbols.
As discussed on the previous PAuth meeting, it would be nice to allow link-time relaxation for such cases. See the following ticket for details: ARM-software/abi-aa#393. I would be happy to discuss any details regarding that.
I suppose that it's worth making such a relaxation mandatory in lld, since similar non-auth relaxations are already mandatory.
So, as soon as we have a clear understanding of how things would look like in the docs, I'll submit a PR against AArch64 AsmPrinter (LLVM) and update the PR #194636 correspondingly.
[PAC][lld] Do not emit AUTH relocs against undef weak non-preemptible…
[PAC][lld] Do not emit AUTH relocs against undef weak non-preemptible…
kovdan01 commentedon May 18, 2026
JFYI: I've updated the lld PR #194636 to use the
R_AARCH64_AUTH_TLSDESC_CALLintroduced in ARM-software/abi-aa#395.I've also submitted #198327 implementing backend support for that. The lld PR it dependent on it.
[PAC][lld] Do not emit AUTH relocs against undef weak non-preemptible…
[PAC][lld] Do not emit AUTH relocs against undef weak non-preemptible…
jrtc27 commentedon Jun 3, 2026
For the slightly more general case, absolute symbols are also mis-handled (something we accidentally missed for CHERI until last week1...); for both data and GOT auth relocations they will end up with relative relocations, which is rather unhelpful when you want an absolute address. In CHERI land we made them behave the same as undef weak, i.e. link-time constants that look like you cast a plain integer to a pointer, which would translate to an unsigned integer value for PAuth. That may not be what makes most sense for you, though, in which case I guess you'd have to translate them to AUTH_ABS64 relocations against a null symbol instead as a special PAuth-specific class of handling? Test below that demonstrates the wrong behaviour, adapted from the PIE test in #194636 (notably, drops the TLSDESC case; absolute+TLS is just so utterly nonsensical I don't even want to think about how you might interpret it in some twisted manner that makes any semblance of being valid input):
Footnotes
https://github.com/CTSRD-CHERI/llvm-project/commit/71fefccdd45ed34b1f010809c0ed383add556fae#diff-7bda54aace526c7e883a5e1c34446b3ffca171b50a4340a8795ef0ecc0d1f291 if interested, though the actual code change is not very exciting ↩
[PAC][lld] Do not emit AUTH relocs against undef weak non-preemptible…
[PAC][lld] Do not emit AUTH relocs against undef weak non-preemptible…
[PAC][lld] Do not emit AUTH relocs against undef weak non-preemptible…
[PAC][lld] Do not emit AUTH relocs against undef weak non-preemptible…
[PAC][lld] Do not emit AUTH relocs against undef weak non-preemptible…
[PAC][lld] Do not emit AUTH relocs against undef weak non-preemptible…
[PAC][lld] Do not emit AUTH relocs against undef weak non-preemptible…