Index: ELF/Arch/PPC64.cpp =================================================================== --- ELF/Arch/PPC64.cpp +++ ELF/Arch/PPC64.cpp @@ -157,20 +157,37 @@ 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 toAddr16Rel(RelType Type, uint64_t Val) { Index: test/ELF/Inputs/shared-ppc64le.s =================================================================== --- /dev/null +++ test/ELF/Inputs/shared-ppc64le.s @@ -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 Index: test/ELF/ppc64le-plt-stub.s =================================================================== --- /dev/null +++ test/ELF/ppc64le-plt-stub.s @@ -0,0 +1,42 @@ +// 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) +// The next 2 instructions _should be_ +// 00 00 82 3d addis 12, 2, 0 +// 08 80 8c e9 ld 12, -32760(12) +// But we are putting the function address into the GOTPLT instead +// of the GOT. +// 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