[PPC64] Write plt stubs for ElfV2 abi
authorSean Fertile <sfertile@ca.ibm.com>
Mon, 2 Apr 2018 19:17:12 +0000 (19:17 +0000)
committerSean Fertile <sfertile@ca.ibm.com>
Mon, 2 Apr 2018 19:17:12 +0000 (19:17 +0000)
Add the default version of a plt stub for the V2 Elf abi.

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

llvm-svn: 329004

lld/ELF/Arch/PPC64.cpp
lld/test/ELF/Inputs/shared-ppc64le.s [new file with mode: 0644]
lld/test/ELF/ppc64le-plt-stub.s [new file with mode: 0644]

index d3c2dbd..382f7a6 100644 (file)
@@ -157,20 +157,37 @@ void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
                      unsigned RelOff) const {
   uint64_t Off = GotPltEntryAddr - getPPC64TocBase();
 
-  // FIXME: What we should do, in theory, is get the offset of the function
-  // descriptor in the .opd section, and use that as the offset from %r2 (the
-  // TOC-base pointer). Instead, we have the GOT-entry offset, and that will
-  // be a pointer to the function descriptor in the .opd section. Using
-  // this scheme is simpler, but requires an extra indirection per PLT dispatch.
-
-  write32(Buf, 0xf8410028);                       // std %r2, 40(%r1)
-  write32(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha
-  write32(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11)
-  write32(Buf + 12, 0xe96c0000);                  // ld %r11,0(%r12)
-  write32(Buf + 16, 0x7d6903a6);                  // mtctr %r11
-  write32(Buf + 20, 0xe84c0008);                  // ld %r2,8(%r12)
-  write32(Buf + 24, 0xe96c0010);                  // ld %r11,16(%r12)
-  write32(Buf + 28, 0x4e800420);                  // bctr
+  if (Config->EKind == ELF64LEKind) {
+    // The most-common form of the plt stub. This assumes that the toc-pointer
+    // register is properly initalized, and that the stub must save the toc
+    // pointer value to the stack-save slot reserved for it (sp + 24).
+    // There are 2 other variants but we don't have to emit those until we add
+    // support for R_PPC64_REL24_NOTOC and R_PPC64_TOCSAVE relocations.
+    // We are missing a super simple optimization, where if the upper 16 bits of
+    // the offset are zero, then we can omit the addis instruction, and load
+    // r2 + lo-offset directly into r12. I decided to leave this out in the
+    // spirit of keeping it simple until we can link actual non-trivial
+    // programs.
+    write32(Buf +  0, 0xf8410018);                    // std     r2,24(r1)
+    write32(Buf +  4, 0x3d820000 | applyPPCHa(Off));  // addis   r12,r2, X@plt@to@ha
+    write32(Buf +  8, 0xe98c0000 | applyPPCLo(Off));  // ld      r12,X@plt@toc@l(r12)
+    write32(Buf + 12, 0x7d8903a6);                    // mtctr    r12
+    write32(Buf + 16, 0x4e800420);                    // bctr
+  } else {
+    // FIXME: What we should do, in theory, is get the offset of the function
+    // descriptor in the .opd section, and use that as the offset from %r2 (the
+    // TOC-base pointer). Instead, we have the GOT-entry offset, and that will
+    // be a pointer to the function descriptor in the .opd section. Using
+    // this scheme is simpler, but requires an extra indirection per PLT dispatch.
+    write32(Buf, 0xf8410028);                       // std %r2, 40(%r1)
+    write32(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha
+    write32(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11)
+    write32(Buf + 12, 0xe96c0000);                  // ld %r11,0(%r12)
+    write32(Buf + 16, 0x7d6903a6);                  // mtctr %r11
+    write32(Buf + 20, 0xe84c0008);                  // ld %r2,8(%r12)
+    write32(Buf + 24, 0xe96c0010);                  // ld %r11,16(%r12)
+    write32(Buf + 28, 0x4e800420);                  // bctr
+  }
 }
 
 static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) {
diff --git a/lld/test/ELF/Inputs/shared-ppc64le.s b/lld/test/ELF/Inputs/shared-ppc64le.s
new file mode 100644 (file)
index 0000000..0e1ecf7
--- /dev/null
@@ -0,0 +1,14 @@
+    .text
+    .abiversion 2
+    .globl  foo
+    .p2align        4
+    .type   foo,@function
+
+foo:
+.Lfunc_begin0:
+  li 3, 55
+  blr
+  .long   0
+  .quad   0
+.Lfunc_end0:
+  .size foo, .Lfunc_end0-.Lfunc_begin0
diff --git a/lld/test/ELF/ppc64le-plt-stub.s b/lld/test/ELF/ppc64le-plt-stub.s
new file mode 100644 (file)
index 0000000..f1edb4a
--- /dev/null
@@ -0,0 +1,37 @@
+// REQUIRES: ppc
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64le.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+
+// CHECK:          Disassembly of section .text:
+// CHECK:            _start:
+// CHECK:            bl .+24
+        .text
+        .abiversion 2
+        .globl  _start
+        .p2align        4
+        .type   _start,@function
+_start:
+.Lfunc_begin0:
+.Lfunc_gep0:
+  addis 2, 12, .TOC.-.Lfunc_gep0@ha
+  addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+  .localentry     _start, .Lfunc_lep0-.Lfunc_gep0
+  bl foo
+  nop
+  li 0, 1
+  sc
+  .size _start, .-.Lfunc_begin0
+
+
+
+// CHECK:          Disassembly of section .plt:
+// CHECK:          .plt:
+// CHECK-NEXT:            18 00 41 f8     std 2, 24(1)
+// CHECK-NEXT:            fe ff 82 3d     addis 12, 2, -2
+// CHECK-NEXT:            48 7f 8c e9     ld 12, 32584(12)
+// CHECK-NEXT:            a6 03 89 7d     mtctr 12
+// CHECK:                 20 04 80 4e     bctr