Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -288,6 +288,8 @@ static HashTableSection *HashTab; static InterpSection *Interp; static OutputSection *Bss; + static OutputSection *Opd; + static uint8_t *OpdBuf; static PltSection *Plt; static RelocationSection *RelaDyn; static StringTableSection *DynStrTab; @@ -301,6 +303,8 @@ template HashTableSection *Out::HashTab; template InterpSection *Out::Interp; template OutputSection *Out::Bss; +template OutputSection *Out::Opd; +template uint8_t *Out::OpdBuf; template PltSection *Out::Plt; template RelocationSection *Out::RelaDyn; template StringTableSection *Out::DynStrTab; Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -395,15 +395,26 @@ write32be(L, R); break; case R_PPC64_REL24: { + uint64_t PltStart = Out::Plt->getVA(); + uint64_t PltEnd = PltStart + Out::Plt->getSize(); + bool InPlt = PltStart <= S + A && S + A < PltEnd; + + if (!InPlt && Out::Opd) { + // If this is a local call, and we currently have the address of a + // function-descriptor, get the underlying code address instead. + uint64_t OpdStart = Out::Opd->getVA(); + uint64_t OpdEnd = OpdStart + Out::Opd->getSize(); + bool InOpd = OpdStart <= S + A && S + A < OpdEnd; + + if (InOpd) + R = read64be(&Out::OpdBuf[S + A - OpdStart]); + } + uint32_t Mask = 0x03FFFFFC; if (!isInt<24>(R - P)) error("Relocation R_PPC64_REL24 overflow"); write32be(L, (read32be(L) & ~Mask) | ((R - P) & Mask)); - uint64_t PltStart = Out::Plt->getVA(); - uint64_t PltEnd = PltStart + Out::Plt->getSize(); - bool InPlt = PltStart <= S + A && S + A < PltEnd; - if (InPlt && L + 8 < BufEnd && read32be(L + 4) == 0x60000000 /* nop */) write32be(L + 4, 0xe8410028); // ld %r2, 40(%r1) Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -472,6 +472,11 @@ Out::StrTab->add(Sec->getName()); Sec->finalize(); } + + // If we have a .opd section (used under PPC64 for function descriptors), + // store a pointer to it here so that we can use it later when processing + // relocations. + Out::Opd = Map.lookup({".opd", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC}); } template @@ -644,8 +649,18 @@ // Write section contents to a mmap'ed file. template void Writer::writeSections() { uint8_t *Buf = Buffer->getBufferStart(); + + // PPC64 needs to process relocations in the .opd section before processing + // relocations in code-containing sections. + for (OutputSectionBase *&Sec : OutputSections) + if (Sec->getName() == ".opd") { + Out::OpdBuf = Buf + Sec->getFileOff(); + Sec->writeTo(Buf + Sec->getFileOff()); + } + for (OutputSectionBase *Sec : OutputSections) - Sec->writeTo(Buf + Sec->getFileOff()); + if (Sec->getName() != ".opd") + Sec->writeTo(Buf + Sec->getFileOff()); } template Index: test/elf2/ppc64-rel-calls.s =================================================================== --- /dev/null +++ test/elf2/ppc64-rel-calls.s @@ -0,0 +1,42 @@ +# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t +# RUN: ld.lld2 %t -o %t2 +# RUN: llvm-objdump -d %t2 | FileCheck %s +# REQUIRES: ppc + +# CHECK: Disassembly of section .text: + +.section ".opd","aw" +.global _start +_start: +.quad .Lfoo,.TOC.@tocbase,0 + +.text +.Lfoo: + li 0,1 + li 3,42 + sc + +# CHECK: 10010000: 38 00 00 01 li 0, 1 +# CHECK: 10010004: 38 60 00 2a li 3, 42 +# CHECK: 10010008: 44 00 00 02 sc + +.section ".opd","aw" +.global bar +bar: +.quad .Lbar,.TOC.@tocbase,0 + +.text +.Lbar: + bl _start + nop + bl .Lfoo + nop + blr + +# FIXME: The printing here is misleading, the branch offset here is negative. +# CHECK: 1001000c: 4b ff ff f5 bl .+67108852 +# CHECK: 10010010: 60 00 00 00 nop +# CHECK: 10010014: 4b ff ff ed bl .+67108844 +# CHECK: 10010018: 60 00 00 00 nop +# CHECK: 1001001c: 4e 80 00 20 blr +