Fix addend computation for IRELATIVE relocations.

llvm-svn: 259692
This commit is contained in:
Rafael Espindola 2016-02-03 21:02:48 +00:00
parent f99f0d5a7e
commit 9e3f84bf95
2 changed files with 36 additions and 13 deletions

View File

@ -285,6 +285,18 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
bool NeedsGot = Body && Target->needsGot(Type, *Body);
bool CBP = canBePreempted(Body, NeedsGot);
if (IsRela) {
auto R = static_cast<const Elf_Rela &>(RI);
auto S = static_cast<Elf_Rela *>(P);
uintX_t A = NeedsGot ? 0 : R.r_addend;
if (CBP)
S->r_addend = A;
else if (Body)
S->r_addend = Body->getVA<ELFT>() + A;
else
S->r_addend = getLocalRelTarget(File, R, A);
}
// For a symbol with STT_GNU_IFUNC type, we always create a PLT and
// a GOT entry for the symbol, and emit an IRELATIVE reloc rather than
// the usual JUMP_SLOT reloc for the GOT entry. For the details, you
@ -318,19 +330,6 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
P->r_offset = Body->getGotVA<ELFT>();
else
P->r_offset = C.getOffset(RI.r_offset) + C.OutSec->getVA();
if (!IsRela)
continue;
auto R = static_cast<const Elf_Rela &>(RI);
auto S = static_cast<Elf_Rela *>(P);
uintX_t A = NeedsGot ? 0 : R.r_addend;
if (CBP)
S->r_addend = A;
else if (Body)
S->r_addend = Body->getVA<ELFT>() + A;
else
S->r_addend = getLocalRelTarget(File, R, A);
}
}

View File

@ -0,0 +1,24 @@
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
// RUN: ld.lld -static %t.o -o %tout
// RUN: llvm-readobj -r -t %tout | FileCheck %s
// REQUIRES: x86
.type foo STT_GNU_IFUNC
.globl foo
.type foo, @function
foo:
ret
.globl _start
_start:
call foo
// CHECK: Section ({{.*}}) .rela.plt {
// CHECK-NEXT: R_X86_64_IRELATIVE - 0x[[ADDR:.*]]
// CHECK-NEXT: }
// CHECK: Name: foo
// CHECK-NEXT: Value: 0x[[ADDR]]
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Global
// CHECK-NEXT: Type: GNU_IFunc