summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/SyntheticSections.cpp6
-rw-r--r--lld/ELF/Target.cpp16
-rw-r--r--lld/ELF/Target.h1
-rw-r--r--lld/test/ELF/gnu-ifunc-plt-i386.s76
4 files changed, 94 insertions, 5 deletions
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index e833251fd55..59d5fe99e49 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -727,11 +727,7 @@ template <class ELFT> size_t IgotPltSection<ELFT>::getSize() const {
template <class ELFT> void IgotPltSection<ELFT>::writeTo(uint8_t *Buf) {
for (const SymbolBody *B : Entries) {
- if (Config->EMachine == EM_ARM)
- // On ARM we are actually part of the Got and not GotPlt.
- write32le(Buf, B->getVA<ELFT>());
- else
- Target->writeGotPlt(Buf, *B);
+ Target->writeIgotPlt(Buf, *B);
Buf += sizeof(uintX_t);
}
}
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index aa8873667c7..f16853bd876 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -95,6 +95,7 @@ public:
bool isTlsGlobalDynamicRel(uint32_t Type) const override;
bool isTlsInitialExecRel(uint32_t Type) const override;
void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
+ void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
@@ -189,6 +190,7 @@ public:
bool isTlsGlobalDynamicRel(uint32_t Type) const override;
bool isTlsInitialExecRel(uint32_t Type) const override;
void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
+ void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
@@ -274,6 +276,10 @@ bool TargetInfo::isTlsLocalDynamicRel(uint32_t Type) const { return false; }
bool TargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const { return false; }
+void TargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
+ writeGotPlt(Buf, S);
+}
+
RelExpr TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
RelExpr Expr) const {
return Expr;
@@ -371,6 +377,11 @@ void X86TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {
write32le(Buf, S.getPltVA<ELF32LE>() + 6);
}
+void X86TargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
+ // An x86 entry is the address of the ifunc resolver function.
+ write32le(Buf, S.getVA<ELF32LE>());
+}
+
uint32_t X86TargetInfo::getDynRel(uint32_t Type) const {
if (Type == R_386_TLS_LE)
return R_386_TLS_TPOFF;
@@ -1649,6 +1660,11 @@ void ARMTargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
write32le(Buf, In<ELF32LE>::Plt->getVA());
}
+void ARMTargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
+ // An ARM entry is the address of the ifunc resolver function.
+ write32le(Buf, S.getVA<ELF32LE>());
+}
+
void ARMTargetInfo::writePltHeader(uint8_t *Buf) const {
const uint8_t PltData[] = {
0x04, 0xe0, 0x2d, 0xe5, // str lr, [sp,#-4]!
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index c393b7261f8..156a2c02323 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -30,6 +30,7 @@ public:
virtual uint32_t getDynRel(uint32_t Type) const { return Type; }
virtual void writeGotPltHeader(uint8_t *Buf) const {}
virtual void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {};
+ virtual void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const;
virtual uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const;
// If lazy binding is supported, the first entry of the PLT has code
diff --git a/lld/test/ELF/gnu-ifunc-plt-i386.s b/lld/test/ELF/gnu-ifunc-plt-i386.s
new file mode 100644
index 00000000000..75ebc8dd76e
--- /dev/null
+++ b/lld/test/ELF/gnu-ifunc-plt-i386.s
@@ -0,0 +1,76 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %S/Inputs/shared2-x86-64.s -o %t1.o
+// RUN: ld.lld %t1.o --shared -o %t.so
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: ld.lld %t.so %t.o -o %tout
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT
+// RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s
+// REQUIRES: x86
+
+// Check that the IRELATIVE relocations are after the JUMP_SLOT in the plt
+// CHECK: Relocations [
+// CHECK-NEXT: Section (4) .rel.plt {
+// CHECK-NEXT: 0x1300C R_386_JUMP_SLOT bar2
+// CHECK-NEXT: 0x13010 R_386_JUMP_SLOT zed2
+// CHECK-NEXT: 0x13014 R_386_IRELATIVE
+// CHECK-NEXT: 0x13018 R_386_IRELATIVE
+
+// Check that IRELATIVE .got.plt entries point to ifunc resolver and not
+// back to the plt entry + 6.
+// GOTPLT: Contents of section .got.plt:
+// GOTPLT: 13000 00200100 00000000 00000000 36100100
+// GOTPLT-NEXT: 13010 46100100 00100100 01100100
+
+// Check that the PLTRELSZ tag includes the IRELATIVE relocations
+// CHECK: DynamicSection [
+// CHECK: 0x00000002 PLTRELSZ 32 (bytes)
+
+// Check that a PLT header is written and the ifunc entries appear last
+// DISASM: Disassembly of section .text:
+// DISASM-NEXT: foo:
+// DISASM-NEXT: 11000: c3 retl
+// DISASM: bar:
+// DISASM-NEXT: 11001: c3 retl
+// DISASM: _start:
+// DISASM-NEXT: 11002: e8 49 00 00 00 calll 73
+// DISASM-NEXT: 11007: e8 54 00 00 00 calll 84
+// DISASM-NEXT: 1100c: e8 1f 00 00 00 calll 31
+// DISASM-NEXT: 11011: e8 2a 00 00 00 calll 42
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT: 11020: ff 35 04 30 01 00 pushl 77828
+// DISASM-NEXT: 11026: ff 25 08 30 01 00 jmpl *77832
+// DISASM-NEXT: 1102c: 90 nop
+// DISASM-NEXT: 1102d: 90 nop
+// DISASM-NEXT: 1102e: 90 nop
+// DISASM-NEXT: 1102f: 90 nop
+// DISASM-NEXT: 11030: ff 25 0c 30 01 00 jmpl *77836
+// DISASM-NEXT: 11036: 68 00 00 00 00 pushl $0
+// DISASM-NEXT: 1103b: e9 e0 ff ff ff jmp -32 <.plt>
+// DISASM-NEXT: 11040: ff 25 10 30 01 00 jmpl *77840
+// DISASM-NEXT: 11046: 68 08 00 00 00 pushl $8
+// DISASM-NEXT: 1104b: e9 d0 ff ff ff jmp -48 <.plt>
+// DISASM-NEXT: 11050: ff 25 14 30 01 00 jmpl *77844
+// DISASM-NEXT: 11056: 68 30 00 00 00 pushl $48
+// DISASM-NEXT: 1105b: e9 e0 ff ff ff jmp -32 <.plt+0x20>
+// DISASM-NEXT: 11060: ff 25 18 30 01 00 jmpl *77848
+// DISASM-NEXT: 11066: 68 38 00 00 00 pushl $56
+// DISASM-NEXT: 1106b: e9 d0 ff ff ff jmp -48 <.plt+0x20>
+
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ ret
+
+.globl _start
+_start:
+ call foo
+ call bar
+ call bar2
+ call zed2
OpenPOWER on IntegriCloud