714 lines
26 KiB
C++
714 lines
26 KiB
C++
//===- SyntheticSections.cpp ----------------------------------------------===//
|
|
//
|
|
// The LLVM Linker
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file contains linker-synthesized sections. Currently,
|
|
// synthetic sections are created either output sections or input sections,
|
|
// but we are rewriting code so that all synthetic sections are created as
|
|
// input sections.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "SyntheticSections.h"
|
|
#include "Config.h"
|
|
#include "Error.h"
|
|
#include "InputFiles.h"
|
|
#include "Memory.h"
|
|
#include "OutputSections.h"
|
|
#include "Strings.h"
|
|
#include "SymbolTable.h"
|
|
#include "Target.h"
|
|
#include "Writer.h"
|
|
|
|
#include "lld/Config/Version.h"
|
|
#include "lld/Core/Parallel.h"
|
|
#include "llvm/Support/Endian.h"
|
|
#include "llvm/Support/MD5.h"
|
|
#include "llvm/Support/RandomNumberGenerator.h"
|
|
#include "llvm/Support/SHA1.h"
|
|
#include "llvm/Support/xxhash.h"
|
|
#include <cstdlib>
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::ELF;
|
|
using namespace llvm::object;
|
|
using namespace llvm::support;
|
|
using namespace llvm::support::endian;
|
|
|
|
using namespace lld;
|
|
using namespace lld::elf;
|
|
|
|
template <class ELFT> static std::vector<DefinedCommon *> getCommonSymbols() {
|
|
std::vector<DefinedCommon *> V;
|
|
for (Symbol *S : Symtab<ELFT>::X->getSymbols())
|
|
if (auto *B = dyn_cast<DefinedCommon>(S->body()))
|
|
V.push_back(B);
|
|
return V;
|
|
}
|
|
|
|
// Find all common symbols and allocate space for them.
|
|
template <class ELFT> InputSection<ELFT> *elf::createCommonSection() {
|
|
auto *Ret = make<InputSection<ELFT>>(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, 1,
|
|
ArrayRef<uint8_t>(), "COMMON");
|
|
Ret->Live = true;
|
|
|
|
// Sort the common symbols by alignment as an heuristic to pack them better.
|
|
std::vector<DefinedCommon *> Syms = getCommonSymbols<ELFT>();
|
|
std::stable_sort(Syms.begin(), Syms.end(),
|
|
[](const DefinedCommon *A, const DefinedCommon *B) {
|
|
return A->Alignment > B->Alignment;
|
|
});
|
|
|
|
// Assign offsets to symbols.
|
|
size_t Size = 0;
|
|
size_t Alignment = 1;
|
|
for (DefinedCommon *Sym : Syms) {
|
|
Alignment = std::max<size_t>(Alignment, Sym->Alignment);
|
|
Size = alignTo(Size, Sym->Alignment);
|
|
|
|
// Compute symbol offset relative to beginning of input section.
|
|
Sym->Offset = Size;
|
|
Size += Sym->Size;
|
|
}
|
|
Ret->Alignment = Alignment;
|
|
Ret->Data = makeArrayRef<uint8_t>(nullptr, Size);
|
|
return Ret;
|
|
}
|
|
|
|
// Returns an LLD version string.
|
|
static ArrayRef<uint8_t> getVersion() {
|
|
// Check LLD_VERSION first for ease of testing.
|
|
// You can get consitent output by using the environment variable.
|
|
// This is only for testing.
|
|
StringRef S = getenv("LLD_VERSION");
|
|
if (S.empty())
|
|
S = Saver.save(Twine("Linker: ") + getLLDVersion());
|
|
|
|
// +1 to include the terminating '\0'.
|
|
return {(const uint8_t *)S.data(), S.size() + 1};
|
|
}
|
|
|
|
// Creates a .comment section containing LLD version info.
|
|
// With this feature, you can identify LLD-generated binaries easily
|
|
// by "objdump -s -j .comment <file>".
|
|
// The returned object is a mergeable string section.
|
|
template <class ELFT> MergeInputSection<ELFT> *elf::createCommentSection() {
|
|
typename ELFT::Shdr Hdr = {};
|
|
Hdr.sh_flags = SHF_MERGE | SHF_STRINGS;
|
|
Hdr.sh_type = SHT_PROGBITS;
|
|
Hdr.sh_entsize = 1;
|
|
Hdr.sh_addralign = 1;
|
|
|
|
auto *Ret = make<MergeInputSection<ELFT>>(/*file=*/nullptr, &Hdr, ".comment");
|
|
Ret->Data = getVersion();
|
|
Ret->splitIntoPieces();
|
|
return Ret;
|
|
}
|
|
|
|
// Iterate over sections of the specified type. For each section call
|
|
// provided function. After that "kill" the section by turning off
|
|
// "Live" flag, so that they won't be included in the final output.
|
|
template <class ELFT>
|
|
static void iterateSectionContents(
|
|
uint32_t Type,
|
|
std::function<void(elf::ObjectFile<ELFT> *, ArrayRef<uint8_t>)> F) {
|
|
for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections) {
|
|
if (Sec && Sec->Live && Sec->Type == Type) {
|
|
Sec->Live = false;
|
|
F(Sec->getFile(), Sec->Data);
|
|
}
|
|
}
|
|
}
|
|
|
|
// .MIPS.abiflags section.
|
|
template <class ELFT>
|
|
MipsAbiFlagsSection<ELFT>::MipsAbiFlagsSection()
|
|
: InputSection<ELFT>(SHF_ALLOC, SHT_MIPS_ABIFLAGS, 8, ArrayRef<uint8_t>(),
|
|
".MIPS.abiflags") {
|
|
auto Func = [this](ObjectFile<ELFT> *F, ArrayRef<uint8_t> D) {
|
|
if (D.size() != sizeof(Elf_Mips_ABIFlags)) {
|
|
error(getFilename(F) + ": invalid size of .MIPS.abiflags section");
|
|
return;
|
|
}
|
|
auto *S = reinterpret_cast<const Elf_Mips_ABIFlags *>(D.data());
|
|
if (S->version != 0) {
|
|
error(getFilename(F) + ": unexpected .MIPS.abiflags version " +
|
|
Twine(S->version));
|
|
return;
|
|
}
|
|
// LLD checks ISA compatibility in getMipsEFlags(). Here we just
|
|
// select the highest number of ISA/Rev/Ext.
|
|
Flags.isa_level = std::max(Flags.isa_level, S->isa_level);
|
|
Flags.isa_rev = std::max(Flags.isa_rev, S->isa_rev);
|
|
Flags.isa_ext = std::max(Flags.isa_ext, S->isa_ext);
|
|
Flags.gpr_size = std::max(Flags.gpr_size, S->gpr_size);
|
|
Flags.cpr1_size = std::max(Flags.cpr1_size, S->cpr1_size);
|
|
Flags.cpr2_size = std::max(Flags.cpr2_size, S->cpr2_size);
|
|
Flags.ases |= S->ases;
|
|
Flags.flags1 |= S->flags1;
|
|
Flags.flags2 |= S->flags2;
|
|
Flags.fp_abi =
|
|
elf::getMipsFpAbiFlag(Flags.fp_abi, S->fp_abi, getFilename(F));
|
|
};
|
|
iterateSectionContents<ELFT>(SHT_MIPS_ABIFLAGS, Func);
|
|
|
|
this->Data = ArrayRef<uint8_t>((const uint8_t *)&Flags, sizeof(Flags));
|
|
this->Live = true;
|
|
}
|
|
|
|
// .MIPS.options section.
|
|
template <class ELFT>
|
|
MipsOptionsSection<ELFT>::MipsOptionsSection()
|
|
: InputSection<ELFT>(SHF_ALLOC, SHT_MIPS_OPTIONS, 8, ArrayRef<uint8_t>(),
|
|
".MIPS.options") {
|
|
Buf.resize(sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo));
|
|
getOptions()->kind = ODK_REGINFO;
|
|
getOptions()->size = Buf.size();
|
|
auto Func = [this](ObjectFile<ELFT> *F, ArrayRef<uint8_t> D) {
|
|
while (!D.empty()) {
|
|
if (D.size() < sizeof(Elf_Mips_Options)) {
|
|
error(getFilename(F) + ": invalid size of .MIPS.options section");
|
|
break;
|
|
}
|
|
auto *O = reinterpret_cast<const Elf_Mips_Options *>(D.data());
|
|
if (O->kind == ODK_REGINFO) {
|
|
if (Config->Relocatable && O->getRegInfo().ri_gp_value)
|
|
error(getFilename(F) + ": unsupported non-zero ri_gp_value");
|
|
getOptions()->getRegInfo().ri_gprmask |= O->getRegInfo().ri_gprmask;
|
|
F->MipsGp0 = O->getRegInfo().ri_gp_value;
|
|
break;
|
|
}
|
|
if (!O->size)
|
|
fatal(getFilename(F) + ": zero option descriptor size");
|
|
D = D.slice(O->size);
|
|
}
|
|
};
|
|
iterateSectionContents<ELFT>(SHT_MIPS_OPTIONS, Func);
|
|
|
|
this->Data = ArrayRef<uint8_t>(Buf);
|
|
// Section should be alive for N64 ABI only.
|
|
this->Live = ELFT::Is64Bits;
|
|
}
|
|
|
|
template <class ELFT> void MipsOptionsSection<ELFT>::finalize() {
|
|
if (!Config->Relocatable)
|
|
getOptions()->getRegInfo().ri_gp_value =
|
|
In<ELFT>::Got->getVA() + MipsGPOffset;
|
|
}
|
|
|
|
// MIPS .reginfo section.
|
|
template <class ELFT>
|
|
MipsReginfoSection<ELFT>::MipsReginfoSection()
|
|
: InputSection<ELFT>(SHF_ALLOC, SHT_MIPS_REGINFO, 4, ArrayRef<uint8_t>(),
|
|
".reginfo") {
|
|
auto Func = [this](ObjectFile<ELFT> *F, ArrayRef<uint8_t> D) {
|
|
if (D.size() != sizeof(Elf_Mips_RegInfo)) {
|
|
error(getFilename(F) + ": invalid size of .reginfo section");
|
|
return;
|
|
}
|
|
auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(D.data());
|
|
if (Config->Relocatable && R->ri_gp_value)
|
|
error(getFilename(F) + ": unsupported non-zero ri_gp_value");
|
|
Reginfo.ri_gprmask |= R->ri_gprmask;
|
|
F->MipsGp0 = R->ri_gp_value;
|
|
};
|
|
iterateSectionContents<ELFT>(SHT_MIPS_REGINFO, Func);
|
|
|
|
this->Data = ArrayRef<uint8_t>((const uint8_t *)&Reginfo, sizeof(Reginfo));
|
|
// Section should be alive for O32 and N32 ABIs only.
|
|
this->Live = !ELFT::Is64Bits;
|
|
}
|
|
|
|
template <class ELFT> void MipsReginfoSection<ELFT>::finalize() {
|
|
if (!Config->Relocatable)
|
|
Reginfo.ri_gp_value = In<ELFT>::Got->getVA() + MipsGPOffset;
|
|
}
|
|
|
|
static ArrayRef<uint8_t> createInterp() {
|
|
// StringSaver guarantees that the returned string ends with '\0'.
|
|
StringRef S = Saver.save(Config->DynamicLinker);
|
|
return {(const uint8_t *)S.data(), S.size() + 1};
|
|
}
|
|
|
|
template <class ELFT> InputSection<ELFT> *elf::createInterpSection() {
|
|
auto *Ret = make<InputSection<ELFT>>(SHF_ALLOC, SHT_PROGBITS, 1,
|
|
createInterp(), ".interp");
|
|
Ret->Live = true;
|
|
return Ret;
|
|
}
|
|
|
|
template <class ELFT>
|
|
BuildIdSection<ELFT>::BuildIdSection(size_t HashSize)
|
|
: InputSection<ELFT>(SHF_ALLOC, SHT_NOTE, 1, ArrayRef<uint8_t>(),
|
|
".note.gnu.build-id"),
|
|
HashSize(HashSize) {
|
|
this->Live = true;
|
|
|
|
Buf.resize(HeaderSize + HashSize);
|
|
const endianness E = ELFT::TargetEndianness;
|
|
write32<E>(Buf.data(), 4); // Name size
|
|
write32<E>(Buf.data() + 4, HashSize); // Content size
|
|
write32<E>(Buf.data() + 8, NT_GNU_BUILD_ID); // Type
|
|
memcpy(Buf.data() + 12, "GNU", 4); // Name string
|
|
this->Data = ArrayRef<uint8_t>(Buf);
|
|
}
|
|
|
|
// Returns the location of the build-id hash value in the output.
|
|
template <class ELFT>
|
|
uint8_t *BuildIdSection<ELFT>::getOutputLoc(uint8_t *Start) const {
|
|
return Start + this->OutSec->Offset + this->OutSecOff + HeaderSize;
|
|
}
|
|
|
|
// Split one uint8 array into small pieces of uint8 arrays.
|
|
static std::vector<ArrayRef<uint8_t>> split(ArrayRef<uint8_t> Arr,
|
|
size_t ChunkSize) {
|
|
std::vector<ArrayRef<uint8_t>> Ret;
|
|
while (Arr.size() > ChunkSize) {
|
|
Ret.push_back(Arr.take_front(ChunkSize));
|
|
Arr = Arr.drop_front(ChunkSize);
|
|
}
|
|
if (!Arr.empty())
|
|
Ret.push_back(Arr);
|
|
return Ret;
|
|
}
|
|
|
|
// Computes a hash value of Data using a given hash function.
|
|
// In order to utilize multiple cores, we first split data into 1MB
|
|
// chunks, compute a hash for each chunk, and then compute a hash value
|
|
// of the hash values.
|
|
template <class ELFT>
|
|
void BuildIdSection<ELFT>::computeHash(
|
|
llvm::MutableArrayRef<uint8_t> Data,
|
|
std::function<void(ArrayRef<uint8_t> Arr, uint8_t *Dest)> HashFn) {
|
|
std::vector<ArrayRef<uint8_t>> Chunks = split(Data, 1024 * 1024);
|
|
std::vector<uint8_t> HashList(Chunks.size() * HashSize);
|
|
|
|
auto Fn = [&](ArrayRef<uint8_t> &Chunk) {
|
|
size_t Idx = &Chunk - Chunks.data();
|
|
HashFn(Chunk, HashList.data() + Idx * HashSize);
|
|
};
|
|
|
|
if (Config->Threads)
|
|
parallel_for_each(Chunks.begin(), Chunks.end(), Fn);
|
|
else
|
|
std::for_each(Chunks.begin(), Chunks.end(), Fn);
|
|
|
|
HashFn(HashList, this->getOutputLoc(Data.begin()));
|
|
}
|
|
|
|
template <class ELFT>
|
|
void BuildIdFastHash<ELFT>::writeBuildId(MutableArrayRef<uint8_t> Buf) {
|
|
this->computeHash(Buf, [](ArrayRef<uint8_t> Arr, uint8_t *Dest) {
|
|
write64le(Dest, xxHash64(toStringRef(Arr)));
|
|
});
|
|
}
|
|
|
|
template <class ELFT>
|
|
void BuildIdMd5<ELFT>::writeBuildId(MutableArrayRef<uint8_t> Buf) {
|
|
this->computeHash(Buf, [](ArrayRef<uint8_t> Arr, uint8_t *Dest) {
|
|
MD5 Hash;
|
|
Hash.update(Arr);
|
|
MD5::MD5Result Res;
|
|
Hash.final(Res);
|
|
memcpy(Dest, Res, 16);
|
|
});
|
|
}
|
|
|
|
template <class ELFT>
|
|
void BuildIdSha1<ELFT>::writeBuildId(MutableArrayRef<uint8_t> Buf) {
|
|
this->computeHash(Buf, [](ArrayRef<uint8_t> Arr, uint8_t *Dest) {
|
|
SHA1 Hash;
|
|
Hash.update(Arr);
|
|
memcpy(Dest, Hash.final().data(), 20);
|
|
});
|
|
}
|
|
|
|
template <class ELFT>
|
|
void BuildIdUuid<ELFT>::writeBuildId(MutableArrayRef<uint8_t> Buf) {
|
|
if (getRandomBytes(this->getOutputLoc(Buf.data()), this->HashSize))
|
|
error("entropy source failure");
|
|
}
|
|
|
|
template <class ELFT>
|
|
BuildIdHexstring<ELFT>::BuildIdHexstring()
|
|
: BuildIdSection<ELFT>(Config->BuildIdVector.size()) {}
|
|
|
|
template <class ELFT>
|
|
void BuildIdHexstring<ELFT>::writeBuildId(MutableArrayRef<uint8_t> Buf) {
|
|
memcpy(this->getOutputLoc(Buf.data()), Config->BuildIdVector.data(),
|
|
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,
|
|
Target->GotPltEntrySize, ".got.plt") {
|
|
}
|
|
|
|
template <class ELFT> void GotPltSection<ELFT>::addEntry(SymbolBody &Sym) {
|
|
Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size();
|
|
Entries.push_back(&Sym);
|
|
}
|
|
|
|
template <class ELFT> bool GotPltSection<ELFT>::empty() const {
|
|
return Entries.empty();
|
|
}
|
|
|
|
template <class ELFT> size_t GotPltSection<ELFT>::getSize() const {
|
|
return (Target->GotPltHeaderEntriesNum + Entries.size()) *
|
|
Target->GotPltEntrySize;
|
|
}
|
|
|
|
template <class ELFT> void GotPltSection<ELFT>::writeTo(uint8_t *Buf) {
|
|
Target->writeGotPltHeader(Buf);
|
|
Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize;
|
|
for (const SymbolBody *B : Entries) {
|
|
Target->writeGotPlt(Buf, *B);
|
|
Buf += sizeof(uintX_t);
|
|
}
|
|
}
|
|
|
|
template InputSection<ELF32LE> *elf::createCommonSection();
|
|
template InputSection<ELF32BE> *elf::createCommonSection();
|
|
template InputSection<ELF64LE> *elf::createCommonSection();
|
|
template InputSection<ELF64BE> *elf::createCommonSection();
|
|
|
|
template InputSection<ELF32LE> *elf::createInterpSection();
|
|
template InputSection<ELF32BE> *elf::createInterpSection();
|
|
template InputSection<ELF64LE> *elf::createInterpSection();
|
|
template InputSection<ELF64BE> *elf::createInterpSection();
|
|
|
|
template MergeInputSection<ELF32LE> *elf::createCommentSection();
|
|
template MergeInputSection<ELF32BE> *elf::createCommentSection();
|
|
template MergeInputSection<ELF64LE> *elf::createCommentSection();
|
|
template MergeInputSection<ELF64BE> *elf::createCommentSection();
|
|
|
|
template class elf::MipsAbiFlagsSection<ELF32LE>;
|
|
template class elf::MipsAbiFlagsSection<ELF32BE>;
|
|
template class elf::MipsAbiFlagsSection<ELF64LE>;
|
|
template class elf::MipsAbiFlagsSection<ELF64BE>;
|
|
|
|
template class elf::MipsOptionsSection<ELF32LE>;
|
|
template class elf::MipsOptionsSection<ELF32BE>;
|
|
template class elf::MipsOptionsSection<ELF64LE>;
|
|
template class elf::MipsOptionsSection<ELF64BE>;
|
|
|
|
template class elf::MipsReginfoSection<ELF32LE>;
|
|
template class elf::MipsReginfoSection<ELF32BE>;
|
|
template class elf::MipsReginfoSection<ELF64LE>;
|
|
template class elf::MipsReginfoSection<ELF64BE>;
|
|
|
|
template class elf::BuildIdSection<ELF32LE>;
|
|
template class elf::BuildIdSection<ELF32BE>;
|
|
template class elf::BuildIdSection<ELF64LE>;
|
|
template class elf::BuildIdSection<ELF64BE>;
|
|
|
|
template class elf::BuildIdFastHash<ELF32LE>;
|
|
template class elf::BuildIdFastHash<ELF32BE>;
|
|
template class elf::BuildIdFastHash<ELF64LE>;
|
|
template class elf::BuildIdFastHash<ELF64BE>;
|
|
|
|
template class elf::BuildIdMd5<ELF32LE>;
|
|
template class elf::BuildIdMd5<ELF32BE>;
|
|
template class elf::BuildIdMd5<ELF64LE>;
|
|
template class elf::BuildIdMd5<ELF64BE>;
|
|
|
|
template class elf::BuildIdSha1<ELF32LE>;
|
|
template class elf::BuildIdSha1<ELF32BE>;
|
|
template class elf::BuildIdSha1<ELF64LE>;
|
|
template class elf::BuildIdSha1<ELF64BE>;
|
|
|
|
template class elf::BuildIdUuid<ELF32LE>;
|
|
template class elf::BuildIdUuid<ELF32BE>;
|
|
template class elf::BuildIdUuid<ELF64LE>;
|
|
template class elf::BuildIdUuid<ELF64BE>;
|
|
|
|
template class elf::BuildIdHexstring<ELF32LE>;
|
|
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>;
|
|
template class elf::GotPltSection<ELF64BE>;
|