summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/InputSection.cpp2
-rw-r--r--lld/ELF/Relocations.cpp20
-rw-r--r--lld/ELF/Relocations.h7
-rw-r--r--lld/test/ELF/aarch64-gnu-ifunc2.s52
4 files changed, 77 insertions, 4 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 18414b6e931..3847cc74f84 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -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:
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index c1ef385d0f2..d7850c4ce51 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -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,
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index a4e9024d8f0..d00e68bd36e 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -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
index 00000000000..2caff3f1458
--- /dev/null
+++ b/lld/test/ELF/aarch64-gnu-ifunc2.s
@@ -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
OpenPOWER on IntegriCloud