diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -465,7 +465,7 @@ if (!RelTy::IsRela) addend = target->getImplicitAddend(bufLoc, type); - if (config->emachine == EM_MIPS && config->relocatable && + if (config->relocatable && config->emachine == EM_MIPS && target->getRelExpr(type, sym, bufLoc) == R_MIPS_GOTREL) { // Some MIPS relocations depend on "gp" value. By default, // this value has 0x7ff0 offset from a .got section. But @@ -485,6 +485,13 @@ p->r_addend = sym.getVA(addend) - section->getOutputSection()->addr; else if (config->relocatable && type != target->noneRel) sec->relocations.push_back({R_ABS, type, rel.r_offset, addend, &sym}); + } else if (config->relocatable && config->emachine == EM_PPC && + type == R_PPC_PLTREL24 && p->r_addend >= 0x8000) { + // Similar to R_MIPS_GOTREL{16,32}, if r_addend indicates .got2 + // (>=0x8000), adjust it by the local .got2's output section offset. If + // r_addend=0, don't adjust. The PLT call stub is relative to .got. + // Because .got should not exist as an input section, the adjustment is 0. + p->r_addend += sec->file->ppc32Got2OutSecOff; } } } diff --git a/lld/test/ELF/ppc32-relocatable-pltrel24.s b/lld/test/ELF/ppc32-relocatable-pltrel24.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/ppc32-relocatable-pltrel24.s @@ -0,0 +1,45 @@ +# REQUIRES: ppc +## Test addend adjustment of R_PPC_PLTREL24 in -r mode. 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 %t.o -o %t +# RUN: llvm-readobj -r %t | FileCheck %s + +# RUN: ld.lld -shared --emit-relocs %t.o %t.o %t.o -o %t.so +# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=DSO %s + +# CHECK: .rela.adjust { +# CHECK-NEXT: 0x0 R_PPC_PLTREL24 foo 0x8000 +# CHECK-NEXT: 0x4 R_PPC_PLTREL24 bar 0x8000 +# CHECK-NEXT: 0x8 R_PPC_PLTREL24 foo 0x8004 +# CHECK-NEXT: 0xC R_PPC_PLTREL24 bar 0x8004 +# CHECK-NEXT: 0x10 R_PPC_PLTREL24 foo 0x8008 +# CHECK-NEXT: 0x14 R_PPC_PLTREL24 bar 0x8008 +# CHECK-NEXT: } +# CHECK-NEXT: .rela.no_adjust { +# CHECK-NEXT: 0x0 R_PPC_PLTREL24 foo 0x0 +# CHECK-NEXT: 0x4 R_PPC_PLTREL24 foo 0x0 +# CHECK-NEXT: 0x8 R_PPC_PLTREL24 foo 0x0 +# CHECK-NEXT: } + +## No adjustment in non -r mode. +# DSO: .rela.adjust { +# DSO-NEXT: R_PPC_PLTREL24 foo 0x8000 +# DSO-NEXT: R_PPC_PLTREL24 bar 0x8000 +# DSO-NEXT: R_PPC_PLTREL24 foo 0x8000 +# DSO-NEXT: R_PPC_PLTREL24 bar 0x8000 +# DSO-NEXT: R_PPC_PLTREL24 foo 0x8000 +# DSO-NEXT: R_PPC_PLTREL24 bar 0x8000 +# DSO-NEXT: } +.section .got2,"aw" +.long 0 + +.section .adjust,"ax" +## Refers to .got2+addend, adjust. +bl foo+0x8000@plt +bl bar+0x8000@plt + +.section .no_adjust,"ax" +## Refers to .got, no adjustment. +bl foo@plt