[ELF][X86] Support R_X86_64_PLTOFF64

For a function call (using the default `-fplt`), GCC `-mcmodel=large` generates an assembly modifier which
leads to an R_X86_64_PLTOFF64 relocation. In real world,
http://git.ageinghacker.net/jitter (used by GNU poke) uses `-mcmodel=large`.

R_X86_64_PLTOFF64's formula is (if preemptible) `L - GOT + A` or (if non-preemptible) `S - GOT + A`
where `GOT` is (confusingly) the address of `.got.plt`

Reviewed By: peter.smith

Differential Revision: https://reviews.llvm.org/D112386
This commit is contained in:
Fangrui Song 2021-10-25 13:05:17 -07:00
parent a14ccaf509
commit ca8105b76c
5 changed files with 59 additions and 8 deletions

View File

@ -356,6 +356,8 @@ RelExpr X86_64::getRelExpr(RelType type, const Symbol &s,
return R_GOT_PC;
case R_X86_64_GOTOFF64:
return R_GOTPLTREL;
case R_X86_64_PLTOFF64:
return R_PLT_GOTPLT;
case R_X86_64_GOTPC32:
case R_X86_64_GOTPC64:
return R_GOTPLTONLY_PC;
@ -718,6 +720,7 @@ int64_t X86_64::getImplicitAddend(const uint8_t *buf, RelType type) const {
case R_X86_64_GOT64:
case R_X86_64_GOTOFF64:
case R_X86_64_GOTPC64:
case R_X86_64_PLTOFF64:
case R_X86_64_IRELATIVE:
case R_X86_64_RELATIVE:
return read64le(buf);
@ -779,6 +782,7 @@ void X86_64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
case R_X86_64_GOT64:
case R_X86_64_GOTOFF64:
case R_X86_64_GOTPC64:
case R_X86_64_PLTOFF64:
write64le(loc, val);
break;
default:

View File

@ -795,6 +795,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
case R_PLT_PC:
case R_PPC64_CALL_PLT:
return sym.getPltVA() + a - p;
case R_PLT_GOTPLT:
return sym.getPltVA() + a - in.gotPlt->getVA();
case R_PPC32_PLTREL:
// R_PPC_PLTREL24 uses the addend (usually 0 or 0x8000) to indicate r30
// stores _GLOBAL_OFFSET_TABLE_ or .got2+0x8000. The addend is ignored for

View File

@ -188,7 +188,8 @@ static bool isAbsoluteValue(const Symbol &sym) {
// Returns true if Expr refers a PLT entry.
static bool needsPlt(RelExpr expr) {
return oneof<R_PLT_PC, R_PPC32_PLTREL, R_PPC64_CALL_PLT, R_PLT>(expr);
return oneof<R_PLT, R_PLT_PC, R_PLT_GOTPLT, R_PPC32_PLTREL, R_PPC64_CALL_PLT>(
expr);
}
// Returns true if Expr refers a GOT entry. Note that this function
@ -224,11 +225,10 @@ static bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym,
R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOTREL, R_MIPS_GOT_OFF,
R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, R_MIPS_TLSGD,
R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC,
R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC, R_PPC32_PLTREL,
R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD, R_TLSDESC_CALL,
R_TLSDESC_PC, R_AARCH64_TLSDESC_PAGE, R_TLSLD_HINT, R_TLSIE_HINT,
R_AARCH64_GOT_PAGE>(
e))
R_PLT_PC, R_PLT_GOTPLT, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC,
R_PPC32_PLTREL, R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD,
R_TLSDESC_CALL, R_TLSDESC_PC, R_AARCH64_TLSDESC_PAGE, R_TLSLD_HINT,
R_TLSIE_HINT, R_AARCH64_GOT_PAGE>(e))
return true;
// These never do, except if the entire file is position dependent or if
@ -300,6 +300,8 @@ static RelExpr fromPlt(RelExpr expr) {
return R_PPC64_CALL;
case R_PLT:
return R_ABS;
case R_PLT_GOTPLT:
return R_GOTPLTREL;
default:
return expr;
}
@ -1394,8 +1396,9 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
// If the relocation does not emit a GOT or GOTPLT entry but its computation
// uses their addresses, we need GOT or GOTPLT to be created.
//
// The 4 types that relative GOTPLT are all x86 and x86-64 specific.
if (oneof<R_GOTPLTONLY_PC, R_GOTPLTREL, R_GOTPLT, R_TLSGD_GOTPLT>(expr)) {
// The 5 types that relative GOTPLT are all x86 and x86-64 specific.
if (oneof<R_GOTPLTONLY_PC, R_GOTPLTREL, R_GOTPLT, R_PLT_GOTPLT,
R_TLSGD_GOTPLT>(expr)) {
in.gotPlt->hasGotPltOffRel = true;
} else if (oneof<R_GOTONLY_PC, R_GOTREL, R_PPC64_TOCBASE, R_PPC64_RELAX_TOC>(
expr)) {

View File

@ -45,6 +45,7 @@ enum RelExpr {
R_PC,
R_PLT,
R_PLT_PC,
R_PLT_GOTPLT,
R_RELAX_GOT_PC,
R_RELAX_GOT_PC_NOPIC,
R_RELAX_TLS_GD_TO_IE,

View File

@ -0,0 +1,41 @@
# REQUIRES: x86
## Test R_X86_64_PLTOFF64 (preemptible: L - GOT + A; non-preemptible: S - GOT + A).
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
# RUN: ld.lld %t.o -shared -o %t.so
# RUN: llvm-readelf -S %t.so | FileCheck %s --check-prefix=SEC-SHARED
# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck %s --check-prefix=SHARED
# RUN: ld.lld %t.o -o %t
# RUN: llvm-readelf -S %t | FileCheck %s --check-prefix=SEC-PDE
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s --check-prefix=PDE
# SEC-SHARED: .got.plt PROGBITS 00000000000033c0 0003c0 000028
## foo@plt - .got.plt = 0x12f0 - 0x33c0 = -8400
## undefweak@plt - .got.plt = 0x1300 - 0x33c0 = -8384
# SHARED-LABEL: <.text>:
# SHARED-NEXT: movabsq $-8400, %rdx
# SHARED-NEXT: movabsq $-8384, %rdx
# SHARED-LABEL: <foo@plt>:
# SHARED-NEXT: 12f0: jmpq {{.*}}(%rip)
# SEC-PDE: .got.plt PROGBITS 0000000000202170 000170 000018
## Avoid PLT since the referenced symbol is non-preemptible.
## foo - .got.plt = 0x20116c - 0x202170 = -4100
## 0 - .got.plt = 0 - 0x202168 = -2105712
# PDE-LABEL: <.text>:
# PDE-NEXT: movabsq $-4100, %rdx
# PDE-NEXT: movabsq $-2105712, %rdx
# PDE-LABEL: <foo>:
# PDE-NEXT: 20116c: retq
movabsq $foo@PLTOFF, %rdx
movabsq $undefweak@PLTOFF, %rdx
.globl foo
foo:
ret
.weak undefweak