[lld] r289198 - [ELF][I386] .got.plt entries for i386 should use VA of ifunc resolver

Peter Smith via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 9 01:59:54 PST 2016


Author: psmith
Date: Fri Dec  9 03:59:54 2016
New Revision: 289198

URL: http://llvm.org/viewvc/llvm-project?rev=289198&view=rev
Log:
[ELF][I386] .got.plt entries for i386 should use VA of ifunc resolver

The i386 glibc ld.so expects the .got.slot entry that is relocated by a 
R_386_IRELATIVE relocation to point directly at the ifunc resolver and
not the address of the PLT entry + 6 (thus entering the lazy resolver).
This is also the case for ARM and I suspect it is because these use REL
relocations and can't use the addend field to store the address of the
ifunc resolver. If the lazy resolver is used we get an error message
stating that only R_386_JUMP_SLOT is supported.

As ARM and i386 share the same code, I've removed the ARM specific test
and added a writeIgotPlt() function that by default calls writeGotPlt().
ARM and i386 override this to write the address of the ifunc resolver.

Differential Revision: https://reviews.llvm.org/D27581


Added:
    lld/trunk/test/ELF/gnu-ifunc-plt-i386.s   (with props)
Modified:
    lld/trunk/ELF/SyntheticSections.cpp
    lld/trunk/ELF/Target.cpp
    lld/trunk/ELF/Target.h

Modified: lld/trunk/ELF/SyntheticSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.cpp?rev=289198&r1=289197&r2=289198&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.cpp (original)
+++ lld/trunk/ELF/SyntheticSections.cpp Fri Dec  9 03:59:54 2016
@@ -727,11 +727,7 @@ template <class ELFT> size_t IgotPltSect
 
 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);
   }
 }

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=289198&r1=289197&r2=289198&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Fri Dec  9 03:59:54 2016
@@ -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(ui
 
 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
   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
   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]!

Modified: lld/trunk/ELF/Target.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=289198&r1=289197&r2=289198&view=diff
==============================================================================
--- lld/trunk/ELF/Target.h (original)
+++ lld/trunk/ELF/Target.h Fri Dec  9 03:59:54 2016
@@ -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

Added: lld/trunk/test/ELF/gnu-ifunc-plt-i386.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/gnu-ifunc-plt-i386.s?rev=289198&view=auto
==============================================================================
--- lld/trunk/test/ELF/gnu-ifunc-plt-i386.s (added)
+++ lld/trunk/test/ELF/gnu-ifunc-plt-i386.s Fri Dec  9 03:59:54 2016
@@ -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

Propchange: lld/trunk/test/ELF/gnu-ifunc-plt-i386.s
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lld/trunk/test/ELF/gnu-ifunc-plt-i386.s
------------------------------------------------------------------------------
    svn:keywords = Rev Date Author URL Id




More information about the llvm-commits mailing list