Index: lld/ELF/LinkerScript.cpp =================================================================== --- lld/ELF/LinkerScript.cpp +++ lld/ELF/LinkerScript.cpp @@ -664,14 +664,30 @@ // to be created before we create relocation output section, so we want // to create target sections first. We do not want priority handling // for synthetic sections because them are special. + std::vector TocSections; for (InputSectionBase *IS : InputSections) { - if (auto *Sec = dyn_cast(IS)) + if (auto *Sec = dyn_cast(IS)) { + // Both the .toc and the .got input sections will be added to the .got + // OutputSection. However, .got needs to be added first, since the first + // entry in the GOT has to be the .TOC. value. This is the first entry + // in the input .got section. + if (Config->EMachine == EM_PPC64) { + if (Sec->Name.equals(".toc")) { + TocSections.push_back(IS); + continue; + } + } if (InputSectionBase *Rel = Sec->getRelocatedSection()) if (auto *RelIS = dyn_cast_or_null(Rel->Parent)) Add(RelIS); + } Add(IS); } + // Add the .toc input sections now that .got has been added. + for (InputSectionBase *IS : TocSections) + Add(IS); + // If no SECTIONS command was given, we should insert sections commands // before others, so that we can handle scripts which refers them, // for example: "foo = ABSOLUTE(ADDR(.text)));". Index: lld/ELF/Writer.cpp =================================================================== --- lld/ELF/Writer.cpp +++ lld/ELF/Writer.cpp @@ -117,6 +117,13 @@ if (S->Name == "COMMON") return ".bss"; + // PPC64 has a compiler managed got in the .toc section which has to be + // added into the linker created .got. + if (Config->EMachine == EM_PPC64 && Config->EFlags == 2) { + if (S->Name == ".toc") + return ".got"; + } + return S->Name; } Index: lld/test/ELF/ppc64le-got-indirect.s =================================================================== --- /dev/null +++ lld/test/ELF/ppc64le-got-indirect.s @@ -0,0 +1,79 @@ +# REQUIRES: ppc +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +# RUN: llvm-readobj -relocations %t.o | FileCheck -check-prefix=RELOCS %s +# RUN: ld.lld %t.o -o %t2 +# RUN: llvm-objdump -D %t2 | FileCheck %s + +# Make sure we calculate the offset correctly for a got-indirect access to a +# global variable as described by the PPC64 ELF V2 abi. + .text + .abiversion 2 + .globl _start # -- Begin function _start + .p2align 4 + .type _start,@function +_start: # @_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 +# %bb.0: # %entry + addis 3, 2, .LC0@toc@ha + ld 3, .LC0@toc@l(3) + li 4, 0 + stw 4, -12(1) + li 0,1 + lwa 3, 0(3) + sc + .long 0 + .quad 0 +.Lfunc_end0: + .size _start, .Lfunc_end0-.Lfunc_begin0 + # -- End function + .section .toc,"aw",@progbits +.LC0: + .tc glob[TC],glob + .type glob,@object # @glob + .data + .globl glob + .p2align 2 +glob: + .long 55 # 0x37 + .size glob, 4 + +# Verify the relocations emitted for glob are through the .toc + +# RELOCS: Relocations [ +# RELOCS: .rela.text { +# RELOCS: 0x0 R_PPC64_REL16_HA .TOC. 0x0 +# RELOCS: 0x4 R_PPC64_REL16_LO .TOC. 0x4 +# RELOCS: 0x8 R_PPC64_TOC16_HA .toc 0x0 +# RELOCS: 0xC R_PPC64_TOC16_LO_DS .toc 0x0 +# RELOCS: } +# RELOCS: .rela.toc { +# RELOCS: 0x0 R_PPC64_ADDR64 glob 0x0 +# RELOCS: } + +# Verify that the global variable access is done through the correct +# got entry: +# r2 = .TOC. = 0x10038000. +# r3 = r2 - 32760 = 0x10030008 -> .got entry for glob. + +# CHECK: _start: +# CHECK-NEXT: 10010000: 03 00 4c 3c addis 2, 12, 3 +# CHECK-NEXT: 10010004: 00 80 42 38 addi 2, 2, -32768 +# CHECK-NEXT: 10010008: 00 00 62 3c addis 3, 2, 0 +# CHECK-NEXT: 1001000c: 08 80 63 e8 ld 3, -32760(3) +# CHECK: 1001001c: 02 00 63 e8 lwa 3, 0(3) + +# CHECK: Disassembly of section .data: +# CHECK-NEXT: glob: +# CHECK-NEXT: 10020000: 37 00 00 00 + +# Verify that .got contains the .toc entries. +# CHECK: Disassembly of section .got: +# CHECK-NEXT: .got: +# CHECK-NEXT: 10030000: 00 80 03 10 +# CHECK: 10030004: 00 00 00 00 +# CHECK: 10030008: 00 00 02 10