diff options
author | Fangrui Song <i@maskray.me> | 2022-03-29 08:56:21 -0700 |
---|---|---|
committer | Tom Stellard <tstellar@redhat.com> | 2022-04-25 15:18:15 -0700 |
commit | dc30b0d3320da810f402a3fd1f79720cfa8eb98d (patch) | |
tree | 196a8d3d5d9ff4c0ae23c8eef2e9fdb9732a0f45 | |
parent | 324127d8da95554086c02d609c5b05d3405f73a0 (diff) | |
download | llvm-dc30b0d3320da810f402a3fd1f79720cfa8eb98d.tar.gz |
[ELF] --emit-relocs: fix missing STT_SECTION when the first input section is synthetic
addSectionSymbols suppresses the STT_SECTION symbol if the first input section
is non-SHF_MERGE synthetic. This is incorrect when the first input section is synthetic
while a non-synthetic input section exists:
* `.bss : { *(COMMON) *(.bss) }`
(abc388ed3cf0ef7e617ebe243d3b0b32d29e69a5 regressed the case because
COMMON symbols precede .bss in the absence of a linker script)
* Place a synthetic section in another section: `.data : { *(.got) *(.data) }`
For `%t/a1` in the new test emit-relocs-synthetic.s, ld.lld produces incorrect
relocations with symbol index 0.
```
0000000000000000 <_start>:
0: 8b 05 33 00 00 00 movl 51(%rip), %eax # 0x39 <bss>
0000000000000002: R_X86_64_PC32 *ABS*+0xd
6: 8b 05 1c 00 00 00 movl 28(%rip), %eax # 0x28 <common>
0000000000000008: R_X86_64_PC32 common-0x4
c: 8b 05 06 00 00 00 movl 6(%rip), %eax # 0x18
000000000000000e: R_X86_64_GOTPCRELX *ABS*+0x4
```
Fix the issue by checking every input section.
Reviewed By: ikudrin
Differential Revision: https://reviews.llvm.org/D122463
(cherry picked from commit 7370a489b1005e424b23bd0009af2365aef4db53)
-rw-r--r-- | lld/ELF/Writer.cpp | 41 | ||||
-rw-r--r-- | lld/test/ELF/emit-relocs-synthetic.s | 54 |
2 files changed, 78 insertions, 17 deletions
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 9383ac46c8e7..5794f048c990 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -722,23 +722,30 @@ template <class ELFT> void Writer<ELFT>::addSectionSymbols() { auto *sec = dyn_cast<OutputSection>(cmd); if (!sec) continue; - auto i = llvm::find_if(sec->commands, [](SectionCommand *cmd) { - if (auto *isd = dyn_cast<InputSectionDescription>(cmd)) - return !isd->sections.empty(); - return false; - }); - if (i == sec->commands.end()) - continue; - InputSectionBase *isec = cast<InputSectionDescription>(*i)->sections[0]; - - // Relocations are not using REL[A] section symbols. - if (isec->type == SHT_REL || isec->type == SHT_RELA) - continue; - - // Unlike other synthetic sections, mergeable output sections contain data - // copied from input sections, and there may be a relocation pointing to its - // contents if -r or --emit-reloc is given. - if (isa<SyntheticSection>(isec) && !(isec->flags & SHF_MERGE)) + OutputSection &osec = *sec; + InputSectionBase *isec = nullptr; + // Iterate over all input sections and add a STT_SECTION symbol if any input + // section may be a relocation target. + for (SectionCommand *cmd : osec.commands) { + auto *isd = dyn_cast<InputSectionDescription>(cmd); + if (!isd) + continue; + for (InputSectionBase *s : isd->sections) { + // Relocations are not using REL[A] section symbols. + if (s->type == SHT_REL || s->type == SHT_RELA) + continue; + + // Unlike other synthetic sections, mergeable output sections contain + // data copied from input sections, and there may be a relocation + // pointing to its contents if -r or --emit-reloc is given. + if (isa<SyntheticSection>(s) && !(s->flags & SHF_MERGE)) + continue; + + isec = s; + break; + } + } + if (!isec) continue; // Set the symbol to be relative to the output section so that its st_value diff --git a/lld/test/ELF/emit-relocs-synthetic.s b/lld/test/ELF/emit-relocs-synthetic.s new file mode 100644 index 000000000000..737f96e5e191 --- /dev/null +++ b/lld/test/ELF/emit-relocs-synthetic.s @@ -0,0 +1,54 @@ +# REQUIRES: x86 +## Regression test: add STT_SECTION even if synthetic sections are interleaved +## with regular input sections. + +# RUN: rm -rf %t && split-file %s %t +# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/a.s -o %t/a.o +# RUN: ld.lld --emit-relocs --no-relax -T %t/1.t %t/a.o -o %t/a1 +# RUN: llvm-objdump -dr %t/a1 | FileCheck %s --check-prefixes=CHECK,CHECK1 +# RUN: ld.lld --emit-relocs --no-relax -T %t/2.t %t/a.o -o %t/a2 +# RUN: llvm-objdump -dr %t/a2 | FileCheck %s --check-prefixes=CHECK,CHECK2 + +# CHECK: <_start>: +## %t/a1: bss is at offset 17. bss-4 = .bss + 0xd +## %t/a2: bss is at offset 16. bss-4 = .bss + 0xc +# CHECK-NEXT: movl [[#]](%rip), %eax +# CHECK1-NEXT: R_X86_64_PC32 .bss+0xd +# CHECK2-NEXT: R_X86_64_PC32 .bss+0xc +# CHECK-NEXT: movl [[#]](%rip), %eax +# CHECK-NEXT: R_X86_64_PC32 common-0x4 +# CHECK-NEXT: movl [[#]](%rip), %eax +## %t/a1: input .data is at offset 8. 8-4 = 0x4 +## %t/a2: input .data is at offset 0. 0-4 = -0x4 +# CHECK1-NEXT: R_X86_64_GOTPCRELX .data+0x4 +# CHECK2-NEXT: R_X86_64_GOTPCRELX .data-0x4 + +#--- a.s +.globl _start +_start: + movl bss(%rip), %eax + movl common(%rip), %eax +## Compilers don't produce this. We just check the behavior. + movl .data@gotpcrel(%rip), %eax + +.section .data,"aw",@progbits +.quad 0 + +.section .bss,"aw",@nobits +.space 16 +bss: +.byte 0 + +.comm common,1,1 + +#--- 1.t +SECTIONS { + .data : { *(.got) *(.data) } + .bss : { *(COMMON) *(.bss) } +} + +#--- 2.t +SECTIONS { + .data : { *(.data) *(.got) } + .bss : { *(.bss) *(COMMON) } +} |