diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -41,6 +41,7 @@ using llvm::object::Archive; +class InputSection; class Symbol; // If --reproduce is specified, all input files are written to this tar archive. @@ -110,13 +111,13 @@ SmallVector 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 diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -474,13 +474,13 @@ 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; } } } diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -3620,14 +3620,12 @@ // .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(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; } } } diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -806,8 +806,9 @@ // 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). diff --git a/lld/test/ELF/linkerscript/ppc32-got2.s b/lld/test/ELF/linkerscript/ppc32-got2.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/linkerscript/ppc32-got2.s @@ -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) } +} diff --git a/lld/test/ELF/ppc32-relocatable-got2.s b/lld/test/ELF/ppc32-relocatable-got2.s --- a/lld/test/ELF/ppc32-relocatable-got2.s +++ b/lld/test/ELF/ppc32-relocatable-got2.s @@ -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