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

[ELF] Don't resolve relocations referencing SHN_ABS to tombstone in non-SHF_ALLOC sections #79238

Conversation

MaskRay
Copy link
Member

@MaskRay MaskRay commented Jan 24, 2024

A SHN_ABS symbol has never been considered for InputSection::relocateNonAlloc.
Before #74686, the code did made it work in the absence of -z dead-reloc-in-nonalloc=.
There is now a report about such SHN_ABS uses
(#74686 (comment))
and I think it makes sense for non-SHF_ALLOC to support SHN_ABS, like
SHF_ALLOC sections do.

// clang -g
__attribute__((weak)) int symbol;
int *foo() { return &symbol; }

0x00000023:   DW_TAG_variable [2]   (0x0000000c)
                ...
                DW_AT_location [DW_FORM_exprloc]        (DW_OP_addrx 0x0)

.debug_addr references symbol, which can be redefined by a symbol
assignment or --defsym to become a SHN_ABS symbol.

The problem is that !sym.getOutputSection() cannot discern SHN_ABS
from a symbol whose section has been discarded. Since commit
1981b1b, a symbol relative to a
discarded section is changed to Undefined, so the SHN_ABS check
become trivial.

We currently apply tombstone for a relocation referencing
SharedSymbol. This patch does not change the behavior.

Created using spr 1.3.4
@llvmbot
Copy link
Collaborator

llvmbot commented Jan 24, 2024

@llvm/pr-subscribers-lld-elf

@llvm/pr-subscribers-lld

Author: Fangrui Song (MaskRay)

Changes

A SHN_ABS symbol has never been considered for InputSection::relocateNonAlloc.
Before #74686, the code did made it work in the absence of -z dead-reloc-in-nonalloc=.
There is now a report about such SHN_AVS uses
(#74686 (comment))
and I think it makes sense for non-SHF_ALLOC to support SHN_ABS, like
SHF_ALLOC sections do.

The problem is that !sym.getOutputSection() cannot discern SHN_ABS
from a symbol whose section has been discarded. Since commit
1981b1b, a symbol relative to a
discarded section is changed to Undefined, so the SHN_ABS check
become trivial.

We currently apply tombstone for a relocation referencing
SharedSymbol. This patch does not change the behavior.


Full diff: https://github.com/llvm/llvm-project/pull/79238.diff

2 Files Affected:

  • (modified) lld/ELF/InputSection.cpp (+6-7)
  • (modified) lld/test/ELF/dead-reloc-in-nonalloc.s (+1-1)
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index c728dd6c6306aa0..0e0b9783bd88a0f 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -961,12 +961,11 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
       // vector. The computed value is st_value plus a non-negative offset.
       // Negative values are invalid, so -1 can be used as the tombstone value.
       //
-      // If the referenced symbol is discarded (made Undefined), or the
-      // section defining the referenced symbol is garbage collected,
-      // sym.getOutputSection() is nullptr. `ds->folded` catches the ICF folded
-      // case. However, resolving a relocation in .debug_line to -1 would stop
-      // debugger users from setting breakpoints on the folded-in function, so
-      // exclude .debug_line.
+      // If the referenced symbol is relative to a discarded section (due to
+      // --gc-sections, COMDAT, etc), it has been converted to a Undefined.
+      // `ds->folded` catches the ICF folded case. However, resolving a
+      // relocation in .debug_line to -1 would stop debugger users from setting
+      // breakpoints on the folded-in function, so exclude .debug_line.
       //
       // For pre-DWARF-v5 .debug_loc and .debug_ranges, -1 is a reserved value
       // (base address selection entry), use 1 (which is used by GNU ld for
@@ -974,7 +973,7 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
       //
       // TODO To reduce disruption, we use 0 instead of -1 as the tombstone
       // value. Enable -1 in a future release.
-      if (!sym.getOutputSection() || (ds && ds->folded && !isDebugLine)) {
+      if (!ds || (ds->folded && !isDebugLine)) {
         // If -z dead-reloc-in-nonalloc= is specified, respect it.
         uint64_t value = SignExtend64<bits>(*tombstone);
         // For a 32-bit local TU reference in .debug_names, X86_64::relocate
diff --git a/lld/test/ELF/dead-reloc-in-nonalloc.s b/lld/test/ELF/dead-reloc-in-nonalloc.s
index 145604eb883a9af..b675fc50fc2ea2f 100644
--- a/lld/test/ELF/dead-reloc-in-nonalloc.s
+++ b/lld/test/ELF/dead-reloc-in-nonalloc.s
@@ -17,7 +17,7 @@
 # AA:          Contents of section .debug_info:
 # AA-NEXT:      0000 [[ADDR]] 00000000 aaaaaaaa 00000000
 # AA:          Contents of section .not_debug:
-# AA-NEXT:      0000 bbbbbbbb bbbbbbbb 00000000          .
+# AA-NEXT:      0000 bbbbbbbb 2a000000 00000000          .
 
 ## Specifying zero can get a behavior similar to GNU ld.
 # RUN: ld.lld --icf=all -z dead-reloc-in-nonalloc=.debug_info=0 %t.o %tabs.o -o %tzero

@bevin-hansson
Copy link
Contributor

This patch resolves the issue we have. I posted an example of the kind of code that triggers it in the previous PR.

@MaskRay
Copy link
Member Author

MaskRay commented Jan 24, 2024

This patch resolves the issue we have. I posted an example of the kind of code that triggers it in the previous PR.

Thanks for verification. Do you have more information about SHN_ABS in debug sections? Ideally you can share a reproduce tarball (ld.lld --reproduce=rep.tar) after minimization.

edit: figured out. added to the description.

Created using spr 1.3.4
Copy link
Contributor

@bevin-hansson bevin-hansson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me, but someone else should probably chime in as well to approve.

Copy link
Collaborator

@smithp35 smithp35 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code changes LGTM too. I can't think of a case when a C/C++ compiler would directly generate a reference to an SHN_ABS symbol as I don't think there is a way of expressing such a symbol in C/C++ and debug generation concentrates on describing entities in the same module. I've asked a colleague that knows more about debug generation than I do. If I get an answer I'll post another comment.

There is a typo in the description (SHN_ANS) -> (SHN_ABS)

Created using spr 1.3.4
@MaskRay
Copy link
Member Author

MaskRay commented Jan 24, 2024

Fixed a typo and added an example

// clang -g
__attribute__((weak)) int symbol;
int *foo() { return &symbol; }

0x00000023:   DW_TAG_variable [2]   (0x0000000c)
                ...
                DW_AT_location [DW_FORM_exprloc]        (DW_OP_addrx 0x0)

.debug_addr references symbol, which can be redefined by a symbol
assignment or --defsym to become a SHN_ABS symbol.

@MaskRay MaskRay merged commit 8abf8d1 into main Jan 24, 2024
3 of 4 checks passed
@MaskRay MaskRay deleted the users/MaskRay/spr/elf-dont-resolve-relocations-referencing-shn_abs-to-tombstone-in-non-shf_alloc-sections branch January 24, 2024 16:53
@ayermolo
Copy link
Contributor

Hmm, interesting. Thanks for the fix.

llvmbot pushed a commit to llvmbot/llvm-project that referenced this pull request Jan 24, 2024
…on-SHF_ALLOC sections (llvm#79238)

A SHN_ABS symbol has never been considered for
InputSection::relocateNonAlloc.
Before llvm#74686, the code did made it work in the absence of `-z
dead-reloc-in-nonalloc=`.
There is now a report about such SHN_ABS uses

(llvm#74686 (comment))
and I think it makes sense for non-SHF_ALLOC to support SHN_ABS, like
SHF_ALLOC sections do.

```
// clang -g
__attribute__((weak)) int symbol;
int *foo() { return &symbol; }

0x00000023:   DW_TAG_variable [2]   (0x0000000c)
                ...
                DW_AT_location [DW_FORM_exprloc]        (DW_OP_addrx 0x0)

```

.debug_addr references `symbol`, which can be redefined by a symbol
assignment or --defsym to become a SHN_ABS symbol.

The problem is that `!sym.getOutputSection()` cannot discern SHN_ABS
from a symbol whose section has been discarded. Since commit
1981b1b, a symbol relative to a
discarded section is changed to `Undefined`, so the `SHN_ABS` check
become trivial.

We currently apply tombstone for a relocation referencing
`SharedSymbol`. This patch does not change the behavior.

(cherry picked from commit 8abf8d1)
tstellar pushed a commit that referenced this pull request Jan 26, 2024
…on-SHF_ALLOC sections (#79238)

A SHN_ABS symbol has never been considered for
InputSection::relocateNonAlloc.
Before #74686, the code did made it work in the absence of `-z
dead-reloc-in-nonalloc=`.
There is now a report about such SHN_ABS uses

(#74686 (comment))
and I think it makes sense for non-SHF_ALLOC to support SHN_ABS, like
SHF_ALLOC sections do.

```
// clang -g
__attribute__((weak)) int symbol;
int *foo() { return &symbol; }

0x00000023:   DW_TAG_variable [2]   (0x0000000c)
                ...
                DW_AT_location [DW_FORM_exprloc]        (DW_OP_addrx 0x0)

```

.debug_addr references `symbol`, which can be redefined by a symbol
assignment or --defsym to become a SHN_ABS symbol.

The problem is that `!sym.getOutputSection()` cannot discern SHN_ABS
from a symbol whose section has been discarded. Since commit
1981b1b, a symbol relative to a
discarded section is changed to `Undefined`, so the `SHN_ABS` check
become trivial.

We currently apply tombstone for a relocation referencing
`SharedSymbol`. This patch does not change the behavior.

(cherry picked from commit 8abf8d1)
tstellar pushed a commit to tstellar/llvm-project that referenced this pull request Feb 14, 2024
…on-SHF_ALLOC sections (llvm#79238)

A SHN_ABS symbol has never been considered for
InputSection::relocateNonAlloc.
Before llvm#74686, the code did made it work in the absence of `-z
dead-reloc-in-nonalloc=`.
There is now a report about such SHN_ABS uses

(llvm#74686 (comment))
and I think it makes sense for non-SHF_ALLOC to support SHN_ABS, like
SHF_ALLOC sections do.

```
// clang -g
__attribute__((weak)) int symbol;
int *foo() { return &symbol; }

0x00000023:   DW_TAG_variable [2]   (0x0000000c)
                ...
                DW_AT_location [DW_FORM_exprloc]        (DW_OP_addrx 0x0)

```

.debug_addr references `symbol`, which can be redefined by a symbol
assignment or --defsym to become a SHN_ABS symbol.

The problem is that `!sym.getOutputSection()` cannot discern SHN_ABS
from a symbol whose section has been discarded. Since commit
1981b1b, a symbol relative to a
discarded section is changed to `Undefined`, so the `SHN_ABS` check
become trivial.

We currently apply tombstone for a relocation referencing
`SharedSymbol`. This patch does not change the behavior.

(cherry picked from commit 8abf8d1)
tstellar pushed a commit to tstellar/llvm-project that referenced this pull request Feb 14, 2024
…on-SHF_ALLOC sections (llvm#79238)

A SHN_ABS symbol has never been considered for
InputSection::relocateNonAlloc.
Before llvm#74686, the code did made it work in the absence of `-z
dead-reloc-in-nonalloc=`.
There is now a report about such SHN_ABS uses

(llvm#74686 (comment))
and I think it makes sense for non-SHF_ALLOC to support SHN_ABS, like
SHF_ALLOC sections do.

```
// clang -g
__attribute__((weak)) int symbol;
int *foo() { return &symbol; }

0x00000023:   DW_TAG_variable [2]   (0x0000000c)
                ...
                DW_AT_location [DW_FORM_exprloc]        (DW_OP_addrx 0x0)

```

.debug_addr references `symbol`, which can be redefined by a symbol
assignment or --defsym to become a SHN_ABS symbol.

The problem is that `!sym.getOutputSection()` cannot discern SHN_ABS
from a symbol whose section has been discarded. Since commit
1981b1b, a symbol relative to a
discarded section is changed to `Undefined`, so the `SHN_ABS` check
become trivial.

We currently apply tombstone for a relocation referencing
`SharedSymbol`. This patch does not change the behavior.

(cherry picked from commit 8abf8d1)
tstellar pushed a commit to tstellar/llvm-project that referenced this pull request Feb 14, 2024
…on-SHF_ALLOC sections (llvm#79238)

A SHN_ABS symbol has never been considered for
InputSection::relocateNonAlloc.
Before llvm#74686, the code did made it work in the absence of `-z
dead-reloc-in-nonalloc=`.
There is now a report about such SHN_ABS uses

(llvm#74686 (comment))
and I think it makes sense for non-SHF_ALLOC to support SHN_ABS, like
SHF_ALLOC sections do.

```
// clang -g
__attribute__((weak)) int symbol;
int *foo() { return &symbol; }

0x00000023:   DW_TAG_variable [2]   (0x0000000c)
                ...
                DW_AT_location [DW_FORM_exprloc]        (DW_OP_addrx 0x0)

```

.debug_addr references `symbol`, which can be redefined by a symbol
assignment or --defsym to become a SHN_ABS symbol.

The problem is that `!sym.getOutputSection()` cannot discern SHN_ABS
from a symbol whose section has been discarded. Since commit
1981b1b, a symbol relative to a
discarded section is changed to `Undefined`, so the `SHN_ABS` check
become trivial.

We currently apply tombstone for a relocation referencing
`SharedSymbol`. This patch does not change the behavior.

(cherry picked from commit 8abf8d1)
tstellar pushed a commit to tstellar/llvm-project that referenced this pull request Feb 14, 2024
…on-SHF_ALLOC sections (llvm#79238)

A SHN_ABS symbol has never been considered for
InputSection::relocateNonAlloc.
Before llvm#74686, the code did made it work in the absence of `-z
dead-reloc-in-nonalloc=`.
There is now a report about such SHN_ABS uses

(llvm#74686 (comment))
and I think it makes sense for non-SHF_ALLOC to support SHN_ABS, like
SHF_ALLOC sections do.

```
// clang -g
__attribute__((weak)) int symbol;
int *foo() { return &symbol; }

0x00000023:   DW_TAG_variable [2]   (0x0000000c)
                ...
                DW_AT_location [DW_FORM_exprloc]        (DW_OP_addrx 0x0)

```

.debug_addr references `symbol`, which can be redefined by a symbol
assignment or --defsym to become a SHN_ABS symbol.

The problem is that `!sym.getOutputSection()` cannot discern SHN_ABS
from a symbol whose section has been discarded. Since commit
1981b1b, a symbol relative to a
discarded section is changed to `Undefined`, so the `SHN_ABS` check
become trivial.

We currently apply tombstone for a relocation referencing
`SharedSymbol`. This patch does not change the behavior.

(cherry picked from commit 8abf8d1)
@ayermolo
Copy link
Contributor

@MaskRay Is there an equivalent check that can be done before 1981b1b?

@MaskRay
Copy link
Member Author

MaskRay commented Feb 29, 2024

@MaskRay Is there an equivalent check that can be done before 1981b1b?

Do you want to cherry pick #74686 and this follow-up #79238 with an older code base like lld 17?
I believe it's difficult before 1981b1b . I personally would not try doing that...

You can consider cherry picking 1981b1b as well, but there are multiple follow-up commits.

Note, if your llvm is locked into a certain version, it should be quite straightforward to sync just lld/ to the trunk version, and ninja lld will likely still compile (if not it'd be straightforward to fix). I've locally done this to check the performance improvement of lld across several llvm releases.

@ayermolo
Copy link
Contributor

@MaskRay Is there an equivalent check that can be done before 1981b1b?

Do you want to cherry pick #74686 and this follow-up #79238 with an older code base like lld 17? I believe it's difficult before 1981b1b . I personally would not try doing that...

You can consider cherry picking 1981b1b as well, but there are multiple follow-up commits.

Note, if you llvm locked into a certain version, it should be quite straightforward to sync just lld/ to the trunk version, and ninja lld will likely still compile (if not it'd be straightforward to fix).

It's even worse I am trying to cherry pick #74686 and #79238 onto llvm-15 (although llvm-17 is next).

I looked into cherry picking 1981b1b, but it touches a lot of code that is not even in llvm-15. Thus I was wondering if check is possible some other way.

So without this LLD will tombstone some addresses in a .debug section OR if dead-reloc-in-nonalloc is specified, correct?

@MaskRay
Copy link
Member Author

MaskRay commented Feb 29, 2024

@MaskRay Is there an equivalent check that can be done before 1981b1b?

Do you want to cherry pick #74686 and this follow-up #79238 with an older code base like lld 17? I believe it's difficult before 1981b1b . I personally would not try doing that...
You can consider cherry picking 1981b1b as well, but there are multiple follow-up commits.
Note, if you llvm locked into a certain version, it should be quite straightforward to sync just lld/ to the trunk version, and ninja lld will likely still compile (if not it'd be straightforward to fix).

It's even worse I am trying to cherry pick #74686 and #79238 onto llvm-15 (although llvm-17 is next).

I looked into cherry picking 1981b1b, but it touches a lot of code that is not even in llvm-15. Thus I was wondering if check is possible some other way.

So without this LLD will tombstone some addresses in a .debug section OR if dead-reloc-in-nonalloc is specified, correct?

Without checking 1981b1b , you can check a SHN_ABS symbol with something like !cast<Defined>(sym).section. I haven't tested the use in relocateNonAlloc, though.

@ayermolo
Copy link
Contributor

ayermolo commented Feb 29, 2024

@MaskRay Is there an equivalent check that can be done before 1981b1b?

Do you want to cherry pick #74686 and this follow-up #79238 with an older code base like lld 17? I believe it's difficult before 1981b1b . I personally would not try doing that...
You can consider cherry picking 1981b1b as well, but there are multiple follow-up commits.
Note, if you llvm locked into a certain version, it should be quite straightforward to sync just lld/ to the trunk version, and ninja lld will likely still compile (if not it'd be straightforward to fix).

It's even worse I am trying to cherry pick #74686 and #79238 onto llvm-15 (although llvm-17 is next).
I looked into cherry picking 1981b1b, but it touches a lot of code that is not even in llvm-15. Thus I was wondering if check is possible some other way.
So without this LLD will tombstone some addresses in a .debug section OR if dead-reloc-in-nonalloc is specified, correct?

Without checking 1981b1b , you can check a SHN_ABS symbol with something like !cast<Defined>(sym).section. I haven't tested the use in relocateNonAlloc, though.

ok thanks. Appreciate the help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants