[ELF][PPC32] Support .got2 in an output section description

I added `PPC32Got2Section` D62464 to support .got2 but did not implement .got2
in another output section.

PR52799 has a linker script placing .got2 in .rodata, which causes a null
pointer dereference because a MergeSyntheticSection's file is nullptr.
Add the support.
This commit is contained in:
Fangrui Song 2021-12-23 11:32:44 -08:00
parent f103ee2e9e
commit bf45624ba0
6 changed files with 81 additions and 16 deletions

View File

@ -41,6 +41,7 @@ namespace elf {
using llvm::object::Archive;
class InputSection;
class Symbol;
// If --reproduce is specified, all input files are written to this tar archive.
@ -114,13 +115,13 @@ public:
SmallVector<Symbol *, 0> symbols;
// .got2 in the current file. This is used by PPC32 -fPIC/-fPIE to compute
// offsets in PLT call stubs.
InputSection *ppc32Got2 = nullptr;
// Index of MIPS GOT built for this file.
uint32_t mipsGotIndex = -1;
// outSecOff of .got2 in the current file. This is used by PPC32 -fPIC/-fPIE
// to compute offsets in PLT call stubs.
uint32_t ppc32Got2OutSecOff = 0;
// groupId is used for --warn-backrefs which is an optional error
// checking feature. All files within the same --{start,end}-group or
// --{start,end}-lib get the same group ID. Otherwise, each file gets a new

View File

@ -474,13 +474,13 @@ void InputSection::copyRelocations(uint8_t *buf, ArrayRef<RelTy> rels) {
else if (config->relocatable && type != target->noneRel)
sec->relocations.push_back({R_ABS, type, rel.r_offset, addend, &sym});
} else if (config->emachine == EM_PPC && type == R_PPC_PLTREL24 &&
p->r_addend >= 0x8000) {
p->r_addend >= 0x8000 && sec->file->ppc32Got2) {
// Similar to R_MIPS_GPREL{16,32}. If the addend of R_PPC_PLTREL24
// indicates that r30 is relative to the input section .got2
// (r_addend>=0x8000), after linking, r30 should be relative to the output
// section .got2 . To compensate for the shift, adjust r_addend by
// ppc32Got2OutSecOff.
p->r_addend += sec->file->ppc32Got2OutSecOff;
// ppc32Got->outSecOff.
p->r_addend += sec->file->ppc32Got2->outSecOff;
}
}
}

View File

@ -3620,14 +3620,12 @@ void PPC32Got2Section::finalizeContents() {
// .got2 . This function computes outSecOff of each .got2 to be used in
// PPC32PltCallStub::writeTo(). The purpose of this empty synthetic section is
// to collect input sections named ".got2".
uint32_t offset = 0;
for (SectionCommand *cmd : getParent()->commands)
if (auto *isd = dyn_cast<InputSectionDescription>(cmd)) {
for (InputSection *isec : isd->sections) {
if (isec == this)
continue;
isec->file->ppc32Got2OutSecOff = offset;
offset += (uint32_t)isec->getSize();
// isec->file may be nullptr for MergeSyntheticSection.
if (isec != this && isec->file)
isec->file->ppc32Got2 = isec;
}
}
}

View File

@ -806,8 +806,9 @@ void elf::writePPC32PltCallStub(uint8_t *buf, uint64_t gotPltVA,
// The stub loads an address relative to r30 (.got2+Addend). Addend is
// almost always 0x8000. The address of .got2 is different in another object
// file, so a stub cannot be shared.
offset = gotPltVA - (in.ppc32Got2->getParent()->getVA() +
file->ppc32Got2OutSecOff + addend);
offset = gotPltVA -
(in.ppc32Got2->getParent()->getVA() +
(file->ppc32Got2 ? file->ppc32Got2->outSecOff : 0) + addend);
} else {
// The stub loads an address relative to _GLOBAL_OFFSET_TABLE_ (which is
// currently the address of .got).

View File

@ -0,0 +1,59 @@
# REQUIRES: ppc
## Test .got2 placed in a different output section.
# RUN: rm -rf %t && split-file %s %t
# RUN: llvm-mc -filetype=obj -triple=powerpc %t/a.s -o %t/a.o
# RUN: llvm-mc -filetype=obj -triple=powerpc %t/b.s -o %t/b.o
# RUN: ld.lld -shared -T %t/t %t/a.o %t/b.o -o %t/a.so
# RUN: llvm-readobj -r %t/a.so | FileCheck --check-prefix=RELOC %s
# RUN: llvm-readelf -S %t/a.so | FileCheck --check-prefix=SEC %s
# RELOC: .rela.plt {
# RELOC-NEXT: 0x1A4 R_PPC_JMP_SLOT f 0x0
# RELOC-NEXT: }
# SEC: .got PROGBITS 0000018c
# SEC-NEXT: .rodata PROGBITS 00000198
## .got2+0x8000-0xb0 = .rodata+4+0x8000-0xb0 = 0x198+4+0x8000-0xb0 = 65536*1-32532
# CHECK: <_start>:
# CHECK-NEXT: bcl 20, 31, 0x
# CHECK-NEXT: b0: mflr 30
# CHECK-NEXT: addis 30, 30, 1
# CHECK-NEXT: addi 30, 30, -32532
# CHECK-NEXT: bl {{.*}} <00008000.got2.plt_pic32.f>
## &.got[2] - (.got2+0x8000) = &.got[2] - (.rodata+4+0x8000) = 0x1A4 - (0x198+4+0x8000) = -32760
# CHECK: <00008000.got2.plt_pic32.f>:
# CHECK-NEXT: lwz 11, -32760(30)
# CHECK-NEXT: mtctr 11
# CHECK-NEXT: bctr
# CHECK-NEXT: nop
#--- a.s
.section .rodata.cst4,"aM",@progbits,4
.long 1
.section .got2,"aw"
.long f
.text
.globl _start, f, g
_start:
bcl 20,31,.L
.L:
mflr 30
addis 30, 30, .got2+0x8000-.L@ha
addi 30, 30, .got2+0x8000-.L@l
bl f+0x8000@plt
#--- b.s
.section .got2,"aw"
.globl f
f:
bl f+0x8000@plt
#--- t
SECTIONS {
.rodata : { *(.rodata .rodata.*) *(.got2) }
}

View File

@ -3,10 +3,11 @@
## If r_addend indicates .got2, adjust it by the local .got2's output section offset.
# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o
# RUN: ld.lld -r %t.o %t.o -o %t
# RUN: echo 'bl f+0x8000@plt' | llvm-mc -filetype=obj -triple=powerpc - -o %t2.o
# RUN: ld.lld -r %t.o %t.o %t2.o -o %t
# RUN: llvm-readobj -r %t | FileCheck %s
# RUN: ld.lld -shared --emit-relocs %t.o %t.o -o %t.so
# RUN: ld.lld -shared --emit-relocs %t.o %t.o %t2.o -o %t.so
# RUN: llvm-readobj -r %t.so | FileCheck %s
# CHECK: .rela.adjust {
@ -23,6 +24,11 @@
# CHECK-NEXT: R_PPC_PLTREL24 foo 0x0
# CHECK-NEXT: R_PPC_PLTREL24 foo 0x0
# CHECK-NEXT: }
## %t2.o has an invalid relocation with r_addend=0x8000. Test we don't crash.
## The addend doesn't matter.
# CHECK-NEXT: .rela.text {
# CHECK-NEXT: R_PPC_PLTREL24 f 0x8000
# CHECK-NEXT: }
.section .got2,"aw"
.long 0