summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFangrui Song <i@maskray.me>2022-03-29 08:56:21 -0700
committerTom Stellard <tstellar@redhat.com>2022-04-25 15:18:15 -0700
commitdc30b0d3320da810f402a3fd1f79720cfa8eb98d (patch)
tree196a8d3d5d9ff4c0ae23c8eef2e9fdb9732a0f45
parent324127d8da95554086c02d609c5b05d3405f73a0 (diff)
downloadllvm-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.cpp41
-rw-r--r--lld/test/ELF/emit-relocs-synthetic.s54
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) }
+}