[PATCH] D22683: [ELF] Symbol assignment within input section list
Rafael EspĂndola via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 4 08:51:33 PDT 2016
And making sure it has the patch.
Sorry for the noise, somehow my initial replies went just to phab and
I think it dropped it.
The patch includes a few improvements and is a rebased version of the
old patch. The rest of the feedback is:
>> This is looking much better.
>>
>> This brings back support for PROVIDE both in and out of output
>> sections, right? Unfortunately this still crashes if I bring
>> test/ELF/linkerscript/linkerscript-provide-in-section.s back.
>>
>> Could you extract readProvideOrAssignment and commit it first?
Cheers,
Rafael
-------------- next part --------------
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index b69c02a..b46fd42 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -1,1154 +1,1197 @@
//===- LinkerScript.cpp ---------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the parser/evaluator of the linker script.
// It parses a linker script and write the result to Config or ScriptConfig
// objects.
//
// If SECTIONS command is used, a ScriptConfig contains an AST
// of the command which will later be consumed by createSections() and
// assignAddresses().
//
//===----------------------------------------------------------------------===//
#include "LinkerScript.h"
#include "Config.h"
#include "Driver.h"
#include "InputSection.h"
#include "OutputSections.h"
#include "ScriptParser.h"
#include "Strings.h"
#include "Symbols.h"
#include "SymbolTable.h"
#include "Target.h"
#include "Writer.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/StringSaver.h"
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace lld;
using namespace lld::elf;
ScriptConfiguration *elf::ScriptConfig;
+template <class ELFT, template <typename> class SymbolT>
+static Symbol *addSymbolToSymtabAux(StringRef Name, uint8_t StOther) {
+ return Symtab<ELFT>::X->addRegular(Name, STB_GLOBAL, StOther);
+}
+
+template <class ELFT, template <typename> class SymbolT>
+static Symbol *addSymbolToSymtabAux(StringRef Name, typename ELFT::uint Value,
+ OutputSectionBase<ELFT> *Section) {
+ return Symtab<ELFT>::X->addSynthetic(Name, Section, Value);
+}
+
+template <class ELFT, template <typename> class SymbolT, class... ArgsT>
+static void addSymbolToSymtab(SymbolAssignment &Cmd, ArgsT... Args) {
+ if (Cmd.Name == ".")
+ return;
+
+ // If a symbol was in PROVIDE(), define it only when it is an
+ // undefined symbol.
+ SymbolBody *B = Symtab<ELFT>::X->find(Cmd.Name);
+ if (Cmd.Provide && !(B && B->isUndefined()))
+ return;
+
+ // Define a symbol. The symbol value will be assigned later.(At this point, we
+ // don't know the final address yet.)
+ Symbol *Sym = addSymbolToSymtabAux<ELFT, SymbolT>(
+ Cmd.Name, std::forward<ArgsT>(Args)...);
+ Sym->Visibility = Cmd.Hidden ? STV_HIDDEN : STV_DEFAULT;
+ Cmd.Sym = Sym->body();
+}
+
bool SymbolAssignment::classof(const BaseCommand *C) {
return C->Kind == AssignmentKind;
}
bool OutputSectionCommand::classof(const BaseCommand *C) {
return C->Kind == OutputSectionKind;
}
bool InputSectionDescription::classof(const BaseCommand *C) {
return C->Kind == InputSectionKind;
}
bool AssertCommand::classof(const BaseCommand *C) {
return C->Kind == AssertKind;
}
template <class ELFT> static bool isDiscarded(InputSectionBase<ELFT> *S) {
return !S || !S->Live;
}
template <class ELFT>
bool LinkerScript<ELFT>::shouldKeep(InputSectionBase<ELFT> *S) {
for (StringRef Pat : Opt.KeptSections)
if (globMatch(Pat, S->getSectionName()))
return true;
return false;
}
static bool match(ArrayRef<StringRef> Patterns, StringRef S) {
for (StringRef Pat : Patterns)
if (globMatch(Pat, S))
return true;
return false;
}
-// Create a vector of (<output section name>, <input section description>).
-template <class ELFT>
-std::vector<std::pair<StringRef, const InputSectionDescription *>>
-LinkerScript<ELFT>::getSectionMap() {
- std::vector<std::pair<StringRef, const InputSectionDescription *>> Ret;
-
- for (const std::unique_ptr<BaseCommand> &Base1 : Opt.Commands)
- if (auto *Cmd1 = dyn_cast<OutputSectionCommand>(Base1.get()))
- for (const std::unique_ptr<BaseCommand> &Base2 : Cmd1->Commands)
- if (auto *Cmd2 = dyn_cast<InputSectionDescription>(Base2.get()))
- Ret.emplace_back(Cmd1->Name, Cmd2);
-
- return Ret;
-}
-
static bool fileMatches(const InputSectionDescription *Desc,
StringRef Filename) {
if (!globMatch(Desc->FilePattern, Filename))
return false;
return Desc->ExcludedFiles.empty() || !match(Desc->ExcludedFiles, Filename);
}
// Returns input sections filtered by given glob patterns.
template <class ELFT>
std::vector<InputSectionBase<ELFT> *>
LinkerScript<ELFT>::getInputSections(const InputSectionDescription *I) {
ArrayRef<StringRef> Patterns = I->SectionPatterns;
std::vector<InputSectionBase<ELFT> *> Ret;
for (const std::unique_ptr<ObjectFile<ELFT>> &F :
Symtab<ELFT>::X->getObjectFiles()) {
if (fileMatches(I, sys::path::filename(F->getName())))
for (InputSectionBase<ELFT> *S : F->getSections())
if (!isDiscarded(S) && !S->OutSec &&
match(Patterns, S->getSectionName()))
Ret.push_back(S);
}
if ((llvm::find(Patterns, "COMMON") != Patterns.end()))
Ret.push_back(CommonInputSection<ELFT>::X);
return Ret;
}
-// Add input section to output section. If there is no output section yet,
-// then create it and add to output section list.
+namespace {
+// Helper class, which builds output section list, also
+// creating symbol sections, when needed
+template <class ELFT> class OutputSectionBuilder {
+public:
+ OutputSectionBuilder(OutputSectionFactory<ELFT> &F,
+ std::vector<OutputSectionBase<ELFT> *> *Out)
+ : Factory(F), OutputSections(Out) {}
+
+ void addSection(StringRef OutputName, InputSectionBase<ELFT> *I);
+ void addSymbol(SymbolAssignment *Cmd) { PendingSymbols.push_back(Cmd); }
+ void flushSymbols();
+
+private:
+ OutputSectionFactory<ELFT> &Factory;
+ std::vector<OutputSectionBase<ELFT> *> *OutputSections;
+ OutputSectionBase<ELFT> *Current = nullptr;
+ std::vector<SymbolAssignment *> PendingSymbols;
+};
+}
+
template <class ELFT>
-static void addSection(OutputSectionFactory<ELFT> &Factory,
- std::vector<OutputSectionBase<ELFT> *> &Out,
- InputSectionBase<ELFT> *C, StringRef Name) {
- OutputSectionBase<ELFT> *Sec;
+void OutputSectionBuilder<ELFT>::addSection(StringRef OutputName,
+ InputSectionBase<ELFT> *C) {
bool IsNew;
- std::tie(Sec, IsNew) = Factory.create(C, Name);
+ std::tie(Current, IsNew) = Factory.create(C, OutputName);
if (IsNew)
- Out.push_back(Sec);
- Sec->addSection(C);
+ OutputSections->push_back(Current);
+ flushSymbols();
+ Current->addSection(C);
+}
+
+template <class ELFT> void OutputSectionBuilder<ELFT>::flushSymbols() {
+ for (SymbolAssignment *Cmd : PendingSymbols)
+ addSymbolToSymtab<ELFT, DefinedSynthetic>(
+ *Cmd, Cmd->Expression(Current->getSize()), Current);
+ PendingSymbols.clear();
}
template <class ELFT> struct SectionsSorter {
SectionsSorter(SortKind Kind) : Kind(Kind) {}
bool operator()(InputSectionBase<ELFT> *A, InputSectionBase<ELFT> *B) {
int AlignmentCmp = A->Alignment - B->Alignment;
if (Kind == SortKind::Align || (Kind == SortKind::AlignName && AlignmentCmp != 0))
return AlignmentCmp > 0;
int NameCmp = A->getSectionName().compare(B->getSectionName());
if (Kind == SortKind::Name || (Kind == SortKind::NameAlign && NameCmp != 0))
return NameCmp < 0;
if (Kind == SortKind::NameAlign)
return AlignmentCmp > 0;
if (Kind == SortKind::AlignName)
return NameCmp < 0;
llvm_unreachable("unknown section sort kind in predicate");
return false;
}
SortKind Kind;
};
+// Create output sections and symbols as listed in linker script.
template <class ELFT>
void LinkerScript<ELFT>::createSections(
OutputSectionFactory<ELFT> &Factory) {
- for (auto &P : getSectionMap()) {
- StringRef OutputName = P.first;
- const InputSectionDescription *Cmd = P.second;
- std::vector<InputSectionBase<ELFT> *> Sections = getInputSections(Cmd);
+ OutputSectionBuilder<ELFT> Builder(Factory, OutputSections);
+ auto Add = [&](StringRef OutputName, const InputSectionDescription *Cmd) {
+ std::vector<InputSectionBase<ELFT> *> Sections = getInputSections(Cmd);
if (OutputName == "/DISCARD/") {
for (InputSectionBase<ELFT> *S : Sections) {
S->Live = false;
reportDiscarded(S);
}
- continue;
+ return;
}
if (Cmd->Sort != SortKind::None)
std::stable_sort(Sections.begin(), Sections.end(),
SectionsSorter<ELFT>(Cmd->Sort));
for (InputSectionBase<ELFT> *S : Sections)
- addSection(Factory, *OutputSections, S, OutputName);
- }
+ Builder.addSection(OutputName, S);
+ };
+
+ for (const std::unique_ptr<BaseCommand> &Base1 : Opt.Commands)
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base1.get())) {
+ for (const std::unique_ptr<BaseCommand> &Base2 : Cmd->Commands)
+ if (auto *Assignment = dyn_cast<SymbolAssignment>(Base2.get()))
+ Builder.addSymbol(Assignment);
+ else
+ Add(Cmd->Name, cast<InputSectionDescription>(Base2.get()));
+
+ Builder.flushSymbols();
+ } else if (auto *Cmd2 = dyn_cast<SymbolAssignment>(Base1.get())) {
+ addSymbolToSymtab<ELFT, DefinedRegular>(*Cmd2, STV_DEFAULT);
+ }
// Add all other input sections, which are not listed in script.
for (const std::unique_ptr<ObjectFile<ELFT>> &F :
Symtab<ELFT>::X->getObjectFiles())
for (InputSectionBase<ELFT> *S : F->getSections())
if (!isDiscarded(S) && !S->OutSec)
- addSection(Factory, *OutputSections, S, getOutputSectionName(S));
+ Builder.addSection(getOutputSectionName(S), S);
// Remove from the output all the sections which did not meet
// the optional constraints.
filter();
}
template <class R, class T>
static inline void removeElementsIf(R &Range, const T &Pred) {
Range.erase(std::remove_if(Range.begin(), Range.end(), Pred), Range.end());
}
// Process ONLY_IF_RO and ONLY_IF_RW.
template <class ELFT> void LinkerScript<ELFT>::filter() {
// In this loop, we remove output sections if they don't satisfy
// requested properties.
for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
if (!Cmd || Cmd->Name == "/DISCARD/")
continue;
if (Cmd->Constraint == ConstraintKind::NoConstraint)
continue;
removeElementsIf(*OutputSections, [&](OutputSectionBase<ELFT> *S) {
bool Writable = (S->getFlags() & SHF_WRITE);
bool RO = (Cmd->Constraint == ConstraintKind::ReadOnly);
bool RW = (Cmd->Constraint == ConstraintKind::ReadWrite);
return S->getName() == Cmd->Name &&
((RO && Writable) || (RW && !Writable));
});
}
}
template <class ELFT> void LinkerScript<ELFT>::assignAddresses() {
ArrayRef<OutputSectionBase<ELFT> *> Sections = *OutputSections;
// Orphan sections are sections present in the input files which
// are not explicitly placed into the output file by the linker script.
// We place orphan sections at end of file.
// Other linkers places them using some heuristics as described in
// https://sourceware.org/binutils/docs/ld/Orphan-Sections.html#Orphan-Sections.
for (OutputSectionBase<ELFT> *Sec : Sections) {
StringRef Name = Sec->getName();
if (getSectionIndex(Name) == INT_MAX)
Opt.Commands.push_back(llvm::make_unique<OutputSectionCommand>(Name));
}
// Assign addresses as instructed by linker script SECTIONS sub-commands.
Dot = Out<ELFT>::ElfHeader->getSize() + Out<ELFT>::ProgramHeaders->getSize();
uintX_t MinVA = std::numeric_limits<uintX_t>::max();
uintX_t ThreadBssOffset = 0;
for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
if (auto *Cmd = dyn_cast<SymbolAssignment>(Base.get())) {
if (Cmd->Name == ".") {
Dot = Cmd->Expression(Dot);
} else if (Cmd->Sym) {
cast<DefinedRegular<ELFT>>(Cmd->Sym)->Value = Cmd->Expression(Dot);
}
continue;
}
if (auto *Cmd = dyn_cast<AssertCommand>(Base.get())) {
Cmd->Expression(Dot);
continue;
}
// Find all the sections with required name. There can be more than
// one section with such name, if the alignment, flags or type
// attribute differs.
auto *Cmd = cast<OutputSectionCommand>(Base.get());
for (OutputSectionBase<ELFT> *Sec : Sections) {
if (Sec->getName() != Cmd->Name)
continue;
if (Cmd->AddrExpr)
Dot = Cmd->AddrExpr(Dot);
if (Cmd->AlignExpr)
Sec->updateAlignment(Cmd->AlignExpr(Dot));
if ((Sec->getFlags() & SHF_TLS) && Sec->getType() == SHT_NOBITS) {
uintX_t TVA = Dot + ThreadBssOffset;
TVA = alignTo(TVA, Sec->getAlignment());
Sec->setVA(TVA);
ThreadBssOffset = TVA - Dot + Sec->getSize();
continue;
}
if (Sec->getFlags() & SHF_ALLOC) {
Dot = alignTo(Dot, Sec->getAlignment());
Sec->setVA(Dot);
MinVA = std::min(MinVA, Dot);
Dot += Sec->getSize();
continue;
}
}
}
// ELF and Program headers need to be right before the first section in
// memory. Set their addresses accordingly.
MinVA = alignDown(MinVA - Out<ELFT>::ElfHeader->getSize() -
Out<ELFT>::ProgramHeaders->getSize(),
Target->PageSize);
Out<ELFT>::ElfHeader->setVA(MinVA);
Out<ELFT>::ProgramHeaders->setVA(Out<ELFT>::ElfHeader->getSize() + MinVA);
}
template <class ELFT>
std::vector<PhdrEntry<ELFT>> LinkerScript<ELFT>::createPhdrs() {
ArrayRef<OutputSectionBase<ELFT> *> Sections = *OutputSections;
std::vector<PhdrEntry<ELFT>> Ret;
for (const PhdrsCommand &Cmd : Opt.PhdrsCommands) {
Ret.emplace_back(Cmd.Type, Cmd.Flags == UINT_MAX ? PF_R : Cmd.Flags);
PhdrEntry<ELFT> &Phdr = Ret.back();
if (Cmd.HasFilehdr)
Phdr.add(Out<ELFT>::ElfHeader);
if (Cmd.HasPhdrs)
Phdr.add(Out<ELFT>::ProgramHeaders);
switch (Cmd.Type) {
case PT_INTERP:
if (Out<ELFT>::Interp)
Phdr.add(Out<ELFT>::Interp);
break;
case PT_DYNAMIC:
if (isOutputDynamic<ELFT>()) {
Phdr.H.p_flags = Out<ELFT>::Dynamic->getPhdrFlags();
Phdr.add(Out<ELFT>::Dynamic);
}
break;
case PT_GNU_EH_FRAME:
if (!Out<ELFT>::EhFrame->empty() && Out<ELFT>::EhFrameHdr) {
Phdr.H.p_flags = Out<ELFT>::EhFrameHdr->getPhdrFlags();
Phdr.add(Out<ELFT>::EhFrameHdr);
}
break;
}
}
PhdrEntry<ELFT> *Load = nullptr;
uintX_t Flags = PF_R;
for (OutputSectionBase<ELFT> *Sec : Sections) {
if (!(Sec->getFlags() & SHF_ALLOC))
break;
std::vector<size_t> PhdrIds = getPhdrIndices(Sec->getName());
if (!PhdrIds.empty()) {
// Assign headers specified by linker script
for (size_t Id : PhdrIds) {
Ret[Id].add(Sec);
if (Opt.PhdrsCommands[Id].Flags == UINT_MAX)
Ret[Id].H.p_flags |= Sec->getPhdrFlags();
}
} else {
// If we have no load segment or flags've changed then we want new load
// segment.
uintX_t NewFlags = Sec->getPhdrFlags();
if (Load == nullptr || Flags != NewFlags) {
Load = &*Ret.emplace(Ret.end(), PT_LOAD, NewFlags);
Flags = NewFlags;
}
Load->add(Sec);
}
}
return Ret;
}
template <class ELFT>
ArrayRef<uint8_t> LinkerScript<ELFT>::getFiller(StringRef Name) {
for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands)
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get()))
if (Cmd->Name == Name)
return Cmd->Filler;
return {};
}
// Returns the index of the given section name in linker script
// SECTIONS commands. Sections are laid out as the same order as they
// were in the script. If a given name did not appear in the script,
// it returns INT_MAX, so that it will be laid out at end of file.
template <class ELFT> int LinkerScript<ELFT>::getSectionIndex(StringRef Name) {
int I = 0;
for (std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get()))
if (Cmd->Name == Name)
return I;
++I;
}
return INT_MAX;
}
// A compartor to sort output sections. Returns -1 or 1 if
// A or B are mentioned in linker script. Otherwise, returns 0.
template <class ELFT>
int LinkerScript<ELFT>::compareSections(StringRef A, StringRef B) {
int I = getSectionIndex(A);
int J = getSectionIndex(B);
if (I == INT_MAX && J == INT_MAX)
return 0;
return I < J ? -1 : 1;
}
-// Add symbols defined by linker scripts.
-template <class ELFT> void LinkerScript<ELFT>::addScriptedSymbols() {
- for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
- auto *Cmd = dyn_cast<SymbolAssignment>(Base.get());
- if (!Cmd || Cmd->Name == ".")
- continue;
-
- // If a symbol was in PROVIDE(), define it only when it is an
- // undefined symbol.
- SymbolBody *B = Symtab<ELFT>::X->find(Cmd->Name);
- if (Cmd->Provide && !(B && B->isUndefined()))
- continue;
-
- // Define an absolute symbol. The symbol value will be assigned later.
- // (At this point, we don't know the final address yet.)
- Symbol *Sym = Symtab<ELFT>::X->addUndefined(Cmd->Name);
- replaceBody<DefinedRegular<ELFT>>(Sym, Cmd->Name, STV_DEFAULT);
- Sym->Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
- Cmd->Sym = Sym->body();
- }
-}
-
template <class ELFT> bool LinkerScript<ELFT>::hasPhdrsCommands() {
return !Opt.PhdrsCommands.empty();
}
template <class ELFT>
typename ELFT::uint LinkerScript<ELFT>::getOutputSectionSize(StringRef Name) {
for (OutputSectionBase<ELFT> *Sec : *OutputSections)
if (Sec->getName() == Name)
return Sec->getSize();
error("undefined section " + Name);
return 0;
}
// Returns indices of ELF headers containing specific section, identified
// by Name. Each index is a zero based number of ELF header listed within
// PHDRS {} script block.
template <class ELFT>
std::vector<size_t> LinkerScript<ELFT>::getPhdrIndices(StringRef SectionName) {
for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
if (!Cmd || Cmd->Name != SectionName)
continue;
std::vector<size_t> Ret;
for (StringRef PhdrName : Cmd->Phdrs)
Ret.push_back(getPhdrIndex(PhdrName));
return Ret;
}
return {};
}
template <class ELFT>
size_t LinkerScript<ELFT>::getPhdrIndex(StringRef PhdrName) {
size_t I = 0;
for (PhdrsCommand &Cmd : Opt.PhdrsCommands) {
if (Cmd.Name == PhdrName)
return I;
++I;
}
error("section header '" + PhdrName + "' is not listed in PHDRS");
return 0;
}
class elf::ScriptParser : public ScriptParserBase {
typedef void (ScriptParser::*Handler)();
public:
ScriptParser(StringRef S, bool B) : ScriptParserBase(S), IsUnderSysroot(B) {}
void run();
private:
void addFile(StringRef Path);
void readAsNeeded();
void readEntry();
void readExtern();
void readGroup();
void readInclude();
void readNothing() {}
void readOutput();
void readOutputArch();
void readOutputFormat();
void readPhdrs();
void readSearchDir();
void readSections();
SymbolAssignment *readAssignment(StringRef Name);
OutputSectionCommand *readOutputSectionDescription(StringRef OutSec);
std::vector<uint8_t> readOutputSectionFiller();
std::vector<StringRef> readOutputSectionPhdrs();
InputSectionDescription *readInputSectionDescription();
std::vector<StringRef> readInputFilePatterns();
InputSectionDescription *readInputSectionRules();
unsigned readPhdrType();
SymbolAssignment *readProvide(bool Hidden);
+ SymbolAssignment *readProvideOrAssignment(StringRef Tok);
Expr readAlign();
void readSort();
Expr readAssert();
Expr readExpr();
Expr readExpr1(Expr Lhs, int MinPrec);
Expr readPrimary();
Expr readTernary(Expr Cond);
Expr combine(StringRef Op, Expr Lhs, Expr Rhs);
const static StringMap<Handler> Cmd;
ScriptConfiguration &Opt = *ScriptConfig;
StringSaver Saver = {ScriptConfig->Alloc};
bool IsUnderSysroot;
};
const StringMap<elf::ScriptParser::Handler> elf::ScriptParser::Cmd = {
{"ENTRY", &ScriptParser::readEntry},
{"EXTERN", &ScriptParser::readExtern},
{"GROUP", &ScriptParser::readGroup},
{"INCLUDE", &ScriptParser::readInclude},
{"INPUT", &ScriptParser::readGroup},
{"OUTPUT", &ScriptParser::readOutput},
{"OUTPUT_ARCH", &ScriptParser::readOutputArch},
{"OUTPUT_FORMAT", &ScriptParser::readOutputFormat},
{"PHDRS", &ScriptParser::readPhdrs},
{"SEARCH_DIR", &ScriptParser::readSearchDir},
{"SECTIONS", &ScriptParser::readSections},
{";", &ScriptParser::readNothing}};
void ScriptParser::run() {
while (!atEOF()) {
StringRef Tok = next();
if (Handler Fn = Cmd.lookup(Tok))
(this->*Fn)();
else
setError("unknown directive: " + Tok);
}
}
void ScriptParser::addFile(StringRef S) {
if (IsUnderSysroot && S.startswith("/")) {
SmallString<128> Path;
(Config->Sysroot + S).toStringRef(Path);
if (sys::fs::exists(Path)) {
Driver->addFile(Saver.save(Path.str()));
return;
}
}
if (sys::path::is_absolute(S)) {
Driver->addFile(S);
} else if (S.startswith("=")) {
if (Config->Sysroot.empty())
Driver->addFile(S.substr(1));
else
Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)));
} else if (S.startswith("-l")) {
Driver->addLibrary(S.substr(2));
} else if (sys::fs::exists(S)) {
Driver->addFile(S);
} else {
std::string Path = findFromSearchPaths(S);
if (Path.empty())
setError("unable to find " + S);
else
Driver->addFile(Saver.save(Path));
}
}
void ScriptParser::readAsNeeded() {
expect("(");
bool Orig = Config->AsNeeded;
Config->AsNeeded = true;
while (!Error) {
StringRef Tok = next();
if (Tok == ")")
break;
addFile(Tok);
}
Config->AsNeeded = Orig;
}
void ScriptParser::readEntry() {
// -e <symbol> takes predecence over ENTRY(<symbol>).
expect("(");
StringRef Tok = next();
if (Config->Entry.empty())
Config->Entry = Tok;
expect(")");
}
void ScriptParser::readExtern() {
expect("(");
while (!Error) {
StringRef Tok = next();
if (Tok == ")")
return;
Config->Undefined.push_back(Tok);
}
}
void ScriptParser::readGroup() {
expect("(");
while (!Error) {
StringRef Tok = next();
if (Tok == ")")
return;
if (Tok == "AS_NEEDED") {
readAsNeeded();
continue;
}
addFile(Tok);
}
}
void ScriptParser::readInclude() {
StringRef Tok = next();
auto MBOrErr = MemoryBuffer::getFile(Tok);
if (!MBOrErr) {
setError("cannot open " + Tok);
return;
}
std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
StringRef S = Saver.save(MB->getMemBufferRef().getBuffer());
std::vector<StringRef> V = tokenize(S);
Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end());
}
void ScriptParser::readOutput() {
// -o <file> takes predecence over OUTPUT(<file>).
expect("(");
StringRef Tok = next();
if (Config->OutputFile.empty())
Config->OutputFile = Tok;
expect(")");
}
void ScriptParser::readOutputArch() {
// Error checking only for now.
expect("(");
next();
expect(")");
}
void ScriptParser::readOutputFormat() {
// Error checking only for now.
expect("(");
next();
StringRef Tok = next();
if (Tok == ")")
return;
if (Tok != ",") {
setError("unexpected token: " + Tok);
return;
}
next();
expect(",");
next();
expect(")");
}
void ScriptParser::readPhdrs() {
expect("{");
while (!Error && !skip("}")) {
StringRef Tok = next();
Opt.PhdrsCommands.push_back({Tok, PT_NULL, false, false, UINT_MAX});
PhdrsCommand &PhdrCmd = Opt.PhdrsCommands.back();
PhdrCmd.Type = readPhdrType();
do {
Tok = next();
if (Tok == ";")
break;
if (Tok == "FILEHDR")
PhdrCmd.HasFilehdr = true;
else if (Tok == "PHDRS")
PhdrCmd.HasPhdrs = true;
else if (Tok == "FLAGS") {
expect("(");
// Passing 0 for the value of dot is a bit of a hack. It means that
// we accept expressions like ".|1".
PhdrCmd.Flags = readExpr()(0);
expect(")");
} else
setError("unexpected header attribute: " + Tok);
} while (!Error);
}
}
void ScriptParser::readSearchDir() {
expect("(");
Config->SearchPaths.push_back(next());
expect(")");
}
void ScriptParser::readSections() {
Opt.HasContents = true;
expect("{");
while (!Error && !skip("}")) {
StringRef Tok = next();
BaseCommand *Cmd;
- if (peek() == "=" || peek() == "+=") {
- Cmd = readAssignment(Tok);
- expect(";");
- } else if (Tok == "PROVIDE") {
- Cmd = readProvide(false);
- } else if (Tok == "PROVIDE_HIDDEN") {
- Cmd = readProvide(true);
- } else if (Tok == "ASSERT") {
+ if (Tok == "ASSERT")
Cmd = new AssertCommand(readAssert());
- } else {
- Cmd = readOutputSectionDescription(Tok);
+ else {
+ Cmd = readProvideOrAssignment(Tok);
+ if (!Cmd)
+ Cmd = readOutputSectionDescription(Tok);
}
Opt.Commands.emplace_back(Cmd);
}
}
static int precedence(StringRef Op) {
return StringSwitch<int>(Op)
.Case("*", 4)
.Case("/", 4)
.Case("+", 3)
.Case("-", 3)
.Case("<", 2)
.Case(">", 2)
.Case(">=", 2)
.Case("<=", 2)
.Case("==", 2)
.Case("!=", 2)
.Case("&", 1)
.Default(-1);
}
std::vector<StringRef> ScriptParser::readInputFilePatterns() {
std::vector<StringRef> V;
while (!Error && !skip(")"))
V.push_back(next());
return V;
}
InputSectionDescription *ScriptParser::readInputSectionRules() {
auto *Cmd = new InputSectionDescription;
Cmd->FilePattern = next();
expect("(");
if (skip("EXCLUDE_FILE")) {
expect("(");
while (!Error && !skip(")"))
Cmd->ExcludedFiles.push_back(next());
}
if (skip("SORT") || skip("SORT_BY_NAME")) {
expect("(");
if (skip("SORT_BY_ALIGNMENT")) {
Cmd->Sort = SortKind::NameAlign;
expect("(");
Cmd->SectionPatterns = readInputFilePatterns();
expect(")");
} else {
Cmd->Sort = SortKind::Name;
Cmd->SectionPatterns = readInputFilePatterns();
}
expect(")");
return Cmd;
}
if (skip("SORT_BY_ALIGNMENT")) {
expect("(");
if (skip("SORT") || skip("SORT_BY_NAME")) {
Cmd->Sort = SortKind::AlignName;
expect("(");
Cmd->SectionPatterns = readInputFilePatterns();
expect(")");
} else {
Cmd->Sort = SortKind::Align;
Cmd->SectionPatterns = readInputFilePatterns();
}
expect(")");
return Cmd;
}
Cmd->SectionPatterns = readInputFilePatterns();
return Cmd;
}
InputSectionDescription *ScriptParser::readInputSectionDescription() {
// Input section wildcard can be surrounded by KEEP.
// https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#Input-Section-Keep
if (skip("KEEP")) {
expect("(");
InputSectionDescription *Cmd = readInputSectionRules();
expect(")");
Opt.KeptSections.insert(Opt.KeptSections.end(),
Cmd->SectionPatterns.begin(),
Cmd->SectionPatterns.end());
return Cmd;
}
return readInputSectionRules();
}
Expr ScriptParser::readAlign() {
expect("(");
Expr E = readExpr();
expect(")");
return E;
}
void ScriptParser::readSort() {
expect("(");
expect("CONSTRUCTORS");
expect(")");
}
Expr ScriptParser::readAssert() {
expect("(");
Expr E = readExpr();
expect(",");
StringRef Msg = next();
expect(")");
return [=](uint64_t Dot) {
uint64_t V = E(Dot);
if (!V)
error(Msg);
return V;
};
}
OutputSectionCommand *
ScriptParser::readOutputSectionDescription(StringRef OutSec) {
OutputSectionCommand *Cmd = new OutputSectionCommand(OutSec);
// Read an address expression.
// https://sourceware.org/binutils/docs/ld/Output-Section-Address.html#Output-Section-Address
if (peek() != ":")
Cmd->AddrExpr = readExpr();
expect(":");
if (skip("ALIGN"))
Cmd->AlignExpr = readAlign();
// Parse constraints.
if (skip("ONLY_IF_RO"))
Cmd->Constraint = ConstraintKind::ReadOnly;
if (skip("ONLY_IF_RW"))
Cmd->Constraint = ConstraintKind::ReadWrite;
expect("{");
while (!Error && !skip("}")) {
if (peek().startswith("*") || peek() == "KEEP") {
Cmd->Commands.emplace_back(readInputSectionDescription());
continue;
}
- if (skip("SORT")) {
+
+ StringRef Tok = next();
+ if (SymbolAssignment *Assignment = readProvideOrAssignment(Tok))
+ Cmd->Commands.emplace_back(Assignment);
+ else if (Tok == "SORT")
readSort();
- continue;
- }
- setError("unknown command " + peek());
+ else
+ setError("unknown command " + Tok);
}
Cmd->Phdrs = readOutputSectionPhdrs();
Cmd->Filler = readOutputSectionFiller();
return Cmd;
}
std::vector<uint8_t> ScriptParser::readOutputSectionFiller() {
StringRef Tok = peek();
if (!Tok.startswith("="))
return {};
next();
// Read a hexstring of arbitrary length.
if (Tok.startswith("=0x"))
return parseHex(Tok.substr(3));
// Read a decimal or octal value as a big-endian 32 bit value.
// Why do this? I don't know, but that's what gold does.
uint32_t V;
if (Tok.substr(1).getAsInteger(0, V)) {
setError("invalid filler expression: " + Tok);
return {};
}
return { uint8_t(V >> 24), uint8_t(V >> 16), uint8_t(V >> 8), uint8_t(V) };
}
SymbolAssignment *ScriptParser::readProvide(bool Hidden) {
expect("(");
SymbolAssignment *Cmd = readAssignment(next());
Cmd->Provide = true;
Cmd->Hidden = Hidden;
expect(")");
expect(";");
return Cmd;
}
+SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) {
+ SymbolAssignment *Cmd = nullptr;
+ if (peek() == "=" || peek() == "+=") {
+ Cmd = readAssignment(Tok);
+ expect(";");
+ } else if (Tok == "PROVIDE") {
+ Cmd = readProvide(false);
+ } else if (Tok == "PROVIDE_HIDDEN") {
+ Cmd = readProvide(true);
+ }
+ return Cmd;
+}
+
static uint64_t getSymbolValue(StringRef S, uint64_t Dot) {
if (S == ".")
return Dot;
switch (Config->EKind) {
case ELF32LEKind:
if (SymbolBody *B = Symtab<ELF32LE>::X->find(S))
return B->getVA<ELF32LE>();
break;
case ELF32BEKind:
if (SymbolBody *B = Symtab<ELF32BE>::X->find(S))
return B->getVA<ELF32BE>();
break;
case ELF64LEKind:
if (SymbolBody *B = Symtab<ELF64LE>::X->find(S))
return B->getVA<ELF64LE>();
break;
case ELF64BEKind:
if (SymbolBody *B = Symtab<ELF64BE>::X->find(S))
return B->getVA<ELF64BE>();
break;
default:
llvm_unreachable("unsupported target");
}
error("symbol not found: " + S);
return 0;
}
static uint64_t getSectionSize(StringRef Name) {
switch (Config->EKind) {
case ELF32LEKind:
return Script<ELF32LE>::X->getOutputSectionSize(Name);
case ELF32BEKind:
return Script<ELF32BE>::X->getOutputSectionSize(Name);
case ELF64LEKind:
return Script<ELF64LE>::X->getOutputSectionSize(Name);
case ELF64BEKind:
return Script<ELF64BE>::X->getOutputSectionSize(Name);
default:
llvm_unreachable("unsupported target");
}
return 0;
}
SymbolAssignment *ScriptParser::readAssignment(StringRef Name) {
StringRef Op = next();
assert(Op == "=" || Op == "+=");
Expr E = readExpr();
if (Op == "+=")
E = [=](uint64_t Dot) { return getSymbolValue(Name, Dot) + E(Dot); };
return new SymbolAssignment(Name, E);
}
// This is an operator-precedence parser to parse a linker
// script expression.
Expr ScriptParser::readExpr() { return readExpr1(readPrimary(), 0); }
// This is a part of the operator-precedence parser. This function
// assumes that the remaining token stream starts with an operator.
Expr ScriptParser::readExpr1(Expr Lhs, int MinPrec) {
while (!atEOF() && !Error) {
// Read an operator and an expression.
StringRef Op1 = peek();
if (Op1 == "?")
return readTernary(Lhs);
if (precedence(Op1) < MinPrec)
break;
next();
Expr Rhs = readPrimary();
// Evaluate the remaining part of the expression first if the
// next operator has greater precedence than the previous one.
// For example, if we have read "+" and "3", and if the next
// operator is "*", then we'll evaluate 3 * ... part first.
while (!atEOF()) {
StringRef Op2 = peek();
if (precedence(Op2) <= precedence(Op1))
break;
Rhs = readExpr1(Rhs, precedence(Op2));
}
Lhs = combine(Op1, Lhs, Rhs);
}
return Lhs;
}
uint64_t static getConstant(StringRef S) {
if (S == "COMMONPAGESIZE" || S == "MAXPAGESIZE")
return Target->PageSize;
error("unknown constant: " + S);
return 0;
}
Expr ScriptParser::readPrimary() {
StringRef Tok = next();
if (Tok == "(") {
Expr E = readExpr();
expect(")");
return E;
}
// Built-in functions are parsed here.
// https://sourceware.org/binutils/docs/ld/Builtin-Functions.html.
if (Tok == "ASSERT")
return readAssert();
if (Tok == "ALIGN") {
expect("(");
Expr E = readExpr();
expect(")");
return [=](uint64_t Dot) { return alignTo(Dot, E(Dot)); };
}
if (Tok == "CONSTANT") {
expect("(");
StringRef Tok = next();
expect(")");
return [=](uint64_t Dot) { return getConstant(Tok); };
}
if (Tok == "SEGMENT_START") {
expect("(");
next();
expect(",");
uint64_t Val;
next().getAsInteger(0, Val);
expect(")");
return [=](uint64_t Dot) { return Val; };
}
if (Tok == "DATA_SEGMENT_ALIGN") {
expect("(");
Expr E = readExpr();
expect(",");
readExpr();
expect(")");
return [=](uint64_t Dot) { return alignTo(Dot, E(Dot)); };
}
if (Tok == "DATA_SEGMENT_END") {
expect("(");
expect(".");
expect(")");
return [](uint64_t Dot) { return Dot; };
}
// GNU linkers implements more complicated logic to handle
// DATA_SEGMENT_RELRO_END. We instead ignore the arguments and just align to
// the next page boundary for simplicity.
if (Tok == "DATA_SEGMENT_RELRO_END") {
expect("(");
next();
expect(",");
readExpr();
expect(")");
return [](uint64_t Dot) { return alignTo(Dot, Target->PageSize); };
}
if (Tok == "SIZEOF") {
expect("(");
StringRef Name = next();
expect(")");
return [=](uint64_t Dot) { return getSectionSize(Name); };
}
// Parse a symbol name or a number literal.
uint64_t V = 0;
if (Tok.getAsInteger(0, V)) {
if (Tok != "." && !isValidCIdentifier(Tok))
setError("malformed number: " + Tok);
return [=](uint64_t Dot) { return getSymbolValue(Tok, Dot); };
}
return [=](uint64_t Dot) { return V; };
}
Expr ScriptParser::readTernary(Expr Cond) {
next();
Expr L = readExpr();
expect(":");
Expr R = readExpr();
return [=](uint64_t Dot) { return Cond(Dot) ? L(Dot) : R(Dot); };
}
Expr ScriptParser::combine(StringRef Op, Expr L, Expr R) {
if (Op == "*")
return [=](uint64_t Dot) { return L(Dot) * R(Dot); };
if (Op == "/") {
return [=](uint64_t Dot) -> uint64_t {
uint64_t RHS = R(Dot);
if (RHS == 0) {
error("division by zero");
return 0;
}
return L(Dot) / RHS;
};
}
if (Op == "+")
return [=](uint64_t Dot) { return L(Dot) + R(Dot); };
if (Op == "-")
return [=](uint64_t Dot) { return L(Dot) - R(Dot); };
if (Op == "<")
return [=](uint64_t Dot) { return L(Dot) < R(Dot); };
if (Op == ">")
return [=](uint64_t Dot) { return L(Dot) > R(Dot); };
if (Op == ">=")
return [=](uint64_t Dot) { return L(Dot) >= R(Dot); };
if (Op == "<=")
return [=](uint64_t Dot) { return L(Dot) <= R(Dot); };
if (Op == "==")
return [=](uint64_t Dot) { return L(Dot) == R(Dot); };
if (Op == "!=")
return [=](uint64_t Dot) { return L(Dot) != R(Dot); };
if (Op == "&")
return [=](uint64_t Dot) { return L(Dot) & R(Dot); };
llvm_unreachable("invalid operator");
}
std::vector<StringRef> ScriptParser::readOutputSectionPhdrs() {
std::vector<StringRef> Phdrs;
while (!Error && peek().startswith(":")) {
StringRef Tok = next();
Tok = (Tok.size() == 1) ? next() : Tok.substr(1);
if (Tok.empty()) {
setError("section header name is empty");
break;
}
Phdrs.push_back(Tok);
}
return Phdrs;
}
unsigned ScriptParser::readPhdrType() {
StringRef Tok = next();
unsigned Ret = StringSwitch<unsigned>(Tok)
.Case("PT_NULL", PT_NULL)
.Case("PT_LOAD", PT_LOAD)
.Case("PT_DYNAMIC", PT_DYNAMIC)
.Case("PT_INTERP", PT_INTERP)
.Case("PT_NOTE", PT_NOTE)
.Case("PT_SHLIB", PT_SHLIB)
.Case("PT_PHDR", PT_PHDR)
.Case("PT_TLS", PT_TLS)
.Case("PT_GNU_EH_FRAME", PT_GNU_EH_FRAME)
.Case("PT_GNU_STACK", PT_GNU_STACK)
.Case("PT_GNU_RELRO", PT_GNU_RELRO)
.Default(-1);
if (Ret == (unsigned)-1) {
setError("invalid program header type: " + Tok);
return PT_NULL;
}
return Ret;
}
static bool isUnderSysroot(StringRef Path) {
if (Config->Sysroot == "")
return false;
for (; !Path.empty(); Path = sys::path::parent_path(Path))
if (sys::fs::equivalent(Config->Sysroot, Path))
return true;
return false;
}
// Entry point.
void elf::readLinkerScript(MemoryBufferRef MB) {
StringRef Path = MB.getBufferIdentifier();
ScriptParser(MB.getBuffer(), isUnderSysroot(Path)).run();
}
template class elf::LinkerScript<ELF32LE>;
template class elf::LinkerScript<ELF32BE>;
template class elf::LinkerScript<ELF64LE>;
template class elf::LinkerScript<ELF64BE>;
diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h
index 642c7c7..5105c51 100644
--- a/ELF/LinkerScript.h
+++ b/ELF/LinkerScript.h
@@ -1,181 +1,177 @@
//===- LinkerScript.h -------------------------------------------*- C++ -*-===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_ELF_LINKER_SCRIPT_H
#define LLD_ELF_LINKER_SCRIPT_H
#include "Writer.h"
#include "lld/Core/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/MemoryBuffer.h"
#include <functional>
namespace lld {
namespace elf {
class SymbolBody;
template <class ELFT> class InputSectionBase;
template <class ELFT> class OutputSectionBase;
template <class ELFT> class OutputSectionFactory;
template <class ELFT> class DefinedCommon;
typedef std::function<uint64_t(uint64_t)> Expr;
// Parses a linker script. Calling this function updates
// Config and ScriptConfig.
void readLinkerScript(MemoryBufferRef MB);
class ScriptParser;
template <class ELFT> class InputSectionBase;
template <class ELFT> class OutputSectionBase;
// This enum is used to implement linker script SECTIONS command.
// https://sourceware.org/binutils/docs/ld/SECTIONS.html#SECTIONS
enum SectionsCommandKind {
AssignmentKind,
OutputSectionKind,
InputSectionKind,
AssertKind
};
struct BaseCommand {
BaseCommand(int K) : Kind(K) {}
virtual ~BaseCommand() {}
int Kind;
};
struct SymbolAssignment : BaseCommand {
SymbolAssignment(StringRef Name, Expr E)
: BaseCommand(AssignmentKind), Name(Name), Expression(E) {}
static bool classof(const BaseCommand *C);
// The LHS of an expression. Name is either a symbol name or ".".
StringRef Name;
SymbolBody *Sym = nullptr;
// The RHS of an expression.
Expr Expression;
// Command attributes for PROVIDE, HIDDEN and PROVIDE_HIDDEN.
bool Provide = false;
bool Hidden = false;
};
// Linker scripts allow additional constraints to be put on ouput sections.
// An output section will only be created if all of its input sections are
// read-only
// or all of its input sections are read-write by using the keyword ONLY_IF_RO
// and ONLY_IF_RW respectively.
enum class ConstraintKind { NoConstraint, ReadOnly, ReadWrite };
struct OutputSectionCommand : BaseCommand {
OutputSectionCommand(StringRef Name)
: BaseCommand(OutputSectionKind), Name(Name) {}
static bool classof(const BaseCommand *C);
StringRef Name;
Expr AddrExpr;
Expr AlignExpr;
std::vector<std::unique_ptr<BaseCommand>> Commands;
std::vector<StringRef> Phdrs;
std::vector<uint8_t> Filler;
ConstraintKind Constraint = ConstraintKind::NoConstraint;
};
enum class SortKind { None, Name, Align, NameAlign, AlignName };
struct InputSectionDescription : BaseCommand {
InputSectionDescription() : BaseCommand(InputSectionKind) {}
static bool classof(const BaseCommand *C);
StringRef FilePattern;
SortKind Sort = SortKind::None;
std::vector<StringRef> ExcludedFiles;
std::vector<StringRef> SectionPatterns;
};
struct AssertCommand : BaseCommand {
AssertCommand(Expr E) : BaseCommand(AssertKind), Expression(E) {}
static bool classof(const BaseCommand *C);
Expr Expression;
};
struct PhdrsCommand {
StringRef Name;
unsigned Type;
bool HasFilehdr;
bool HasPhdrs;
unsigned Flags;
};
// ScriptConfiguration holds linker script parse results.
struct ScriptConfiguration {
// Used to assign addresses to sections.
std::vector<std::unique_ptr<BaseCommand>> Commands;
// Used to assign sections to headers.
std::vector<PhdrsCommand> PhdrsCommands;
bool HasContents = false;
llvm::BumpPtrAllocator Alloc;
// List of section patterns specified with KEEP commands. They will
// be kept even if they are unused and --gc-sections is specified.
std::vector<StringRef> KeptSections;
};
extern ScriptConfiguration *ScriptConfig;
// This is a runner of the linker script.
template <class ELFT> class LinkerScript {
typedef typename ELFT::uint uintX_t;
public:
void createSections(OutputSectionFactory<ELFT> &Factory);
std::vector<PhdrEntry<ELFT>> createPhdrs();
ArrayRef<uint8_t> getFiller(StringRef Name);
bool shouldKeep(InputSectionBase<ELFT> *S);
void assignAddresses();
int compareSections(StringRef A, StringRef B);
- void addScriptedSymbols();
bool hasPhdrsCommands();
uintX_t getOutputSectionSize(StringRef Name);
std::vector<OutputSectionBase<ELFT> *> *OutputSections;
private:
- std::vector<std::pair<StringRef, const InputSectionDescription *>>
- getSectionMap();
-
std::vector<InputSectionBase<ELFT> *>
getInputSections(const InputSectionDescription *);
// "ScriptConfig" is a bit too long, so define a short name for it.
ScriptConfiguration &Opt = *ScriptConfig;
void filter();
int getSectionIndex(StringRef Name);
std::vector<size_t> getPhdrIndices(StringRef SectionName);
size_t getPhdrIndex(StringRef PhdrName);
uintX_t Dot;
};
// Variable template is a C++14 feature, so we can't template
// a global variable. Use a struct to workaround.
template <class ELFT> struct Script { static LinkerScript<ELFT> *X; };
template <class ELFT> LinkerScript<ELFT> *Script<ELFT>::X;
} // namespace elf
} // namespace lld
#endif
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
index bf065d3..61b75f7 100644
--- a/ELF/OutputSections.cpp
+++ b/ELF/OutputSections.cpp
@@ -1,1958 +1,1964 @@
//===- OutputSections.cpp -------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "OutputSections.h"
#include "Config.h"
#include "EhFrame.h"
#include "LinkerScript.h"
#include "Strings.h"
#include "SymbolTable.h"
#include "Target.h"
#include "lld/Core/Parallel.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/SHA1.h"
#include <map>
using namespace llvm;
using namespace llvm::dwarf;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
template <class ELFT>
OutputSectionBase<ELFT>::OutputSectionBase(StringRef Name, uint32_t Type,
uintX_t Flags)
: Name(Name) {
memset(&Header, 0, sizeof(Elf_Shdr));
Header.sh_type = Type;
Header.sh_flags = Flags;
Header.sh_addralign = 1;
}
template <class ELFT> uint32_t OutputSectionBase<ELFT>::getPhdrFlags() const {
uintX_t Flags = getFlags();
uint32_t Ret = PF_R;
if (Flags & SHF_WRITE)
Ret |= PF_W;
if (Flags & SHF_EXECINSTR)
Ret |= PF_X;
return Ret;
}
template <class ELFT>
void OutputSectionBase<ELFT>::writeHeaderTo(Elf_Shdr *Shdr) {
*Shdr = Header;
}
template <class ELFT>
GotPltSection<ELFT>::GotPltSection()
: OutputSectionBase<ELFT>(".got.plt", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) {
this->Header.sh_addralign = Target->GotPltEntrySize;
}
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> void GotPltSection<ELFT>::finalize() {
this->Header.sh_size = (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 <class ELFT>
GotSection<ELFT>::GotSection()
: OutputSectionBase<ELFT>(".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) {
if (Config->EMachine == EM_MIPS)
this->Header.sh_flags |= SHF_MIPS_GPREL;
this->Header.sh_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
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 {
uintX_t Off = MipsPageEntries;
if (B.isTls())
Off += MipsLocal.size() + MipsGlobal.size() + B.GotIndex;
else if (B.IsInGlobalMipsGot)
Off += MipsLocal.size() + B.GotIndex;
else if (B.isInGot())
Off += B.GotIndex;
else {
auto It = MipsGotMap.find({&B, Addend});
assert(It != MipsGotMap.end());
Off += It->second;
}
return Off * sizeof(uintX_t) - MipsGPOffset;
}
template <class ELFT>
typename GotSection<ELFT>::uintX_t GotSection<ELFT>::getMipsTlsOffset() {
return (MipsPageEntries + MipsLocal.size() + 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();
}
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<ELFT> *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->getSize() + 0x8000 + 0xfffe) / 0xffff;
}
EntriesNum += MipsPageEntries + MipsLocal.size() + MipsGlobal.size();
}
this->Header.sh_size = EntriesNum * sizeof(uintX_t);
}
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);
write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(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);
write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA);
};
std::for_each(std::begin(MipsLocal), std::end(MipsLocal), AddEntry);
std::for_each(std::begin(MipsGlobal), std::end(MipsGlobal), AddEntry);
}
template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
if (Config->EMachine == EM_MIPS)
writeMipsGot(Buf);
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>();
write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA);
}
}
template <class ELFT>
PltSection<ELFT>::PltSection()
: OutputSectionBase<ELFT>(".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR) {
this->Header.sh_addralign = 16;
}
template <class ELFT> void PltSection<ELFT>::writeTo(uint8_t *Buf) {
// At beginning of PLT, we have code to call the dynamic linker
// to resolve dynsyms at runtime. Write such code.
Target->writePltHeader(Buf);
size_t Off = Target->PltHeaderSize;
for (auto &I : Entries) {
const SymbolBody *B = I.first;
unsigned RelOff = I.second;
uint64_t Got = B->getGotPltVA<ELFT>();
uint64_t Plt = this->getVA() + Off;
Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff);
Off += Target->PltEntrySize;
}
}
template <class ELFT> void PltSection<ELFT>::addEntry(SymbolBody &Sym) {
Sym.PltIndex = Entries.size();
unsigned RelOff = Out<ELFT>::RelaPlt->getRelocOffset();
Entries.push_back(std::make_pair(&Sym, RelOff));
}
template <class ELFT> void PltSection<ELFT>::finalize() {
this->Header.sh_size =
Target->PltHeaderSize + Entries.size() * Target->PltEntrySize;
}
template <class ELFT>
RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort)
: OutputSectionBase<ELFT>(Name, Config->Rela ? SHT_RELA : SHT_REL,
SHF_ALLOC),
Sort(Sort) {
this->Header.sh_entsize = Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
this->Header.sh_addralign = sizeof(uintX_t);
}
template <class ELFT>
void RelocationSection<ELFT>::addReloc(const DynamicReloc<ELFT> &Reloc) {
Relocs.push_back(Reloc);
}
template <class ELFT, class RelTy>
static bool compRelocations(const RelTy &A, const RelTy &B) {
return A.getSymbol(Config->Mips64EL) < B.getSymbol(Config->Mips64EL);
}
template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
uint8_t *BufBegin = Buf;
for (const DynamicReloc<ELFT> &Rel : Relocs) {
auto *P = reinterpret_cast<Elf_Rela *>(Buf);
Buf += Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
if (Config->Rela)
P->r_addend = Rel.getAddend();
P->r_offset = Rel.getOffset();
if (Config->EMachine == EM_MIPS && Rel.getOutputSec() == Out<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->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->Mips64EL);
}
if (Sort) {
if (Config->Rela)
std::stable_sort((Elf_Rela *)BufBegin,
(Elf_Rela *)BufBegin + Relocs.size(),
compRelocations<ELFT, Elf_Rela>);
else
std::stable_sort((Elf_Rel *)BufBegin, (Elf_Rel *)BufBegin + Relocs.size(),
compRelocations<ELFT, Elf_Rel>);
}
}
template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() {
return this->Header.sh_entsize * Relocs.size();
}
template <class ELFT> void RelocationSection<ELFT>::finalize() {
this->Header.sh_link = Static ? Out<ELFT>::SymTab->SectionIndex
: Out<ELFT>::DynSymTab->SectionIndex;
this->Header.sh_size = Relocs.size() * this->Header.sh_entsize;
}
template <class ELFT>
InterpSection<ELFT>::InterpSection()
: OutputSectionBase<ELFT>(".interp", SHT_PROGBITS, SHF_ALLOC) {
this->Header.sh_size = Config->DynamicLinker.size() + 1;
}
template <class ELFT> void InterpSection<ELFT>::writeTo(uint8_t *Buf) {
StringRef S = Config->DynamicLinker;
memcpy(Buf, S.data(), S.size());
}
template <class ELFT>
HashTableSection<ELFT>::HashTableSection()
: OutputSectionBase<ELFT>(".hash", SHT_HASH, SHF_ALLOC) {
this->Header.sh_entsize = sizeof(Elf_Word);
this->Header.sh_addralign = sizeof(Elf_Word);
}
static uint32_t hashSysv(StringRef Name) {
uint32_t H = 0;
for (char C : Name) {
H = (H << 4) + C;
uint32_t G = H & 0xf0000000;
if (G)
H ^= G >> 24;
H &= ~G;
}
return H;
}
template <class ELFT> void HashTableSection<ELFT>::finalize() {
this->Header.sh_link = Out<ELFT>::DynSymTab->SectionIndex;
unsigned NumEntries = 2; // nbucket and nchain.
NumEntries += Out<ELFT>::DynSymTab->getNumSymbols(); // The chain entries.
// Create as many buckets as there are symbols.
// FIXME: This is simplistic. We can try to optimize it, but implementing
// support for SHT_GNU_HASH is probably even more profitable.
NumEntries += Out<ELFT>::DynSymTab->getNumSymbols();
this->Header.sh_size = NumEntries * sizeof(Elf_Word);
}
template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
unsigned NumSymbols = Out<ELFT>::DynSymTab->getNumSymbols();
auto *P = reinterpret_cast<Elf_Word *>(Buf);
*P++ = NumSymbols; // nbucket
*P++ = NumSymbols; // nchain
Elf_Word *Buckets = P;
Elf_Word *Chains = P + NumSymbols;
for (const std::pair<SymbolBody *, unsigned> &P :
Out<ELFT>::DynSymTab->getSymbols()) {
SymbolBody *Body = P.first;
StringRef Name = Body->getName();
unsigned I = Body->DynsymIndex;
uint32_t Hash = hashSysv(Name) % NumSymbols;
Chains[I] = Buckets[Hash];
Buckets[Hash] = I;
}
}
static uint32_t hashGnu(StringRef Name) {
uint32_t H = 5381;
for (uint8_t C : Name)
H = (H << 5) + H + C;
return H;
}
template <class ELFT>
GnuHashTableSection<ELFT>::GnuHashTableSection()
: OutputSectionBase<ELFT>(".gnu.hash", SHT_GNU_HASH, SHF_ALLOC) {
this->Header.sh_entsize = ELFT::Is64Bits ? 0 : 4;
this->Header.sh_addralign = sizeof(uintX_t);
}
template <class ELFT>
unsigned GnuHashTableSection<ELFT>::calcNBuckets(unsigned NumHashed) {
if (!NumHashed)
return 0;
// These values are prime numbers which are not greater than 2^(N-1) + 1.
// In result, for any particular NumHashed we return a prime number
// which is not greater than NumHashed.
static const unsigned Primes[] = {
1, 1, 3, 3, 7, 13, 31, 61, 127, 251,
509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071};
return Primes[std::min<unsigned>(Log2_32_Ceil(NumHashed),
array_lengthof(Primes) - 1)];
}
// Bloom filter estimation: at least 8 bits for each hashed symbol.
// GNU Hash table requirement: it should be a power of 2,
// the minimum value is 1, even for an empty table.
// Expected results for a 32-bit target:
// calcMaskWords(0..4) = 1
// calcMaskWords(5..8) = 2
// calcMaskWords(9..16) = 4
// For a 64-bit target:
// calcMaskWords(0..8) = 1
// calcMaskWords(9..16) = 2
// calcMaskWords(17..32) = 4
template <class ELFT>
unsigned GnuHashTableSection<ELFT>::calcMaskWords(unsigned NumHashed) {
if (!NumHashed)
return 1;
return NextPowerOf2((NumHashed - 1) / sizeof(Elf_Off));
}
template <class ELFT> void GnuHashTableSection<ELFT>::finalize() {
unsigned NumHashed = Symbols.size();
NBuckets = calcNBuckets(NumHashed);
MaskWords = calcMaskWords(NumHashed);
// Second hash shift estimation: just predefined values.
Shift2 = ELFT::Is64Bits ? 6 : 5;
this->Header.sh_link = Out<ELFT>::DynSymTab->SectionIndex;
this->Header.sh_size = sizeof(Elf_Word) * 4 // Header
+ sizeof(Elf_Off) * MaskWords // Bloom Filter
+ sizeof(Elf_Word) * NBuckets // Hash Buckets
+ sizeof(Elf_Word) * NumHashed; // Hash Values
}
template <class ELFT> void GnuHashTableSection<ELFT>::writeTo(uint8_t *Buf) {
writeHeader(Buf);
if (Symbols.empty())
return;
writeBloomFilter(Buf);
writeHashTable(Buf);
}
template <class ELFT>
void GnuHashTableSection<ELFT>::writeHeader(uint8_t *&Buf) {
auto *P = reinterpret_cast<Elf_Word *>(Buf);
*P++ = NBuckets;
*P++ = Out<ELFT>::DynSymTab->getNumSymbols() - Symbols.size();
*P++ = MaskWords;
*P++ = Shift2;
Buf = reinterpret_cast<uint8_t *>(P);
}
template <class ELFT>
void GnuHashTableSection<ELFT>::writeBloomFilter(uint8_t *&Buf) {
unsigned C = sizeof(Elf_Off) * 8;
auto *Masks = reinterpret_cast<Elf_Off *>(Buf);
for (const SymbolData &Sym : Symbols) {
size_t Pos = (Sym.Hash / C) & (MaskWords - 1);
uintX_t V = (uintX_t(1) << (Sym.Hash % C)) |
(uintX_t(1) << ((Sym.Hash >> Shift2) % C));
Masks[Pos] |= V;
}
Buf += sizeof(Elf_Off) * MaskWords;
}
template <class ELFT>
void GnuHashTableSection<ELFT>::writeHashTable(uint8_t *Buf) {
Elf_Word *Buckets = reinterpret_cast<Elf_Word *>(Buf);
Elf_Word *Values = Buckets + NBuckets;
int PrevBucket = -1;
int I = 0;
for (const SymbolData &Sym : Symbols) {
int Bucket = Sym.Hash % NBuckets;
assert(PrevBucket <= Bucket);
if (Bucket != PrevBucket) {
Buckets[Bucket] = Sym.Body->DynsymIndex;
PrevBucket = Bucket;
if (I > 0)
Values[I - 1] |= 1;
}
Values[I] = Sym.Hash & ~1;
++I;
}
if (I > 0)
Values[I - 1] |= 1;
}
// Add symbols to this symbol hash table. Note that this function
// destructively sort a given vector -- which is needed because
// GNU-style hash table places some sorting requirements.
template <class ELFT>
void GnuHashTableSection<ELFT>::addSymbols(
std::vector<std::pair<SymbolBody *, size_t>> &V) {
// Ideally this will just be 'auto' but GCC 6.1 is not able
// to deduce it correctly.
std::vector<std::pair<SymbolBody *, size_t>>::iterator Mid =
std::stable_partition(V.begin(), V.end(),
[](std::pair<SymbolBody *, size_t> &P) {
return P.first->isUndefined();
});
if (Mid == V.end())
return;
for (auto I = Mid, E = V.end(); I != E; ++I) {
SymbolBody *B = I->first;
size_t StrOff = I->second;
Symbols.push_back({B, StrOff, hashGnu(B->getName())});
}
unsigned NBuckets = calcNBuckets(Symbols.size());
std::stable_sort(Symbols.begin(), Symbols.end(),
[&](const SymbolData &L, const SymbolData &R) {
return L.Hash % NBuckets < R.Hash % NBuckets;
});
V.erase(Mid, V.end());
for (const SymbolData &Sym : Symbols)
V.push_back({Sym.Body, Sym.STName});
}
// Returns the number of version definition entries. Because the first entry
// is for the version definition itself, it is the number of versioned symbols
// plus one. Note that we don't support multiple versions yet.
static unsigned getVerDefNum() { return Config->VersionDefinitions.size() + 1; }
template <class ELFT>
DynamicSection<ELFT>::DynamicSection()
: OutputSectionBase<ELFT>(".dynamic", SHT_DYNAMIC, SHF_ALLOC | SHF_WRITE) {
Elf_Shdr &Header = this->Header;
Header.sh_addralign = sizeof(uintX_t);
Header.sh_entsize = ELFT::Is64Bits ? 16 : 8;
// .dynamic section is not writable on MIPS.
// See "Special Section" in Chapter 4 in the following document:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
if (Config->EMachine == EM_MIPS)
Header.sh_flags = SHF_ALLOC;
}
template <class ELFT> void DynamicSection<ELFT>::finalize() {
if (this->Header.sh_size)
return; // Already finalized.
Elf_Shdr &Header = this->Header;
Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex;
auto Add = [=](Entry E) { Entries.push_back(E); };
// Add strings. We know that these are the last strings to be added to
// DynStrTab and doing this here allows this function to set DT_STRSZ.
if (!Config->RPath.empty())
Add({Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH,
Out<ELFT>::DynStrTab->addString(Config->RPath)});
for (const std::unique_ptr<SharedFile<ELFT>> &F :
Symtab<ELFT>::X->getSharedFiles())
if (F->isNeeded())
Add({DT_NEEDED, Out<ELFT>::DynStrTab->addString(F->getSoName())});
if (!Config->SoName.empty())
Add({DT_SONAME, Out<ELFT>::DynStrTab->addString(Config->SoName)});
Out<ELFT>::DynStrTab->finalize();
if (Out<ELFT>::RelaDyn->hasRelocs()) {
bool IsRela = Config->Rela;
Add({IsRela ? DT_RELA : DT_REL, Out<ELFT>::RelaDyn});
Add({IsRela ? DT_RELASZ : DT_RELSZ, Out<ELFT>::RelaDyn->getSize()});
Add({IsRela ? DT_RELAENT : DT_RELENT,
uintX_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))});
}
if (Out<ELFT>::RelaPlt && Out<ELFT>::RelaPlt->hasRelocs()) {
Add({DT_JMPREL, Out<ELFT>::RelaPlt});
Add({DT_PLTRELSZ, Out<ELFT>::RelaPlt->getSize()});
Add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT,
Out<ELFT>::GotPlt});
Add({DT_PLTREL, uint64_t(Config->Rela ? DT_RELA : DT_REL)});
}
Add({DT_SYMTAB, Out<ELFT>::DynSymTab});
Add({DT_SYMENT, sizeof(Elf_Sym)});
Add({DT_STRTAB, Out<ELFT>::DynStrTab});
Add({DT_STRSZ, Out<ELFT>::DynStrTab->getSize()});
if (Out<ELFT>::GnuHashTab)
Add({DT_GNU_HASH, Out<ELFT>::GnuHashTab});
if (Out<ELFT>::HashTab)
Add({DT_HASH, Out<ELFT>::HashTab});
if (PreInitArraySec) {
Add({DT_PREINIT_ARRAY, PreInitArraySec});
Add({DT_PREINIT_ARRAYSZ, PreInitArraySec->getSize()});
}
if (InitArraySec) {
Add({DT_INIT_ARRAY, InitArraySec});
Add({DT_INIT_ARRAYSZ, (uintX_t)InitArraySec->getSize()});
}
if (FiniArraySec) {
Add({DT_FINI_ARRAY, FiniArraySec});
Add({DT_FINI_ARRAYSZ, (uintX_t)FiniArraySec->getSize()});
}
if (SymbolBody *B = Symtab<ELFT>::X->find(Config->Init))
Add({DT_INIT, B});
if (SymbolBody *B = Symtab<ELFT>::X->find(Config->Fini))
Add({DT_FINI, B});
uint32_t DtFlags = 0;
uint32_t DtFlags1 = 0;
if (Config->Bsymbolic)
DtFlags |= DF_SYMBOLIC;
if (Config->ZNodelete)
DtFlags1 |= DF_1_NODELETE;
if (Config->ZNow) {
DtFlags |= DF_BIND_NOW;
DtFlags1 |= DF_1_NOW;
}
if (Config->ZOrigin) {
DtFlags |= DF_ORIGIN;
DtFlags1 |= DF_1_ORIGIN;
}
if (DtFlags)
Add({DT_FLAGS, DtFlags});
if (DtFlags1)
Add({DT_FLAGS_1, DtFlags1});
if (!Config->Entry.empty())
Add({DT_DEBUG, (uint64_t)0});
bool HasVerNeed = Out<ELFT>::VerNeed->getNeedNum() != 0;
if (HasVerNeed || Out<ELFT>::VerDef)
Add({DT_VERSYM, Out<ELFT>::VerSym});
if (Out<ELFT>::VerDef) {
Add({DT_VERDEF, Out<ELFT>::VerDef});
Add({DT_VERDEFNUM, getVerDefNum()});
}
if (HasVerNeed) {
Add({DT_VERNEED, Out<ELFT>::VerNeed});
Add({DT_VERNEEDNUM, Out<ELFT>::VerNeed->getNeedNum()});
}
if (Config->EMachine == EM_MIPS) {
Add({DT_MIPS_RLD_VERSION, 1});
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_GOTSYM, B->DynsymIndex});
else
Add({DT_MIPS_GOTSYM, Out<ELFT>::DynSymTab->getNumSymbols()});
Add({DT_PLTGOT, Out<ELFT>::Got});
if (Out<ELFT>::MipsRldMap)
Add({DT_MIPS_RLD_MAP, Out<ELFT>::MipsRldMap});
}
// +1 for DT_NULL
Header.sh_size = (Entries.size() + 1) * Header.sh_entsize;
}
template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
auto *P = reinterpret_cast<Elf_Dyn *>(Buf);
for (const Entry &E : Entries) {
P->d_tag = E.Tag;
switch (E.Kind) {
case Entry::SecAddr:
P->d_un.d_ptr = E.OutSec->getVA();
break;
case Entry::SymAddr:
P->d_un.d_ptr = E.Sym->template getVA<ELFT>();
break;
case Entry::PlainInt:
P->d_un.d_val = E.Val;
break;
}
++P;
}
}
template <class ELFT>
EhFrameHeader<ELFT>::EhFrameHeader()
: OutputSectionBase<ELFT>(".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC) {}
// .eh_frame_hdr contains a binary search table of pointers to FDEs.
// Each entry of the search table consists of two values,
// the starting PC from where FDEs covers, and the FDE's address.
// It is sorted by PC.
template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
const endianness E = ELFT::TargetEndianness;
// Sort the FDE list by their PC and uniqueify. Usually there is only
// one FDE for a PC (i.e. function), but if ICF merges two functions
// into one, there can be more than one FDEs pointing to the address.
auto Less = [](const FdeData &A, const FdeData &B) { return A.Pc < B.Pc; };
std::stable_sort(Fdes.begin(), Fdes.end(), Less);
auto Eq = [](const FdeData &A, const FdeData &B) { return A.Pc == B.Pc; };
Fdes.erase(std::unique(Fdes.begin(), Fdes.end(), Eq), Fdes.end());
Buf[0] = 1;
Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
Buf[2] = DW_EH_PE_udata4;
Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
write32<E>(Buf + 4, Out<ELFT>::EhFrame->getVA() - this->getVA() - 4);
write32<E>(Buf + 8, Fdes.size());
Buf += 12;
uintX_t VA = this->getVA();
for (FdeData &Fde : Fdes) {
write32<E>(Buf, Fde.Pc - VA);
write32<E>(Buf + 4, Fde.FdeVA - VA);
Buf += 8;
}
}
template <class ELFT> void EhFrameHeader<ELFT>::finalize() {
// .eh_frame_hdr has a 12 bytes header followed by an array of FDEs.
this->Header.sh_size = 12 + Out<ELFT>::EhFrame->NumFdes * 8;
}
template <class ELFT>
void EhFrameHeader<ELFT>::addFde(uint32_t Pc, uint32_t FdeVA) {
Fdes.push_back({Pc, FdeVA});
}
template <class ELFT>
OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t Type, uintX_t Flags)
: OutputSectionBase<ELFT>(Name, Type, Flags) {
if (Type == SHT_RELA)
this->Header.sh_entsize = sizeof(Elf_Rela);
else if (Type == SHT_REL)
this->Header.sh_entsize = sizeof(Elf_Rel);
}
template <class ELFT> void OutputSection<ELFT>::finalize() {
uint32_t Type = this->Header.sh_type;
if (Type != SHT_RELA && Type != SHT_REL)
return;
this->Header.sh_link = Out<ELFT>::SymTab->SectionIndex;
// sh_info for SHT_REL[A] sections should contain the section header index of
// the section to which the relocation applies.
InputSectionBase<ELFT> *S = Sections[0]->getRelocatedSection();
this->Header.sh_info = S->OutSec->SectionIndex;
}
template <class ELFT>
void OutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
assert(C->Live);
auto *S = cast<InputSection<ELFT>>(C);
Sections.push_back(S);
S->OutSec = this;
this->updateAlignment(S->Alignment);
+ uintX_t Off = alignTo(this->Header.sh_size, S->Alignment);
+ S->OutSecOff = Off;
+ this->Header.sh_size = Off + S->getSize();
}
// If an input string is in the form of "foo.N" where N is a number,
// return N. Otherwise, returns 65536, which is one greater than the
// lowest priority.
static int getPriority(StringRef S) {
size_t Pos = S.rfind('.');
if (Pos == StringRef::npos)
return 65536;
int V;
if (S.substr(Pos + 1).getAsInteger(10, V))
return 65536;
return V;
}
// This function is called after we sort input sections
// and scan relocations to setup sections' offsets.
template <class ELFT> void OutputSection<ELFT>::assignOffsets() {
- uintX_t Off = this->Header.sh_size;
+ uintX_t Off = 0;
for (InputSection<ELFT> *S : Sections) {
Off = alignTo(Off, S->Alignment);
S->OutSecOff = Off;
Off += S->getSize();
}
this->Header.sh_size = Off;
}
// Sorts input sections by section name suffixes, so that .foo.N comes
// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections.
// We want to keep the original order if the priorities are the same
// because the compiler keeps the original initialization order in a
// translation unit and we need to respect that.
// For more detail, read the section of the GCC's manual about init_priority.
template <class ELFT> void OutputSection<ELFT>::sortInitFini() {
// Sort sections by priority.
typedef std::pair<int, InputSection<ELFT> *> Pair;
auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
std::vector<Pair> V;
for (InputSection<ELFT> *S : Sections)
V.push_back({getPriority(S->getSectionName()), S});
std::stable_sort(V.begin(), V.end(), Comp);
Sections.clear();
for (Pair &P : V)
- Sections.push_back(P.second);
+ addSection(P.second);
+
+ assignOffsets();
}
// Returns true if S matches /Filename.?\.o$/.
static bool isCrtBeginEnd(StringRef S, StringRef Filename) {
if (!S.endswith(".o"))
return false;
S = S.drop_back(2);
if (S.endswith(Filename))
return true;
return !S.empty() && S.drop_back().endswith(Filename);
}
static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); }
static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); }
// .ctors and .dtors are sorted by this priority from highest to lowest.
//
// 1. The section was contained in crtbegin (crtbegin contains
// some sentinel value in its .ctors and .dtors so that the runtime
// can find the beginning of the sections.)
//
// 2. The section has an optional priority value in the form of ".ctors.N"
// or ".dtors.N" where N is a number. Unlike .{init,fini}_array,
// they are compared as string rather than number.
//
// 3. The section is just ".ctors" or ".dtors".
//
// 4. The section was contained in crtend, which contains an end marker.
//
// In an ideal world, we don't need this function because .init_array and
// .ctors are duplicate features (and .init_array is newer.) However, there
// are too many real-world use cases of .ctors, so we had no choice to
// support that with this rather ad-hoc semantics.
template <class ELFT>
static bool compCtors(const InputSection<ELFT> *A,
const InputSection<ELFT> *B) {
bool BeginA = isCrtbegin(A->getFile()->getName());
bool BeginB = isCrtbegin(B->getFile()->getName());
if (BeginA != BeginB)
return BeginA;
bool EndA = isCrtend(A->getFile()->getName());
bool EndB = isCrtend(B->getFile()->getName());
if (EndA != EndB)
return EndB;
StringRef X = A->getSectionName();
StringRef Y = B->getSectionName();
assert(X.startswith(".ctors") || X.startswith(".dtors"));
assert(Y.startswith(".ctors") || Y.startswith(".dtors"));
X = X.substr(6);
Y = Y.substr(6);
if (X.empty() && Y.empty())
return false;
return X < Y;
}
// Sorts input sections by the special rules for .ctors and .dtors.
// Unfortunately, the rules are different from the one for .{init,fini}_array.
// Read the comment above.
template <class ELFT> void OutputSection<ELFT>::sortCtorsDtors() {
std::stable_sort(Sections.begin(), Sections.end(), compCtors<ELFT>);
+ assignOffsets();
}
static void fill(uint8_t *Buf, size_t Size, ArrayRef<uint8_t> A) {
size_t I = 0;
for (; I + A.size() < Size; I += A.size())
memcpy(Buf + I, A.data(), A.size());
memcpy(Buf + I, A.data(), Size - I);
}
template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
ArrayRef<uint8_t> Filler = Script<ELFT>::X->getFiller(this->Name);
if (!Filler.empty())
fill(Buf, this->getSize(), Filler);
if (Config->Threads) {
parallel_for_each(Sections.begin(), Sections.end(),
[=](InputSection<ELFT> *C) { C->writeTo(Buf); });
} else {
for (InputSection<ELFT> *C : Sections)
C->writeTo(Buf);
}
}
template <class ELFT>
EhOutputSection<ELFT>::EhOutputSection()
: OutputSectionBase<ELFT>(".eh_frame", SHT_PROGBITS, SHF_ALLOC) {}
// Search for an existing CIE record or create a new one.
// CIE records from input object files are uniquified by their contents
// and where their relocations point to.
template <class ELFT>
template <class RelTy>
CieRecord *EhOutputSection<ELFT>::addCie(EhSectionPiece &Piece,
EhInputSection<ELFT> *Sec,
ArrayRef<RelTy> Rels) {
const endianness E = ELFT::TargetEndianness;
if (read32<E>(Piece.data().data() + 4) != 0)
fatal("CIE expected at beginning of .eh_frame: " + Sec->getSectionName());
SymbolBody *Personality = nullptr;
unsigned FirstRelI = Piece.FirstRelocation;
if (FirstRelI != (unsigned)-1)
Personality = &Sec->getFile()->getRelocTargetSym(Rels[FirstRelI]);
// Search for an existing CIE by CIE contents/relocation target pair.
CieRecord *Cie = &CieMap[{Piece.data(), Personality}];
// If not found, create a new one.
if (Cie->Piece == nullptr) {
Cie->Piece = &Piece;
Cies.push_back(Cie);
}
return Cie;
}
// There is one FDE per function. Returns true if a given FDE
// points to a live function.
template <class ELFT>
template <class RelTy>
bool EhOutputSection<ELFT>::isFdeLive(EhSectionPiece &Piece,
EhInputSection<ELFT> *Sec,
ArrayRef<RelTy> Rels) {
unsigned FirstRelI = Piece.FirstRelocation;
if (FirstRelI == (unsigned)-1)
fatal("FDE doesn't reference another section");
const RelTy &Rel = Rels[FirstRelI];
SymbolBody &B = Sec->getFile()->getRelocTargetSym(Rel);
auto *D = dyn_cast<DefinedRegular<ELFT>>(&B);
if (!D || !D->Section)
return false;
InputSectionBase<ELFT> *Target = D->Section->Repl;
return Target && Target->Live;
}
// .eh_frame is a sequence of CIE or FDE records. In general, there
// is one CIE record per input object file which is followed by
// a list of FDEs. This function searches an existing CIE or create a new
// one and associates FDEs to the CIE.
template <class ELFT>
template <class RelTy>
void EhOutputSection<ELFT>::addSectionAux(EhInputSection<ELFT> *Sec,
ArrayRef<RelTy> Rels) {
const endianness E = ELFT::TargetEndianness;
DenseMap<size_t, CieRecord *> OffsetToCie;
for (EhSectionPiece &Piece : Sec->Pieces) {
// The empty record is the end marker.
if (Piece.size() == 4)
return;
size_t Offset = Piece.InputOff;
uint32_t ID = read32<E>(Piece.data().data() + 4);
if (ID == 0) {
OffsetToCie[Offset] = addCie(Piece, Sec, Rels);
continue;
}
uint32_t CieOffset = Offset + 4 - ID;
CieRecord *Cie = OffsetToCie[CieOffset];
if (!Cie)
fatal("invalid CIE reference");
if (!isFdeLive(Piece, Sec, Rels))
continue;
Cie->FdePieces.push_back(&Piece);
NumFdes++;
}
}
template <class ELFT>
void EhOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
auto *Sec = cast<EhInputSection<ELFT>>(C);
Sec->OutSec = this;
this->updateAlignment(Sec->Alignment);
Sections.push_back(Sec);
// .eh_frame is a sequence of CIE or FDE records. This function
// splits it into pieces so that we can call
// SplitInputSection::getSectionPiece on the section.
Sec->split();
if (Sec->Pieces.empty())
return;
if (const Elf_Shdr *RelSec = Sec->RelocSection) {
ELFFile<ELFT> &Obj = Sec->getFile()->getObj();
if (RelSec->sh_type == SHT_RELA)
addSectionAux(Sec, Obj.relas(RelSec));
else
addSectionAux(Sec, Obj.rels(RelSec));
return;
}
addSectionAux(Sec, makeArrayRef<Elf_Rela>(nullptr, nullptr));
}
template <class ELFT>
static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
memcpy(Buf, D.data(), D.size());
// Fix the size field. -4 since size does not include the size field itself.
const endianness E = ELFT::TargetEndianness;
write32<E>(Buf, alignTo(D.size(), sizeof(typename ELFT::uint)) - 4);
}
template <class ELFT> void EhOutputSection<ELFT>::finalize() {
if (this->Header.sh_size)
return; // Already finalized.
size_t Off = 0;
for (CieRecord *Cie : Cies) {
Cie->Piece->OutputOff = Off;
Off += alignTo(Cie->Piece->size(), sizeof(uintX_t));
for (SectionPiece *Fde : Cie->FdePieces) {
Fde->OutputOff = Off;
Off += alignTo(Fde->size(), sizeof(uintX_t));
}
}
this->Header.sh_size = Off;
}
template <class ELFT> static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
const endianness E = ELFT::TargetEndianness;
switch (Size) {
case DW_EH_PE_udata2:
return read16<E>(Buf);
case DW_EH_PE_udata4:
return read32<E>(Buf);
case DW_EH_PE_udata8:
return read64<E>(Buf);
case DW_EH_PE_absptr:
if (ELFT::Is64Bits)
return read64<E>(Buf);
return read32<E>(Buf);
}
fatal("unknown FDE size encoding");
}
// Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to.
// We need it to create .eh_frame_hdr section.
template <class ELFT>
typename ELFT::uint EhOutputSection<ELFT>::getFdePc(uint8_t *Buf, size_t FdeOff,
uint8_t Enc) {
// The starting address to which this FDE applies is
// stored at FDE + 8 byte.
size_t Off = FdeOff + 8;
uint64_t Addr = readFdeAddr<ELFT>(Buf + Off, Enc & 0x7);
if ((Enc & 0x70) == DW_EH_PE_absptr)
return Addr;
if ((Enc & 0x70) == DW_EH_PE_pcrel)
return Addr + this->getVA() + Off;
fatal("unknown FDE size relative encoding");
}
template <class ELFT> void EhOutputSection<ELFT>::writeTo(uint8_t *Buf) {
const endianness E = ELFT::TargetEndianness;
for (CieRecord *Cie : Cies) {
size_t CieOffset = Cie->Piece->OutputOff;
writeCieFde<ELFT>(Buf + CieOffset, Cie->Piece->data());
for (SectionPiece *Fde : Cie->FdePieces) {
size_t Off = Fde->OutputOff;
writeCieFde<ELFT>(Buf + Off, Fde->data());
// FDE's second word should have the offset to an associated CIE.
// Write it.
write32<E>(Buf + Off + 4, Off + 4 - CieOffset);
}
}
for (EhInputSection<ELFT> *S : Sections)
S->relocate(Buf, nullptr);
// Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table
// to get a FDE from an address to which FDE is applied. So here
// we obtain two addresses and pass them to EhFrameHdr object.
if (Out<ELFT>::EhFrameHdr) {
for (CieRecord *Cie : Cies) {
uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece->data());
for (SectionPiece *Fde : Cie->FdePieces) {
uintX_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
uintX_t FdeVA = this->getVA() + Fde->OutputOff;
Out<ELFT>::EhFrameHdr->addFde(Pc, FdeVA);
}
}
}
}
template <class ELFT>
MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t Type,
uintX_t Flags, uintX_t Alignment)
: OutputSectionBase<ELFT>(Name, Type, Flags),
Builder(StringTableBuilder::RAW, Alignment) {}
template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) {
if (shouldTailMerge()) {
StringRef Data = Builder.data();
memcpy(Buf, Data.data(), Data.size());
return;
}
for (const std::pair<CachedHash<StringRef>, size_t> &P : Builder.getMap()) {
StringRef Data = P.first.Val;
memcpy(Buf + P.second, Data.data(), Data.size());
}
}
static StringRef toStringRef(ArrayRef<uint8_t> A) {
return {(const char *)A.data(), A.size()};
}
template <class ELFT>
void MergeOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
auto *Sec = cast<MergeInputSection<ELFT>>(C);
Sec->OutSec = this;
this->updateAlignment(Sec->Alignment);
this->Header.sh_entsize = Sec->getSectionHdr()->sh_entsize;
Sections.push_back(Sec);
bool IsString = this->Header.sh_flags & SHF_STRINGS;
for (SectionPiece &Piece : Sec->Pieces) {
if (!Piece.Live)
continue;
uintX_t OutputOffset = Builder.add(toStringRef(Piece.data()));
if (!IsString || !shouldTailMerge())
Piece.OutputOff = OutputOffset;
}
}
template <class ELFT>
unsigned MergeOutputSection<ELFT>::getOffset(StringRef Val) {
return Builder.getOffset(Val);
}
template <class ELFT> bool MergeOutputSection<ELFT>::shouldTailMerge() const {
return Config->Optimize >= 2 && this->Header.sh_flags & SHF_STRINGS;
}
template <class ELFT> void MergeOutputSection<ELFT>::finalize() {
if (shouldTailMerge())
Builder.finalize();
this->Header.sh_size = Builder.getSize();
}
template <class ELFT> void MergeOutputSection<ELFT>::finalizePieces() {
for (MergeInputSection<ELFT> *Sec : Sections)
Sec->finalizePieces();
}
template <class ELFT>
StringTableSection<ELFT>::StringTableSection(StringRef Name, bool Dynamic)
: OutputSectionBase<ELFT>(Name, SHT_STRTAB,
Dynamic ? (uintX_t)SHF_ALLOC : 0),
Dynamic(Dynamic) {}
// Adds a string to the string table. If HashIt is true we hash and check for
// duplicates. It is optional because the name of global symbols are already
// uniqued and hashing them again has a big cost for a small value: uniquing
// them with some other string that happens to be the same.
template <class ELFT>
unsigned StringTableSection<ELFT>::addString(StringRef S, bool HashIt) {
if (HashIt) {
auto R = StringMap.insert(std::make_pair(S, Size));
if (!R.second)
return R.first->second;
}
unsigned Ret = Size;
Size += S.size() + 1;
Strings.push_back(S);
return Ret;
}
template <class ELFT> void StringTableSection<ELFT>::writeTo(uint8_t *Buf) {
// ELF string tables start with NUL byte, so advance the pointer by one.
++Buf;
for (StringRef S : Strings) {
memcpy(Buf, S.data(), S.size());
Buf += S.size() + 1;
}
}
template <class ELFT>
typename ELFT::uint DynamicReloc<ELFT>::getOffset() const {
if (OutputSec)
return OutputSec->getVA() + OffsetInSec;
return InputSec->OutSec->getVA() + OffsetInSec;
}
template <class ELFT>
typename ELFT::uint DynamicReloc<ELFT>::getAddend() const {
if (UseSymVA)
return Sym->getVA<ELFT>(Addend);
return Addend;
}
template <class ELFT> uint32_t DynamicReloc<ELFT>::getSymIndex() const {
if (Sym && !UseSymVA)
return Sym->DynsymIndex;
return 0;
}
template <class ELFT>
SymbolTableSection<ELFT>::SymbolTableSection(
StringTableSection<ELFT> &StrTabSec)
: OutputSectionBase<ELFT>(StrTabSec.isDynamic() ? ".dynsym" : ".symtab",
StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
StrTabSec.isDynamic() ? (uintX_t)SHF_ALLOC : 0),
StrTabSec(StrTabSec) {
this->Header.sh_entsize = sizeof(Elf_Sym);
this->Header.sh_addralign = sizeof(uintX_t);
}
// Orders symbols according to their positions in the GOT,
// in compliance with MIPS ABI rules.
// 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
static bool sortMipsSymbols(const std::pair<SymbolBody *, unsigned> &L,
const std::pair<SymbolBody *, unsigned> &R) {
// Sort entries related to non-local preemptible symbols by GOT indexes.
// All other entries go to the first part of GOT in arbitrary order.
bool LIsInLocalGot = !L.first->IsInGlobalMipsGot;
bool RIsInLocalGot = !R.first->IsInGlobalMipsGot;
if (LIsInLocalGot || RIsInLocalGot)
return !RIsInLocalGot;
return L.first->GotIndex < R.first->GotIndex;
}
static uint8_t getSymbolBinding(SymbolBody *Body) {
Symbol *S = Body->symbol();
uint8_t Visibility = S->Visibility;
if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
return STB_LOCAL;
if (Config->NoGnuUnique && S->Binding == STB_GNU_UNIQUE)
return STB_GLOBAL;
return S->Binding;
}
template <class ELFT> void SymbolTableSection<ELFT>::finalize() {
if (this->Header.sh_size)
return; // Already finalized.
this->Header.sh_size = getNumSymbols() * sizeof(Elf_Sym);
this->Header.sh_link = StrTabSec.SectionIndex;
this->Header.sh_info = NumLocals + 1;
if (Config->Relocatable) {
size_t I = NumLocals;
for (const std::pair<SymbolBody *, size_t> &P : Symbols)
P.first->DynsymIndex = ++I;
return;
}
if (!StrTabSec.isDynamic()) {
std::stable_sort(Symbols.begin(), Symbols.end(),
[](const std::pair<SymbolBody *, unsigned> &L,
const std::pair<SymbolBody *, unsigned> &R) {
return getSymbolBinding(L.first) == STB_LOCAL &&
getSymbolBinding(R.first) != STB_LOCAL;
});
return;
}
if (Out<ELFT>::GnuHashTab)
// NB: It also sorts Symbols to meet the GNU hash table requirements.
Out<ELFT>::GnuHashTab->addSymbols(Symbols);
else if (Config->EMachine == EM_MIPS)
std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
size_t I = 0;
for (const std::pair<SymbolBody *, size_t> &P : Symbols)
P.first->DynsymIndex = ++I;
}
template <class ELFT>
void SymbolTableSection<ELFT>::addSymbol(SymbolBody *B) {
Symbols.push_back({B, StrTabSec.addString(B->getName(), false)});
}
template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
Buf += sizeof(Elf_Sym);
// All symbols with STB_LOCAL binding precede the weak and global symbols.
// .dynsym only contains global symbols.
if (!Config->DiscardAll && !StrTabSec.isDynamic())
writeLocalSymbols(Buf);
writeGlobalSymbols(Buf);
}
template <class ELFT>
void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
// Iterate over all input object files to copy their local symbols
// to the output symbol table pointed by Buf.
for (const std::unique_ptr<ObjectFile<ELFT>> &File :
Symtab<ELFT>::X->getObjectFiles()) {
for (const std::pair<const DefinedRegular<ELFT> *, size_t> &P :
File->KeptLocalSyms) {
const DefinedRegular<ELFT> &Body = *P.first;
InputSectionBase<ELFT> *Section = Body.Section;
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
if (!Section) {
ESym->st_shndx = SHN_ABS;
ESym->st_value = Body.Value;
} else {
const OutputSectionBase<ELFT> *OutSec = Section->OutSec;
ESym->st_shndx = OutSec->SectionIndex;
ESym->st_value = OutSec->getVA() + Section->getOffset(Body);
}
ESym->st_name = P.second;
ESym->st_size = Body.template getSize<ELFT>();
ESym->setBindingAndType(STB_LOCAL, Body.Type);
Buf += sizeof(*ESym);
}
}
}
template <class ELFT>
void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) {
// Write the internal symbol table contents to the output symbol table
// pointed by Buf.
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
for (const std::pair<SymbolBody *, size_t> &P : Symbols) {
SymbolBody *Body = P.first;
size_t StrOff = P.second;
uint8_t Type = Body->Type;
uintX_t Size = Body->getSize<ELFT>();
ESym->setBindingAndType(getSymbolBinding(Body), Type);
ESym->st_size = Size;
ESym->st_name = StrOff;
ESym->setVisibility(Body->symbol()->Visibility);
ESym->st_value = Body->getVA<ELFT>();
if (const OutputSectionBase<ELFT> *OutSec = getOutputSection(Body))
ESym->st_shndx = OutSec->SectionIndex;
else if (isa<DefinedRegular<ELFT>>(Body))
ESym->st_shndx = SHN_ABS;
// On MIPS we need to mark symbol which has a PLT entry and requires pointer
// equality by STO_MIPS_PLT flag. That is necessary to help dynamic linker
// distinguish such symbols and MIPS lazy-binding stubs.
// https://sourceware.org/ml/binutils/2008-07/txt00000.txt
if (Config->EMachine == EM_MIPS && Body->isInPlt() &&
Body->NeedsCopyOrPltAddr)
ESym->st_other |= STO_MIPS_PLT;
++ESym;
}
}
template <class ELFT>
const OutputSectionBase<ELFT> *
SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) {
switch (Sym->kind()) {
case SymbolBody::DefinedSyntheticKind:
return cast<DefinedSynthetic<ELFT>>(Sym)->Section;
case SymbolBody::DefinedRegularKind: {
auto &D = cast<DefinedRegular<ELFT>>(*Sym);
if (D.Section)
return D.Section->OutSec;
break;
}
case SymbolBody::DefinedCommonKind:
return CommonInputSection<ELFT>::X->OutSec;
case SymbolBody::SharedKind:
if (cast<SharedSymbol<ELFT>>(Sym)->needsCopy())
return Out<ELFT>::Bss;
break;
case SymbolBody::UndefinedKind:
case SymbolBody::LazyArchiveKind:
case SymbolBody::LazyObjectKind:
break;
case SymbolBody::DefinedBitcodeKind:
llvm_unreachable("should have been replaced");
}
return nullptr;
}
template <class ELFT>
VersionDefinitionSection<ELFT>::VersionDefinitionSection()
: OutputSectionBase<ELFT>(".gnu.version_d", SHT_GNU_verdef, SHF_ALLOC) {
this->Header.sh_addralign = sizeof(uint32_t);
}
static StringRef getFileDefName() {
if (!Config->SoName.empty())
return Config->SoName;
return Config->OutputFile;
}
template <class ELFT> void VersionDefinitionSection<ELFT>::finalize() {
FileDefNameOff = Out<ELFT>::DynStrTab->addString(getFileDefName());
for (VersionDefinition &V : Config->VersionDefinitions)
V.NameOff = Out<ELFT>::DynStrTab->addString(V.Name);
this->Header.sh_size =
(sizeof(Elf_Verdef) + sizeof(Elf_Verdaux)) * getVerDefNum();
this->Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex;
// sh_info should be set to the number of definitions. This fact is missed in
// documentation, but confirmed by binutils community:
// https://sourceware.org/ml/binutils/2014-11/msg00355.html
this->Header.sh_info = getVerDefNum();
}
template <class ELFT>
void VersionDefinitionSection<ELFT>::writeOne(uint8_t *Buf, uint32_t Index,
StringRef Name, size_t NameOff) {
auto *Verdef = reinterpret_cast<Elf_Verdef *>(Buf);
Verdef->vd_version = 1;
Verdef->vd_cnt = 1;
Verdef->vd_aux = sizeof(Elf_Verdef);
Verdef->vd_next = sizeof(Elf_Verdef) + sizeof(Elf_Verdaux);
Verdef->vd_flags = (Index == 1 ? VER_FLG_BASE : 0);
Verdef->vd_ndx = Index;
Verdef->vd_hash = hashSysv(Name);
auto *Verdaux = reinterpret_cast<Elf_Verdaux *>(Buf + sizeof(Elf_Verdef));
Verdaux->vda_name = NameOff;
Verdaux->vda_next = 0;
}
template <class ELFT>
void VersionDefinitionSection<ELFT>::writeTo(uint8_t *Buf) {
writeOne(Buf, 1, getFileDefName(), FileDefNameOff);
for (VersionDefinition &V : Config->VersionDefinitions) {
Buf += sizeof(Elf_Verdef) + sizeof(Elf_Verdaux);
writeOne(Buf, V.Id, V.Name, V.NameOff);
}
// Need to terminate the last version definition.
Elf_Verdef *Verdef = reinterpret_cast<Elf_Verdef *>(Buf);
Verdef->vd_next = 0;
}
template <class ELFT>
VersionTableSection<ELFT>::VersionTableSection()
: OutputSectionBase<ELFT>(".gnu.version", SHT_GNU_versym, SHF_ALLOC) {
this->Header.sh_addralign = sizeof(uint16_t);
}
template <class ELFT> void VersionTableSection<ELFT>::finalize() {
this->Header.sh_size =
sizeof(Elf_Versym) * (Out<ELFT>::DynSymTab->getSymbols().size() + 1);
this->Header.sh_entsize = sizeof(Elf_Versym);
// At the moment of june 2016 GNU docs does not mention that sh_link field
// should be set, but Sun docs do. Also readelf relies on this field.
this->Header.sh_link = Out<ELFT>::DynSymTab->SectionIndex;
}
template <class ELFT> void VersionTableSection<ELFT>::writeTo(uint8_t *Buf) {
auto *OutVersym = reinterpret_cast<Elf_Versym *>(Buf) + 1;
for (const std::pair<SymbolBody *, size_t> &P :
Out<ELFT>::DynSymTab->getSymbols()) {
OutVersym->vs_index = P.first->symbol()->VersionId;
++OutVersym;
}
}
template <class ELFT>
VersionNeedSection<ELFT>::VersionNeedSection()
: OutputSectionBase<ELFT>(".gnu.version_r", SHT_GNU_verneed, SHF_ALLOC) {
this->Header.sh_addralign = sizeof(uint32_t);
// Identifiers in verneed section start at 2 because 0 and 1 are reserved
// for VER_NDX_LOCAL and VER_NDX_GLOBAL.
// First identifiers are reserved by verdef section if it exist.
NextIndex = getVerDefNum() + 1;
}
template <class ELFT>
void VersionNeedSection<ELFT>::addSymbol(SharedSymbol<ELFT> *SS) {
if (!SS->Verdef) {
SS->symbol()->VersionId = VER_NDX_GLOBAL;
return;
}
SharedFile<ELFT> *F = SS->file();
// If we don't already know that we need an Elf_Verneed for this DSO, prepare
// to create one by adding it to our needed list and creating a dynstr entry
// for the soname.
if (F->VerdefMap.empty())
Needed.push_back({F, Out<ELFT>::DynStrTab->addString(F->getSoName())});
typename SharedFile<ELFT>::NeededVer &NV = F->VerdefMap[SS->Verdef];
// If we don't already know that we need an Elf_Vernaux for this Elf_Verdef,
// prepare to create one by allocating a version identifier and creating a
// dynstr entry for the version name.
if (NV.Index == 0) {
NV.StrTab = Out<ELFT>::DynStrTab->addString(
SS->file()->getStringTable().data() + SS->Verdef->getAux()->vda_name);
NV.Index = NextIndex++;
}
SS->symbol()->VersionId = NV.Index;
}
template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) {
// The Elf_Verneeds need to appear first, followed by the Elf_Vernauxs.
auto *Verneed = reinterpret_cast<Elf_Verneed *>(Buf);
auto *Vernaux = reinterpret_cast<Elf_Vernaux *>(Verneed + Needed.size());
for (std::pair<SharedFile<ELFT> *, size_t> &P : Needed) {
// Create an Elf_Verneed for this DSO.
Verneed->vn_version = 1;
Verneed->vn_cnt = P.first->VerdefMap.size();
Verneed->vn_file = P.second;
Verneed->vn_aux =
reinterpret_cast<char *>(Vernaux) - reinterpret_cast<char *>(Verneed);
Verneed->vn_next = sizeof(Elf_Verneed);
++Verneed;
// Create the Elf_Vernauxs for this Elf_Verneed. The loop iterates over
// VerdefMap, which will only contain references to needed version
// definitions. Each Elf_Vernaux is based on the information contained in
// the Elf_Verdef in the source DSO. This loop iterates over a std::map of
// pointers, but is deterministic because the pointers refer to Elf_Verdef
// data structures within a single input file.
for (auto &NV : P.first->VerdefMap) {
Vernaux->vna_hash = NV.first->vd_hash;
Vernaux->vna_flags = 0;
Vernaux->vna_other = NV.second.Index;
Vernaux->vna_name = NV.second.StrTab;
Vernaux->vna_next = sizeof(Elf_Vernaux);
++Vernaux;
}
Vernaux[-1].vna_next = 0;
}
Verneed[-1].vn_next = 0;
}
template <class ELFT> void VersionNeedSection<ELFT>::finalize() {
this->Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex;
this->Header.sh_info = Needed.size();
unsigned Size = Needed.size() * sizeof(Elf_Verneed);
for (std::pair<SharedFile<ELFT> *, size_t> &P : Needed)
Size += P.first->VerdefMap.size() * sizeof(Elf_Vernaux);
this->Header.sh_size = Size;
}
template <class ELFT>
BuildIdSection<ELFT>::BuildIdSection(size_t HashSize)
: OutputSectionBase<ELFT>(".note.gnu.build-id", SHT_NOTE, SHF_ALLOC),
HashSize(HashSize) {
// 16 bytes for the note section header.
this->Header.sh_size = 16 + HashSize;
}
template <class ELFT> void BuildIdSection<ELFT>::writeTo(uint8_t *Buf) {
const endianness E = ELFT::TargetEndianness;
write32<E>(Buf, 4); // Name size
write32<E>(Buf + 4, HashSize); // Content size
write32<E>(Buf + 8, NT_GNU_BUILD_ID); // Type
memcpy(Buf + 12, "GNU", 4); // Name string
HashBuf = Buf + 16;
}
template <class ELFT>
void BuildIdFnv1<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) {
const endianness E = ELFT::TargetEndianness;
// 64-bit FNV-1 hash
uint64_t Hash = 0xcbf29ce484222325;
for (ArrayRef<uint8_t> Buf : Bufs) {
for (uint8_t B : Buf) {
Hash *= 0x100000001b3;
Hash ^= B;
}
}
write64<E>(this->HashBuf, Hash);
}
template <class ELFT>
void BuildIdMd5<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) {
MD5 Hash;
for (ArrayRef<uint8_t> Buf : Bufs)
Hash.update(Buf);
MD5::MD5Result Res;
Hash.final(Res);
memcpy(this->HashBuf, Res, 16);
}
template <class ELFT>
void BuildIdSha1<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) {
SHA1 Hash;
for (ArrayRef<uint8_t> Buf : Bufs)
Hash.update(Buf);
memcpy(this->HashBuf, Hash.final().data(), 20);
}
template <class ELFT>
BuildIdHexstring<ELFT>::BuildIdHexstring()
: BuildIdSection<ELFT>(Config->BuildIdVector.size()) {}
template <class ELFT>
void BuildIdHexstring<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) {
memcpy(this->HashBuf, Config->BuildIdVector.data(),
Config->BuildIdVector.size());
}
template <class ELFT>
MipsReginfoOutputSection<ELFT>::MipsReginfoOutputSection()
: OutputSectionBase<ELFT>(".reginfo", SHT_MIPS_REGINFO, SHF_ALLOC) {
this->Header.sh_addralign = 4;
this->Header.sh_entsize = sizeof(Elf_Mips_RegInfo);
this->Header.sh_size = sizeof(Elf_Mips_RegInfo);
}
template <class ELFT>
void MipsReginfoOutputSection<ELFT>::writeTo(uint8_t *Buf) {
auto *R = reinterpret_cast<Elf_Mips_RegInfo *>(Buf);
R->ri_gp_value = Out<ELFT>::Got->getVA() + MipsGPOffset;
R->ri_gprmask = GprMask;
}
template <class ELFT>
void MipsReginfoOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
// Copy input object file's .reginfo gprmask to output.
auto *S = cast<MipsReginfoInputSection<ELFT>>(C);
GprMask |= S->Reginfo->ri_gprmask;
S->OutSec = this;
}
template <class ELFT>
MipsOptionsOutputSection<ELFT>::MipsOptionsOutputSection()
: OutputSectionBase<ELFT>(".MIPS.options", SHT_MIPS_OPTIONS,
SHF_ALLOC | SHF_MIPS_NOSTRIP) {
this->Header.sh_addralign = 8;
this->Header.sh_entsize = 1;
this->Header.sh_size = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo);
}
template <class ELFT>
void MipsOptionsOutputSection<ELFT>::writeTo(uint8_t *Buf) {
auto *Opt = reinterpret_cast<Elf_Mips_Options *>(Buf);
Opt->kind = ODK_REGINFO;
Opt->size = this->Header.sh_size;
Opt->section = 0;
Opt->info = 0;
auto *Reg = reinterpret_cast<Elf_Mips_RegInfo *>(Buf + sizeof(*Opt));
Reg->ri_gp_value = Out<ELFT>::Got->getVA() + MipsGPOffset;
Reg->ri_gprmask = GprMask;
}
template <class ELFT>
void MipsOptionsOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
auto *S = cast<MipsOptionsInputSection<ELFT>>(C);
if (S->Reginfo)
GprMask |= S->Reginfo->ri_gprmask;
S->OutSec = this;
}
template <class ELFT>
std::pair<OutputSectionBase<ELFT> *, bool>
OutputSectionFactory<ELFT>::create(InputSectionBase<ELFT> *C,
StringRef OutsecName) {
SectionKey<ELFT::Is64Bits> Key = createKey(C, OutsecName);
OutputSectionBase<ELFT> *&Sec = Map[Key];
if (Sec)
return {Sec, false};
switch (C->SectionKind) {
case InputSectionBase<ELFT>::Regular:
Sec = new OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
break;
case InputSectionBase<ELFT>::EHFrame:
return {Out<ELFT>::EhFrame, false};
case InputSectionBase<ELFT>::Merge:
Sec = new MergeOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags,
Key.Alignment);
break;
case InputSectionBase<ELFT>::MipsReginfo:
Sec = new MipsReginfoOutputSection<ELFT>();
break;
case InputSectionBase<ELFT>::MipsOptions:
Sec = new MipsOptionsOutputSection<ELFT>();
break;
}
OwningSections.emplace_back(Sec);
return {Sec, true};
}
template <class ELFT>
OutputSectionBase<ELFT> *OutputSectionFactory<ELFT>::lookup(StringRef Name,
uint32_t Type,
uintX_t Flags) {
return Map.lookup({Name, Type, Flags, 0});
}
template <class ELFT>
SectionKey<ELFT::Is64Bits>
OutputSectionFactory<ELFT>::createKey(InputSectionBase<ELFT> *C,
StringRef OutsecName) {
const Elf_Shdr *H = C->getSectionHdr();
uintX_t Flags = H->sh_flags & ~SHF_GROUP & ~SHF_COMPRESSED;
// For SHF_MERGE we create different output sections for each alignment.
// This makes each output section simple and keeps a single level mapping from
// input to output.
uintX_t Alignment = 0;
if (isa<MergeInputSection<ELFT>>(C))
Alignment = std::max(H->sh_addralign, H->sh_entsize);
uint32_t Type = H->sh_type;
return SectionKey<ELFT::Is64Bits>{OutsecName, Type, Flags, Alignment};
}
template <bool Is64Bits>
typename lld::elf::SectionKey<Is64Bits>
DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::getEmptyKey() {
return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0, 0};
}
template <bool Is64Bits>
typename lld::elf::SectionKey<Is64Bits>
DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::getTombstoneKey() {
return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0, 0,
0};
}
template <bool Is64Bits>
unsigned
DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::getHashValue(const Key &Val) {
return hash_combine(Val.Name, Val.Type, Val.Flags, Val.Alignment);
}
template <bool Is64Bits>
bool DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::isEqual(const Key &LHS,
const Key &RHS) {
return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) &&
LHS.Type == RHS.Type && LHS.Flags == RHS.Flags &&
LHS.Alignment == RHS.Alignment;
}
namespace llvm {
template struct DenseMapInfo<SectionKey<true>>;
template struct DenseMapInfo<SectionKey<false>>;
}
namespace lld {
namespace elf {
template class OutputSectionBase<ELF32LE>;
template class OutputSectionBase<ELF32BE>;
template class OutputSectionBase<ELF64LE>;
template class OutputSectionBase<ELF64BE>;
template class EhFrameHeader<ELF32LE>;
template class EhFrameHeader<ELF32BE>;
template class EhFrameHeader<ELF64LE>;
template class EhFrameHeader<ELF64BE>;
template class GotPltSection<ELF32LE>;
template class GotPltSection<ELF32BE>;
template class GotPltSection<ELF64LE>;
template class GotPltSection<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>;
template class PltSection<ELF64BE>;
template class RelocationSection<ELF32LE>;
template class RelocationSection<ELF32BE>;
template class RelocationSection<ELF64LE>;
template class RelocationSection<ELF64BE>;
template class InterpSection<ELF32LE>;
template class InterpSection<ELF32BE>;
template class InterpSection<ELF64LE>;
template class InterpSection<ELF64BE>;
template class GnuHashTableSection<ELF32LE>;
template class GnuHashTableSection<ELF32BE>;
template class GnuHashTableSection<ELF64LE>;
template class GnuHashTableSection<ELF64BE>;
template class HashTableSection<ELF32LE>;
template class HashTableSection<ELF32BE>;
template class HashTableSection<ELF64LE>;
template class HashTableSection<ELF64BE>;
template class DynamicSection<ELF32LE>;
template class DynamicSection<ELF32BE>;
template class DynamicSection<ELF64LE>;
template class DynamicSection<ELF64BE>;
template class OutputSection<ELF32LE>;
template class OutputSection<ELF32BE>;
template class OutputSection<ELF64LE>;
template class OutputSection<ELF64BE>;
template class EhOutputSection<ELF32LE>;
template class EhOutputSection<ELF32BE>;
template class EhOutputSection<ELF64LE>;
template class EhOutputSection<ELF64BE>;
template class MipsReginfoOutputSection<ELF32LE>;
template class MipsReginfoOutputSection<ELF32BE>;
template class MipsReginfoOutputSection<ELF64LE>;
template class MipsReginfoOutputSection<ELF64BE>;
template class MipsOptionsOutputSection<ELF32LE>;
template class MipsOptionsOutputSection<ELF32BE>;
template class MipsOptionsOutputSection<ELF64LE>;
template class MipsOptionsOutputSection<ELF64BE>;
template class MergeOutputSection<ELF32LE>;
template class MergeOutputSection<ELF32BE>;
template class MergeOutputSection<ELF64LE>;
template class MergeOutputSection<ELF64BE>;
template class StringTableSection<ELF32LE>;
template class StringTableSection<ELF32BE>;
template class StringTableSection<ELF64LE>;
template class StringTableSection<ELF64BE>;
template class SymbolTableSection<ELF32LE>;
template class SymbolTableSection<ELF32BE>;
template class SymbolTableSection<ELF64LE>;
template class SymbolTableSection<ELF64BE>;
template class VersionTableSection<ELF32LE>;
template class VersionTableSection<ELF32BE>;
template class VersionTableSection<ELF64LE>;
template class VersionTableSection<ELF64BE>;
template class VersionNeedSection<ELF32LE>;
template class VersionNeedSection<ELF32BE>;
template class VersionNeedSection<ELF64LE>;
template class VersionNeedSection<ELF64BE>;
template class VersionDefinitionSection<ELF32LE>;
template class VersionDefinitionSection<ELF32BE>;
template class VersionDefinitionSection<ELF64LE>;
template class VersionDefinitionSection<ELF64BE>;
template class BuildIdSection<ELF32LE>;
template class BuildIdSection<ELF32BE>;
template class BuildIdSection<ELF64LE>;
template class BuildIdSection<ELF64BE>;
template class BuildIdFnv1<ELF32LE>;
template class BuildIdFnv1<ELF32BE>;
template class BuildIdFnv1<ELF64LE>;
template class BuildIdFnv1<ELF64BE>;
template class BuildIdMd5<ELF32LE>;
template class BuildIdMd5<ELF32BE>;
template class BuildIdMd5<ELF64LE>;
template class BuildIdMd5<ELF64BE>;
template class BuildIdSha1<ELF32LE>;
template class BuildIdSha1<ELF32BE>;
template class BuildIdSha1<ELF64LE>;
template class BuildIdSha1<ELF64BE>;
template class BuildIdHexstring<ELF32LE>;
template class BuildIdHexstring<ELF32BE>;
template class BuildIdHexstring<ELF64LE>;
template class BuildIdHexstring<ELF64BE>;
template class OutputSectionFactory<ELF32LE>;
template class OutputSectionFactory<ELF32BE>;
template class OutputSectionFactory<ELF64LE>;
template class OutputSectionFactory<ELF64BE>;
}
}
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h
index 4b40e78..d5572b9 100644
--- a/ELF/OutputSections.h
+++ b/ELF/OutputSections.h
@@ -1,734 +1,735 @@
//===- OutputSections.h -----------------------------------------*- C++ -*-===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_ELF_OUTPUT_SECTIONS_H
#define LLD_ELF_OUTPUT_SECTIONS_H
#include "Config.h"
#include "Relocations.h"
#include "lld/Core/LLVM.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/SHA1.h"
namespace lld {
namespace elf {
class SymbolBody;
struct EhSectionPiece;
template <class ELFT> class SymbolTable;
template <class ELFT> class SymbolTableSection;
template <class ELFT> class StringTableSection;
template <class ELFT> class EhInputSection;
template <class ELFT> class InputSection;
template <class ELFT> class InputSectionBase;
template <class ELFT> class MergeInputSection;
template <class ELFT> class MipsReginfoInputSection;
template <class ELFT> class OutputSection;
template <class ELFT> class ObjectFile;
template <class ELFT> class SharedFile;
template <class ELFT> class SharedSymbol;
template <class ELFT> class DefinedRegular;
// This represents a section in an output file.
// Different sub classes represent different types of sections. Some contain
// input sections, others are created by the linker.
// The writer creates multiple OutputSections and assign them unique,
// non-overlapping file offsets and VAs.
template <class ELFT> class OutputSectionBase {
public:
typedef typename ELFT::uint uintX_t;
typedef typename ELFT::Shdr Elf_Shdr;
OutputSectionBase(StringRef Name, uint32_t Type, uintX_t Flags);
void setVA(uintX_t VA) { Header.sh_addr = VA; }
uintX_t getVA() const { return Header.sh_addr; }
void setFileOffset(uintX_t Off) { Header.sh_offset = Off; }
void setSHName(unsigned Val) { Header.sh_name = Val; }
void writeHeaderTo(Elf_Shdr *SHdr);
StringRef getName() { return Name; }
virtual void addSection(InputSectionBase<ELFT> *C) {}
unsigned SectionIndex;
// Returns the size of the section in the output file.
uintX_t getSize() const { return Header.sh_size; }
void setSize(uintX_t Val) { Header.sh_size = Val; }
uintX_t getFlags() const { return Header.sh_flags; }
uint32_t getPhdrFlags() const;
uintX_t getFileOff() const { return Header.sh_offset; }
uintX_t getAlignment() const { return Header.sh_addralign; }
uint32_t getType() const { return Header.sh_type; }
void updateAlignment(uintX_t Alignment) {
if (Alignment > Header.sh_addralign)
Header.sh_addralign = Alignment;
}
// If true, this section will be page aligned on disk.
// Typically the first section of each PT_LOAD segment has this flag.
bool PageAlign = false;
virtual void finalize() {}
virtual void finalizePieces() {}
- virtual void assignOffsets() {}
virtual void writeTo(uint8_t *Buf) {}
virtual ~OutputSectionBase() = default;
protected:
StringRef Name;
Elf_Shdr Header;
};
template <class ELFT> class GotSection final : public OutputSectionBase<ELFT> {
typedef OutputSectionBase<ELFT> Base;
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;
uintX_t getNumEntries() const { return Entries.size(); }
// 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();
uintX_t getTlsIndexVA() { return Base::getVA() + TlsIndexOff; }
uint32_t getTlsIndexOff() { 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<ELFT> *, 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 MipsGlobal;
// Write MIPS-specific parts of the GOT.
void writeMipsGot(uint8_t *&Buf);
};
template <class ELFT>
class GotPltSection final : public OutputSectionBase<ELFT> {
typedef typename ELFT::uint uintX_t;
public:
GotPltSection();
void finalize() override;
void writeTo(uint8_t *Buf) override;
void addEntry(SymbolBody &Sym);
bool empty() const;
private:
std::vector<const SymbolBody *> Entries;
};
template <class ELFT> class PltSection final : public OutputSectionBase<ELFT> {
typedef OutputSectionBase<ELFT> Base;
typedef typename ELFT::uint uintX_t;
public:
PltSection();
void finalize() override;
void writeTo(uint8_t *Buf) override;
void addEntry(SymbolBody &Sym);
bool empty() const { return Entries.empty(); }
private:
std::vector<std::pair<const SymbolBody *, unsigned>> Entries;
};
template <class ELFT> class DynamicReloc {
typedef typename ELFT::uint uintX_t;
public:
DynamicReloc(uint32_t Type, const InputSectionBase<ELFT> *InputSec,
uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
uintX_t Addend)
: Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec),
UseSymVA(UseSymVA), Addend(Addend) {}
DynamicReloc(uint32_t Type, const OutputSectionBase<ELFT> *OutputSec,
uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
uintX_t Addend)
: Type(Type), Sym(Sym), OutputSec(OutputSec), OffsetInSec(OffsetInSec),
UseSymVA(UseSymVA), Addend(Addend) {}
uintX_t getOffset() const;
uintX_t getAddend() const;
uint32_t getSymIndex() const;
const OutputSectionBase<ELFT> *getOutputSec() const { return OutputSec; }
uint32_t Type;
private:
SymbolBody *Sym;
const InputSectionBase<ELFT> *InputSec = nullptr;
const OutputSectionBase<ELFT> *OutputSec = nullptr;
uintX_t OffsetInSec;
bool UseSymVA;
uintX_t Addend;
};
template <class ELFT>
class SymbolTableSection final : public OutputSectionBase<ELFT> {
public:
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::SymRange Elf_Sym_Range;
typedef typename ELFT::uint uintX_t;
SymbolTableSection(StringTableSection<ELFT> &StrTabSec);
void finalize() override;
void writeTo(uint8_t *Buf) override;
void addSymbol(SymbolBody *Body);
StringTableSection<ELFT> &getStrTabSec() const { return StrTabSec; }
unsigned getNumSymbols() const { return NumLocals + Symbols.size() + 1; }
ArrayRef<std::pair<SymbolBody *, size_t>> getSymbols() const {
return Symbols;
}
unsigned NumLocals = 0;
StringTableSection<ELFT> &StrTabSec;
private:
void writeLocalSymbols(uint8_t *&Buf);
void writeGlobalSymbols(uint8_t *Buf);
const OutputSectionBase<ELFT> *getOutputSection(SymbolBody *Sym);
// A vector of symbols and their string table offsets.
std::vector<std::pair<SymbolBody *, size_t>> Symbols;
};
// For more information about .gnu.version and .gnu.version_r see:
// https://www.akkadia.org/drepper/symbol-versioning
// The .gnu.version_d section which has a section type of SHT_GNU_verdef shall
// contain symbol version definitions. The number of entries in this section
// shall be contained in the DT_VERDEFNUM entry of the .dynamic section.
// The section shall contain an array of Elf_Verdef structures, optionally
// followed by an array of Elf_Verdaux structures.
template <class ELFT>
class VersionDefinitionSection final : public OutputSectionBase<ELFT> {
typedef typename ELFT::Verdef Elf_Verdef;
typedef typename ELFT::Verdaux Elf_Verdaux;
public:
VersionDefinitionSection();
void finalize() override;
void writeTo(uint8_t *Buf) override;
private:
void writeOne(uint8_t *Buf, uint32_t Index, StringRef Name, size_t NameOff);
unsigned FileDefNameOff;
};
// The .gnu.version section specifies the required version of each symbol in the
// dynamic symbol table. It contains one Elf_Versym for each dynamic symbol
// table entry. An Elf_Versym is just a 16-bit integer that refers to a version
// identifier defined in the either .gnu.version_r or .gnu.version_d section.
// The values 0 and 1 are reserved. All other values are used for versions in
// the own object or in any of the dependencies.
template <class ELFT>
class VersionTableSection final : public OutputSectionBase<ELFT> {
typedef typename ELFT::Versym Elf_Versym;
public:
VersionTableSection();
void finalize() override;
void writeTo(uint8_t *Buf) override;
};
// The .gnu.version_r section defines the version identifiers used by
// .gnu.version. It contains a linked list of Elf_Verneed data structures. Each
// Elf_Verneed specifies the version requirements for a single DSO, and contains
// a reference to a linked list of Elf_Vernaux data structures which define the
// mapping from version identifiers to version names.
template <class ELFT>
class VersionNeedSection final : public OutputSectionBase<ELFT> {
typedef typename ELFT::Verneed Elf_Verneed;
typedef typename ELFT::Vernaux Elf_Vernaux;
// A vector of shared files that need Elf_Verneed data structures and the
// string table offsets of their sonames.
std::vector<std::pair<SharedFile<ELFT> *, size_t>> Needed;
// The next available version identifier.
unsigned NextIndex;
public:
VersionNeedSection();
void addSymbol(SharedSymbol<ELFT> *SS);
void finalize() override;
void writeTo(uint8_t *Buf) override;
size_t getNeedNum() const { return Needed.size(); }
};
template <class ELFT>
class RelocationSection final : public OutputSectionBase<ELFT> {
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Rela Elf_Rela;
typedef typename ELFT::uint uintX_t;
public:
RelocationSection(StringRef Name, bool Sort);
void addReloc(const DynamicReloc<ELFT> &Reloc);
unsigned getRelocOffset();
void finalize() override;
void writeTo(uint8_t *Buf) override;
bool hasRelocs() const { return !Relocs.empty(); }
bool Static = false;
private:
bool Sort;
std::vector<DynamicReloc<ELFT>> Relocs;
};
template <class ELFT>
class OutputSection final : public OutputSectionBase<ELFT> {
public:
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Rela Elf_Rela;
typedef typename ELFT::uint uintX_t;
OutputSection(StringRef Name, uint32_t Type, uintX_t Flags);
void addSection(InputSectionBase<ELFT> *C) override;
void sortInitFini();
void sortCtorsDtors();
void writeTo(uint8_t *Buf) override;
void finalize() override;
- void assignOffsets() override;
std::vector<InputSection<ELFT> *> Sections;
+
+private:
+ void assignOffsets();
};
template <class ELFT>
class MergeOutputSection final : public OutputSectionBase<ELFT> {
typedef typename ELFT::uint uintX_t;
public:
MergeOutputSection(StringRef Name, uint32_t Type, uintX_t Flags,
uintX_t Alignment);
void addSection(InputSectionBase<ELFT> *S) override;
void writeTo(uint8_t *Buf) override;
unsigned getOffset(StringRef Val);
void finalize() override;
void finalizePieces() override;
bool shouldTailMerge() const;
private:
llvm::StringTableBuilder Builder;
std::vector<MergeInputSection<ELFT> *> Sections;
};
struct CieRecord {
EhSectionPiece *Piece = nullptr;
std::vector<EhSectionPiece *> FdePieces;
};
// Output section for .eh_frame.
template <class ELFT>
class EhOutputSection final : public OutputSectionBase<ELFT> {
typedef typename ELFT::uint uintX_t;
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Rela Elf_Rela;
public:
EhOutputSection();
void writeTo(uint8_t *Buf) override;
void finalize() override;
bool empty() const { return Sections.empty(); }
void addSection(InputSectionBase<ELFT> *S) override;
size_t NumFdes = 0;
private:
template <class RelTy>
void addSectionAux(EhInputSection<ELFT> *S, llvm::ArrayRef<RelTy> Rels);
template <class RelTy>
CieRecord *addCie(EhSectionPiece &Piece, EhInputSection<ELFT> *Sec,
ArrayRef<RelTy> Rels);
template <class RelTy>
bool isFdeLive(EhSectionPiece &Piece, EhInputSection<ELFT> *Sec,
ArrayRef<RelTy> Rels);
uintX_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc);
std::vector<EhInputSection<ELFT> *> Sections;
std::vector<CieRecord *> Cies;
// CIE records are uniquified by their contents and personality functions.
llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap;
};
template <class ELFT>
class InterpSection final : public OutputSectionBase<ELFT> {
public:
InterpSection();
void writeTo(uint8_t *Buf) override;
};
template <class ELFT>
class StringTableSection final : public OutputSectionBase<ELFT> {
public:
typedef typename ELFT::uint uintX_t;
StringTableSection(StringRef Name, bool Dynamic);
unsigned addString(StringRef S, bool HashIt = true);
void writeTo(uint8_t *Buf) override;
unsigned getSize() const { return Size; }
void finalize() override { this->Header.sh_size = getSize(); }
bool isDynamic() const { return Dynamic; }
private:
const bool Dynamic;
llvm::DenseMap<StringRef, unsigned> StringMap;
std::vector<StringRef> Strings;
unsigned Size = 1; // ELF string tables start with a NUL byte, so 1.
};
template <class ELFT>
class HashTableSection final : public OutputSectionBase<ELFT> {
typedef typename ELFT::Word Elf_Word;
public:
HashTableSection();
void finalize() override;
void writeTo(uint8_t *Buf) override;
};
// Outputs GNU Hash section. For detailed explanation see:
// https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections
template <class ELFT>
class GnuHashTableSection final : public OutputSectionBase<ELFT> {
typedef typename ELFT::Off Elf_Off;
typedef typename ELFT::Word Elf_Word;
typedef typename ELFT::uint uintX_t;
public:
GnuHashTableSection();
void finalize() override;
void writeTo(uint8_t *Buf) override;
// Adds symbols to the hash table.
// Sorts the input to satisfy GNU hash section requirements.
void addSymbols(std::vector<std::pair<SymbolBody *, size_t>> &Symbols);
private:
static unsigned calcNBuckets(unsigned NumHashed);
static unsigned calcMaskWords(unsigned NumHashed);
void writeHeader(uint8_t *&Buf);
void writeBloomFilter(uint8_t *&Buf);
void writeHashTable(uint8_t *Buf);
struct SymbolData {
SymbolBody *Body;
size_t STName;
uint32_t Hash;
};
std::vector<SymbolData> Symbols;
unsigned MaskWords;
unsigned NBuckets;
unsigned Shift2;
};
template <class ELFT>
class DynamicSection final : public OutputSectionBase<ELFT> {
typedef OutputSectionBase<ELFT> Base;
typedef typename ELFT::Dyn Elf_Dyn;
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Rela Elf_Rela;
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::uint uintX_t;
// The .dynamic section contains information for the dynamic linker.
// The section consists of fixed size entries, which consist of
// type and value fields. Value are one of plain integers, symbol
// addresses, or section addresses. This struct represents the entry.
struct Entry {
int32_t Tag;
union {
OutputSectionBase<ELFT> *OutSec;
uint64_t Val;
const SymbolBody *Sym;
};
enum KindT { SecAddr, SymAddr, PlainInt } Kind;
Entry(int32_t Tag, OutputSectionBase<ELFT> *OutSec)
: Tag(Tag), OutSec(OutSec), Kind(SecAddr) {}
Entry(int32_t Tag, uint64_t Val) : Tag(Tag), Val(Val), Kind(PlainInt) {}
Entry(int32_t Tag, const SymbolBody *Sym)
: Tag(Tag), Sym(Sym), Kind(SymAddr) {}
};
// finalize() fills this vector with the section contents. finalize()
// cannot directly create final section contents because when the
// function is called, symbol or section addresses are not fixed yet.
std::vector<Entry> Entries;
public:
explicit DynamicSection();
void finalize() override;
void writeTo(uint8_t *Buf) override;
OutputSectionBase<ELFT> *PreInitArraySec = nullptr;
OutputSectionBase<ELFT> *InitArraySec = nullptr;
OutputSectionBase<ELFT> *FiniArraySec = nullptr;
};
template <class ELFT>
class MipsReginfoOutputSection final : public OutputSectionBase<ELFT> {
typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
public:
MipsReginfoOutputSection();
void writeTo(uint8_t *Buf) override;
void addSection(InputSectionBase<ELFT> *S) override;
private:
uint32_t GprMask = 0;
};
template <class ELFT>
class MipsOptionsOutputSection final : public OutputSectionBase<ELFT> {
typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options;
typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
public:
MipsOptionsOutputSection();
void writeTo(uint8_t *Buf) override;
void addSection(InputSectionBase<ELFT> *S) override;
private:
uint32_t GprMask = 0;
};
// --eh-frame-hdr option tells linker to construct a header for all the
// .eh_frame sections. This header is placed to a section named .eh_frame_hdr
// and also to a PT_GNU_EH_FRAME segment.
// At runtime the unwinder then can find all the PT_GNU_EH_FRAME segments by
// calling dl_iterate_phdr.
// This section contains a lookup table for quick binary search of FDEs.
// Detailed info about internals can be found in Ian Lance Taylor's blog:
// http://www.airs.com/blog/archives/460 (".eh_frame")
// http://www.airs.com/blog/archives/462 (".eh_frame_hdr")
template <class ELFT>
class EhFrameHeader final : public OutputSectionBase<ELFT> {
typedef typename ELFT::uint uintX_t;
public:
EhFrameHeader();
void finalize() override;
void writeTo(uint8_t *Buf) override;
void addFde(uint32_t Pc, uint32_t FdeVA);
private:
struct FdeData {
uint32_t Pc;
uint32_t FdeVA;
};
std::vector<FdeData> Fdes;
};
template <class ELFT> class BuildIdSection : public OutputSectionBase<ELFT> {
public:
void writeTo(uint8_t *Buf) override;
virtual void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) = 0;
protected:
BuildIdSection(size_t HashSize);
size_t HashSize;
uint8_t *HashBuf = nullptr;
};
template <class ELFT> class BuildIdFnv1 final : public BuildIdSection<ELFT> {
public:
BuildIdFnv1() : BuildIdSection<ELFT>(8) {}
void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override;
};
template <class ELFT> class BuildIdMd5 final : public BuildIdSection<ELFT> {
public:
BuildIdMd5() : BuildIdSection<ELFT>(16) {}
void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override;
};
template <class ELFT> class BuildIdSha1 final : public BuildIdSection<ELFT> {
public:
BuildIdSha1() : BuildIdSection<ELFT>(20) {}
void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override;
};
template <class ELFT>
class BuildIdHexstring final : public BuildIdSection<ELFT> {
public:
BuildIdHexstring();
void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override;
};
// All output sections that are hadnled by the linker specially are
// globally accessible. Writer initializes them, so don't use them
// until Writer is initialized.
template <class ELFT> struct Out {
typedef typename ELFT::uint uintX_t;
typedef typename ELFT::Phdr Elf_Phdr;
static BuildIdSection<ELFT> *BuildId;
static DynamicSection<ELFT> *Dynamic;
static EhFrameHeader<ELFT> *EhFrameHdr;
static EhOutputSection<ELFT> *EhFrame;
static GnuHashTableSection<ELFT> *GnuHashTab;
static GotPltSection<ELFT> *GotPlt;
static GotSection<ELFT> *Got;
static HashTableSection<ELFT> *HashTab;
static InterpSection<ELFT> *Interp;
static OutputSection<ELFT> *Bss;
static OutputSection<ELFT> *MipsRldMap;
static OutputSectionBase<ELFT> *Opd;
static uint8_t *OpdBuf;
static PltSection<ELFT> *Plt;
static RelocationSection<ELFT> *RelaDyn;
static RelocationSection<ELFT> *RelaPlt;
static StringTableSection<ELFT> *DynStrTab;
static StringTableSection<ELFT> *ShStrTab;
static StringTableSection<ELFT> *StrTab;
static SymbolTableSection<ELFT> *DynSymTab;
static SymbolTableSection<ELFT> *SymTab;
static VersionDefinitionSection<ELFT> *VerDef;
static VersionTableSection<ELFT> *VerSym;
static VersionNeedSection<ELFT> *VerNeed;
static Elf_Phdr *TlsPhdr;
static OutputSectionBase<ELFT> *ElfHeader;
static OutputSectionBase<ELFT> *ProgramHeaders;
};
template <bool Is64Bits> struct SectionKey {
typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t;
StringRef Name;
uint32_t Type;
uintX_t Flags;
uintX_t Alignment;
};
// This class knows how to create an output section for a given
// input section. Output section type is determined by various
// factors, including input section's sh_flags, sh_type and
// linker scripts.
template <class ELFT> class OutputSectionFactory {
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::uint uintX_t;
typedef typename elf::SectionKey<ELFT::Is64Bits> Key;
public:
std::pair<OutputSectionBase<ELFT> *, bool> create(InputSectionBase<ELFT> *C,
StringRef OutsecName);
OutputSectionBase<ELFT> *lookup(StringRef Name, uint32_t Type, uintX_t Flags);
private:
Key createKey(InputSectionBase<ELFT> *C, StringRef OutsecName);
llvm::SmallDenseMap<Key, OutputSectionBase<ELFT> *> Map;
std::vector<std::unique_ptr<OutputSectionBase<ELFT>>> OwningSections;
};
template <class ELFT> BuildIdSection<ELFT> *Out<ELFT>::BuildId;
template <class ELFT> DynamicSection<ELFT> *Out<ELFT>::Dynamic;
template <class ELFT> EhFrameHeader<ELFT> *Out<ELFT>::EhFrameHdr;
template <class ELFT> EhOutputSection<ELFT> *Out<ELFT>::EhFrame;
template <class ELFT> GnuHashTableSection<ELFT> *Out<ELFT>::GnuHashTab;
template <class ELFT> GotPltSection<ELFT> *Out<ELFT>::GotPlt;
template <class ELFT> GotSection<ELFT> *Out<ELFT>::Got;
template <class ELFT> HashTableSection<ELFT> *Out<ELFT>::HashTab;
template <class ELFT> InterpSection<ELFT> *Out<ELFT>::Interp;
template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Bss;
template <class ELFT> OutputSection<ELFT> *Out<ELFT>::MipsRldMap;
template <class ELFT> OutputSectionBase<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> RelocationSection<ELFT> *Out<ELFT>::RelaPlt;
template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::DynStrTab;
template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::ShStrTab;
template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::StrTab;
template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::DynSymTab;
template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::SymTab;
template <class ELFT> VersionDefinitionSection<ELFT> *Out<ELFT>::VerDef;
template <class ELFT> VersionTableSection<ELFT> *Out<ELFT>::VerSym;
template <class ELFT> VersionNeedSection<ELFT> *Out<ELFT>::VerNeed;
template <class ELFT> typename ELFT::Phdr *Out<ELFT>::TlsPhdr;
template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::ElfHeader;
template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::ProgramHeaders;
} // namespace elf
} // namespace lld
namespace llvm {
template <bool Is64Bits> struct DenseMapInfo<lld::elf::SectionKey<Is64Bits>> {
typedef typename lld::elf::SectionKey<Is64Bits> Key;
static Key getEmptyKey();
static Key getTombstoneKey();
static unsigned getHashValue(const Key &Val);
static bool isEqual(const Key &LHS, const Key &RHS);
};
}
#endif
diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp
index b1056f8..0d63281 100644
--- a/ELF/Symbols.cpp
+++ b/ELF/Symbols.cpp
@@ -1,340 +1,340 @@
//===- Symbols.cpp --------------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Symbols.h"
#include "Error.h"
#include "InputFiles.h"
#include "InputSection.h"
#include "OutputSections.h"
#include "Target.h"
#include "llvm/ADT/STLExtras.h"
using namespace llvm;
using namespace llvm::object;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
template <class ELFT>
static typename ELFT::uint getSymVA(const SymbolBody &Body,
typename ELFT::uint &Addend) {
typedef typename ELFT::uint uintX_t;
switch (Body.kind()) {
case SymbolBody::DefinedSyntheticKind: {
auto &D = cast<DefinedSynthetic<ELFT>>(Body);
const OutputSectionBase<ELFT> *Sec = D.Section;
if (!Sec)
return D.Value;
if (D.Value == DefinedSynthetic<ELFT>::SectionEnd)
return Sec->getVA() + Sec->getSize();
return Sec->getVA() + D.Value;
}
case SymbolBody::DefinedRegularKind: {
auto &D = cast<DefinedRegular<ELFT>>(Body);
InputSectionBase<ELFT> *SC = D.Section;
// According to the ELF spec reference to a local symbol from outside
// the group are not allowed. Unfortunately .eh_frame breaks that rule
// and must be treated specially. For now we just replace the symbol with
// 0.
if (SC == &InputSection<ELFT>::Discarded)
return 0;
// This is an absolute symbol.
if (!SC)
return D.Value;
uintX_t Offset = D.Value;
if (D.isSection()) {
Offset += Addend;
Addend = 0;
}
- uintX_t VA = SC->OutSec->getVA() + SC->getOffset(Offset);
+ uintX_t VA = (SC->OutSec ? SC->OutSec->getVA() : 0) + SC->getOffset(Offset);
if (D.isTls())
return VA - Out<ELFT>::TlsPhdr->p_vaddr;
return VA;
}
case SymbolBody::DefinedCommonKind:
return CommonInputSection<ELFT>::X->OutSec->getVA() +
CommonInputSection<ELFT>::X->OutSecOff +
cast<DefinedCommon<ELFT>>(Body).Offset;
case SymbolBody::SharedKind: {
auto &SS = cast<SharedSymbol<ELFT>>(Body);
if (!SS.NeedsCopyOrPltAddr)
return 0;
if (SS.isFunc())
return Body.getPltVA<ELFT>();
return Out<ELFT>::Bss->getVA() + SS.OffsetInBss;
}
case SymbolBody::UndefinedKind:
return 0;
case SymbolBody::LazyArchiveKind:
case SymbolBody::LazyObjectKind:
assert(Body.symbol()->IsUsedInRegularObj && "lazy symbol reached writer");
return 0;
case SymbolBody::DefinedBitcodeKind:
llvm_unreachable("should have been replaced");
}
llvm_unreachable("invalid symbol kind");
}
SymbolBody::SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther,
uint8_t Type)
: SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(true),
IsInGlobalMipsGot(false), Type(Type), StOther(StOther),
NameOffset(NameOffset) {}
SymbolBody::SymbolBody(Kind K, StringRef Name, uint8_t StOther, uint8_t Type)
: SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(false),
IsInGlobalMipsGot(false), Type(Type), StOther(StOther),
Name({Name.data(), Name.size()}) {}
StringRef SymbolBody::getName() const {
assert(!isLocal());
return StringRef(Name.S, Name.Len);
}
// Returns true if a symbol can be replaced at load-time by a symbol
// with the same name defined in other ELF executable or DSO.
bool SymbolBody::isPreemptible() const {
if (isLocal())
return false;
// Shared symbols resolve to the definition in the DSO. The exceptions are
// symbols with copy relocations (which resolve to .bss) or preempt plt
// entries (which resolve to that plt entry).
if (isShared())
return !NeedsCopyOrPltAddr;
// That's all that can be preempted in a non-DSO.
if (!Config->Shared)
return false;
// Only symbols that appear in dynsym can be preempted.
if (!symbol()->includeInDynsym())
return false;
// Only default visibility symbols can be preempted.
if (symbol()->Visibility != STV_DEFAULT)
return false;
// -Bsymbolic means that definitions are not preempted.
if (Config->Bsymbolic || (Config->BsymbolicFunctions && isFunc()))
return !isDefined();
return true;
}
template <class ELFT> bool SymbolBody::hasThunk() const {
if (auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
return DR->ThunkData != nullptr;
if (auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
return S->ThunkData != nullptr;
return false;
}
template <class ELFT>
typename ELFT::uint SymbolBody::getVA(typename ELFT::uint Addend) const {
typename ELFT::uint OutVA = getSymVA<ELFT>(*this, Addend);
return OutVA + Addend;
}
template <class ELFT> typename ELFT::uint SymbolBody::getGotVA() const {
return Out<ELFT>::Got->getVA() + getGotOffset<ELFT>();
}
template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const {
return GotIndex * Target->GotEntrySize;
}
template <class ELFT> typename ELFT::uint SymbolBody::getGotPltVA() const {
return Out<ELFT>::GotPlt->getVA() + getGotPltOffset<ELFT>();
}
template <class ELFT> typename ELFT::uint SymbolBody::getGotPltOffset() const {
return GotPltIndex * Target->GotPltEntrySize;
}
template <class ELFT> typename ELFT::uint SymbolBody::getPltVA() const {
return Out<ELFT>::Plt->getVA() + Target->PltHeaderSize +
PltIndex * Target->PltEntrySize;
}
template <class ELFT> typename ELFT::uint SymbolBody::getThunkVA() const {
if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
return DR->ThunkData->getVA();
if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
return S->ThunkData->getVA();
fatal("getThunkVA() not supported for Symbol class\n");
}
template <class ELFT> typename ELFT::uint SymbolBody::getSize() const {
if (const auto *C = dyn_cast<DefinedCommon<ELFT>>(this))
return C->Size;
if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
return DR->Size;
if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
return S->Sym.st_size;
return 0;
}
Defined::Defined(Kind K, StringRef Name, uint8_t StOther, uint8_t Type)
: SymbolBody(K, Name, StOther, Type) {}
Defined::Defined(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type)
: SymbolBody(K, NameOffset, StOther, Type) {}
DefinedBitcode::DefinedBitcode(StringRef Name, uint8_t StOther, uint8_t Type,
BitcodeFile *F)
: Defined(DefinedBitcodeKind, Name, StOther, Type) {
this->File = F;
}
bool DefinedBitcode::classof(const SymbolBody *S) {
return S->kind() == DefinedBitcodeKind;
}
Undefined::Undefined(StringRef Name, uint8_t StOther, uint8_t Type,
InputFile *File)
: SymbolBody(SymbolBody::UndefinedKind, Name, StOther, Type) {
this->File = File;
}
Undefined::Undefined(uint32_t NameOffset, uint8_t StOther, uint8_t Type,
InputFile *File)
: SymbolBody(SymbolBody::UndefinedKind, NameOffset, StOther, Type) {
this->File = File;
}
template <typename ELFT>
DefinedSynthetic<ELFT>::DefinedSynthetic(StringRef N, uintX_t Value,
OutputSectionBase<ELFT> *Section)
: Defined(SymbolBody::DefinedSyntheticKind, N, STV_HIDDEN, 0 /* Type */),
Value(Value), Section(Section) {}
template <class ELFT>
DefinedCommon<ELFT>::DefinedCommon(StringRef N, uint64_t Size,
uint64_t Alignment, uint8_t StOther,
uint8_t Type, InputFile *File)
: Defined(SymbolBody::DefinedCommonKind, N, StOther, Type),
Alignment(Alignment), Size(Size) {
this->File = File;
}
std::unique_ptr<InputFile> Lazy::fetch() {
if (auto *S = dyn_cast<LazyArchive>(this))
return S->fetch();
return cast<LazyObject>(this)->fetch();
}
LazyArchive::LazyArchive(ArchiveFile &File,
const llvm::object::Archive::Symbol S, uint8_t Type)
: Lazy(LazyArchiveKind, S.getName(), Type), Sym(S) {
this->File = &File;
}
LazyObject::LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type)
: Lazy(LazyObjectKind, Name, Type) {
this->File = &File;
}
std::unique_ptr<InputFile> LazyArchive::fetch() {
MemoryBufferRef MBRef = file()->getMember(&Sym);
// getMember returns an empty buffer if the member was already
// read from the library.
if (MBRef.getBuffer().empty())
return std::unique_ptr<InputFile>(nullptr);
return createObjectFile(MBRef, file()->getName());
}
std::unique_ptr<InputFile> LazyObject::fetch() {
MemoryBufferRef MBRef = file()->getBuffer();
if (MBRef.getBuffer().empty())
return std::unique_ptr<InputFile>(nullptr);
return createObjectFile(MBRef);
}
bool Symbol::includeInDynsym() const {
if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
return false;
return (ExportDynamic && VersionId != VER_NDX_LOCAL) || body()->isShared() ||
(body()->isUndefined() && Config->Shared);
}
// Print out a log message for --trace-symbol.
void elf::printTraceSymbol(Symbol *Sym) {
SymbolBody *B = Sym->body();
outs() << getFilename(B->File);
if (B->isUndefined())
outs() << ": reference to ";
else if (B->isCommon())
outs() << ": common definition of ";
else
outs() << ": definition of ";
outs() << B->getName() << "\n";
}
template bool SymbolBody::hasThunk<ELF32LE>() const;
template bool SymbolBody::hasThunk<ELF32BE>() const;
template bool SymbolBody::hasThunk<ELF64LE>() const;
template bool SymbolBody::hasThunk<ELF64BE>() const;
template uint32_t SymbolBody::template getVA<ELF32LE>(uint32_t) const;
template uint32_t SymbolBody::template getVA<ELF32BE>(uint32_t) const;
template uint64_t SymbolBody::template getVA<ELF64LE>(uint64_t) const;
template uint64_t SymbolBody::template getVA<ELF64BE>(uint64_t) const;
template uint32_t SymbolBody::template getGotVA<ELF32LE>() const;
template uint32_t SymbolBody::template getGotVA<ELF32BE>() const;
template uint64_t SymbolBody::template getGotVA<ELF64LE>() const;
template uint64_t SymbolBody::template getGotVA<ELF64BE>() const;
template uint32_t SymbolBody::template getGotOffset<ELF32LE>() const;
template uint32_t SymbolBody::template getGotOffset<ELF32BE>() const;
template uint64_t SymbolBody::template getGotOffset<ELF64LE>() const;
template uint64_t SymbolBody::template getGotOffset<ELF64BE>() const;
template uint32_t SymbolBody::template getGotPltVA<ELF32LE>() const;
template uint32_t SymbolBody::template getGotPltVA<ELF32BE>() const;
template uint64_t SymbolBody::template getGotPltVA<ELF64LE>() const;
template uint64_t SymbolBody::template getGotPltVA<ELF64BE>() const;
template uint32_t SymbolBody::template getThunkVA<ELF32LE>() const;
template uint32_t SymbolBody::template getThunkVA<ELF32BE>() const;
template uint64_t SymbolBody::template getThunkVA<ELF64LE>() const;
template uint64_t SymbolBody::template getThunkVA<ELF64BE>() const;
template uint32_t SymbolBody::template getGotPltOffset<ELF32LE>() const;
template uint32_t SymbolBody::template getGotPltOffset<ELF32BE>() const;
template uint64_t SymbolBody::template getGotPltOffset<ELF64LE>() const;
template uint64_t SymbolBody::template getGotPltOffset<ELF64BE>() const;
template uint32_t SymbolBody::template getPltVA<ELF32LE>() const;
template uint32_t SymbolBody::template getPltVA<ELF32BE>() const;
template uint64_t SymbolBody::template getPltVA<ELF64LE>() const;
template uint64_t SymbolBody::template getPltVA<ELF64BE>() const;
template uint32_t SymbolBody::template getSize<ELF32LE>() const;
template uint32_t SymbolBody::template getSize<ELF32BE>() const;
template uint64_t SymbolBody::template getSize<ELF64LE>() const;
template uint64_t SymbolBody::template getSize<ELF64BE>() const;
template class elf::DefinedSynthetic<ELF32LE>;
template class elf::DefinedSynthetic<ELF32BE>;
template class elf::DefinedSynthetic<ELF64LE>;
template class elf::DefinedSynthetic<ELF64BE>;
template class elf::DefinedCommon<ELF32LE>;
template class elf::DefinedCommon<ELF32BE>;
template class elf::DefinedCommon<ELF64LE>;
template class elf::DefinedCommon<ELF64BE>;
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index dd28c68..8de7844 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -1,1325 +1,1316 @@
//===- Writer.cpp ---------------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Writer.h"
#include "Config.h"
#include "LinkerScript.h"
#include "OutputSections.h"
#include "Relocations.h"
#include "Strings.h"
#include "SymbolTable.h"
#include "Target.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace lld;
using namespace lld::elf;
namespace {
// The writer writes a SymbolTable result to a file.
template <class ELFT> class Writer {
public:
typedef typename ELFT::uint uintX_t;
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Ehdr Elf_Ehdr;
typedef typename ELFT::Phdr Elf_Phdr;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::SymRange Elf_Sym_Range;
typedef typename ELFT::Rela Elf_Rela;
Writer(SymbolTable<ELFT> &S) : Symtab(S) {}
void run();
private:
typedef PhdrEntry<ELFT> Phdr;
void copyLocalSymbols();
void addReservedSymbols();
void createSections();
void forEachRelSec(
std::function<void(InputSectionBase<ELFT> &, const typename ELFT::Shdr &)>
Fn);
void finalizeSections();
void addPredefinedSections();
bool needsGot();
std::vector<Phdr> createPhdrs();
void assignAddresses();
void assignFileOffsets();
void setPhdrs();
void fixHeaders();
void fixSectionAlignments();
void fixAbsoluteSymbols();
void openFile();
void writeHeader();
void writeSections();
void writeBuildId();
std::unique_ptr<FileOutputBuffer> Buffer;
BumpPtrAllocator Alloc;
std::vector<OutputSectionBase<ELFT> *> OutputSections;
OutputSectionFactory<ELFT> Factory;
void addRelIpltSymbols();
void addStartEndSymbols();
void addStartStopSymbols(OutputSectionBase<ELFT> *Sec);
SymbolTable<ELFT> &Symtab;
std::vector<Phdr> Phdrs;
uintX_t FileSize;
uintX_t SectionHeaderOff;
};
} // anonymous namespace
template <class ELFT>
StringRef elf::getOutputSectionName(InputSectionBase<ELFT> *S) {
StringRef Name = S->getSectionName();
for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.",
".init_array.", ".fini_array.", ".ctors.", ".dtors.",
".tbss.", ".gcc_except_table.", ".tdata."})
if (Name.startswith(V))
return V.drop_back();
return Name;
}
template <class ELFT> void elf::reportDiscarded(InputSectionBase<ELFT> *IS) {
if (!Config->PrintGcSections || !IS || IS->Live)
return;
errs() << "removing unused section from '" << IS->getSectionName()
<< "' in file '" << IS->getFile()->getName() << "'\n";
}
template <class ELFT> static bool needsInterpSection() {
return !Symtab<ELFT>::X->getSharedFiles().empty() &&
!Config->DynamicLinker.empty();
}
template <class ELFT> void elf::writeResult(SymbolTable<ELFT> *Symtab) {
typedef typename ELFT::uint uintX_t;
typedef typename ELFT::Ehdr Elf_Ehdr;
// Create singleton output sections.
OutputSection<ELFT> Bss(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
DynamicSection<ELFT> Dynamic;
EhOutputSection<ELFT> EhFrame;
GotSection<ELFT> Got;
PltSection<ELFT> Plt;
RelocationSection<ELFT> RelaDyn(Config->Rela ? ".rela.dyn" : ".rel.dyn",
Config->ZCombreloc);
StringTableSection<ELFT> DynStrTab(".dynstr", true);
StringTableSection<ELFT> ShStrTab(".shstrtab", false);
SymbolTableSection<ELFT> DynSymTab(DynStrTab);
VersionTableSection<ELFT> VerSym;
VersionNeedSection<ELFT> VerNeed;
OutputSectionBase<ELFT> ElfHeader("", 0, SHF_ALLOC);
ElfHeader.setSize(sizeof(Elf_Ehdr));
OutputSectionBase<ELFT> ProgramHeaders("", 0, SHF_ALLOC);
ProgramHeaders.updateAlignment(sizeof(uintX_t));
// Instantiate optional output sections if they are needed.
std::unique_ptr<InterpSection<ELFT>> Interp;
std::unique_ptr<BuildIdSection<ELFT>> BuildId;
std::unique_ptr<EhFrameHeader<ELFT>> EhFrameHdr;
std::unique_ptr<GnuHashTableSection<ELFT>> GnuHashTab;
std::unique_ptr<GotPltSection<ELFT>> GotPlt;
std::unique_ptr<HashTableSection<ELFT>> HashTab;
std::unique_ptr<RelocationSection<ELFT>> RelaPlt;
std::unique_ptr<StringTableSection<ELFT>> StrTab;
std::unique_ptr<SymbolTableSection<ELFT>> SymTabSec;
std::unique_ptr<OutputSection<ELFT>> MipsRldMap;
std::unique_ptr<VersionDefinitionSection<ELFT>> VerDef;
if (needsInterpSection<ELFT>())
Interp.reset(new InterpSection<ELFT>);
if (Config->BuildId == BuildIdKind::Fnv1)
BuildId.reset(new BuildIdFnv1<ELFT>);
else if (Config->BuildId == BuildIdKind::Md5)
BuildId.reset(new BuildIdMd5<ELFT>);
else if (Config->BuildId == BuildIdKind::Sha1)
BuildId.reset(new BuildIdSha1<ELFT>);
else if (Config->BuildId == BuildIdKind::Hexstring)
BuildId.reset(new BuildIdHexstring<ELFT>);
if (Config->EhFrameHdr)
EhFrameHdr.reset(new EhFrameHeader<ELFT>);
if (Config->GnuHash)
GnuHashTab.reset(new GnuHashTableSection<ELFT>);
if (Config->SysvHash)
HashTab.reset(new HashTableSection<ELFT>);
StringRef S = Config->Rela ? ".rela.plt" : ".rel.plt";
GotPlt.reset(new GotPltSection<ELFT>);
RelaPlt.reset(new RelocationSection<ELFT>(S, false /*Sort*/));
if (!Config->StripAll) {
StrTab.reset(new StringTableSection<ELFT>(".strtab", false));
SymTabSec.reset(new SymbolTableSection<ELFT>(*StrTab));
}
if (Config->EMachine == EM_MIPS && !Config->Shared) {
// This is a MIPS specific section to hold a space within the data segment
// of executable file which is pointed to by the DT_MIPS_RLD_MAP entry.
// See "Dynamic section" in Chapter 5 in the following document:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
MipsRldMap.reset(new OutputSection<ELFT>(".rld_map", SHT_PROGBITS,
SHF_ALLOC | SHF_WRITE));
MipsRldMap->setSize(sizeof(uintX_t));
MipsRldMap->updateAlignment(sizeof(uintX_t));
}
if (!Config->VersionDefinitions.empty())
VerDef.reset(new VersionDefinitionSection<ELFT>());
Out<ELFT>::Bss = &Bss;
Out<ELFT>::BuildId = BuildId.get();
Out<ELFT>::DynStrTab = &DynStrTab;
Out<ELFT>::DynSymTab = &DynSymTab;
Out<ELFT>::Dynamic = &Dynamic;
Out<ELFT>::EhFrame = &EhFrame;
Out<ELFT>::EhFrameHdr = EhFrameHdr.get();
Out<ELFT>::GnuHashTab = GnuHashTab.get();
Out<ELFT>::Got = &Got;
Out<ELFT>::GotPlt = GotPlt.get();
Out<ELFT>::HashTab = HashTab.get();
Out<ELFT>::Interp = Interp.get();
Out<ELFT>::Plt = &Plt;
Out<ELFT>::RelaDyn = &RelaDyn;
Out<ELFT>::RelaPlt = RelaPlt.get();
Out<ELFT>::ShStrTab = &ShStrTab;
Out<ELFT>::StrTab = StrTab.get();
Out<ELFT>::SymTab = SymTabSec.get();
Out<ELFT>::VerDef = VerDef.get();
Out<ELFT>::VerSym = &VerSym;
Out<ELFT>::VerNeed = &VerNeed;
Out<ELFT>::MipsRldMap = MipsRldMap.get();
Out<ELFT>::Opd = nullptr;
Out<ELFT>::OpdBuf = nullptr;
Out<ELFT>::TlsPhdr = nullptr;
Out<ELFT>::ElfHeader = &ElfHeader;
Out<ELFT>::ProgramHeaders = &ProgramHeaders;
Writer<ELFT>(*Symtab).run();
}
template <class ELFT>
static std::vector<DefinedCommon<ELFT> *> getCommonSymbols() {
std::vector<DefinedCommon<ELFT> *> V;
for (Symbol *S : Symtab<ELFT>::X->getSymbols())
if (auto *B = dyn_cast<DefinedCommon<ELFT>>(S->body()))
V.push_back(B);
return V;
}
// The main function of the writer.
template <class ELFT> void Writer<ELFT>::run() {
if (!Config->DiscardAll)
copyLocalSymbols();
addReservedSymbols();
+ if (Target->NeedsThunks)
+ forEachRelSec(createThunks<ELFT>);
+
CommonInputSection<ELFT> Common(getCommonSymbols<ELFT>());
CommonInputSection<ELFT>::X = &Common;
Script<ELFT>::X->OutputSections = &OutputSections;
if (ScriptConfig->HasContents)
Script<ELFT>::X->createSections(Factory);
else
createSections();
finalizeSections();
if (HasError)
return;
if (Config->Relocatable) {
assignFileOffsets();
} else {
Phdrs = Script<ELFT>::X->hasPhdrsCommands() ? Script<ELFT>::X->createPhdrs()
: createPhdrs();
fixHeaders();
if (ScriptConfig->HasContents) {
Script<ELFT>::X->assignAddresses();
} else {
fixSectionAlignments();
assignAddresses();
}
assignFileOffsets();
setPhdrs();
fixAbsoluteSymbols();
}
openFile();
if (HasError)
return;
writeHeader();
writeSections();
writeBuildId();
if (HasError)
return;
if (auto EC = Buffer->commit())
error(EC, "failed to write to the output file");
}
template <class ELFT>
static void reportUndefined(SymbolTable<ELFT> &Symtab, SymbolBody *Sym) {
if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore)
return;
if (Config->Shared && Sym->symbol()->Visibility == STV_DEFAULT &&
Config->UnresolvedSymbols != UnresolvedPolicy::NoUndef)
return;
std::string Msg = "undefined symbol: " + Sym->getName().str();
if (Sym->File)
Msg += " in " + getFilename(Sym->File);
if (Config->UnresolvedSymbols == UnresolvedPolicy::Warn)
warning(Msg);
else
error(Msg);
}
template <class ELFT>
static bool shouldKeepInSymtab(InputSectionBase<ELFT> *Sec, StringRef SymName,
const SymbolBody &B) {
if (B.isFile())
return false;
// We keep sections in symtab for relocatable output.
if (B.isSection())
return Config->Relocatable;
// If sym references a section in a discarded group, don't keep it.
if (Sec == &InputSection<ELFT>::Discarded)
return false;
if (Config->DiscardNone)
return true;
// In ELF assembly .L symbols are normally discarded by the assembler.
// If the assembler fails to do so, the linker discards them if
// * --discard-locals is used.
// * The symbol is in a SHF_MERGE section, which is normally the reason for
// the assembler keeping the .L symbol.
if (!SymName.startswith(".L") && !SymName.empty())
return true;
if (Config->DiscardLocals)
return false;
return !(Sec->getSectionHdr()->sh_flags & SHF_MERGE);
}
template <class ELFT> static bool includeInSymtab(const SymbolBody &B) {
if (!B.isLocal() && !B.symbol()->IsUsedInRegularObj)
return false;
if (auto *D = dyn_cast<DefinedRegular<ELFT>>(&B)) {
// Always include absolute symbols.
if (!D->Section)
return true;
// Exclude symbols pointing to garbage-collected sections.
if (!D->Section->Live)
return false;
if (auto *S = dyn_cast<MergeInputSection<ELFT>>(D->Section))
if (!S->getSectionPiece(D->Value)->Live)
return false;
}
return true;
}
// Local symbols are not in the linker's symbol table. This function scans
// each object file's symbol table to copy local symbols to the output.
template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
if (!Out<ELFT>::SymTab)
return;
for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
Symtab.getObjectFiles()) {
const char *StrTab = F->getStringTable().data();
for (SymbolBody *B : F->getLocalSymbols()) {
auto *DR = dyn_cast<DefinedRegular<ELFT>>(B);
// No reason to keep local undefined symbol in symtab.
if (!DR)
continue;
if (!includeInSymtab<ELFT>(*B))
continue;
StringRef SymName(StrTab + B->getNameOffset());
InputSectionBase<ELFT> *Sec = DR->Section;
if (!shouldKeepInSymtab<ELFT>(Sec, SymName, *B))
continue;
++Out<ELFT>::SymTab->NumLocals;
if (Config->Relocatable)
B->DynsymIndex = Out<ELFT>::SymTab->NumLocals;
F->KeptLocalSyms.push_back(
std::make_pair(DR, Out<ELFT>::SymTab->StrTabSec.addString(SymName)));
}
}
}
// PPC64 has a number of special SHT_PROGBITS+SHF_ALLOC+SHF_WRITE sections that
// we would like to make sure appear is a specific order to maximize their
// coverage by a single signed 16-bit offset from the TOC base pointer.
// Conversely, the special .tocbss section should be first among all SHT_NOBITS
// sections. This will put it next to the loaded special PPC64 sections (and,
// thus, within reach of the TOC base pointer).
static int getPPC64SectionRank(StringRef SectionName) {
return StringSwitch<int>(SectionName)
.Case(".tocbss", 0)
.Case(".branch_lt", 2)
.Case(".toc", 3)
.Case(".toc1", 4)
.Case(".opd", 5)
.Default(1);
}
template <class ELFT> bool elf::isRelroSection(OutputSectionBase<ELFT> *Sec) {
if (!Config->ZRelro)
return false;
typename ELFT::uint Flags = Sec->getFlags();
if (!(Flags & SHF_ALLOC) || !(Flags & SHF_WRITE))
return false;
if (Flags & SHF_TLS)
return true;
uint32_t Type = Sec->getType();
if (Type == SHT_INIT_ARRAY || Type == SHT_FINI_ARRAY ||
Type == SHT_PREINIT_ARRAY)
return true;
if (Sec == Out<ELFT>::GotPlt)
return Config->ZNow;
if (Sec == Out<ELFT>::Dynamic || Sec == Out<ELFT>::Got)
return true;
StringRef S = Sec->getName();
return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" ||
S == ".eh_frame";
}
// Output section ordering is determined by this function.
template <class ELFT>
static bool compareSections(OutputSectionBase<ELFT> *A,
OutputSectionBase<ELFT> *B) {
typedef typename ELFT::uint uintX_t;
int Comp = Script<ELFT>::X->compareSections(A->getName(), B->getName());
if (Comp != 0)
return Comp < 0;
uintX_t AFlags = A->getFlags();
uintX_t BFlags = B->getFlags();
// Allocatable sections go first to reduce the total PT_LOAD size and
// so debug info doesn't change addresses in actual code.
bool AIsAlloc = AFlags & SHF_ALLOC;
bool BIsAlloc = BFlags & SHF_ALLOC;
if (AIsAlloc != BIsAlloc)
return AIsAlloc;
// We don't have any special requirements for the relative order of
// two non allocatable sections.
if (!AIsAlloc)
return false;
// We want the read only sections first so that they go in the PT_LOAD
// covering the program headers at the start of the file.
bool AIsWritable = AFlags & SHF_WRITE;
bool BIsWritable = BFlags & SHF_WRITE;
if (AIsWritable != BIsWritable)
return BIsWritable;
// For a corresponding reason, put non exec sections first (the program
// header PT_LOAD is not executable).
bool AIsExec = AFlags & SHF_EXECINSTR;
bool BIsExec = BFlags & SHF_EXECINSTR;
if (AIsExec != BIsExec)
return BIsExec;
// If we got here we know that both A and B are in the same PT_LOAD.
// The TLS initialization block needs to be a single contiguous block in a R/W
// PT_LOAD, so stick TLS sections directly before R/W sections. The TLS NOBITS
// sections are placed here as they don't take up virtual address space in the
// PT_LOAD.
bool AIsTls = AFlags & SHF_TLS;
bool BIsTls = BFlags & SHF_TLS;
if (AIsTls != BIsTls)
return AIsTls;
// The next requirement we have is to put nobits sections last. The
// reason is that the only thing the dynamic linker will see about
// them is a p_memsz that is larger than p_filesz. Seeing that it
// zeros the end of the PT_LOAD, so that has to correspond to the
// nobits sections.
bool AIsNoBits = A->getType() == SHT_NOBITS;
bool BIsNoBits = B->getType() == SHT_NOBITS;
if (AIsNoBits != BIsNoBits)
return BIsNoBits;
// We place RelRo section before plain r/w ones.
bool AIsRelRo = isRelroSection(A);
bool BIsRelRo = isRelroSection(B);
if (AIsRelRo != BIsRelRo)
return AIsRelRo;
// Some architectures have additional ordering restrictions for sections
// within the same PT_LOAD.
if (Config->EMachine == EM_PPC64)
return getPPC64SectionRank(A->getName()) <
getPPC64SectionRank(B->getName());
return false;
}
template <class ELFT> bool elf::isOutputDynamic() {
return !Symtab<ELFT>::X->getSharedFiles().empty() || Config->Pic;
}
template <class ELFT> static bool isDiscarded(InputSectionBase<ELFT> *S) {
return !S || S == &InputSection<ELFT>::Discarded || !S->Live;
}
// Program header entry
template<class ELFT>
PhdrEntry<ELFT>::PhdrEntry(unsigned Type, unsigned Flags) {
H.p_type = Type;
H.p_flags = Flags;
}
template<class ELFT>
void PhdrEntry<ELFT>::add(OutputSectionBase<ELFT> *Sec) {
Last = Sec;
if (!First)
First = Sec;
H.p_align = std::max<typename ELFT::uint>(H.p_align, Sec->getAlignment());
}
template <class ELFT>
static Symbol *addOptionalSynthetic(SymbolTable<ELFT> &Table, StringRef Name,
OutputSectionBase<ELFT> *Sec,
typename ELFT::uint Val) {
SymbolBody *S = Table.find(Name);
if (!S)
return nullptr;
if (!S->isUndefined() && !S->isShared())
return S->symbol();
return Table.addSynthetic(Name, Sec, Val);
}
// 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
// all IRELATIVE relocs on startup. For dynamic executables, we don't
// need these symbols, since IRELATIVE relocs are resolved through GOT
// and PLT. For details, see http://www.airs.com/blog/archives/403.
template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
if (isOutputDynamic<ELFT>() || !Out<ELFT>::RelaPlt)
return;
StringRef S = Config->Rela ? "__rela_iplt_start" : "__rel_iplt_start";
addOptionalSynthetic(Symtab, S, Out<ELFT>::RelaPlt, 0);
S = Config->Rela ? "__rela_iplt_end" : "__rel_iplt_end";
addOptionalSynthetic(Symtab, S, Out<ELFT>::RelaPlt,
DefinedSynthetic<ELFT>::SectionEnd);
}
// The linker is expected to define some symbols depending on
// the linking result. This function defines such symbols.
template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
if (Config->EMachine == EM_MIPS && !Config->Relocatable) {
// Define _gp for MIPS. st_value of _gp symbol will be updated by Writer
// 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.addSynthetic("_gp", Out<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(Symtab, "_gp_disp", Out<ELFT>::Got, MipsGPOffset);
if (Sym)
ElfSym<ELFT>::MipsGpDisp = Sym->body();
// The __gnu_local_gp is a magic symbol equal to the current value of 'gp'
// 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(Symtab, "__gnu_local_gp", Out<ELFT>::Got,
MipsGPOffset);
}
// In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
// is magical and is used to produce a R_386_GOTPC relocation.
// The R_386_GOTPC relocation value doesn't actually depend on the
// symbol value, so it could use an index of STN_UNDEF which, according
// to the spec, means the symbol value is 0.
// Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in
// the object file.
// The situation is even stranger on x86_64 where the assembly doesn't
// need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as
// an undefined symbol in the .o files.
// Given that the symbol is effectively unused, we just create a dummy
// hidden one to avoid the undefined symbol error.
if (!Config->Relocatable)
Symtab.addIgnored("_GLOBAL_OFFSET_TABLE_");
// __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For
// static linking the linker is required to optimize away any references to
// __tls_get_addr, so it's not defined anywhere. Create a hidden definition
// to avoid the undefined symbol error.
if (!isOutputDynamic<ELFT>())
Symtab.addIgnored("__tls_get_addr");
auto Define = [this](StringRef S, DefinedRegular<ELFT> *&Sym1,
DefinedRegular<ELFT> *&Sym2) {
Sym1 = Symtab.addIgnored(S, STV_DEFAULT);
// The name without the underscore is not a reserved name,
// so it is defined only when there is a reference against it.
assert(S.startswith("_"));
S = S.substr(1);
if (SymbolBody *B = Symtab.find(S))
if (B->isUndefined())
Sym2 = Symtab.addAbsolute(S, STV_DEFAULT);
};
Define("_end", ElfSym<ELFT>::End, ElfSym<ELFT>::End2);
Define("_etext", ElfSym<ELFT>::Etext, ElfSym<ELFT>::Etext2);
Define("_edata", ElfSym<ELFT>::Edata, ElfSym<ELFT>::Edata2);
}
// Sort input sections by section name suffixes for
// __attribute__((init_priority(N))).
template <class ELFT> static void sortInitFini(OutputSectionBase<ELFT> *S) {
if (S)
reinterpret_cast<OutputSection<ELFT> *>(S)->sortInitFini();
}
// Sort input sections by the special rule for .ctors and .dtors.
template <class ELFT> static void sortCtorsDtors(OutputSectionBase<ELFT> *S) {
if (S)
reinterpret_cast<OutputSection<ELFT> *>(S)->sortCtorsDtors();
}
template <class ELFT>
void Writer<ELFT>::forEachRelSec(
std::function<void(InputSectionBase<ELFT> &, const typename ELFT::Shdr &)>
Fn) {
for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
Symtab.getObjectFiles()) {
for (InputSectionBase<ELFT> *C : F->getSections()) {
if (isDiscarded(C))
continue;
// Scan all relocations. Each relocation goes through a series
// of tests to determine if it needs special treatment, such as
// creating GOT, PLT, copy relocations, etc.
// Note that relocations for non-alloc sections are directly
// processed by InputSection::relocateNonAlloc.
if (!(C->getSectionHdr()->sh_flags & SHF_ALLOC))
continue;
if (auto *S = dyn_cast<InputSection<ELFT>>(C)) {
for (const Elf_Shdr *RelSec : S->RelocSections)
Fn(*S, *RelSec);
continue;
}
if (auto *S = dyn_cast<EhInputSection<ELFT>>(C))
if (S->RelocSection)
Fn(*S, *S->RelocSection);
}
}
}
template <class ELFT> void Writer<ELFT>::createSections() {
for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
Symtab.getObjectFiles()) {
for (InputSectionBase<ELFT> *C : F->getSections()) {
if (isDiscarded(C)) {
reportDiscarded(C);
continue;
}
OutputSectionBase<ELFT> *Sec;
bool IsNew;
std::tie(Sec, IsNew) = Factory.create(C, getOutputSectionName(C));
if (IsNew)
OutputSections.push_back(Sec);
Sec->addSection(C);
}
}
}
// Create output section objects and add them to OutputSections.
template <class ELFT> void Writer<ELFT>::finalizeSections() {
// Create output sections for input object file sections.
std::vector<OutputSectionBase<ELFT> *> RegularSections = OutputSections;
// 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 = Factory.lookup(".opd", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC);
Out<ELFT>::Dynamic->PreInitArraySec = Factory.lookup(
".preinit_array", SHT_PREINIT_ARRAY, SHF_WRITE | SHF_ALLOC);
Out<ELFT>::Dynamic->InitArraySec =
Factory.lookup(".init_array", SHT_INIT_ARRAY, SHF_WRITE | SHF_ALLOC);
Out<ELFT>::Dynamic->FiniArraySec =
Factory.lookup(".fini_array", SHT_FINI_ARRAY, SHF_WRITE | SHF_ALLOC);
// Sort section contents for __attribute__((init_priority(N)).
sortInitFini(Out<ELFT>::Dynamic->InitArraySec);
sortInitFini(Out<ELFT>::Dynamic->FiniArraySec);
sortCtorsDtors(Factory.lookup(".ctors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC));
sortCtorsDtors(Factory.lookup(".dtors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC));
// The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop
// symbols for sections, so that the runtime can get the start and end
// addresses of each section by section name. Add such symbols.
if (!Config->Relocatable) {
addStartEndSymbols();
for (OutputSectionBase<ELFT> *Sec : RegularSections)
addStartStopSymbols(Sec);
}
// Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type.
// It should be okay as no one seems to care about the type.
// Even the author of gold doesn't remember why gold behaves that way.
// https://sourceware.org/ml/binutils/2002-03/msg00360.html
if (isOutputDynamic<ELFT>())
Symtab.addSynthetic("_DYNAMIC", Out<ELFT>::Dynamic, 0);
// Define __rel[a]_iplt_{start,end} symbols if needed.
addRelIpltSymbols();
- // Add scripted symbols with zero values now.
- // Real values will be assigned later
- Script<ELFT>::X->addScriptedSymbols();
-
if (!Out<ELFT>::EhFrame->empty()) {
OutputSections.push_back(Out<ELFT>::EhFrame);
Out<ELFT>::EhFrame->finalize();
}
- if (Target->NeedsThunks)
- forEachRelSec(createThunks<ELFT>);
-
- for (OutputSectionBase<ELFT> *Sec : OutputSections)
- Sec->assignOffsets();
-
// Scan relocations. This must be done after every symbol is declared so that
// we can correctly decide if a dynamic relocation is needed.
forEachRelSec(scanRelocations<ELFT>);
// Now that we have defined all possible symbols including linker-
// synthesized ones. Visit all symbols to give the finishing touches.
for (Symbol *S : Symtab.getSymbols()) {
SymbolBody *Body = S->body();
// We only report undefined symbols in regular objects. This means that we
// will accept an undefined reference in bitcode if it can be optimized out.
if (S->IsUsedInRegularObj && Body->isUndefined() && !S->isWeak())
reportUndefined<ELFT>(Symtab, Body);
if (!includeInSymtab<ELFT>(*Body))
continue;
if (Out<ELFT>::SymTab)
Out<ELFT>::SymTab->addSymbol(Body);
if (isOutputDynamic<ELFT>() && S->includeInDynsym()) {
Out<ELFT>::DynSymTab->addSymbol(Body);
if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(Body))
if (SS->file()->isNeeded())
Out<ELFT>::VerNeed->addSymbol(SS);
}
}
// Do not proceed if there was an undefined symbol.
if (HasError)
return;
// If linker script processor hasn't added common symbol section yet,
// then add it to .bss now.
- if (!CommonInputSection<ELFT>::X->OutSec) {
+ if (!CommonInputSection<ELFT>::X->OutSec)
Out<ELFT>::Bss->addSection(CommonInputSection<ELFT>::X);
- Out<ELFT>::Bss->assignOffsets();
- }
// So far we have added sections from input object files.
// This function adds linker-created Out<ELFT>::* sections.
addPredefinedSections();
std::stable_sort(OutputSections.begin(), OutputSections.end(),
compareSections<ELFT>);
unsigned I = 1;
for (OutputSectionBase<ELFT> *Sec : OutputSections) {
Sec->SectionIndex = I++;
Sec->setSHName(Out<ELFT>::ShStrTab->addString(Sec->getName()));
}
// Finalizers fix each section's size.
// .dynsym is finalized early since that may fill up .gnu.hash.
if (isOutputDynamic<ELFT>())
Out<ELFT>::DynSymTab->finalize();
// Fill other section headers. The dynamic table is finalized
// at the end because some tags like RELSZ depend on result
// of finalizing other sections. The dynamic string table is
// finalized once the .dynamic finalizer has added a few last
// strings. See DynamicSection::finalize()
for (OutputSectionBase<ELFT> *Sec : OutputSections)
if (Sec != Out<ELFT>::DynStrTab && Sec != Out<ELFT>::Dynamic)
Sec->finalize();
if (isOutputDynamic<ELFT>())
Out<ELFT>::Dynamic->finalize();
// Now that all output offsets are fixed. Finalize mergeable sections
// to fix their maps from input offsets to output offsets.
for (OutputSectionBase<ELFT> *Sec : OutputSections)
Sec->finalizePieces();
}
template <class ELFT> bool Writer<ELFT>::needsGot() {
if (!Out<ELFT>::Got->empty())
return true;
// We add the .got section to the result for dynamic MIPS target because
// its address and properties are mentioned in the .dynamic section.
if (Config->EMachine == EM_MIPS && !Config->Relocatable)
return true;
// 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;
}
// This function add Out<ELFT>::* sections to OutputSections.
template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
auto Add = [&](OutputSectionBase<ELFT> *C) {
if (C)
OutputSections.push_back(C);
};
// A core file does not usually contain unmodified segments except
// the first page of the executable. Add the build ID section to beginning of
// the file so that the section is included in the first page.
if (Out<ELFT>::BuildId)
OutputSections.insert(OutputSections.begin(), Out<ELFT>::BuildId);
// Add .interp at first because some loaders want to see that section
// on the first page of the executable file when loaded into memory.
if (Out<ELFT>::Interp)
OutputSections.insert(OutputSections.begin(), Out<ELFT>::Interp);
// This order is not the same as the final output order
// because we sort the sections using their attributes below.
Add(Out<ELFT>::SymTab);
Add(Out<ELFT>::ShStrTab);
Add(Out<ELFT>::StrTab);
if (isOutputDynamic<ELFT>()) {
Add(Out<ELFT>::DynSymTab);
bool HasVerNeed = Out<ELFT>::VerNeed->getNeedNum() != 0;
if (Out<ELFT>::VerDef || HasVerNeed)
Add(Out<ELFT>::VerSym);
Add(Out<ELFT>::VerDef);
if (HasVerNeed)
Add(Out<ELFT>::VerNeed);
Add(Out<ELFT>::GnuHashTab);
Add(Out<ELFT>::HashTab);
Add(Out<ELFT>::Dynamic);
Add(Out<ELFT>::DynStrTab);
if (Out<ELFT>::RelaDyn->hasRelocs())
Add(Out<ELFT>::RelaDyn);
Add(Out<ELFT>::MipsRldMap);
}
// We always need to add rel[a].plt to output if it has entries.
// Even during static linking it can contain R_[*]_IRELATIVE relocations.
if (Out<ELFT>::RelaPlt && Out<ELFT>::RelaPlt->hasRelocs()) {
Add(Out<ELFT>::RelaPlt);
Out<ELFT>::RelaPlt->Static = !isOutputDynamic<ELFT>();
}
if (needsGot())
Add(Out<ELFT>::Got);
if (Out<ELFT>::GotPlt && !Out<ELFT>::GotPlt->empty())
Add(Out<ELFT>::GotPlt);
if (!Out<ELFT>::Plt->empty())
Add(Out<ELFT>::Plt);
if (!Out<ELFT>::EhFrame->empty())
Add(Out<ELFT>::EhFrameHdr);
if (Out<ELFT>::Bss->getSize() > 0)
Add(Out<ELFT>::Bss);
}
// The linker is expected to define SECNAME_start and SECNAME_end
// symbols for a few sections. This function defines them.
template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
auto Define = [&](StringRef Start, StringRef End,
OutputSectionBase<ELFT> *OS) {
if (OS) {
this->Symtab.addSynthetic(Start, OS, 0);
this->Symtab.addSynthetic(End, OS, DefinedSynthetic<ELFT>::SectionEnd);
} else {
addOptionalSynthetic(this->Symtab, Start,
(OutputSectionBase<ELFT> *)nullptr, 0);
addOptionalSynthetic(this->Symtab, End,
(OutputSectionBase<ELFT> *)nullptr, 0);
}
};
Define("__preinit_array_start", "__preinit_array_end",
Out<ELFT>::Dynamic->PreInitArraySec);
Define("__init_array_start", "__init_array_end",
Out<ELFT>::Dynamic->InitArraySec);
Define("__fini_array_start", "__fini_array_end",
Out<ELFT>::Dynamic->FiniArraySec);
}
// If a section name is valid as a C identifier (which is rare because of
// the leading '.'), linkers are expected to define __start_<secname> and
// __stop_<secname> symbols. They are at beginning and end of the section,
// respectively. This is not requested by the ELF standard, but GNU ld and
// gold provide the feature, and used by many programs.
template <class ELFT>
void Writer<ELFT>::addStartStopSymbols(OutputSectionBase<ELFT> *Sec) {
StringRef S = Sec->getName();
if (!isValidCIdentifier(S))
return;
StringSaver Saver(Alloc);
StringRef Start = Saver.save("__start_" + S);
StringRef Stop = Saver.save("__stop_" + S);
if (SymbolBody *B = Symtab.find(Start))
if (B->isUndefined())
Symtab.addSynthetic(Start, Sec, 0);
if (SymbolBody *B = Symtab.find(Stop))
if (B->isUndefined())
Symtab.addSynthetic(Stop, Sec, DefinedSynthetic<ELFT>::SectionEnd);
}
template <class ELFT> static bool needsPtLoad(OutputSectionBase<ELFT> *Sec) {
if (!(Sec->getFlags() & SHF_ALLOC))
return false;
// Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is
// responsible for allocating space for them, not the PT_LOAD that
// contains the TLS initialization image.
if (Sec->getFlags() & SHF_TLS && Sec->getType() == SHT_NOBITS)
return false;
return true;
}
// Decide which program headers to create and which sections to include in each
// one.
template <class ELFT>
std::vector<PhdrEntry<ELFT>> Writer<ELFT>::createPhdrs() {
std::vector<Phdr> Ret;
auto AddHdr = [&](unsigned Type, unsigned Flags) -> Phdr * {
Ret.emplace_back(Type, Flags);
return &Ret.back();
};
// The first phdr entry is PT_PHDR which describes the program header itself.
Phdr &Hdr = *AddHdr(PT_PHDR, PF_R);
Hdr.add(Out<ELFT>::ProgramHeaders);
// PT_INTERP must be the second entry if exists.
if (Out<ELFT>::Interp) {
Phdr &Hdr = *AddHdr(PT_INTERP, Out<ELFT>::Interp->getPhdrFlags());
Hdr.add(Out<ELFT>::Interp);
}
// Add the first PT_LOAD segment for regular output sections.
uintX_t Flags = PF_R;
Phdr *Load = AddHdr(PT_LOAD, Flags);
Load->add(Out<ELFT>::ElfHeader);
Load->add(Out<ELFT>::ProgramHeaders);
Phdr TlsHdr(PT_TLS, PF_R);
Phdr RelRo(PT_GNU_RELRO, PF_R);
Phdr Note(PT_NOTE, PF_R);
for (OutputSectionBase<ELFT> *Sec : OutputSections) {
if (!(Sec->getFlags() & SHF_ALLOC))
break;
// If we meet TLS section then we create TLS header
// and put all TLS sections inside for futher use when
// assign addresses.
if (Sec->getFlags() & SHF_TLS)
TlsHdr.add(Sec);
if (!needsPtLoad(Sec))
continue;
// If flags changed then we want new load segment.
uintX_t NewFlags = Sec->getPhdrFlags();
if (Flags != NewFlags) {
Load = AddHdr(PT_LOAD, NewFlags);
Flags = NewFlags;
}
Load->add(Sec);
if (isRelroSection(Sec))
RelRo.add(Sec);
if (Sec->getType() == SHT_NOTE)
Note.add(Sec);
}
// Add the TLS segment unless it's empty.
if (TlsHdr.First)
Ret.push_back(std::move(TlsHdr));
// Add an entry for .dynamic.
if (isOutputDynamic<ELFT>()) {
Phdr &H = *AddHdr(PT_DYNAMIC, Out<ELFT>::Dynamic->getPhdrFlags());
H.add(Out<ELFT>::Dynamic);
}
// PT_GNU_RELRO includes all sections that should be marked as
// read-only by dynamic linker after proccessing relocations.
if (RelRo.First)
Ret.push_back(std::move(RelRo));
// PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr.
if (!Out<ELFT>::EhFrame->empty() && Out<ELFT>::EhFrameHdr) {
Phdr &Hdr = *AddHdr(PT_GNU_EH_FRAME, Out<ELFT>::EhFrameHdr->getPhdrFlags());
Hdr.add(Out<ELFT>::EhFrameHdr);
}
// PT_GNU_STACK is a special section to tell the loader to make the
// pages for the stack non-executable.
if (!Config->ZExecStack)
AddHdr(PT_GNU_STACK, PF_R | PF_W);
if (Note.First)
Ret.push_back(std::move(Note));
return Ret;
}
// The first section of each PT_LOAD and the first section after PT_GNU_RELRO
// have to be page aligned so that the dynamic linker can set the permissions.
template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
for (const Phdr &P : Phdrs)
if (P.H.p_type == PT_LOAD)
P.First->PageAlign = true;
for (const Phdr &P : Phdrs) {
if (P.H.p_type != PT_GNU_RELRO)
continue;
// Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we
// have to align it to a page.
auto End = OutputSections.end();
auto I = std::find(OutputSections.begin(), End, P.Last);
if (I == End || (I + 1) == End)
continue;
OutputSectionBase<ELFT> *Sec = *(I + 1);
if (needsPtLoad(Sec))
Sec->PageAlign = true;
}
}
// We should set file offsets and VAs for elf header and program headers
// sections. These are special, we do not include them into output sections
// list, but have them to simplify the code.
template <class ELFT> void Writer<ELFT>::fixHeaders() {
uintX_t BaseVA = ScriptConfig->HasContents ? 0 : Config->ImageBase;
Out<ELFT>::ElfHeader->setVA(BaseVA);
uintX_t Off = Out<ELFT>::ElfHeader->getSize();
Out<ELFT>::ProgramHeaders->setVA(Off + BaseVA);
Out<ELFT>::ProgramHeaders->setSize(sizeof(Elf_Phdr) * Phdrs.size());
}
// Assign VAs (addresses at run-time) to output sections.
template <class ELFT> void Writer<ELFT>::assignAddresses() {
uintX_t VA = Config->ImageBase + Out<ELFT>::ElfHeader->getSize() +
Out<ELFT>::ProgramHeaders->getSize();
uintX_t ThreadBssOffset = 0;
for (OutputSectionBase<ELFT> *Sec : OutputSections) {
uintX_t Alignment = Sec->getAlignment();
if (Sec->PageAlign)
Alignment = std::max<uintX_t>(Alignment, Target->PageSize);
// We only assign VAs to allocated sections.
if (needsPtLoad(Sec)) {
VA = alignTo(VA, Alignment);
Sec->setVA(VA);
VA += Sec->getSize();
} else if (Sec->getFlags() & SHF_TLS && Sec->getType() == SHT_NOBITS) {
uintX_t TVA = VA + ThreadBssOffset;
TVA = alignTo(TVA, Alignment);
Sec->setVA(TVA);
ThreadBssOffset = TVA - VA + Sec->getSize();
}
}
}
// Adjusts the file alignment for a given output section and returns
// its new file offset. The file offset must be the same with its
// virtual address (modulo the page size) so that the loader can load
// executables without any address adjustment.
template <class ELFT, class uintX_t>
static uintX_t getFileAlignment(uintX_t Off, OutputSectionBase<ELFT> *Sec) {
uintX_t Alignment = Sec->getAlignment();
if (Sec->PageAlign)
Alignment = std::max<uintX_t>(Alignment, Target->PageSize);
Off = alignTo(Off, Alignment);
// Relocatable output does not have program headers
// and does not need any other offset adjusting.
if (Config->Relocatable || !(Sec->getFlags() & SHF_ALLOC))
return Off;
return alignTo(Off, Target->PageSize, Sec->getVA());
}
// Assign file offsets to output sections.
template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
uintX_t Off = 0;
auto Set = [&](OutputSectionBase<ELFT> *Sec) {
if (Sec->getType() == SHT_NOBITS) {
Sec->setFileOffset(Off);
return;
}
Off = getFileAlignment<ELFT>(Off, Sec);
Sec->setFileOffset(Off);
Off += Sec->getSize();
};
Set(Out<ELFT>::ElfHeader);
Set(Out<ELFT>::ProgramHeaders);
for (OutputSectionBase<ELFT> *Sec : OutputSections)
Set(Sec);
SectionHeaderOff = alignTo(Off, sizeof(uintX_t));
FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr);
}
// Finalize the program headers. We call this function after we assign
// file offsets and VAs to all sections.
template <class ELFT> void Writer<ELFT>::setPhdrs() {
for (Phdr &P : Phdrs) {
Elf_Phdr &H = P.H;
OutputSectionBase<ELFT> *First = P.First;
OutputSectionBase<ELFT> *Last = P.Last;
if (First) {
H.p_filesz = Last->getFileOff() - First->getFileOff();
if (Last->getType() != SHT_NOBITS)
H.p_filesz += Last->getSize();
H.p_memsz = Last->getVA() + Last->getSize() - First->getVA();
H.p_offset = First->getFileOff();
H.p_vaddr = First->getVA();
}
if (H.p_type == PT_LOAD)
H.p_align = Target->PageSize;
else if (H.p_type == PT_GNU_RELRO)
H.p_align = 1;
H.p_paddr = H.p_vaddr;
// The TLS pointer goes after PT_TLS. At least glibc will align it,
// so round up the size to make sure the offsets are correct.
if (H.p_type == PT_TLS) {
Out<ELFT>::TlsPhdr = &H;
if (H.p_memsz)
H.p_memsz = alignTo(H.p_memsz, H.p_align);
}
}
}
template <class ELFT> static uint32_t getMipsEFlags() {
// FIXME: ELF flags depends on ELF flags of all input object files and
// selected emulation. For now pick the arch flag from the fisrt input file
// and use hard coded values for other flags.
uint32_t FirstElfFlags =
cast<ELFFileBase<ELFT>>(Config->FirstElf)->getObj().getHeader()->e_flags;
uint32_t ElfFlags = FirstElfFlags & EF_MIPS_ARCH;
if (ELFT::Is64Bits)
ElfFlags |= EF_MIPS_CPIC | EF_MIPS_PIC;
else {
ElfFlags |= EF_MIPS_CPIC | EF_MIPS_ABI_O32;
if (Config->Shared)
ElfFlags |= EF_MIPS_PIC;
}
return ElfFlags;
}
template <class ELFT> static typename ELFT::uint getEntryAddr() {
if (Symbol *S = Config->EntrySym)
return S->body()->getVA<ELFT>();
if (Config->EntryAddr != uint64_t(-1))
return Config->EntryAddr;
return 0;
}
template <class ELFT> static uint8_t getELFEncoding() {
if (ELFT::TargetEndianness == llvm::support::little)
return ELFDATA2LSB;
return ELFDATA2MSB;
}
static uint16_t getELFType() {
if (Config->Pic)
return ET_DYN;
if (Config->Relocatable)
return ET_REL;
return ET_EXEC;
}
// This function is called after we have assigned address and size
// to each section. This function fixes some predefined absolute
// symbol values that depend on section address and size.
template <class ELFT> void Writer<ELFT>::fixAbsoluteSymbols() {
auto Set = [](DefinedRegular<ELFT> *S1, DefinedRegular<ELFT> *S2, uintX_t V) {
if (S1)
S1->Value = V;
if (S2)
S2->Value = V;
};
// _etext is the first location after the last read-only loadable segment.
// _edata is the first location after the last read-write loadable segment.
// _end is the first location after the uninitialized data region.
for (Phdr &P : Phdrs) {
Elf_Phdr &H = P.H;
if (H.p_type != PT_LOAD)
continue;
Set(ElfSym<ELFT>::End, ElfSym<ELFT>::End2, H.p_vaddr + H.p_memsz);
uintX_t Val = H.p_vaddr + H.p_filesz;
if (H.p_flags & PF_W)
Set(ElfSym<ELFT>::Edata, ElfSym<ELFT>::Edata2, Val);
else
Set(ElfSym<ELFT>::Etext, ElfSym<ELFT>::Etext2, Val);
}
}
template <class ELFT> void Writer<ELFT>::writeHeader() {
uint8_t *Buf = Buffer->getBufferStart();
memcpy(Buf, "\177ELF", 4);
auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf);
// Write the ELF header.
auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
EHdr->e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
EHdr->e_ident[EI_DATA] = getELFEncoding<ELFT>();
EHdr->e_ident[EI_VERSION] = EV_CURRENT;
EHdr->e_ident[EI_OSABI] = FirstObj.getOSABI();
EHdr->e_type = getELFType();
EHdr->e_machine = FirstObj.EMachine;
EHdr->e_version = EV_CURRENT;
EHdr->e_entry = getEntryAddr<ELFT>();
EHdr->e_shoff = SectionHeaderOff;
EHdr->e_ehsize = sizeof(Elf_Ehdr);
EHdr->e_phnum = Phdrs.size();
EHdr->e_shentsize = sizeof(Elf_Shdr);
EHdr->e_shnum = OutputSections.size() + 1;
EHdr->e_shstrndx = Out<ELFT>::ShStrTab->SectionIndex;
if (Config->EMachine == EM_MIPS)
EHdr->e_flags = getMipsEFlags<ELFT>();
if (!Config->Relocatable) {
EHdr->e_phoff = sizeof(Elf_Ehdr);
EHdr->e_phentsize = sizeof(Elf_Phdr);
}
// Write the program header table.
auto *HBuf = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff);
for (Phdr &P : Phdrs)
*HBuf++ = P.H;
// Write the section header table. Note that the first table entry is null.
auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
for (OutputSectionBase<ELFT> *Sec : OutputSections)
Sec->writeHeaderTo(++SHdrs);
}
template <class ELFT> void Writer<ELFT>::openFile() {
ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
FileOutputBuffer::create(Config->OutputFile, FileSize,
FileOutputBuffer::F_executable);
if (auto EC = BufferOrErr.getError())
error(EC, "failed to open " + Config->OutputFile);
else
Buffer = std::move(*BufferOrErr);
}
// 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.
if (OutputSectionBase<ELFT> *Sec = Out<ELFT>::Opd) {
Out<ELFT>::OpdBuf = Buf + Sec->getFileOff();
Sec->writeTo(Buf + Sec->getFileOff());
}
for (OutputSectionBase<ELFT> *Sec : OutputSections)
if (Sec != Out<ELFT>::Opd)
Sec->writeTo(Buf + Sec->getFileOff());
}
template <class ELFT> void Writer<ELFT>::writeBuildId() {
if (!Out<ELFT>::BuildId)
return;
// Compute a hash of all sections except .debug_* sections.
// We skip debug sections because they tend to be very large
// and their contents are very likely to be the same as long as
// other sections are the same.
uint8_t *Start = Buffer->getBufferStart();
uint8_t *Last = Start;
std::vector<ArrayRef<uint8_t>> Regions;
for (OutputSectionBase<ELFT> *Sec : OutputSections) {
uint8_t *End = Start + Sec->getFileOff();
if (!Sec->getName().startswith(".debug_"))
Regions.push_back({Last, End});
Last = End;
}
Regions.push_back({Last, Start + FileSize});
Out<ELFT>::BuildId->writeBuildId(Regions);
}
template void elf::writeResult<ELF32LE>(SymbolTable<ELF32LE> *Symtab);
template void elf::writeResult<ELF32BE>(SymbolTable<ELF32BE> *Symtab);
template void elf::writeResult<ELF64LE>(SymbolTable<ELF64LE> *Symtab);
template void elf::writeResult<ELF64BE>(SymbolTable<ELF64BE> *Symtab);
template struct elf::PhdrEntry<ELF32LE>;
template struct elf::PhdrEntry<ELF32BE>;
template struct elf::PhdrEntry<ELF64LE>;
template struct elf::PhdrEntry<ELF64BE>;
template bool elf::isOutputDynamic<ELF32LE>();
template bool elf::isOutputDynamic<ELF32BE>();
template bool elf::isOutputDynamic<ELF64LE>();
template bool elf::isOutputDynamic<ELF64BE>();
template bool elf::isRelroSection<ELF32LE>(OutputSectionBase<ELF32LE> *);
template bool elf::isRelroSection<ELF32BE>(OutputSectionBase<ELF32BE> *);
template bool elf::isRelroSection<ELF64LE>(OutputSectionBase<ELF64LE> *);
template bool elf::isRelroSection<ELF64BE>(OutputSectionBase<ELF64BE> *);
template StringRef elf::getOutputSectionName<ELF32LE>(InputSectionBase<ELF32LE> *);
template StringRef elf::getOutputSectionName<ELF32BE>(InputSectionBase<ELF32BE> *);
template StringRef elf::getOutputSectionName<ELF64LE>(InputSectionBase<ELF64LE> *);
template StringRef elf::getOutputSectionName<ELF64BE>(InputSectionBase<ELF64BE> *);
template void elf::reportDiscarded<ELF32LE>(InputSectionBase<ELF32LE> *);
template void elf::reportDiscarded<ELF32BE>(InputSectionBase<ELF32BE> *);
template void elf::reportDiscarded<ELF64LE>(InputSectionBase<ELF64LE> *);
template void elf::reportDiscarded<ELF64BE>(InputSectionBase<ELF64BE> *);
diff --git a/test/ELF/linkerscript/linkerscript-provide-in-section.s b/test/ELF/linkerscript/linkerscript-provide-in-section.s
new file mode 100644
index 0000000..dc42695
--- /dev/null
+++ b/test/ELF/linkerscript/linkerscript-provide-in-section.s
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo \
+# RUN: "SECTIONS { . = 1000; .blah : { PROVIDE(foo = .); } }" \
+# RUN: > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t -shared
+# RUN: llvm-objdump -t %t1 | FileCheck %s
+# CHECK: 00000000000003e8 *ABS* 00000000 foo
+
+# RUN: echo \
+# RUN: "SECTIONS { . = 1000; .blah : { PROVIDE_HIDDEN(foo = .); } }" \
+# RUN: > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %t -shared
+# RUN: llvm-objdump -t %t2 | FileCheck %s --check-prefix=HIDDEN
+# HIDDEN: 00000000000003e8 *ABS* 00000000 .hidden foo
+
+.section .blah
+.globl patatino
+patatino:
+ movl $foo, %edx
diff --git a/test/ELF/linkerscript/linkerscript-symbols-synthetic.s b/test/ELF/linkerscript/linkerscript-symbols-synthetic.s
new file mode 100644
index 0000000..0401edc
--- /dev/null
+++ b/test/ELF/linkerscript/linkerscript-symbols-synthetic.s
@@ -0,0 +1,29 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# Simple symbol assignment within input section list. The '.' symbol
+# is not location counter but offset from the beginning of output
+# section .foo
+# RUN: echo "SECTIONS { .foo : { \
+# RUN: begin_foo = .; \
+# RUN: *(.foo) \
+# RUN: end_foo = .; \
+# RUN: begin_bar = .; \
+# RUN: *(.bar) \
+# RUN: end_bar = .; } }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=SIMPLE %s
+# SIMPLE: 0000000000000120 .foo 00000000 begin_foo
+# SIMPLE-NEXT: 0000000000000128 .foo 00000000 end_foo
+# SIMPLE-NEXT: 0000000000000128 .foo 00000000 begin_bar
+# SIMPLE-NEXT: 000000000000012c .foo 00000000 end_bar
+
+.global _start
+_start:
+ nop
+
+.section .foo,"a"
+ .quad 0
+
+.section .bar,"a"
+ .long 0
More information about the llvm-commits
mailing list