[ELF][X86] Support R_X86_64_PLTOFF64
authorFangrui Song <i@maskray.me>
Mon, 25 Oct 2021 20:05:17 +0000 (13:05 -0700)
committerFangrui Song <i@maskray.me>
Mon, 25 Oct 2021 20:05:17 +0000 (13:05 -0700)
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

lld/ELF/Arch/X86_64.cpp
lld/ELF/InputSection.cpp
lld/ELF/Relocations.cpp
lld/ELF/Relocations.h
lld/test/ELF/x86-64-reloc-pltoff64.s [new file with mode: 0644]

index 39ac23a..d42acd2 100644 (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:
index 7d952e9..7730eab 100644 (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
index 0ab7e28..629f75f 100644 (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)) {
index a702aac..d7569ac 100644 (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,
diff --git a/lld/test/ELF/x86-64-reloc-pltoff64.s b/lld/test/ELF/x86-64-reloc-pltoff64.s
new file mode 100644 (file)
index 0000000..2fa6c56
--- /dev/null
@@ -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