Skip to content

Commit

Permalink
[ELF] --emit-relocs: fix missing STT_SECTION when the first input sec…
Browse files Browse the repository at this point in the history
…tion 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) }`
  (abc388e 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
  • Loading branch information
MaskRay committed Mar 29, 2022
1 parent f079946 commit 7370a48
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 17 deletions.
40 changes: 23 additions & 17 deletions lld/ELF/Writer.cpp
Expand Up @@ -711,23 +711,29 @@ template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
if (!osd)
continue;
OutputSection &osec = osd->osec;
auto i = llvm::find_if(osec.commands, [](SectionCommand *cmd) {
if (auto *isd = dyn_cast<InputSectionDescription>(cmd))
return !isd->sections.empty();
return false;
});
if (i == osec.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))
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
Expand Down
54 changes: 54 additions & 0 deletions 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) }
}

0 comments on commit 7370a48

Please sign in to comment.