[ELF] - Fix R_AARCH64_ADR_GOT_PAGE, R_AARCH64_LD64_GOT_LO12 handling against IFUNC...
authorGeorge Rimar <grimar@accesssoftek.com>
Tue, 27 Nov 2018 10:30:46 +0000 (10:30 +0000)
committerGeorge Rimar <grimar@accesssoftek.com>
Tue, 27 Nov 2018 10:30:46 +0000 (10:30 +0000)
This is https://bugs.llvm.org/show_bug.cgi?id=38074.

The issue is that when calling a function, LLD generates a
.got entry that points to the IFUNC resolver function when
instead, it should use the PLT entries properly for
handling the IFUNC.

So we should create a got entry that points to PLT entry,
which itself loads the value from
.got.plt, relocated with R_*_IRELATIVE to make things work.
Patch do that.

Differential revision: https://reviews.llvm.org/D54314

llvm-svn: 347650

lld/ELF/InputSection.cpp
lld/ELF/Relocations.cpp
lld/ELF/Relocations.h
lld/test/ELF/aarch64-gnu-ifunc2.s [new file with mode: 0644]

index 18414b6..3847cc7 100644 (file)
@@ -605,6 +605,7 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
   case R_ARM_SBREL:
     return Sym.getVA(A) - getARMStaticBase(Sym);
   case R_GOT:
+  case R_GOT_PLT:
   case R_RELAX_TLS_GD_TO_IE_ABS:
     return Sym.getGotVA() + A;
   case R_GOTONLY_PC:
@@ -623,6 +624,7 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
   case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
     return Sym.getGotOffset() + A;
   case R_AARCH64_GOT_PAGE_PC:
+  case R_AARCH64_GOT_PAGE_PC_PLT:
   case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
     return getAArch64Page(Sym.getGotVA() + A) - getAArch64Page(P);
   case R_GOT_PC:
index c1ef385..d7850c4 100644 (file)
@@ -324,8 +324,8 @@ static bool isAbsoluteValue(const Symbol &Sym) {
 
 // Returns true if Expr refers a PLT entry.
 static bool needsPlt(RelExpr Expr) {
-  return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_AARCH64_PLT_PAGE_PC>(
-      Expr);
+  return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_AARCH64_PLT_PAGE_PC,
+                        R_GOT_PLT, R_AARCH64_GOT_PAGE_PC_PLT>(Expr);
 }
 
 // Returns true if Expr refers a GOT entry. Note that this function
@@ -334,7 +334,8 @@ static bool needsPlt(RelExpr Expr) {
 static bool needsGot(RelExpr Expr) {
   return isRelExprOneOf<R_GOT, R_GOT_OFF, R_HEXAGON_GOT, R_MIPS_GOT_LOCAL_PAGE,
                         R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC,
-                        R_GOT_PC, R_GOT_FROM_END>(Expr);
+                        R_AARCH64_GOT_PAGE_PC_PLT, R_GOT_PC, R_GOT_FROM_END,
+                        R_GOT_PLT>(Expr);
 }
 
 // True if this expression is of the form Sym - X, where X is a position in the
@@ -417,8 +418,12 @@ static RelExpr toPlt(RelExpr Expr) {
     return R_PLT_PC;
   case R_AARCH64_PAGE_PC:
     return R_AARCH64_PLT_PAGE_PC;
+  case R_AARCH64_GOT_PAGE_PC:
+    return R_AARCH64_GOT_PAGE_PC_PLT;
   case R_ABS:
     return R_PLT;
+  case R_GOT:
+    return R_GOT_PLT;
   default:
     return Expr;
   }
@@ -746,7 +751,14 @@ static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt,
 template <class ELFT> static void addGotEntry(Symbol &Sym) {
   In.Got->addEntry(Sym);
 
-  RelExpr Expr = Sym.isTls() ? R_TLS : R_ABS;
+  RelExpr Expr;
+  if (Sym.isTls())
+    Expr = R_TLS;
+  else if (Sym.isGnuIFunc())
+    Expr = R_PLT;
+  else
+    Expr = R_ABS;
+
   uint64_t Off = Sym.getGotOffset();
 
   // If a GOT slot value can be calculated at link-time, which is now,
index a4e9024..d00e68b 100644 (file)
@@ -34,12 +34,19 @@ enum RelExpr {
   R_ABS,
   R_ADDEND,
   R_AARCH64_GOT_PAGE_PC,
+  // The expression is used for IFUNC support. Describes PC-relative
+  // address of the memory page of GOT entry. This entry is used for
+  // a redirection to IPLT.
+  R_AARCH64_GOT_PAGE_PC_PLT,
   R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
   R_AARCH64_PAGE_PC,
   R_AARCH64_PLT_PAGE_PC,
   R_AARCH64_TLSDESC_PAGE,
   R_ARM_SBREL,
   R_GOT,
+  // The expression is used for IFUNC support. Evaluates to GOT entry,
+  // containing redirection to the IPLT.
+  R_GOT_PLT,
   R_GOTONLY_PC,
   R_GOTONLY_PC_FROM_END,
   R_GOTREL,
diff --git a/lld/test/ELF/aarch64-gnu-ifunc2.s b/lld/test/ELF/aarch64-gnu-ifunc2.s
new file mode 100644 (file)
index 0000000..2caff3f
--- /dev/null
@@ -0,0 +1,52 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o
+# RUN: ld.lld -static %t.o -o %tout
+# RUN: llvm-objdump -D %tout | FileCheck %s
+# RUN: llvm-readobj -r %tout | FileCheck %s --check-prefix=RELOC
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: myfunc:
+# CHECK-NEXT:   210000:
+
+# CHECK:      main:
+# adrp x8, 0x230000, 0x230000 == address in .got
+# CHECK-NEXT:   210004: {{.*}} adrp    x8, #131072
+# CHECK-NEXT:   210008: {{.*}} ldr     x8, [x8]
+# CHECK-NEXT:   21000c: {{.*}} ret
+
+# CHECK:      Disassembly of section .plt:
+# CHECK-NEXT: .plt:
+# adrp x16, 0x220000, 0x220000 == address in .got.plt
+# CHECK-NEXT:   210010: {{.*}} adrp    x16, #65536
+# CHECK-NEXT:   210014: {{.*}} ldr     x17, [x16]
+# CHECK-NEXT:   210018: {{.*}} add     x16, x16, #0
+# CHECK-NEXT:   21001c: {{.*}} br      x17
+
+# CHECK:      Disassembly of section .got.plt:
+# CHECK-NEXT: .got.plt:
+# CHECK-NEXT:   220000:
+
+# CHECK:      Disassembly of section .got:
+# CHECK-NEXT: .got:
+# 0x210010 == address in .plt
+# CHECK-NEXT:   230000: 10 00 21 00
+
+# RELOC:      Relocations [
+# RELOC-NEXT:   Section {{.*}} .rela.plt {
+# RELOC-NEXT:     0x220000 R_AARCH64_IRELATIVE - 0x210000
+# RELOC-NEXT:   }
+# RELOC-NEXT: ]
+
+.text
+.globl myfunc
+.type myfunc,@gnu_indirect_function
+myfunc:
+ ret
+
+.text
+.globl main
+.type main,@function
+main:
+ adrp x8, :got:myfunc
+ ldr  x8, [x8, :got_lo12:myfunc]
+ ret