[lld] r250122 - [ELF2/PPC64] Resolve local-call relocations using the correct function-descriptor values
Hal Finkel via llvm-commits
llvm-commits at lists.llvm.org
Mon Oct 12 16:16:53 PDT 2015
Author: hfinkel
Date: Mon Oct 12 18:16:53 2015
New Revision: 250122
URL: http://llvm.org/viewvc/llvm-project?rev=250122&view=rev
Log:
[ELF2/PPC64] Resolve local-call relocations using the correct function-descriptor values
Under PPC64 ELF v1 ABI, the symbols associated with each function name don't
point directly to the code in the .text section (or similar), but rather to a
function descriptor structure in a special data section named .opd. The
elements in the .opd structure include a pointer to the actual code, and a the
relevant TOC base value. Both of these are themselves set by relocations.
When we have a local call, we need the relevant relocation to refer directly to
the target code, not to the function-descriptor in the .opd section. Only when
we have a .plt stub do we care about the address of the .opd function
descriptor itself.
So we make a few changes here:
1. Always write .opd first, so that its relocated data values are available
for later use when writing the text sections. Record a pointer to the .opd
structure, and its corresponding buffer.
2. When processing a relative branch relocation under ppc64, if the
destination points into the .opd section, read the code pointer out of the
function descriptor structure and use that instead.
This this, I can link, and run, a dynamically-compiled "hello world"
application on big-Endian PPC64/Linux (ELF v1 ABI) using lld.
Added:
lld/trunk/test/elf2/ppc64-rel-calls.s
Modified:
lld/trunk/ELF/OutputSections.h
lld/trunk/ELF/Target.cpp
lld/trunk/ELF/Writer.cpp
Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=250122&r1=250121&r2=250122&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Mon Oct 12 18:16:53 2015
@@ -288,6 +288,8 @@ template <class ELFT> struct Out {
static HashTableSection<ELFT> *HashTab;
static InterpSection<ELFT::Is64Bits> *Interp;
static OutputSection<ELFT> *Bss;
+ static OutputSection<ELFT> *Opd;
+ static uint8_t *OpdBuf;
static PltSection<ELFT> *Plt;
static RelocationSection<ELFT> *RelaDyn;
static StringTableSection<ELFT::Is64Bits> *DynStrTab;
@@ -301,6 +303,8 @@ template <class ELFT> GotSection<ELFT> *
template <class ELFT> HashTableSection<ELFT> *Out<ELFT>::HashTab;
template <class ELFT> InterpSection<ELFT::Is64Bits> *Out<ELFT>::Interp;
template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Bss;
+template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Opd;
+template <class ELFT> uint8_t *Out<ELFT>::OpdBuf;
template <class ELFT> PltSection<ELFT> *Out<ELFT>::Plt;
template <class ELFT> RelocationSection<ELFT> *Out<ELFT>::RelaDyn;
template <class ELFT> StringTableSection<ELFT::Is64Bits> *Out<ELFT>::DynStrTab;
Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=250122&r1=250121&r2=250122&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Mon Oct 12 18:16:53 2015
@@ -395,15 +395,26 @@ void PPC64TargetInfo::relocateOne(uint8_
write32be(L, R);
break;
case R_PPC64_REL24: {
+ uint64_t PltStart = Out<ELF64BE>::Plt->getVA();
+ uint64_t PltEnd = PltStart + Out<ELF64BE>::Plt->getSize();
+ bool InPlt = PltStart <= S + A && S + A < PltEnd;
+
+ if (!InPlt && Out<ELF64BE>::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<ELF64BE>::Opd->getVA();
+ uint64_t OpdEnd = OpdStart + Out<ELF64BE>::Opd->getSize();
+ bool InOpd = OpdStart <= S + A && S + A < OpdEnd;
+
+ if (InOpd)
+ R = read64be(&Out<ELF64BE>::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<ELF64BE>::Plt->getVA();
- uint64_t PltEnd = PltStart + Out<ELF64BE>::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)
Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=250122&r1=250121&r2=250122&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Mon Oct 12 18:16:53 2015
@@ -472,6 +472,11 @@ template <class ELFT> void Writer<ELFT>:
Out<ELFT>::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<ELFT>::Opd = Map.lookup({".opd", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC});
}
template <class ELFT>
@@ -644,8 +649,18 @@ template <class ELFT> void Writer<ELFT>:
// Write section contents to a mmap'ed file.
template <class ELFT> void Writer<ELFT>::writeSections() {
uint8_t *Buf = Buffer->getBufferStart();
+
+ // PPC64 needs to process relocations in the .opd section before processing
+ // relocations in code-containing sections.
+ for (OutputSectionBase<ELFT::Is64Bits> *&Sec : OutputSections)
+ if (Sec->getName() == ".opd") {
+ Out<ELFT>::OpdBuf = Buf + Sec->getFileOff();
+ Sec->writeTo(Buf + Sec->getFileOff());
+ }
+
for (OutputSectionBase<ELFT::Is64Bits> *Sec : OutputSections)
- Sec->writeTo(Buf + Sec->getFileOff());
+ if (Sec->getName() != ".opd")
+ Sec->writeTo(Buf + Sec->getFileOff());
}
template <class ELFT>
Added: lld/trunk/test/elf2/ppc64-rel-calls.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/ppc64-rel-calls.s?rev=250122&view=auto
==============================================================================
--- lld/trunk/test/elf2/ppc64-rel-calls.s (added)
+++ lld/trunk/test/elf2/ppc64-rel-calls.s Mon Oct 12 18:16:53 2015
@@ -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. at 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. at 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
+
More information about the llvm-commits
mailing list