forked from OSchip/llvm-project
[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. llvm-svn: 250122
This commit is contained in:
parent
aa0ec7f45c
commit
daedc12172
|
@ -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> *Out<ELFT>::Got;
|
|||
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;
|
||||
|
|
|
@ -395,15 +395,26 @@ void PPC64TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
|
|||
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)
|
||||
|
|
|
@ -472,6 +472,11 @@ template <class ELFT> void Writer<ELFT>::createSections() {
|
|||
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>::openFile(StringRef Path) {
|
|||
// 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>
|
||||
|
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue