forked from OSchip/llvm-project
[ELF] Convert .got section to input section
Differential revision: https://reviews.llvm.org/D26498 llvm-svn: 286580
This commit is contained in:
parent
08dedfc589
commit
ad4439e802
|
@ -304,9 +304,9 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
|
|||
case R_TLSDESC_CALL:
|
||||
llvm_unreachable("cannot relocate hint relocs");
|
||||
case R_TLSLD:
|
||||
return Out<ELFT>::Got->getTlsIndexOff() + A - Out<ELFT>::Got->Size;
|
||||
return In<ELFT>::Got->getTlsIndexOff() + A - In<ELFT>::Got->getSize();
|
||||
case R_TLSLD_PC:
|
||||
return Out<ELFT>::Got->getTlsIndexVA() + A - P;
|
||||
return In<ELFT>::Got->getTlsIndexVA() + A - P;
|
||||
case R_THUNK_ABS:
|
||||
return Body.getThunkVA<ELFT>() + A;
|
||||
case R_THUNK_PC:
|
||||
|
@ -315,13 +315,14 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
|
|||
case R_PPC_TOC:
|
||||
return getPPC64TocBase() + A;
|
||||
case R_TLSGD:
|
||||
return Out<ELFT>::Got->getGlobalDynOffset(Body) + A - Out<ELFT>::Got->Size;
|
||||
return In<ELFT>::Got->getGlobalDynOffset(Body) + A -
|
||||
In<ELFT>::Got->getSize();
|
||||
case R_TLSGD_PC:
|
||||
return Out<ELFT>::Got->getGlobalDynAddr(Body) + A - P;
|
||||
return In<ELFT>::Got->getGlobalDynAddr(Body) + A - P;
|
||||
case R_TLSDESC:
|
||||
return Out<ELFT>::Got->getGlobalDynAddr(Body) + A;
|
||||
return In<ELFT>::Got->getGlobalDynAddr(Body) + A;
|
||||
case R_TLSDESC_PAGE:
|
||||
return getAArch64Page(Out<ELFT>::Got->getGlobalDynAddr(Body) + A) -
|
||||
return getAArch64Page(In<ELFT>::Got->getGlobalDynAddr(Body) + A) -
|
||||
getAArch64Page(P);
|
||||
case R_PLT:
|
||||
return Body.getPltVA<ELFT>() + A;
|
||||
|
@ -331,12 +332,13 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
|
|||
case R_SIZE:
|
||||
return Body.getSize<ELFT>() + A;
|
||||
case R_GOTREL:
|
||||
return Body.getVA<ELFT>(A) - Out<ELFT>::Got->Addr;
|
||||
return Body.getVA<ELFT>(A) - In<ELFT>::Got->getVA();
|
||||
case R_GOTREL_FROM_END:
|
||||
return Body.getVA<ELFT>(A) - Out<ELFT>::Got->Addr - Out<ELFT>::Got->Size;
|
||||
return Body.getVA<ELFT>(A) - In<ELFT>::Got->getVA() -
|
||||
In<ELFT>::Got->getSize();
|
||||
case R_RELAX_TLS_GD_TO_IE_END:
|
||||
case R_GOT_FROM_END:
|
||||
return Body.getGotOffset<ELFT>() + A - Out<ELFT>::Got->Size;
|
||||
return Body.getGotOffset<ELFT>() + A - In<ELFT>::Got->getSize();
|
||||
case R_RELAX_TLS_GD_TO_IE_ABS:
|
||||
case R_GOT:
|
||||
return Body.getGotVA<ELFT>() + A;
|
||||
|
@ -347,9 +349,9 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
|
|||
case R_GOT_PC:
|
||||
return Body.getGotVA<ELFT>() + A - P;
|
||||
case R_GOTONLY_PC:
|
||||
return Out<ELFT>::Got->Addr + A - P;
|
||||
return In<ELFT>::Got->getVA() + A - P;
|
||||
case R_GOTONLY_PC_FROM_END:
|
||||
return Out<ELFT>::Got->Addr + A - P + Out<ELFT>::Got->Size;
|
||||
return In<ELFT>::Got->getVA() + A - P + In<ELFT>::Got->getSize();
|
||||
case R_RELAX_TLS_LD_TO_LE:
|
||||
case R_RELAX_TLS_IE_TO_LE:
|
||||
case R_RELAX_TLS_GD_TO_LE:
|
||||
|
@ -378,19 +380,19 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
|
|||
// If relocation against MIPS local symbol requires GOT entry, this entry
|
||||
// should be initialized by 'page address'. This address is high 16-bits
|
||||
// of sum the symbol's value and the addend.
|
||||
return Out<ELFT>::Got->getMipsLocalPageOffset(Body.getVA<ELFT>(A));
|
||||
return In<ELFT>::Got->getMipsLocalPageOffset(Body.getVA<ELFT>(A));
|
||||
case R_MIPS_GOT_OFF:
|
||||
case R_MIPS_GOT_OFF32:
|
||||
// In case of MIPS if a GOT relocation has non-zero addend this addend
|
||||
// should be applied to the GOT entry content not to the GOT entry offset.
|
||||
// That is why we use separate expression type.
|
||||
return Out<ELFT>::Got->getMipsGotOffset(Body, A);
|
||||
return In<ELFT>::Got->getMipsGotOffset(Body, A);
|
||||
case R_MIPS_TLSGD:
|
||||
return Out<ELFT>::Got->getGlobalDynOffset(Body) +
|
||||
Out<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset;
|
||||
return In<ELFT>::Got->getGlobalDynOffset(Body) +
|
||||
In<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset;
|
||||
case R_MIPS_TLSLD:
|
||||
return Out<ELFT>::Got->getTlsIndexOff() +
|
||||
Out<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset;
|
||||
return In<ELFT>::Got->getTlsIndexOff() + In<ELFT>::Got->getMipsTlsOffset() -
|
||||
MipsGPOffset;
|
||||
case R_PPC_OPD: {
|
||||
uint64_t SymVA = Body.getVA<ELFT>(A);
|
||||
// If we have an undefined weak symbol, we might get here with a symbol
|
||||
|
|
|
@ -108,275 +108,6 @@ template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
GotSection<ELFT>::GotSection()
|
||||
: OutputSectionBase(".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) {
|
||||
if (Config->EMachine == EM_MIPS)
|
||||
this->Flags |= SHF_MIPS_GPREL;
|
||||
this->Addralign = Target->GotEntrySize;
|
||||
}
|
||||
|
||||
template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody &Sym) {
|
||||
Sym.GotIndex = Entries.size();
|
||||
Entries.push_back(&Sym);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void GotSection<ELFT>::addMipsEntry(SymbolBody &Sym, uintX_t Addend,
|
||||
RelExpr Expr) {
|
||||
// For "true" local symbols which can be referenced from the same module
|
||||
// only compiler creates two instructions for address loading:
|
||||
//
|
||||
// lw $8, 0($gp) # R_MIPS_GOT16
|
||||
// addi $8, $8, 0 # R_MIPS_LO16
|
||||
//
|
||||
// The first instruction loads high 16 bits of the symbol address while
|
||||
// the second adds an offset. That allows to reduce number of required
|
||||
// GOT entries because only one global offset table entry is necessary
|
||||
// for every 64 KBytes of local data. So for local symbols we need to
|
||||
// allocate number of GOT entries to hold all required "page" addresses.
|
||||
//
|
||||
// All global symbols (hidden and regular) considered by compiler uniformly.
|
||||
// It always generates a single `lw` instruction and R_MIPS_GOT16 relocation
|
||||
// to load address of the symbol. So for each such symbol we need to
|
||||
// allocate dedicated GOT entry to store its address.
|
||||
//
|
||||
// If a symbol is preemptible we need help of dynamic linker to get its
|
||||
// final address. The corresponding GOT entries are allocated in the
|
||||
// "global" part of GOT. Entries for non preemptible global symbol allocated
|
||||
// in the "local" part of GOT.
|
||||
//
|
||||
// See "Global Offset Table" in Chapter 5:
|
||||
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
|
||||
if (Expr == R_MIPS_GOT_LOCAL_PAGE) {
|
||||
// At this point we do not know final symbol value so to reduce number
|
||||
// of allocated GOT entries do the following trick. Save all output
|
||||
// sections referenced by GOT relocations. Then later in the `finalize`
|
||||
// method calculate number of "pages" required to cover all saved output
|
||||
// section and allocate appropriate number of GOT entries.
|
||||
auto *OutSec = cast<DefinedRegular<ELFT>>(&Sym)->Section->OutSec;
|
||||
MipsOutSections.insert(OutSec);
|
||||
return;
|
||||
}
|
||||
if (Sym.isTls()) {
|
||||
// GOT entries created for MIPS TLS relocations behave like
|
||||
// almost GOT entries from other ABIs. They go to the end
|
||||
// of the global offset table.
|
||||
Sym.GotIndex = Entries.size();
|
||||
Entries.push_back(&Sym);
|
||||
return;
|
||||
}
|
||||
auto AddEntry = [&](SymbolBody &S, uintX_t A, MipsGotEntries &Items) {
|
||||
if (S.isInGot() && !A)
|
||||
return;
|
||||
size_t NewIndex = Items.size();
|
||||
if (!MipsGotMap.insert({{&S, A}, NewIndex}).second)
|
||||
return;
|
||||
Items.emplace_back(&S, A);
|
||||
if (!A)
|
||||
S.GotIndex = NewIndex;
|
||||
};
|
||||
if (Sym.isPreemptible()) {
|
||||
// Ignore addends for preemptible symbols. They got single GOT entry anyway.
|
||||
AddEntry(Sym, 0, MipsGlobal);
|
||||
Sym.IsInGlobalMipsGot = true;
|
||||
} else if (Expr == R_MIPS_GOT_OFF32) {
|
||||
AddEntry(Sym, Addend, MipsLocal32);
|
||||
Sym.Is32BitMipsGot = true;
|
||||
} else {
|
||||
// Hold local GOT entries accessed via a 16-bit index separately.
|
||||
// That allows to write them in the beginning of the GOT and keep
|
||||
// their indexes as less as possible to escape relocation's overflow.
|
||||
AddEntry(Sym, Addend, MipsLocal);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
|
||||
if (Sym.GlobalDynIndex != -1U)
|
||||
return false;
|
||||
Sym.GlobalDynIndex = Entries.size();
|
||||
// Global Dynamic TLS entries take two GOT slots.
|
||||
Entries.push_back(nullptr);
|
||||
Entries.push_back(&Sym);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reserves TLS entries for a TLS module ID and a TLS block offset.
|
||||
// In total it takes two GOT slots.
|
||||
template <class ELFT> bool GotSection<ELFT>::addTlsIndex() {
|
||||
if (TlsIndexOff != uint32_t(-1))
|
||||
return false;
|
||||
TlsIndexOff = Entries.size() * sizeof(uintX_t);
|
||||
Entries.push_back(nullptr);
|
||||
Entries.push_back(nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
typename GotSection<ELFT>::uintX_t
|
||||
GotSection<ELFT>::getMipsLocalPageOffset(uintX_t EntryValue) {
|
||||
// Initialize the entry by the %hi(EntryValue) expression
|
||||
// but without right-shifting.
|
||||
EntryValue = (EntryValue + 0x8000) & ~0xffff;
|
||||
// Take into account MIPS GOT header.
|
||||
// See comment in the GotSection::writeTo.
|
||||
size_t NewIndex = MipsLocalGotPos.size() + 2;
|
||||
auto P = MipsLocalGotPos.insert(std::make_pair(EntryValue, NewIndex));
|
||||
assert(!P.second || MipsLocalGotPos.size() <= MipsPageEntries);
|
||||
return (uintX_t)P.first->second * sizeof(uintX_t) - MipsGPOffset;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
typename GotSection<ELFT>::uintX_t
|
||||
GotSection<ELFT>::getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const {
|
||||
// Calculate offset of the GOT entries block: TLS, global, local.
|
||||
uintX_t GotBlockOff;
|
||||
if (B.isTls())
|
||||
GotBlockOff = getMipsTlsOffset();
|
||||
else if (B.IsInGlobalMipsGot)
|
||||
GotBlockOff = getMipsLocalEntriesNum() * sizeof(uintX_t);
|
||||
else if (B.Is32BitMipsGot)
|
||||
GotBlockOff = (MipsPageEntries + MipsLocal.size()) * sizeof(uintX_t);
|
||||
else
|
||||
GotBlockOff = MipsPageEntries * sizeof(uintX_t);
|
||||
// Calculate index of the GOT entry in the block.
|
||||
uintX_t GotIndex;
|
||||
if (B.isInGot())
|
||||
GotIndex = B.GotIndex;
|
||||
else {
|
||||
auto It = MipsGotMap.find({&B, Addend});
|
||||
assert(It != MipsGotMap.end());
|
||||
GotIndex = It->second;
|
||||
}
|
||||
return GotBlockOff + GotIndex * sizeof(uintX_t) - MipsGPOffset;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
typename GotSection<ELFT>::uintX_t GotSection<ELFT>::getMipsTlsOffset() const {
|
||||
return (getMipsLocalEntriesNum() + MipsGlobal.size()) * sizeof(uintX_t);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
typename GotSection<ELFT>::uintX_t
|
||||
GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const {
|
||||
return this->Addr + B.GlobalDynIndex * sizeof(uintX_t);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
typename GotSection<ELFT>::uintX_t
|
||||
GotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const {
|
||||
return B.GlobalDynIndex * sizeof(uintX_t);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
const SymbolBody *GotSection<ELFT>::getMipsFirstGlobalEntry() const {
|
||||
return MipsGlobal.empty() ? nullptr : MipsGlobal.front().first;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const {
|
||||
return MipsPageEntries + MipsLocal.size() + MipsLocal32.size();
|
||||
}
|
||||
|
||||
template <class ELFT> void GotSection<ELFT>::finalize() {
|
||||
size_t EntriesNum = Entries.size();
|
||||
if (Config->EMachine == EM_MIPS) {
|
||||
// Take into account MIPS GOT header.
|
||||
// See comment in the GotSection::writeTo.
|
||||
MipsPageEntries += 2;
|
||||
for (const OutputSectionBase *OutSec : MipsOutSections) {
|
||||
// Calculate an upper bound of MIPS GOT entries required to store page
|
||||
// addresses of local symbols. We assume the worst case - each 64kb
|
||||
// page of the output section has at least one GOT relocation against it.
|
||||
// Add 0x8000 to the section's size because the page address stored
|
||||
// in the GOT entry is calculated as (value + 0x8000) & ~0xffff.
|
||||
MipsPageEntries += (OutSec->Size + 0x8000 + 0xfffe) / 0xffff;
|
||||
}
|
||||
EntriesNum += getMipsLocalEntriesNum() + MipsGlobal.size();
|
||||
}
|
||||
this->Size = EntriesNum * sizeof(uintX_t);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
static void writeUint(uint8_t *Buf, typename ELFT::uint Val) {
|
||||
typedef typename ELFT::uint uintX_t;
|
||||
write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Buf, Val);
|
||||
}
|
||||
|
||||
template <class ELFT> void GotSection<ELFT>::writeMipsGot(uint8_t *Buf) {
|
||||
// Set the MSB of the second GOT slot. This is not required by any
|
||||
// MIPS ABI documentation, though.
|
||||
//
|
||||
// There is a comment in glibc saying that "The MSB of got[1] of a
|
||||
// gnu object is set to identify gnu objects," and in GNU gold it
|
||||
// says "the second entry will be used by some runtime loaders".
|
||||
// But how this field is being used is unclear.
|
||||
//
|
||||
// We are not really willing to mimic other linkers behaviors
|
||||
// without understanding why they do that, but because all files
|
||||
// generated by GNU tools have this special GOT value, and because
|
||||
// we've been doing this for years, it is probably a safe bet to
|
||||
// keep doing this for now. We really need to revisit this to see
|
||||
// if we had to do this.
|
||||
auto *P = reinterpret_cast<typename ELFT::Off *>(Buf);
|
||||
P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31);
|
||||
// Write 'page address' entries to the local part of the GOT.
|
||||
for (std::pair<uintX_t, size_t> &L : MipsLocalGotPos) {
|
||||
uint8_t *Entry = Buf + L.second * sizeof(uintX_t);
|
||||
writeUint<ELFT>(Entry, L.first);
|
||||
}
|
||||
Buf += MipsPageEntries * sizeof(uintX_t);
|
||||
auto AddEntry = [&](const MipsGotEntry &SA) {
|
||||
uint8_t *Entry = Buf;
|
||||
Buf += sizeof(uintX_t);
|
||||
const SymbolBody *Body = SA.first;
|
||||
uintX_t VA = Body->template getVA<ELFT>(SA.second);
|
||||
writeUint<ELFT>(Entry, VA);
|
||||
};
|
||||
std::for_each(std::begin(MipsLocal), std::end(MipsLocal), AddEntry);
|
||||
std::for_each(std::begin(MipsLocal32), std::end(MipsLocal32), AddEntry);
|
||||
std::for_each(std::begin(MipsGlobal), std::end(MipsGlobal), AddEntry);
|
||||
// Initialize TLS-related GOT entries. If the entry has a corresponding
|
||||
// dynamic relocations, leave it initialized by zero. Write down adjusted
|
||||
// TLS symbol's values otherwise. To calculate the adjustments use offsets
|
||||
// for thread-local storage.
|
||||
// https://www.linux-mips.org/wiki/NPTL
|
||||
if (TlsIndexOff != -1U && !Config->Pic)
|
||||
writeUint<ELFT>(Buf + TlsIndexOff, 1);
|
||||
for (const SymbolBody *B : Entries) {
|
||||
if (!B || B->isPreemptible())
|
||||
continue;
|
||||
uintX_t VA = B->getVA<ELFT>();
|
||||
if (B->GotIndex != -1U) {
|
||||
uint8_t *Entry = Buf + B->GotIndex * sizeof(uintX_t);
|
||||
writeUint<ELFT>(Entry, VA - 0x7000);
|
||||
}
|
||||
if (B->GlobalDynIndex != -1U) {
|
||||
uint8_t *Entry = Buf + B->GlobalDynIndex * sizeof(uintX_t);
|
||||
writeUint<ELFT>(Entry, 1);
|
||||
Entry += sizeof(uintX_t);
|
||||
writeUint<ELFT>(Entry, VA - 0x8000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
if (Config->EMachine == EM_MIPS) {
|
||||
writeMipsGot(Buf);
|
||||
return;
|
||||
}
|
||||
for (const SymbolBody *B : Entries) {
|
||||
uint8_t *Entry = Buf;
|
||||
Buf += sizeof(uintX_t);
|
||||
if (!B)
|
||||
continue;
|
||||
if (B->isPreemptible())
|
||||
continue; // The dynamic linker will take care of it.
|
||||
uintX_t VA = B->getVA<ELFT>();
|
||||
writeUint<ELFT>(Entry, VA);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
PltSection<ELFT>::PltSection()
|
||||
: OutputSectionBase(".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR) {
|
||||
|
@ -443,11 +174,11 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||
if (Config->Rela)
|
||||
P->r_addend = Rel.getAddend();
|
||||
P->r_offset = Rel.getOffset();
|
||||
if (Config->EMachine == EM_MIPS && Rel.getOutputSec() == Out<ELFT>::Got)
|
||||
if (Config->EMachine == EM_MIPS && Rel.getInputSec() == In<ELFT>::Got)
|
||||
// Dynamic relocation against MIPS GOT section make deal TLS entries
|
||||
// allocated in the end of the GOT. We need to adjust the offset to take
|
||||
// in account 'local' and 'global' GOT entries.
|
||||
P->r_offset += Out<ELFT>::Got->getMipsTlsOffset();
|
||||
P->r_offset += In<ELFT>::Got->getMipsTlsOffset();
|
||||
P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->Mips64EL);
|
||||
}
|
||||
|
||||
|
@ -794,12 +525,12 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() {
|
|||
Add({DT_MIPS_FLAGS, RHF_NOTPOT});
|
||||
Add({DT_MIPS_BASE_ADDRESS, Config->ImageBase});
|
||||
Add({DT_MIPS_SYMTABNO, Out<ELFT>::DynSymTab->getNumSymbols()});
|
||||
Add({DT_MIPS_LOCAL_GOTNO, Out<ELFT>::Got->getMipsLocalEntriesNum()});
|
||||
if (const SymbolBody *B = Out<ELFT>::Got->getMipsFirstGlobalEntry())
|
||||
Add({DT_MIPS_LOCAL_GOTNO, In<ELFT>::Got->getMipsLocalEntriesNum()});
|
||||
if (const SymbolBody *B = In<ELFT>::Got->getMipsFirstGlobalEntry())
|
||||
Add({DT_MIPS_GOTSYM, B->DynsymIndex});
|
||||
else
|
||||
Add({DT_MIPS_GOTSYM, Out<ELFT>::DynSymTab->getNumSymbols()});
|
||||
Add({DT_PLTGOT, Out<ELFT>::Got});
|
||||
Add({DT_PLTGOT, In<ELFT>::Got});
|
||||
if (Out<ELFT>::MipsRldMap)
|
||||
Add({DT_MIPS_RLD_MAP, Out<ELFT>::MipsRldMap});
|
||||
}
|
||||
|
@ -1819,11 +1550,6 @@ template class EhFrameHeader<ELF32BE>;
|
|||
template class EhFrameHeader<ELF64LE>;
|
||||
template class EhFrameHeader<ELF64BE>;
|
||||
|
||||
template class GotSection<ELF32LE>;
|
||||
template class GotSection<ELF32BE>;
|
||||
template class GotSection<ELF64LE>;
|
||||
template class GotSection<ELF64BE>;
|
||||
|
||||
template class PltSection<ELF32LE>;
|
||||
template class PltSection<ELF32BE>;
|
||||
template class PltSection<ELF64LE>;
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "Relocations.h"
|
||||
|
||||
#include "lld/Core/LLVM.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/MC/StringTableBuilder.h"
|
||||
#include "llvm/Object/ELF.h"
|
||||
|
||||
|
@ -50,7 +49,6 @@ public:
|
|||
EHFrame,
|
||||
EHFrameHdr,
|
||||
GnuHashTable,
|
||||
Got,
|
||||
HashTable,
|
||||
Merge,
|
||||
Plt,
|
||||
|
@ -142,74 +140,6 @@ private:
|
|||
uint32_t CuTypesOffset;
|
||||
};
|
||||
|
||||
template <class ELFT> class GotSection final : public OutputSectionBase {
|
||||
typedef typename ELFT::uint uintX_t;
|
||||
|
||||
public:
|
||||
GotSection();
|
||||
void finalize() override;
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
void addEntry(SymbolBody &Sym);
|
||||
void addMipsEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr);
|
||||
bool addDynTlsEntry(SymbolBody &Sym);
|
||||
bool addTlsIndex();
|
||||
bool empty() const { return MipsPageEntries == 0 && Entries.empty(); }
|
||||
uintX_t getMipsLocalPageOffset(uintX_t Addr);
|
||||
uintX_t getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const;
|
||||
uintX_t getGlobalDynAddr(const SymbolBody &B) const;
|
||||
uintX_t getGlobalDynOffset(const SymbolBody &B) const;
|
||||
Kind getKind() const override { return Got; }
|
||||
static bool classof(const OutputSectionBase *B) {
|
||||
return B->getKind() == Got;
|
||||
}
|
||||
|
||||
// Returns the symbol which corresponds to the first entry of the global part
|
||||
// of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic
|
||||
// table properties.
|
||||
// Returns nullptr if the global part is empty.
|
||||
const SymbolBody *getMipsFirstGlobalEntry() const;
|
||||
|
||||
// Returns the number of entries in the local part of GOT including
|
||||
// the number of reserved entries. This method is MIPS-specific.
|
||||
unsigned getMipsLocalEntriesNum() const;
|
||||
|
||||
// Returns offset of TLS part of the MIPS GOT table. This part goes
|
||||
// after 'local' and 'global' entries.
|
||||
uintX_t getMipsTlsOffset() const;
|
||||
|
||||
uintX_t getTlsIndexVA() { return this->Addr + TlsIndexOff; }
|
||||
uint32_t getTlsIndexOff() const { return TlsIndexOff; }
|
||||
|
||||
// Flag to force GOT to be in output if we have relocations
|
||||
// that relies on its address.
|
||||
bool HasGotOffRel = false;
|
||||
|
||||
private:
|
||||
std::vector<const SymbolBody *> Entries;
|
||||
uint32_t TlsIndexOff = -1;
|
||||
uint32_t MipsPageEntries = 0;
|
||||
// Output sections referenced by MIPS GOT relocations.
|
||||
llvm::SmallPtrSet<const OutputSectionBase *, 10> MipsOutSections;
|
||||
llvm::DenseMap<uintX_t, size_t> MipsLocalGotPos;
|
||||
|
||||
// MIPS ABI requires to create unique GOT entry for each Symbol/Addend
|
||||
// pairs. The `MipsGotMap` maps (S,A) pair to the GOT index in the `MipsLocal`
|
||||
// or `MipsGlobal` vectors. In general it does not have a sence to take in
|
||||
// account addend for preemptible symbols because the corresponding
|
||||
// GOT entries should have one-to-one mapping with dynamic symbols table.
|
||||
// But we use the same container's types for both kind of GOT entries
|
||||
// to handle them uniformly.
|
||||
typedef std::pair<const SymbolBody *, uintX_t> MipsGotEntry;
|
||||
typedef std::vector<MipsGotEntry> MipsGotEntries;
|
||||
llvm::DenseMap<MipsGotEntry, size_t> MipsGotMap;
|
||||
MipsGotEntries MipsLocal;
|
||||
MipsGotEntries MipsLocal32;
|
||||
MipsGotEntries MipsGlobal;
|
||||
|
||||
// Write MIPS-specific parts of the GOT.
|
||||
void writeMipsGot(uint8_t *Buf);
|
||||
};
|
||||
|
||||
template <class ELFT> class PltSection final : public OutputSectionBase {
|
||||
typedef typename ELFT::uint uintX_t;
|
||||
|
||||
|
@ -248,6 +178,7 @@ public:
|
|||
uintX_t getAddend() const;
|
||||
uint32_t getSymIndex() const;
|
||||
const OutputSectionBase *getOutputSec() const { return OutputSec; }
|
||||
const InputSectionBase<ELFT> *getInputSec() const { return InputSec; }
|
||||
|
||||
uint32_t Type;
|
||||
|
||||
|
@ -661,7 +592,6 @@ template <class ELFT> struct Out {
|
|||
static EhOutputSection<ELFT> *EhFrame;
|
||||
static GdbIndexSection<ELFT> *GdbIndex;
|
||||
static GnuHashTableSection<ELFT> *GnuHashTab;
|
||||
static GotSection<ELFT> *Got;
|
||||
static HashTableSection<ELFT> *HashTab;
|
||||
static OutputSection<ELFT> *Bss;
|
||||
static OutputSection<ELFT> *MipsRldMap;
|
||||
|
@ -726,7 +656,6 @@ template <class ELFT> EhFrameHeader<ELFT> *Out<ELFT>::EhFrameHdr;
|
|||
template <class ELFT> EhOutputSection<ELFT> *Out<ELFT>::EhFrame;
|
||||
template <class ELFT> GdbIndexSection<ELFT> *Out<ELFT>::GdbIndex;
|
||||
template <class ELFT> GnuHashTableSection<ELFT> *Out<ELFT>::GnuHashTab;
|
||||
template <class ELFT> GotSection<ELFT> *Out<ELFT>::Got;
|
||||
template <class ELFT> HashTableSection<ELFT> *Out<ELFT>::HashTab;
|
||||
template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Bss;
|
||||
template <class ELFT> OutputSection<ELFT> *Out<ELFT>::MipsRldMap;
|
||||
|
|
|
@ -101,23 +101,23 @@ static unsigned handleNoRelaxTlsRelocation(uint32_t Type, SymbolBody &Body,
|
|||
typename ELFT::uint Addend,
|
||||
RelExpr Expr) {
|
||||
if (Expr == R_MIPS_TLSLD || Expr == R_TLSLD_PC) {
|
||||
if (Out<ELFT>::Got->addTlsIndex() &&
|
||||
if (In<ELFT>::Got->addTlsIndex() &&
|
||||
(Config->Pic || Config->EMachine == EM_ARM))
|
||||
Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got,
|
||||
Out<ELFT>::Got->getTlsIndexOff(), false,
|
||||
Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, In<ELFT>::Got,
|
||||
In<ELFT>::Got->getTlsIndexOff(), false,
|
||||
nullptr, 0});
|
||||
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
|
||||
return 1;
|
||||
}
|
||||
typedef typename ELFT::uint uintX_t;
|
||||
if (Target->isTlsGlobalDynamicRel(Type)) {
|
||||
if (Out<ELFT>::Got->addDynTlsEntry(Body) &&
|
||||
if (In<ELFT>::Got->addDynTlsEntry(Body) &&
|
||||
(Body.isPreemptible() || Config->EMachine == EM_ARM)) {
|
||||
uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body);
|
||||
uintX_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
|
||||
Out<ELFT>::RelaDyn->addReloc(
|
||||
{Target->TlsModuleIndexRel, Out<ELFT>::Got, Off, false, &Body, 0});
|
||||
{Target->TlsModuleIndexRel, In<ELFT>::Got, Off, false, &Body, 0});
|
||||
if (Body.isPreemptible())
|
||||
Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Out<ELFT>::Got,
|
||||
Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, In<ELFT>::Got,
|
||||
Off + (uintX_t)sizeof(uintX_t), false,
|
||||
&Body, 0});
|
||||
}
|
||||
|
@ -147,10 +147,10 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
|
|||
|
||||
if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC_CALL) &&
|
||||
Config->Shared) {
|
||||
if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
|
||||
uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body);
|
||||
if (In<ELFT>::Got->addDynTlsEntry(Body)) {
|
||||
uintX_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
|
||||
Out<ELFT>::RelaDyn->addReloc(
|
||||
{Target->TlsDescRel, Out<ELFT>::Got, Off, false, &Body, 0});
|
||||
{Target->TlsDescRel, In<ELFT>::Got, Off, false, &Body, 0});
|
||||
}
|
||||
if (Expr != R_TLSDESC_CALL)
|
||||
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
|
||||
|
@ -164,9 +164,9 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
|
|||
{R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body});
|
||||
return 2;
|
||||
}
|
||||
if (Out<ELFT>::Got->addTlsIndex())
|
||||
Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got,
|
||||
Out<ELFT>::Got->getTlsIndexOff(), false,
|
||||
if (In<ELFT>::Got->addTlsIndex())
|
||||
Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, In<ELFT>::Got,
|
||||
In<ELFT>::Got->getTlsIndexOff(), false,
|
||||
nullptr, 0});
|
||||
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
|
||||
return 1;
|
||||
|
@ -182,15 +182,15 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
|
|||
if (Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC || Expr == R_TLSDESC_CALL ||
|
||||
Target->isTlsGlobalDynamicRel(Type)) {
|
||||
if (Config->Shared) {
|
||||
if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
|
||||
uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body);
|
||||
if (In<ELFT>::Got->addDynTlsEntry(Body)) {
|
||||
uintX_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
|
||||
Out<ELFT>::RelaDyn->addReloc(
|
||||
{Target->TlsModuleIndexRel, Out<ELFT>::Got, Off, false, &Body, 0});
|
||||
{Target->TlsModuleIndexRel, In<ELFT>::Got, Off, false, &Body, 0});
|
||||
|
||||
// If the symbol is preemptible we need the dynamic linker to write
|
||||
// the offset too.
|
||||
if (isPreemptible(Body, Type))
|
||||
Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Out<ELFT>::Got,
|
||||
Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, In<ELFT>::Got,
|
||||
Off + (uintX_t)sizeof(uintX_t), false,
|
||||
&Body, 0});
|
||||
}
|
||||
|
@ -205,8 +205,8 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
|
|||
{Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type,
|
||||
Offset, Addend, &Body});
|
||||
if (!Body.isInGot()) {
|
||||
Out<ELFT>::Got->addEntry(Body);
|
||||
Out<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, Out<ELFT>::Got,
|
||||
In<ELFT>::Got->addEntry(Body);
|
||||
Out<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, In<ELFT>::Got,
|
||||
Body.getGotOffset<ELFT>(), false, &Body,
|
||||
0});
|
||||
}
|
||||
|
@ -671,7 +671,7 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
|||
// needs it to be created. Here we request for that.
|
||||
if (Expr == R_GOTONLY_PC || Expr == R_GOTONLY_PC_FROM_END ||
|
||||
Expr == R_GOTREL || Expr == R_GOTREL_FROM_END || Expr == R_PPC_TOC)
|
||||
Out<ELFT>::Got->HasGotOffRel = true;
|
||||
In<ELFT>::Got->HasGotOffRel = true;
|
||||
|
||||
uintX_t Addend = computeAddend(File, Buf, E, RI, Expr, Body);
|
||||
|
||||
|
@ -725,7 +725,7 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
|||
// a dynamic relocation.
|
||||
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19
|
||||
if (Config->EMachine == EM_MIPS)
|
||||
Out<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
|
||||
In<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -760,9 +760,9 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
|||
// See "Global Offset Table" in Chapter 5 in the following document
|
||||
// for detailed description:
|
||||
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
|
||||
Out<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
|
||||
In<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
|
||||
if (Body.isTls() && Body.isPreemptible())
|
||||
AddDyn({Target->TlsGotRel, Out<ELFT>::Got, Body.getGotOffset<ELFT>(),
|
||||
AddDyn({Target->TlsGotRel, In<ELFT>::Got, Body.getGotOffset<ELFT>(),
|
||||
false, &Body, 0});
|
||||
continue;
|
||||
}
|
||||
|
@ -770,7 +770,7 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
|||
if (Body.isInGot())
|
||||
continue;
|
||||
|
||||
Out<ELFT>::Got->addEntry(Body);
|
||||
In<ELFT>::Got->addEntry(Body);
|
||||
if (Preemptible || (Config->Pic && !isAbsolute<ELFT>(Body))) {
|
||||
uint32_t DynType;
|
||||
if (Body.isTls())
|
||||
|
@ -779,8 +779,8 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
|
|||
DynType = Target->GotRel;
|
||||
else
|
||||
DynType = Target->RelativeRel;
|
||||
AddDyn({DynType, Out<ELFT>::Got, Body.getGotOffset<ELFT>(),
|
||||
!Preemptible, &Body, 0});
|
||||
AddDyn({DynType, In<ELFT>::Got, Body.getGotOffset<ELFT>(), !Preemptible,
|
||||
&Body, 0});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -151,7 +151,7 @@ typename ELFT::uint SymbolBody::getVA(typename ELFT::uint Addend) const {
|
|||
}
|
||||
|
||||
template <class ELFT> typename ELFT::uint SymbolBody::getGotVA() const {
|
||||
return Out<ELFT>::Got->Addr + getGotOffset<ELFT>();
|
||||
return In<ELFT>::Got->getVA() + getGotOffset<ELFT>();
|
||||
}
|
||||
|
||||
template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const {
|
||||
|
|
|
@ -198,7 +198,7 @@ MipsOptionsSection<ELFT>::MipsOptionsSection()
|
|||
template <class ELFT> void MipsOptionsSection<ELFT>::finalize() {
|
||||
if (!Config->Relocatable)
|
||||
getOptions()->getRegInfo().ri_gp_value =
|
||||
Out<ELFT>::Got->Addr + MipsGPOffset;
|
||||
In<ELFT>::Got->getVA() + MipsGPOffset;
|
||||
}
|
||||
|
||||
// MIPS .reginfo section.
|
||||
|
@ -226,7 +226,7 @@ MipsReginfoSection<ELFT>::MipsReginfoSection()
|
|||
|
||||
template <class ELFT> void MipsReginfoSection<ELFT>::finalize() {
|
||||
if (!Config->Relocatable)
|
||||
Reginfo.ri_gp_value = Out<ELFT>::Got->Addr + MipsGPOffset;
|
||||
Reginfo.ri_gp_value = In<ELFT>::Got->getVA() + MipsGPOffset;
|
||||
}
|
||||
|
||||
static ArrayRef<uint8_t> createInterp() {
|
||||
|
@ -344,6 +344,275 @@ void BuildIdHexstring<ELFT>::writeBuildId(MutableArrayRef<uint8_t> Buf) {
|
|||
Config->BuildIdVector.size());
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
GotSection<ELFT>::GotSection()
|
||||
: SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
|
||||
Target->GotEntrySize, ".got") {
|
||||
if (Config->EMachine == EM_MIPS)
|
||||
this->Flags |= SHF_MIPS_GPREL;
|
||||
}
|
||||
|
||||
template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody &Sym) {
|
||||
Sym.GotIndex = Entries.size();
|
||||
Entries.push_back(&Sym);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void GotSection<ELFT>::addMipsEntry(SymbolBody &Sym, uintX_t Addend,
|
||||
RelExpr Expr) {
|
||||
// For "true" local symbols which can be referenced from the same module
|
||||
// only compiler creates two instructions for address loading:
|
||||
//
|
||||
// lw $8, 0($gp) # R_MIPS_GOT16
|
||||
// addi $8, $8, 0 # R_MIPS_LO16
|
||||
//
|
||||
// The first instruction loads high 16 bits of the symbol address while
|
||||
// the second adds an offset. That allows to reduce number of required
|
||||
// GOT entries because only one global offset table entry is necessary
|
||||
// for every 64 KBytes of local data. So for local symbols we need to
|
||||
// allocate number of GOT entries to hold all required "page" addresses.
|
||||
//
|
||||
// All global symbols (hidden and regular) considered by compiler uniformly.
|
||||
// It always generates a single `lw` instruction and R_MIPS_GOT16 relocation
|
||||
// to load address of the symbol. So for each such symbol we need to
|
||||
// allocate dedicated GOT entry to store its address.
|
||||
//
|
||||
// If a symbol is preemptible we need help of dynamic linker to get its
|
||||
// final address. The corresponding GOT entries are allocated in the
|
||||
// "global" part of GOT. Entries for non preemptible global symbol allocated
|
||||
// in the "local" part of GOT.
|
||||
//
|
||||
// See "Global Offset Table" in Chapter 5:
|
||||
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
|
||||
if (Expr == R_MIPS_GOT_LOCAL_PAGE) {
|
||||
// At this point we do not know final symbol value so to reduce number
|
||||
// of allocated GOT entries do the following trick. Save all output
|
||||
// sections referenced by GOT relocations. Then later in the `finalize`
|
||||
// method calculate number of "pages" required to cover all saved output
|
||||
// section and allocate appropriate number of GOT entries.
|
||||
auto *OutSec = cast<DefinedRegular<ELFT>>(&Sym)->Section->OutSec;
|
||||
MipsOutSections.insert(OutSec);
|
||||
return;
|
||||
}
|
||||
if (Sym.isTls()) {
|
||||
// GOT entries created for MIPS TLS relocations behave like
|
||||
// almost GOT entries from other ABIs. They go to the end
|
||||
// of the global offset table.
|
||||
Sym.GotIndex = Entries.size();
|
||||
Entries.push_back(&Sym);
|
||||
return;
|
||||
}
|
||||
auto AddEntry = [&](SymbolBody &S, uintX_t A, MipsGotEntries &Items) {
|
||||
if (S.isInGot() && !A)
|
||||
return;
|
||||
size_t NewIndex = Items.size();
|
||||
if (!MipsGotMap.insert({{&S, A}, NewIndex}).second)
|
||||
return;
|
||||
Items.emplace_back(&S, A);
|
||||
if (!A)
|
||||
S.GotIndex = NewIndex;
|
||||
};
|
||||
if (Sym.isPreemptible()) {
|
||||
// Ignore addends for preemptible symbols. They got single GOT entry anyway.
|
||||
AddEntry(Sym, 0, MipsGlobal);
|
||||
Sym.IsInGlobalMipsGot = true;
|
||||
} else if (Expr == R_MIPS_GOT_OFF32) {
|
||||
AddEntry(Sym, Addend, MipsLocal32);
|
||||
Sym.Is32BitMipsGot = true;
|
||||
} else {
|
||||
// Hold local GOT entries accessed via a 16-bit index separately.
|
||||
// That allows to write them in the beginning of the GOT and keep
|
||||
// their indexes as less as possible to escape relocation's overflow.
|
||||
AddEntry(Sym, Addend, MipsLocal);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
|
||||
if (Sym.GlobalDynIndex != -1U)
|
||||
return false;
|
||||
Sym.GlobalDynIndex = Entries.size();
|
||||
// Global Dynamic TLS entries take two GOT slots.
|
||||
Entries.push_back(nullptr);
|
||||
Entries.push_back(&Sym);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reserves TLS entries for a TLS module ID and a TLS block offset.
|
||||
// In total it takes two GOT slots.
|
||||
template <class ELFT> bool GotSection<ELFT>::addTlsIndex() {
|
||||
if (TlsIndexOff != uint32_t(-1))
|
||||
return false;
|
||||
TlsIndexOff = Entries.size() * sizeof(uintX_t);
|
||||
Entries.push_back(nullptr);
|
||||
Entries.push_back(nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
typename GotSection<ELFT>::uintX_t
|
||||
GotSection<ELFT>::getMipsLocalPageOffset(uintX_t EntryValue) {
|
||||
// Initialize the entry by the %hi(EntryValue) expression
|
||||
// but without right-shifting.
|
||||
EntryValue = (EntryValue + 0x8000) & ~0xffff;
|
||||
// Take into account MIPS GOT header.
|
||||
// See comment in the GotSection::writeTo.
|
||||
size_t NewIndex = MipsLocalGotPos.size() + 2;
|
||||
auto P = MipsLocalGotPos.insert(std::make_pair(EntryValue, NewIndex));
|
||||
assert(!P.second || MipsLocalGotPos.size() <= MipsPageEntries);
|
||||
return (uintX_t)P.first->second * sizeof(uintX_t) - MipsGPOffset;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
typename GotSection<ELFT>::uintX_t
|
||||
GotSection<ELFT>::getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const {
|
||||
// Calculate offset of the GOT entries block: TLS, global, local.
|
||||
uintX_t GotBlockOff;
|
||||
if (B.isTls())
|
||||
GotBlockOff = getMipsTlsOffset();
|
||||
else if (B.IsInGlobalMipsGot)
|
||||
GotBlockOff = getMipsLocalEntriesNum() * sizeof(uintX_t);
|
||||
else if (B.Is32BitMipsGot)
|
||||
GotBlockOff = (MipsPageEntries + MipsLocal.size()) * sizeof(uintX_t);
|
||||
else
|
||||
GotBlockOff = MipsPageEntries * sizeof(uintX_t);
|
||||
// Calculate index of the GOT entry in the block.
|
||||
uintX_t GotIndex;
|
||||
if (B.isInGot())
|
||||
GotIndex = B.GotIndex;
|
||||
else {
|
||||
auto It = MipsGotMap.find({&B, Addend});
|
||||
assert(It != MipsGotMap.end());
|
||||
GotIndex = It->second;
|
||||
}
|
||||
return GotBlockOff + GotIndex * sizeof(uintX_t) - MipsGPOffset;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
typename GotSection<ELFT>::uintX_t GotSection<ELFT>::getMipsTlsOffset() const {
|
||||
return (getMipsLocalEntriesNum() + MipsGlobal.size()) * sizeof(uintX_t);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
typename GotSection<ELFT>::uintX_t
|
||||
GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const {
|
||||
return this->getVA() + B.GlobalDynIndex * sizeof(uintX_t);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
typename GotSection<ELFT>::uintX_t
|
||||
GotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const {
|
||||
return B.GlobalDynIndex * sizeof(uintX_t);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
const SymbolBody *GotSection<ELFT>::getMipsFirstGlobalEntry() const {
|
||||
return MipsGlobal.empty() ? nullptr : MipsGlobal.front().first;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const {
|
||||
return MipsPageEntries + MipsLocal.size() + MipsLocal32.size();
|
||||
}
|
||||
|
||||
template <class ELFT> void GotSection<ELFT>::finalize() {
|
||||
size_t EntriesNum = Entries.size();
|
||||
if (Config->EMachine == EM_MIPS) {
|
||||
// Take into account MIPS GOT header.
|
||||
// See comment in the GotSection::writeTo.
|
||||
MipsPageEntries += 2;
|
||||
for (const OutputSectionBase *OutSec : MipsOutSections) {
|
||||
// Calculate an upper bound of MIPS GOT entries required to store page
|
||||
// addresses of local symbols. We assume the worst case - each 64kb
|
||||
// page of the output section has at least one GOT relocation against it.
|
||||
// Add 0x8000 to the section's size because the page address stored
|
||||
// in the GOT entry is calculated as (value + 0x8000) & ~0xffff.
|
||||
MipsPageEntries += (OutSec->Size + 0x8000 + 0xfffe) / 0xffff;
|
||||
}
|
||||
EntriesNum += getMipsLocalEntriesNum() + MipsGlobal.size();
|
||||
}
|
||||
Size = EntriesNum * sizeof(uintX_t);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
static void writeUint(uint8_t *Buf, typename ELFT::uint Val) {
|
||||
typedef typename ELFT::uint uintX_t;
|
||||
write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Buf, Val);
|
||||
}
|
||||
|
||||
template <class ELFT> void GotSection<ELFT>::writeMipsGot(uint8_t *Buf) {
|
||||
// Set the MSB of the second GOT slot. This is not required by any
|
||||
// MIPS ABI documentation, though.
|
||||
//
|
||||
// There is a comment in glibc saying that "The MSB of got[1] of a
|
||||
// gnu object is set to identify gnu objects," and in GNU gold it
|
||||
// says "the second entry will be used by some runtime loaders".
|
||||
// But how this field is being used is unclear.
|
||||
//
|
||||
// We are not really willing to mimic other linkers behaviors
|
||||
// without understanding why they do that, but because all files
|
||||
// generated by GNU tools have this special GOT value, and because
|
||||
// we've been doing this for years, it is probably a safe bet to
|
||||
// keep doing this for now. We really need to revisit this to see
|
||||
// if we had to do this.
|
||||
auto *P = reinterpret_cast<typename ELFT::Off *>(Buf);
|
||||
P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31);
|
||||
// Write 'page address' entries to the local part of the GOT.
|
||||
for (std::pair<uintX_t, size_t> &L : MipsLocalGotPos) {
|
||||
uint8_t *Entry = Buf + L.second * sizeof(uintX_t);
|
||||
writeUint<ELFT>(Entry, L.first);
|
||||
}
|
||||
Buf += MipsPageEntries * sizeof(uintX_t);
|
||||
auto AddEntry = [&](const MipsGotEntry &SA) {
|
||||
uint8_t *Entry = Buf;
|
||||
Buf += sizeof(uintX_t);
|
||||
const SymbolBody *Body = SA.first;
|
||||
uintX_t VA = Body->template getVA<ELFT>(SA.second);
|
||||
writeUint<ELFT>(Entry, VA);
|
||||
};
|
||||
std::for_each(std::begin(MipsLocal), std::end(MipsLocal), AddEntry);
|
||||
std::for_each(std::begin(MipsLocal32), std::end(MipsLocal32), AddEntry);
|
||||
std::for_each(std::begin(MipsGlobal), std::end(MipsGlobal), AddEntry);
|
||||
// Initialize TLS-related GOT entries. If the entry has a corresponding
|
||||
// dynamic relocations, leave it initialized by zero. Write down adjusted
|
||||
// TLS symbol's values otherwise. To calculate the adjustments use offsets
|
||||
// for thread-local storage.
|
||||
// https://www.linux-mips.org/wiki/NPTL
|
||||
if (TlsIndexOff != -1U && !Config->Pic)
|
||||
writeUint<ELFT>(Buf + TlsIndexOff, 1);
|
||||
for (const SymbolBody *B : Entries) {
|
||||
if (!B || B->isPreemptible())
|
||||
continue;
|
||||
uintX_t VA = B->getVA<ELFT>();
|
||||
if (B->GotIndex != -1U) {
|
||||
uint8_t *Entry = Buf + B->GotIndex * sizeof(uintX_t);
|
||||
writeUint<ELFT>(Entry, VA - 0x7000);
|
||||
}
|
||||
if (B->GlobalDynIndex != -1U) {
|
||||
uint8_t *Entry = Buf + B->GlobalDynIndex * sizeof(uintX_t);
|
||||
writeUint<ELFT>(Entry, 1);
|
||||
Entry += sizeof(uintX_t);
|
||||
writeUint<ELFT>(Entry, VA - 0x8000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
if (Config->EMachine == EM_MIPS) {
|
||||
writeMipsGot(Buf);
|
||||
return;
|
||||
}
|
||||
for (const SymbolBody *B : Entries) {
|
||||
uint8_t *Entry = Buf;
|
||||
Buf += sizeof(uintX_t);
|
||||
if (!B)
|
||||
continue;
|
||||
if (B->isPreemptible())
|
||||
continue; // The dynamic linker will take care of it.
|
||||
uintX_t VA = B->getVA<ELFT>();
|
||||
writeUint<ELFT>(Entry, VA);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
GotPltSection<ELFT>::GotPltSection()
|
||||
: SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
|
||||
|
@ -434,6 +703,11 @@ template class elf::BuildIdHexstring<ELF32BE>;
|
|||
template class elf::BuildIdHexstring<ELF64LE>;
|
||||
template class elf::BuildIdHexstring<ELF64BE>;
|
||||
|
||||
template class elf::GotSection<ELF32LE>;
|
||||
template class elf::GotSection<ELF32BE>;
|
||||
template class elf::GotSection<ELF64LE>;
|
||||
template class elf::GotSection<ELF64BE>;
|
||||
|
||||
template class elf::GotPltSection<ELF32LE>;
|
||||
template class elf::GotPltSection<ELF32BE>;
|
||||
template class elf::GotPltSection<ELF64LE>;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define LLD_ELF_SYNTHETIC_SECTION_H
|
||||
|
||||
#include "InputSection.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
|
@ -69,6 +70,9 @@ public:
|
|||
|
||||
virtual void writeTo(uint8_t *Buf) = 0;
|
||||
virtual size_t getSize() const { return this->Data.size(); }
|
||||
uintX_t getVA() const {
|
||||
return this->OutSec ? this->OutSec->Addr + this->OutSecOff : 0;
|
||||
}
|
||||
|
||||
static bool classof(const InputSectionData *D) {
|
||||
return D->kind() == InputSectionData::Synthetic;
|
||||
|
@ -131,6 +135,72 @@ public:
|
|||
void writeBuildId(llvm::MutableArrayRef<uint8_t>) override;
|
||||
};
|
||||
|
||||
template <class ELFT> class GotSection final : public SyntheticSection<ELFT> {
|
||||
typedef typename ELFT::uint uintX_t;
|
||||
|
||||
public:
|
||||
GotSection();
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
size_t getSize() const override { return Size; }
|
||||
void finalize();
|
||||
void addEntry(SymbolBody &Sym);
|
||||
void addMipsEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr);
|
||||
bool addDynTlsEntry(SymbolBody &Sym);
|
||||
bool addTlsIndex();
|
||||
bool empty() const { return MipsPageEntries == 0 && Entries.empty(); }
|
||||
uintX_t getMipsLocalPageOffset(uintX_t Addr);
|
||||
uintX_t getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const;
|
||||
uintX_t getGlobalDynAddr(const SymbolBody &B) const;
|
||||
uintX_t getGlobalDynOffset(const SymbolBody &B) const;
|
||||
|
||||
// Returns the symbol which corresponds to the first entry of the global part
|
||||
// of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic
|
||||
// table properties.
|
||||
// Returns nullptr if the global part is empty.
|
||||
const SymbolBody *getMipsFirstGlobalEntry() const;
|
||||
|
||||
// Returns the number of entries in the local part of GOT including
|
||||
// the number of reserved entries. This method is MIPS-specific.
|
||||
unsigned getMipsLocalEntriesNum() const;
|
||||
|
||||
// Returns offset of TLS part of the MIPS GOT table. This part goes
|
||||
// after 'local' and 'global' entries.
|
||||
uintX_t getMipsTlsOffset() const;
|
||||
|
||||
uintX_t getTlsIndexVA() { return this->getVA() + TlsIndexOff; }
|
||||
uint32_t getTlsIndexOff() const { return TlsIndexOff; }
|
||||
|
||||
// Flag to force GOT to be in output if we have relocations
|
||||
// that relies on its address.
|
||||
bool HasGotOffRel = false;
|
||||
|
||||
private:
|
||||
std::vector<const SymbolBody *> Entries;
|
||||
uint32_t TlsIndexOff = -1;
|
||||
uint32_t MipsPageEntries = 0;
|
||||
uintX_t Size = 0;
|
||||
// Output sections referenced by MIPS GOT relocations.
|
||||
llvm::SmallPtrSet<const OutputSectionBase *, 10> MipsOutSections;
|
||||
llvm::DenseMap<uintX_t, size_t> MipsLocalGotPos;
|
||||
|
||||
// MIPS ABI requires to create unique GOT entry for each Symbol/Addend
|
||||
// pairs. The `MipsGotMap` maps (S,A) pair to the GOT index in the `MipsLocal`
|
||||
// or `MipsGlobal` vectors. In general it does not have a sence to take in
|
||||
// account addend for preemptible symbols because the corresponding
|
||||
// GOT entries should have one-to-one mapping with dynamic symbols table.
|
||||
// But we use the same container's types for both kind of GOT entries
|
||||
// to handle them uniformly.
|
||||
typedef std::pair<const SymbolBody *, uintX_t> MipsGotEntry;
|
||||
typedef std::vector<MipsGotEntry> MipsGotEntries;
|
||||
llvm::DenseMap<MipsGotEntry, size_t> MipsGotMap;
|
||||
MipsGotEntries MipsLocal;
|
||||
MipsGotEntries MipsLocal32;
|
||||
MipsGotEntries MipsGlobal;
|
||||
|
||||
// Write MIPS-specific parts of the GOT.
|
||||
void writeMipsGot(uint8_t *Buf);
|
||||
};
|
||||
|
||||
template <class ELFT>
|
||||
class GotPltSection final : public SyntheticSection<ELFT> {
|
||||
typedef typename ELFT::uint uintX_t;
|
||||
|
@ -141,7 +211,6 @@ public:
|
|||
bool empty() const;
|
||||
size_t getSize() const override;
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
uintX_t getVA() { return this->OutSec->Addr + this->OutSecOff; }
|
||||
|
||||
private:
|
||||
std::vector<const SymbolBody *> Entries;
|
||||
|
@ -155,6 +224,7 @@ template <class ELFT> MergeInputSection<ELFT> *createCommentSection();
|
|||
template <class ELFT> struct In {
|
||||
static BuildIdSection<ELFT> *BuildId;
|
||||
static InputSection<ELFT> *Common;
|
||||
static GotSection<ELFT> *Got;
|
||||
static GotPltSection<ELFT> *GotPlt;
|
||||
static InputSection<ELFT> *Interp;
|
||||
static MipsAbiFlagsSection<ELFT> *MipsAbiFlags;
|
||||
|
@ -164,6 +234,7 @@ template <class ELFT> struct In {
|
|||
|
||||
template <class ELFT> BuildIdSection<ELFT> *In<ELFT>::BuildId;
|
||||
template <class ELFT> InputSection<ELFT> *In<ELFT>::Common;
|
||||
template <class ELFT> GotSection<ELFT> *In<ELFT>::Got;
|
||||
template <class ELFT> GotPltSection<ELFT> *In<ELFT>::GotPlt;
|
||||
template <class ELFT> InputSection<ELFT> *In<ELFT>::Interp;
|
||||
template <class ELFT> MipsAbiFlagsSection<ELFT> *In<ELFT>::MipsAbiFlags;
|
||||
|
|
|
@ -1020,7 +1020,7 @@ uint64_t getPPC64TocBase() {
|
|||
// TOC starts where the first of these sections starts. We always create a
|
||||
// .got when we see a relocation that uses it, so for us the start is always
|
||||
// the .got.
|
||||
uint64_t TocVA = Out<ELF64BE>::Got->Addr;
|
||||
uint64_t TocVA = In<ELF64BE>::Got->getVA();
|
||||
|
||||
// Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000
|
||||
// thus permitting a full 64 Kbytes segment. Note that the glibc startup
|
||||
|
|
|
@ -212,7 +212,6 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
|
|||
Out<ELFT>::DynStrTab = make<StringTableSection<ELFT>>(".dynstr", true);
|
||||
Out<ELFT>::Dynamic = make<DynamicSection<ELFT>>();
|
||||
Out<ELFT>::EhFrame = make<EhOutputSection<ELFT>>();
|
||||
Out<ELFT>::Got = make<GotSection<ELFT>>();
|
||||
Out<ELFT>::Plt = make<PltSection<ELFT>>();
|
||||
Out<ELFT>::RelaDyn = make<RelocationSection<ELFT>>(
|
||||
Config->Rela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc);
|
||||
|
@ -313,6 +312,7 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
|
|||
}
|
||||
}
|
||||
|
||||
In<ELFT>::Got = make<GotSection<ELFT>>();
|
||||
In<ELFT>::GotPlt = make<GotPltSection<ELFT>>();
|
||||
}
|
||||
|
||||
|
@ -427,7 +427,7 @@ template <class ELFT> bool elf::isRelroSection(const OutputSectionBase *Sec) {
|
|||
return true;
|
||||
if (Sec == In<ELFT>::GotPlt->OutSec)
|
||||
return Config->ZNow;
|
||||
if (Sec == Out<ELFT>::Dynamic || Sec == Out<ELFT>::Got)
|
||||
if (Sec == Out<ELFT>::Dynamic || Sec == In<ELFT>::Got->OutSec)
|
||||
return true;
|
||||
StringRef S = Sec->getName();
|
||||
return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" ||
|
||||
|
@ -557,6 +557,28 @@ static Symbol *addOptionalSynthetic(StringRef Name, OutputSectionBase *Sec,
|
|||
return Symtab<ELFT>::X->addSynthetic(Name, Sec, Val, StOther);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
static Symbol *addRegular(StringRef Name, InputSectionBase<ELFT> *IS,
|
||||
typename ELFT::uint Value) {
|
||||
typename ELFT::Sym LocalHidden = {};
|
||||
LocalHidden.setBindingAndType(STB_LOCAL, STT_NOTYPE);
|
||||
LocalHidden.setVisibility(STV_HIDDEN);
|
||||
Symbol *S = Symtab<ELFT>::X->addRegular(Name, LocalHidden, IS);
|
||||
cast<DefinedRegular<ELFT>>(S->body())->Value = Value;
|
||||
return S;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
static Symbol *addOptionalRegular(StringRef Name, InputSectionBase<ELFT> *IS,
|
||||
typename ELFT::uint Value) {
|
||||
SymbolBody *S = Symtab<ELFT>::X->find(Name);
|
||||
if (!S)
|
||||
return nullptr;
|
||||
if (!S->isUndefined() && !S->isShared())
|
||||
return S->symbol();
|
||||
return addRegular(Name, IS, Value);
|
||||
}
|
||||
|
||||
// The beginning and the ending of .rel[a].plt section are marked
|
||||
// with __rel[a]_iplt_{start,end} symbols if it is a statically linked
|
||||
// executable. The runtime needs these symbols in order to resolve
|
||||
|
@ -582,13 +604,11 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
|
|||
// so that it points to an absolute address which is relative to GOT.
|
||||
// See "Global Data Symbols" in Chapter 6 in the following document:
|
||||
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
|
||||
Symtab<ELFT>::X->addSynthetic("_gp", Out<ELFT>::Got, MipsGPOffset,
|
||||
STV_HIDDEN);
|
||||
addRegular("_gp", In<ELFT>::Got, MipsGPOffset);
|
||||
|
||||
// On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
|
||||
// start of function and 'gp' pointer into GOT.
|
||||
Symbol *Sym =
|
||||
addOptionalSynthetic<ELFT>("_gp_disp", Out<ELFT>::Got, MipsGPOffset);
|
||||
Symbol *Sym = addOptionalRegular("_gp_disp", In<ELFT>::Got, MipsGPOffset);
|
||||
if (Sym)
|
||||
ElfSym<ELFT>::MipsGpDisp = Sym->body();
|
||||
|
||||
|
@ -596,7 +616,7 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
|
|||
// pointer. This symbol is used in the code generated by .cpload pseudo-op
|
||||
// in case of using -mno-shared option.
|
||||
// https://sourceware.org/ml/binutils/2004-12/msg00094.html
|
||||
addOptionalSynthetic<ELFT>("__gnu_local_gp", Out<ELFT>::Got, MipsGPOffset);
|
||||
addOptionalRegular("__gnu_local_gp", In<ELFT>::Got, MipsGPOffset);
|
||||
}
|
||||
|
||||
// In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
|
||||
|
@ -888,13 +908,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
|||
// This function adds linker-created Out<ELFT>::* sections.
|
||||
addPredefinedSections();
|
||||
|
||||
// We fill .got.plt section in scanRelocs(). This is the
|
||||
// reason we don't add it earlier in createSections().
|
||||
if (!In<ELFT>::GotPlt->empty()) {
|
||||
addInputSec(In<ELFT>::GotPlt);
|
||||
In<ELFT>::GotPlt->OutSec->assignOffsets();
|
||||
}
|
||||
|
||||
sortSections();
|
||||
|
||||
unsigned I = 1;
|
||||
|
@ -925,7 +938,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
|||
}
|
||||
|
||||
template <class ELFT> bool Writer<ELFT>::needsGot() {
|
||||
if (!Out<ELFT>::Got->empty())
|
||||
if (!In<ELFT>::Got->empty())
|
||||
return true;
|
||||
|
||||
// We add the .got section to the result for dynamic MIPS target because
|
||||
|
@ -935,7 +948,7 @@ template <class ELFT> bool Writer<ELFT>::needsGot() {
|
|||
|
||||
// If we have a relocation that is relative to GOT (such as GOTOFFREL),
|
||||
// we need to emit a GOT even if it's empty.
|
||||
return Out<ELFT>::Got->HasGotOffRel;
|
||||
return In<ELFT>::Got->HasGotOffRel;
|
||||
}
|
||||
|
||||
// This function add Out<ELFT>::* sections to OutputSections.
|
||||
|
@ -976,8 +989,19 @@ template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
|
|||
if (Out<ELFT>::RelaPlt && Out<ELFT>::RelaPlt->hasRelocs())
|
||||
Add(Out<ELFT>::RelaPlt);
|
||||
|
||||
if (needsGot())
|
||||
Add(Out<ELFT>::Got);
|
||||
// We fill .got and .got.plt sections in scanRelocs(). This is the
|
||||
// reason we don't add it earlier in createSections().
|
||||
if (needsGot()) {
|
||||
In<ELFT>::Got->finalize();
|
||||
addInputSec(In<ELFT>::Got);
|
||||
In<ELFT>::Got->OutSec->assignOffsets();
|
||||
}
|
||||
|
||||
if (!In<ELFT>::GotPlt->empty()) {
|
||||
addInputSec(In<ELFT>::GotPlt);
|
||||
In<ELFT>::GotPlt->OutSec->assignOffsets();
|
||||
}
|
||||
|
||||
if (!Out<ELFT>::Plt->empty())
|
||||
Add(Out<ELFT>::Plt);
|
||||
if (!Out<ELFT>::EhFrame->empty())
|
||||
|
|
Loading…
Reference in New Issue