Fix PLT and GOTPLT entries for 32-bit x86 PIC.
authorRui Ueyama <ruiu@google.com>
Wed, 5 Apr 2017 16:01:33 +0000 (16:01 +0000)
committerRui Ueyama <ruiu@google.com>
Wed, 5 Apr 2017 16:01:33 +0000 (16:01 +0000)
Previously, the code we set to our .plt entries expected that .got
and .got.plt are consecutive in the virtual address space.
Since %ebx points to the last entry of .got for position-independent
code, it assumed that .got is accessible with small negative
displacements and .got.plt are accessible with small positive
displacements.

That assumption was simply wrong. We don't impose any restrictions on
relative layout of .got and .got.plt. As a result, the control is
transferred to a bogus address from .plt at runtime, which resulted in
segfaults.

This patch removes that wrong assumption. We still assume that .got.plt
has a fixed relative address to .got, but we no longer assume that they
are consecutive in memory.

With this change, a "hello world" program compiled with -fPIC works.

Fixes https://bugs.llvm.org/show_bug.cgi?id=31332.

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

llvm-svn: 299553

lld/ELF/Target.cpp
lld/test/ELF/plt-i686.s

index 399c5da11fcbe968bf13e7576b999a595c926d06..18f05d12a64739323f18f90dba8739075d7ac34d 100644 (file)
@@ -444,30 +444,33 @@ bool X86TargetInfo::isTlsInitialExecRel(uint32_t Type) const {
 }
 
 void X86TargetInfo::writePltHeader(uint8_t *Buf) const {
-  // Executable files and shared object files have
-  // separate procedure linkage tables.
   if (Config->Pic) {
     const uint8_t V[] = {
         0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx)
         0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp   *8(%ebx)
-        0x90, 0x90, 0x90, 0x90              // nop; nop; nop; nop
+        0x90, 0x90, 0x90, 0x90              // nop
     };
     memcpy(Buf, V, sizeof(V));
+
+    uint32_t Ebx = In<ELF32LE>::Got->getVA() + In<ELF32LE>::Got->getSize();
+    uint32_t GotPlt = In<ELF32LE>::GotPlt->getVA() - Ebx;
+    write32le(Buf + 2, GotPlt + 4);
+    write32le(Buf + 8, GotPlt + 8);
     return;
   }
 
   const uint8_t PltData[] = {
       0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushl (GOT+4)
       0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp   *(GOT+8)
-      0x90, 0x90, 0x90, 0x90              // nop; nop; nop; nop
+      0x90, 0x90, 0x90, 0x90              // nop
   };
   memcpy(Buf, PltData, sizeof(PltData));
-  uint32_t Got = In<ELF32LE>::GotPlt->getVA();
-  write32le(Buf + 2, Got + 4);
-  write32le(Buf + 8, Got + 8);
+  uint32_t GotPlt = In<ELF32LE>::GotPlt->getVA();
+  write32le(Buf + 2, GotPlt + 4);
+  write32le(Buf + 8, GotPlt + 8);
 }
 
-void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
                              uint64_t PltEntryAddr, int32_t Index,
                              unsigned RelOff) const {
   const uint8_t Inst[] = {
@@ -477,10 +480,17 @@ void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
   };
   memcpy(Buf, Inst, sizeof(Inst));
 
-  // jmp *foo@GOT(%ebx) or jmp *foo_in_GOT
-  Buf[1] = Config->Pic ? 0xa3 : 0x25;
-  uint32_t Got = In<ELF32LE>::GotPlt->getVA();
-  write32le(Buf + 2, Config->Shared ? GotEntryAddr - Got : GotEntryAddr);
+  if (Config->Pic) {
+    // jmp *foo@GOT(%ebx)
+    uint32_t Ebx = In<ELF32LE>::Got->getVA() + In<ELF32LE>::Got->getSize();
+    Buf[1] = 0xa3;
+    write32le(Buf + 2, GotPltEntryAddr - Ebx);
+  } else {
+    // jmp *foo_in_GOT
+    Buf[1] = 0x25;
+    write32le(Buf + 2, GotPltEntryAddr);
+  }
+
   write32le(Buf + 7, RelOff);
   write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
 }
index e169bd4d70f5c55c930e5d5656b71ec5843ecdb3..9a2c7f53dc59df36add6e7640df6a0738eb169b2 100644 (file)
 // DISASMSHARED-NEXT:  1013: e9 e8 ff ff ff jmp -24
 // DISASMSHARED-NEXT:  Disassembly of section .plt:
 // DISASMSHARED-NEXT:  .plt:
-// DISASMSHARED-NEXT:  1020: ff b3 04 00 00 00  pushl 4(%ebx)
-// DISASMSHARED-NEXT:  1026: ff a3 08 00 00 00  jmpl *8(%ebx)
+// DISASMSHARED-NEXT:  1020: ff b3 04 20 00 00 pushl 8196(%ebx)
+// DISASMSHARED-NEXT:  1026: ff a3 08 20 00 00 jmpl *8200(%ebx)
 // DISASMSHARED-NEXT:  102c: 90 nop
 // DISASMSHARED-NEXT:  102d: 90 nop
 // DISASMSHARED-NEXT:  102e: 90 nop
 // DISASMSHARED-NEXT:  102f: 90 nop
-// DISASMSHARED-NEXT:  1030: ff a3 0c 00 00 00  jmpl *12(%ebx)
+// DISASMSHARED-NEXT:  1030: ff a3 0c 20 00 00 jmpl *8204(%ebx)
 // DISASMSHARED-NEXT:  1036: 68 00 00 00 00     pushl $0
 // DISASMSHARED-NEXT:  103b: e9 e0 ff ff ff     jmp -32 <.plt>
-// DISASMSHARED-NEXT:  1040: ff a3 10 00 00 00  jmpl *16(%ebx)
+// DISASMSHARED-NEXT:  1040: ff a3 10 20 00 00 jmpl *8208(%ebx)
 // DISASMSHARED-NEXT:  1046: 68 08 00 00 00     pushl $8
 // DISASMSHARED-NEXT:  104b: e9 d0 ff ff ff     jmp -48 <.plt>
 
 // DISASMPIE:      Disassembly of section .plt:
 // DISASMPIE-NEXT: .plt:
-// DISASMPIE-NEXT:   1020:     ff b3 04 00 00 00 pushl 4(%ebx)
-// DISASMPIE-NEXT:   1026:     ff a3 08 00 00 00 jmpl *8(%ebx)
+// DISASMPIE-NEXT:   1020:     ff b3 04 20 00 00 pushl 8196(%ebx)
+// DISASMPIE-NEXT:   1026:     ff a3 08 20 00 00 jmpl *8200(%ebx)
 // DISASMPIE-NEXT:   102c:     90 nop
 // DISASMPIE-NEXT:   102d:     90 nop
 // DISASMPIE-NEXT:   102e:     90 nop