aboutsummaryrefslogtreecommitdiffstats
path: root/ELF
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-07-13 19:26:06 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-07-13 19:26:06 +0000
commit267829774358b5aebd3e726ae318813bd48129bb (patch)
tree5a8904da0d9716ea10b69258f5d50e0b1ee2ec2c /ELF
parent0317860f00ca8e821989c92c8a6cc461fd5f2009 (diff)
downloadsrc-267829774358b5aebd3e726ae318813bd48129bb.tar.gz
src-267829774358b5aebd3e726ae318813bd48129bb.zip
Vendor import of lld trunk r307894:vendor/lld/lld-trunk-r307894
Notes
Notes: svn path=/vendor/lld/dist/; revision=320965 svn path=/vendor/lld/lld-trunk-r307894/; revision=320966; tag=vendor/lld/lld-trunk-r307894
Diffstat (limited to 'ELF')
-rw-r--r--ELF/Config.h1
-rw-r--r--ELF/Driver.cpp2
-rw-r--r--ELF/Error.cpp5
-rw-r--r--ELF/Error.h1
-rw-r--r--ELF/Filesystem.cpp3
-rw-r--r--ELF/GdbIndex.h1
-rw-r--r--ELF/InputFiles.cpp5
-rw-r--r--ELF/InputSection.cpp6
-rw-r--r--ELF/LinkerScript.cpp308
-rw-r--r--ELF/LinkerScript.h30
-rw-r--r--ELF/OutputSections.cpp98
-rw-r--r--ELF/OutputSections.h7
-rw-r--r--ELF/Relocations.cpp32
-rw-r--r--ELF/Relocations.h9
-rw-r--r--ELF/ScriptParser.cpp3
-rw-r--r--ELF/SymbolTable.cpp49
-rw-r--r--ELF/Symbols.cpp20
-rw-r--r--ELF/Symbols.h6
-rw-r--r--ELF/SyntheticSections.cpp65
-rw-r--r--ELF/SyntheticSections.h5
-rw-r--r--ELF/Thunks.cpp32
-rw-r--r--ELF/Thunks.h4
-rw-r--r--ELF/Writer.cpp167
23 files changed, 453 insertions, 406 deletions
diff --git a/ELF/Config.h b/ELF/Config.h
index 32e86b0ec7b6..5e3b77637316 100644
--- a/ELF/Config.h
+++ b/ELF/Config.h
@@ -97,6 +97,7 @@ struct Configuration {
llvm::StringRef ThinLTOCacheDir;
std::string Rpath;
std::vector<VersionDefinition> VersionDefinitions;
+ std::vector<llvm::StringRef> Argv;
std::vector<llvm::StringRef> AuxiliaryList;
std::vector<llvm::StringRef> SearchPaths;
std::vector<llvm::StringRef> SymbolOrderingFile;
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index 5fb33caea46f..10ad13f214d5 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -74,13 +74,13 @@ bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
raw_ostream &Error) {
ErrorCount = 0;
ErrorOS = &Error;
- Argv0 = Args[0];
InputSections.clear();
Tar = nullptr;
Config = make<Configuration>();
Driver = make<LinkerDriver>();
Script = make<LinkerScript>();
+ Config->Argv = {Args.begin(), Args.end()};
Driver->main(Args, CanExitEarly);
freeArena();
diff --git a/ELF/Error.cpp b/ELF/Error.cpp
index 7a58668bdcc0..224570ea7424 100644
--- a/ELF/Error.cpp
+++ b/ELF/Error.cpp
@@ -27,7 +27,6 @@ using namespace lld::elf;
uint64_t elf::ErrorCount;
raw_ostream *elf::ErrorOS;
-StringRef elf::Argv0;
// The functions defined in this file can be called from multiple threads,
// but outs() or errs() are not thread-safe. We protect them using a mutex.
@@ -46,7 +45,7 @@ static void newline(const Twine &Msg) {
}
static void print(StringRef S, raw_ostream::Colors C) {
- *ErrorOS << Argv0 + ": ";
+ *ErrorOS << Config->Argv[0] << ": ";
if (Config->ColorDiagnostics) {
ErrorOS->changeColor(C, true);
*ErrorOS << S;
@@ -59,7 +58,7 @@ static void print(StringRef S, raw_ostream::Colors C) {
void elf::log(const Twine &Msg) {
if (Config->Verbose) {
std::lock_guard<std::mutex> Lock(Mu);
- outs() << Argv0 << ": " << Msg << "\n";
+ outs() << Config->Argv[0] << ": " << Msg << "\n";
outs().flush();
}
}
diff --git a/ELF/Error.h b/ELF/Error.h
index dd6e37c99b15..89bc2111b44e 100644
--- a/ELF/Error.h
+++ b/ELF/Error.h
@@ -37,7 +37,6 @@ namespace elf {
extern uint64_t ErrorCount;
extern llvm::raw_ostream *ErrorOS;
-extern llvm::StringRef Argv0;
void log(const Twine &Msg);
void message(const Twine &Msg);
diff --git a/ELF/Filesystem.cpp b/ELF/Filesystem.cpp
index b63d521a83b0..d468ae0c618a 100644
--- a/ELF/Filesystem.cpp
+++ b/ELF/Filesystem.cpp
@@ -38,7 +38,8 @@ using namespace lld::elf;
// This function spawns a background thread to call unlink.
// The calling thread returns almost immediately.
void elf::unlinkAsync(StringRef Path) {
- if (!Config->Threads || !sys::fs::exists(Config->OutputFile))
+ if (!Config->Threads || !sys::fs::exists(Config->OutputFile) ||
+ !sys::fs::is_regular_file(Config->OutputFile))
return;
// First, rename Path to avoid race condition. We cannot remove
diff --git a/ELF/GdbIndex.h b/ELF/GdbIndex.h
index 527667f7280e..c49f8946e199 100644
--- a/ELF/GdbIndex.h
+++ b/ELF/GdbIndex.h
@@ -45,6 +45,7 @@ struct NameTypeEntry {
// debug information performed. That information futher used
// for filling gdb index section areas.
struct GdbIndexChunk {
+ InputSection *DebugInfoSec;
std::vector<AddressEntry> AddressArea;
std::vector<CompilationUnitEntry> CompilationUnits;
std::vector<NameTypeEntry> NamesAndTypes;
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index e07f24d665df..d3c307d5cb6b 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -45,14 +45,11 @@ namespace {
// LLVM DWARF parser will not be able to parse .debug_line correctly, unless
// we assign each section some unique address. This callback method assigns
// each section an address equal to its offset in ELF object file.
-class ObjectInfo : public LoadedObjectInfo {
+class ObjectInfo : public LoadedObjectInfoHelper<ObjectInfo> {
public:
uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override {
return static_cast<const ELFSectionRef &>(Sec).getOffset();
}
- std::unique_ptr<LoadedObjectInfo> clone() const override {
- return std::unique_ptr<LoadedObjectInfo>();
- }
};
}
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
index b1d5e1349460..c6a539b8dfa5 100644
--- a/ELF/InputSection.cpp
+++ b/ELF/InputSection.cpp
@@ -276,7 +276,9 @@ template <class ELFT> std::string InputSectionBase::getSrcMsg(uint64_t Offset) {
template <class ELFT> std::string InputSectionBase::getObjMsg(uint64_t Off) {
// Synthetic sections don't have input files.
elf::ObjectFile<ELFT> *File = getFile<ELFT>();
- std::string Filename = File ? File->getName() : "(internal)";
+ if (!File)
+ return ("(internal):(" + Name + "+0x" + utohexstr(Off) + ")").str();
+ std::string Filename = File->getName();
std::string Archive;
if (!File->ArchiveName.empty())
@@ -466,7 +468,7 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A,
static uint64_t getARMStaticBase(const SymbolBody &Body) {
OutputSection *OS = Body.getOutputSection();
if (!OS || !OS->FirstInPtLoad)
- fatal("SBREL relocation to " + Body.getName() + " without static base\n");
+ fatal("SBREL relocation to " + Body.getName() + " without static base");
return OS->FirstInPtLoad->Addr;
}
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index d369a6f978a2..a182d5a3a096 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -111,17 +111,13 @@ LinkerScript::getOrCreateOutputSectionCommand(StringRef Name) {
void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) {
uint64_t Val = E().getValue();
- if (Val < Dot) {
- if (InSec)
- error(Loc + ": unable to move location counter backward for: " +
- CurOutSec->Name);
- else
- error(Loc + ": unable to move location counter backward");
- }
+ if (Val < Dot && InSec)
+ error(Loc + ": unable to move location counter backward for: " +
+ CurAddressState->OutSec->Name);
Dot = Val;
// Update to location counter means update to section size.
if (InSec)
- CurOutSec->Size = Dot - CurOutSec->Addr;
+ CurAddressState->OutSec->Size = Dot - CurAddressState->OutSec->Addr;
}
// Sets value of a symbol. Two kinds of symbols are processed: synthetic
@@ -373,7 +369,13 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) {
// which will map to whatever the first actual section is.
Aether = make<OutputSection>("", 0, SHF_ALLOC);
Aether->SectionIndex = 1;
- CurOutSec = Aether;
+ auto State = make_unique<AddressState>(Opt);
+ // CurAddressState captures the local AddressState and makes it accessible
+ // deliberately. This is needed as there are some cases where we cannot just
+ // thread the current state through to a lambda function created by the
+ // script parser.
+ CurAddressState = State.get();
+ CurAddressState->OutSec = Aether;
Dot = 0;
for (size_t I = 0; I < Opt.Commands.size(); ++I) {
@@ -435,7 +437,7 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) {
}
}
}
- CurOutSec = nullptr;
+ CurAddressState = nullptr;
}
void LinkerScript::fabricateDefaultCommands() {
@@ -481,20 +483,31 @@ void LinkerScript::fabricateDefaultCommands() {
// Add sections that didn't match any sections command.
void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
+ unsigned NumCommands = Opt.Commands.size();
for (InputSectionBase *S : InputSections) {
if (!S->Live || S->Parent)
continue;
StringRef Name = getOutputSectionName(S->Name);
- auto I = std::find_if(
- Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) {
- if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
- return Cmd->Name == Name;
- return false;
- });
- if (I == Opt.Commands.end()) {
+ auto End = Opt.Commands.begin() + NumCommands;
+ auto I = std::find_if(Opt.Commands.begin(), End, [&](BaseCommand *Base) {
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+ return Cmd->Name == Name;
+ return false;
+ });
+ OutputSectionCommand *Cmd;
+ if (I == End) {
Factory.addInputSec(S, Name);
+ OutputSection *Sec = S->getOutputSection();
+ assert(Sec->SectionIndex == INT_MAX);
+ OutputSectionCommand *&CmdRef = SecToCommand[Sec];
+ if (!CmdRef) {
+ CmdRef = createOutputSectionCommand(Sec->Name, "<internal>");
+ CmdRef->Sec = Sec;
+ Opt.Commands.push_back(CmdRef);
+ }
+ Cmd = CmdRef;
} else {
- auto *Cmd = cast<OutputSectionCommand>(*I);
+ Cmd = cast<OutputSectionCommand>(*I);
Factory.addInputSec(S, Name, Cmd->Sec);
if (OutputSection *Sec = Cmd->Sec) {
SecToCommand[Sec] = Cmd;
@@ -502,21 +515,22 @@ void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
assert(Sec->SectionIndex == INT_MAX || Sec->SectionIndex == Index);
Sec->SectionIndex = Index;
}
- auto *ISD = make<InputSectionDescription>("");
- ISD->Sections.push_back(cast<InputSection>(S));
- Cmd->Commands.push_back(ISD);
}
+ auto *ISD = make<InputSectionDescription>("");
+ ISD->Sections.push_back(cast<InputSection>(S));
+ Cmd->Commands.push_back(ISD);
}
}
uint64_t LinkerScript::advance(uint64_t Size, unsigned Align) {
- bool IsTbss = (CurOutSec->Flags & SHF_TLS) && CurOutSec->Type == SHT_NOBITS;
- uint64_t Start = IsTbss ? Dot + ThreadBssOffset : Dot;
+ bool IsTbss = (CurAddressState->OutSec->Flags & SHF_TLS) &&
+ CurAddressState->OutSec->Type == SHT_NOBITS;
+ uint64_t Start = IsTbss ? Dot + CurAddressState->ThreadBssOffset : Dot;
Start = alignTo(Start, Align);
uint64_t End = Start + Size;
if (IsTbss)
- ThreadBssOffset = End - Dot;
+ CurAddressState->ThreadBssOffset = End - Dot;
else
Dot = End;
return End;
@@ -524,40 +538,43 @@ uint64_t LinkerScript::advance(uint64_t Size, unsigned Align) {
void LinkerScript::output(InputSection *S) {
uint64_t Pos = advance(S->getSize(), S->Alignment);
- S->OutSecOff = Pos - S->getSize() - CurOutSec->Addr;
+ S->OutSecOff = Pos - S->getSize() - CurAddressState->OutSec->Addr;
// Update output section size after adding each section. This is so that
// SIZEOF works correctly in the case below:
// .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) }
- CurOutSec->Size = Pos - CurOutSec->Addr;
+ CurAddressState->OutSec->Size = Pos - CurAddressState->OutSec->Addr;
// If there is a memory region associated with this input section, then
// place the section in that region and update the region index.
- if (CurMemRegion) {
- CurMemRegion->Offset += CurOutSec->Size;
- uint64_t CurSize = CurMemRegion->Offset - CurMemRegion->Origin;
- if (CurSize > CurMemRegion->Length) {
- uint64_t OverflowAmt = CurSize - CurMemRegion->Length;
- error("section '" + CurOutSec->Name + "' will not fit in region '" +
- CurMemRegion->Name + "': overflowed by " + Twine(OverflowAmt) +
- " bytes");
+ if (CurAddressState->MemRegion) {
+ uint64_t &CurOffset =
+ CurAddressState->MemRegionOffset[CurAddressState->MemRegion];
+ CurOffset += CurAddressState->OutSec->Size;
+ uint64_t CurSize = CurOffset - CurAddressState->MemRegion->Origin;
+ if (CurSize > CurAddressState->MemRegion->Length) {
+ uint64_t OverflowAmt = CurSize - CurAddressState->MemRegion->Length;
+ error("section '" + CurAddressState->OutSec->Name +
+ "' will not fit in region '" + CurAddressState->MemRegion->Name +
+ "': overflowed by " + Twine(OverflowAmt) + " bytes");
}
}
}
void LinkerScript::switchTo(OutputSection *Sec) {
- if (CurOutSec == Sec)
+ if (CurAddressState->OutSec == Sec)
return;
- CurOutSec = Sec;
- CurOutSec->Addr = advance(0, CurOutSec->Alignment);
+ CurAddressState->OutSec = Sec;
+ CurAddressState->OutSec->Addr =
+ advance(0, CurAddressState->OutSec->Alignment);
// If neither AT nor AT> is specified for an allocatable section, the linker
// will set the LMA such that the difference between VMA and LMA for the
// section is the same as the preceding output section in the same region
// https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html
- if (LMAOffset)
- CurOutSec->LMAOffset = LMAOffset();
+ if (CurAddressState->LMAOffset)
+ CurAddressState->OutSec->LMAOffset = CurAddressState->LMAOffset();
}
void LinkerScript::process(BaseCommand &Base) {
@@ -569,9 +586,9 @@ void LinkerScript::process(BaseCommand &Base) {
// Handle BYTE(), SHORT(), LONG(), or QUAD().
if (auto *Cmd = dyn_cast<BytesDataCommand>(&Base)) {
- Cmd->Offset = Dot - CurOutSec->Addr;
+ Cmd->Offset = Dot - CurAddressState->OutSec->Addr;
Dot += Cmd->Size;
- CurOutSec->Size = Dot - CurOutSec->Addr;
+ CurAddressState->OutSec->Size = Dot - CurAddressState->OutSec->Addr;
return;
}
@@ -596,7 +613,7 @@ void LinkerScript::process(BaseCommand &Base) {
if (!Sec->Live)
continue;
- assert(CurOutSec == Sec->getParent());
+ assert(CurAddressState->OutSec == Sec->getParent());
output(Sec);
}
}
@@ -649,17 +666,17 @@ void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) {
if (Cmd->LMAExpr) {
uint64_t D = Dot;
- LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; };
+ CurAddressState->LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; };
}
- CurMemRegion = Cmd->MemRegion;
- if (CurMemRegion)
- Dot = CurMemRegion->Offset;
+ CurAddressState->MemRegion = Cmd->MemRegion;
+ if (CurAddressState->MemRegion)
+ Dot = CurAddressState->MemRegionOffset[CurAddressState->MemRegion];
switchTo(Sec);
// We do not support custom layout for compressed debug sectons.
// At this point we already know their size and have compressed content.
- if (CurOutSec->Flags & SHF_COMPRESSED)
+ if (CurAddressState->OutSec->Flags & SHF_COMPRESSED)
return;
for (BaseCommand *C : Cmd->Commands)
@@ -746,30 +763,20 @@ void LinkerScript::adjustSectionsAfterSorting() {
if (!Cmd)
continue;
- if (Cmd->Phdrs.empty())
- Cmd->Phdrs = DefPhdrs;
- else
+ if (Cmd->Phdrs.empty()) {
+ OutputSection *Sec = Cmd->Sec;
+ // To match the bfd linker script behaviour, only propagate program
+ // headers to sections that are allocated.
+ if (Sec && (Sec->Flags & SHF_ALLOC))
+ Cmd->Phdrs = DefPhdrs;
+ } else {
DefPhdrs = Cmd->Phdrs;
+ }
}
removeEmptyCommands();
}
-void LinkerScript::createOrphanCommands() {
- for (OutputSection *Sec : OutputSections) {
- if (Sec->SectionIndex != INT_MAX)
- continue;
- OutputSectionCommand *Cmd =
- createOutputSectionCommand(Sec->Name, "<internal>");
- Cmd->Sec = Sec;
- SecToCommand[Sec] = Cmd;
- auto *ISD = make<InputSectionDescription>("");
- ISD->Sections = Sec->Sections;
- Cmd->Commands.push_back(ISD);
- Opt.Commands.push_back(Cmd);
- }
-}
-
void LinkerScript::processNonSectionCommands() {
for (BaseCommand *Base : Opt.Commands) {
if (auto *Cmd = dyn_cast<SymbolAssignment>(Base))
@@ -779,22 +786,25 @@ void LinkerScript::processNonSectionCommands() {
}
}
-static bool
-allocateHeaders(std::vector<PhdrEntry> &Phdrs,
- ArrayRef<OutputSectionCommand *> OutputSectionCommands,
- uint64_t Min) {
- auto FirstPTLoad =
- std::find_if(Phdrs.begin(), Phdrs.end(),
- [](const PhdrEntry &E) { return E.p_type == PT_LOAD; });
+void LinkerScript::allocateHeaders(std::vector<PhdrEntry> &Phdrs) {
+ uint64_t Min = std::numeric_limits<uint64_t>::max();
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+ OutputSection *Sec = Cmd->Sec;
+ if (Sec->Flags & SHF_ALLOC)
+ Min = std::min<uint64_t>(Min, Sec->Addr);
+ }
+
+ auto FirstPTLoad = llvm::find_if(
+ Phdrs, [](const PhdrEntry &E) { return E.p_type == PT_LOAD; });
if (FirstPTLoad == Phdrs.end())
- return false;
+ return;
uint64_t HeaderSize = getHeaderSize();
if (HeaderSize <= Min || Script->hasPhdrsCommands()) {
Min = alignDown(Min - HeaderSize, Config->MaxPageSize);
Out::ElfHeader->Addr = Min;
Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size;
- return true;
+ return;
}
assert(FirstPTLoad->First == Out::ElfHeader);
@@ -817,17 +827,28 @@ allocateHeaders(std::vector<PhdrEntry> &Phdrs,
Phdrs.erase(FirstPTLoad);
}
- auto PhdrI = std::find_if(Phdrs.begin(), Phdrs.end(), [](const PhdrEntry &E) {
- return E.p_type == PT_PHDR;
- });
+ auto PhdrI = llvm::find_if(
+ Phdrs, [](const PhdrEntry &E) { return E.p_type == PT_PHDR; });
if (PhdrI != Phdrs.end())
Phdrs.erase(PhdrI);
- return false;
}
-void LinkerScript::assignAddresses(std::vector<PhdrEntry> &Phdrs) {
+LinkerScript::AddressState::AddressState(const ScriptConfiguration &Opt) {
+ for (auto &MRI : Opt.MemoryRegions) {
+ const MemoryRegion *MR = &MRI.second;
+ MemRegionOffset[MR] = MR->Origin;
+ }
+}
+
+void LinkerScript::assignAddresses() {
// Assign addresses as instructed by linker script SECTIONS sub-commands.
Dot = 0;
+ auto State = make_unique<AddressState>(Opt);
+ // CurAddressState captures the local AddressState and makes it accessible
+ // deliberately. This is needed as there are some cases where we cannot just
+ // thread the current state through to a lambda function created by the
+ // script parser.
+ CurAddressState = State.get();
ErrorOnMissingSection = true;
switchTo(Aether);
@@ -845,15 +866,7 @@ void LinkerScript::assignAddresses(std::vector<PhdrEntry> &Phdrs) {
auto *Cmd = cast<OutputSectionCommand>(Base);
assignOffsets(Cmd);
}
-
- uint64_t MinVA = std::numeric_limits<uint64_t>::max();
- for (OutputSectionCommand *Cmd : OutputSectionCommands) {
- OutputSection *Sec = Cmd->Sec;
- if (Sec->Flags & SHF_ALLOC)
- MinVA = std::min<uint64_t>(MinVA, Sec->Addr);
- }
-
- allocateHeaders(Phdrs, OutputSectionCommands, MinVA);
+ CurAddressState = nullptr;
}
// Creates program headers as instructed by PHDRS linker script command.
@@ -879,12 +892,9 @@ std::vector<PhdrEntry> LinkerScript::createPhdrs() {
// Add output sections to program headers.
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
- OutputSection *Sec = Cmd->Sec;
- if (!(Sec->Flags & SHF_ALLOC))
- break;
-
// Assign headers specified by linker script
- for (size_t Id : getPhdrIndices(Sec)) {
+ for (size_t Id : getPhdrIndices(Cmd)) {
+ OutputSection *Sec = Cmd->Sec;
Ret[Id].add(Sec);
if (Opt.PhdrsCommands[Id].Flags == UINT_MAX)
Ret[Id].p_flags |= Sec->getPhdrFlags();
@@ -911,6 +921,92 @@ OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const {
return I->second;
}
+void OutputSectionCommand::sort(std::function<int(InputSectionBase *S)> Order) {
+ typedef std::pair<unsigned, InputSection *> Pair;
+ auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
+
+ std::vector<Pair> V;
+ assert(Commands.size() == 1);
+ auto *ISD = cast<InputSectionDescription>(Commands[0]);
+ for (InputSection *S : ISD->Sections)
+ V.push_back({Order(S), S});
+ std::stable_sort(V.begin(), V.end(), Comp);
+ ISD->Sections.clear();
+ for (Pair &P : V)
+ ISD->Sections.push_back(P.second);
+}
+
+// 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.
+static bool compCtors(const InputSection *A, const InputSection *B) {
+ bool BeginA = isCrtbegin(A->File->getName());
+ bool BeginB = isCrtbegin(B->File->getName());
+ if (BeginA != BeginB)
+ return BeginA;
+ bool EndA = isCrtend(A->File->getName());
+ bool EndB = isCrtend(B->File->getName());
+ if (EndA != EndB)
+ return EndB;
+ StringRef X = A->Name;
+ StringRef Y = B->Name;
+ 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.
+void OutputSectionCommand::sortCtorsDtors() {
+ assert(Commands.size() == 1);
+ auto *ISD = cast<InputSectionDescription>(Commands[0]);
+ std::stable_sort(ISD->Sections.begin(), ISD->Sections.end(), compCtors);
+}
+
+// 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.
+void OutputSectionCommand::sortInitFini() {
+ // Sort sections by priority.
+ sort([](InputSectionBase *S) { return getPriority(S->Name); });
+}
+
uint32_t OutputSectionCommand::getFiller() {
if (Filler)
return *Filler;
@@ -1085,16 +1181,9 @@ template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) {
writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size);
}
-bool LinkerScript::hasLMA(OutputSection *Sec) {
- if (OutputSectionCommand *Cmd = getCmd(Sec))
- if (Cmd->LMAExpr)
- return true;
- return false;
-}
-
ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) {
if (S == ".")
- return {CurOutSec, Dot - CurOutSec->Addr, Loc};
+ return {CurAddressState->OutSec, Dot - CurAddressState->OutSec->Addr, Loc};
if (SymbolBody *B = findSymbol(S)) {
if (auto *D = dyn_cast<DefinedRegular>(B))
return {D->Section, D->Value, Loc};
@@ -1111,17 +1200,14 @@ static const size_t NoPhdr = -1;
// Returns indices of ELF headers containing specific section. Each index is a
// zero based number of ELF header listed within PHDRS {} script block.
-std::vector<size_t> LinkerScript::getPhdrIndices(OutputSection *Sec) {
- if (OutputSectionCommand *Cmd = getCmd(Sec)) {
- std::vector<size_t> Ret;
- for (StringRef PhdrName : Cmd->Phdrs) {
- size_t Index = getPhdrIndex(Cmd->Location, PhdrName);
- if (Index != NoPhdr)
- Ret.push_back(Index);
- }
- return Ret;
+std::vector<size_t> LinkerScript::getPhdrIndices(OutputSectionCommand *Cmd) {
+ std::vector<size_t> Ret;
+ for (StringRef PhdrName : Cmd->Phdrs) {
+ size_t Index = getPhdrIndex(Cmd->Location, PhdrName);
+ if (Index != NoPhdr)
+ Ret.push_back(Index);
}
- return {};
+ return Ret;
}
// Returns the index of the segment named PhdrName if found otherwise
diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h
index f8a34a1e97dd..dd5a7d797f60 100644
--- a/ELF/LinkerScript.h
+++ b/ELF/LinkerScript.h
@@ -110,7 +110,6 @@ struct MemoryRegion {
std::string Name;
uint64_t Origin;
uint64_t Length;
- uint64_t Offset;
uint32_t Flags;
uint32_t NegFlags;
};
@@ -140,6 +139,10 @@ struct OutputSectionCommand : BaseCommand {
template <class ELFT> void writeTo(uint8_t *Buf);
template <class ELFT> void maybeCompress();
uint32_t getFiller();
+
+ void sort(std::function<int(InputSectionBase *S)> Order);
+ void sortInitFini();
+ void sortCtorsDtors();
};
// This struct represents one section match pattern in SECTIONS() command.
@@ -222,6 +225,17 @@ struct ScriptConfiguration {
};
class LinkerScript final {
+ // Temporary state used in processCommands() and assignAddresses()
+ // that must be reinitialized for each call to the above functions, and must
+ // not be used outside of the scope of a call to the above functions.
+ struct AddressState {
+ uint64_t ThreadBssOffset = 0;
+ OutputSection *OutSec = nullptr;
+ MemoryRegion *MemRegion = nullptr;
+ llvm::DenseMap<const MemoryRegion *, uint64_t> MemRegionOffset;
+ std::function<uint64_t()> LMAOffset;
+ AddressState(const ScriptConfiguration &Opt);
+ };
llvm::DenseMap<OutputSection *, OutputSectionCommand *> SecToCommand;
llvm::DenseMap<StringRef, OutputSectionCommand *> NameToOutputSectionCommand;
@@ -234,7 +248,7 @@ class LinkerScript final {
std::vector<InputSectionBase *>
createInputSectionList(OutputSectionCommand &Cmd);
- std::vector<size_t> getPhdrIndices(OutputSection *Sec);
+ std::vector<size_t> getPhdrIndices(OutputSectionCommand *Cmd);
size_t getPhdrIndex(const Twine &Loc, StringRef PhdrName);
MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd);
@@ -244,14 +258,10 @@ class LinkerScript final {
void output(InputSection *Sec);
void process(BaseCommand &Base);
+ AddressState *CurAddressState = nullptr;
OutputSection *Aether;
uint64_t Dot;
- uint64_t ThreadBssOffset = 0;
-
- std::function<uint64_t()> LMAOffset;
- OutputSection *CurOutSec = nullptr;
- MemoryRegion *CurMemRegion = nullptr;
public:
bool ErrorOnMissingSection = false;
@@ -276,13 +286,11 @@ public:
std::vector<PhdrEntry> createPhdrs();
bool ignoreInterpSection();
- bool hasLMA(OutputSection *Sec);
bool shouldKeep(InputSectionBase *S);
void assignOffsets(OutputSectionCommand *Cmd);
- void createOrphanCommands();
void processNonSectionCommands();
- void assignAddresses(std::vector<PhdrEntry> &Phdrs);
-
+ void assignAddresses();
+ void allocateHeaders(std::vector<PhdrEntry> &Phdrs);
void addSymbol(SymbolAssignment *Cmd);
void processCommands(OutputSectionFactory &Factory);
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
index c0bf6b32e6e2..d6ae5dcae167 100644
--- a/ELF/OutputSections.cpp
+++ b/ELF/OutputSections.cpp
@@ -101,100 +101,6 @@ void OutputSection::addSection(InputSection *S) {
this->Entsize = std::max(this->Entsize, S->Entsize);
}
-// This function is called after we sort input sections
-// and scan relocations to setup sections' offsets.
-void OutputSection::assignOffsets() {
- OutputSectionCommand *Cmd = Script->getCmd(this);
- uint64_t Off = 0;
- for (BaseCommand *Base : Cmd->Commands)
- if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
- for (InputSection *S : ISD->Sections)
- Off = updateOffset(Off, S);
- this->Size = Off;
-}
-
-void OutputSection::sort(std::function<int(InputSectionBase *S)> Order) {
- typedef std::pair<unsigned, InputSection *> Pair;
- auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
-
- std::vector<Pair> V;
- for (InputSection *S : Sections)
- V.push_back({Order(S), S});
- std::stable_sort(V.begin(), V.end(), Comp);
- Sections.clear();
- for (Pair &P : V)
- Sections.push_back(P.second);
-}
-
-// 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.
-void OutputSection::sortInitFini() {
- // Sort sections by priority.
- sort([](InputSectionBase *S) { return getPriority(S->Name); });
-}
-
-// 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.
-static bool compCtors(const InputSection *A, const InputSection *B) {
- bool BeginA = isCrtbegin(A->File->getName());
- bool BeginB = isCrtbegin(B->File->getName());
- if (BeginA != BeginB)
- return BeginA;
- bool EndA = isCrtend(A->File->getName());
- bool EndB = isCrtend(B->File->getName());
- if (EndA != EndB)
- return EndB;
- StringRef X = A->Name;
- StringRef Y = B->Name;
- 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.
-void OutputSection::sortCtorsDtors() {
- std::stable_sort(Sections.begin(), Sections.end(), compCtors);
-}
-
static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) {
// The ELF spec just says
// ----------------------------------------------------------------
@@ -249,9 +155,7 @@ static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) {
return SectionKey{OutsecName, Flags, Alignment};
}
-OutputSectionFactory::OutputSectionFactory(
- std::vector<OutputSection *> &OutputSections)
- : OutputSections(OutputSections) {}
+OutputSectionFactory::OutputSectionFactory() {}
static uint64_t getIncompatibleFlags(uint64_t Flags) {
return Flags & (SHF_ALLOC | SHF_TLS);
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h
index d5f77838d530..68ee066a13da 100644
--- a/ELF/OutputSections.h
+++ b/ELF/OutputSections.h
@@ -80,10 +80,6 @@ public:
uint32_t ShName = 0;
void addSection(InputSection *S);
- void sort(std::function<int(InputSectionBase *S)> Order);
- void sortInitFini();
- void sortCtorsDtors();
- void assignOffsets();
std::vector<InputSection *> Sections;
// Used for implementation of --compress-debug-sections option.
@@ -135,7 +131,7 @@ namespace elf {
// linker scripts.
class OutputSectionFactory {
public:
- OutputSectionFactory(std::vector<OutputSection *> &OutputSections);
+ OutputSectionFactory();
~OutputSectionFactory();
void addInputSec(InputSectionBase *IS, StringRef OutsecName);
@@ -144,7 +140,6 @@ public:
private:
llvm::SmallDenseMap<SectionKey, OutputSection *> Map;
- std::vector<OutputSection *> &OutputSections;
};
uint64_t getHeaderSize();
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
index fd823fe0ed42..52dbe4b583d0 100644
--- a/ELF/Relocations.cpp
+++ b/ELF/Relocations.cpp
@@ -557,9 +557,9 @@ static RelExpr adjustExpr(SymbolBody &Body, RelExpr Expr, uint32_t Type,
// the refered symbol can be preemepted to refer to the executable.
if (Config->Shared || (Config->Pic && !isRelExpr(Expr))) {
error("can't create dynamic relocation " + toString(Type) + " against " +
- (Body.getName().empty() ? "local symbol in readonly segment"
+ (Body.getName().empty() ? "local symbol"
: "symbol: " + toString(Body)) +
- getLocation<ELFT>(S, Body, RelOff));
+ " in readonly segment" + getLocation<ELFT>(S, Body, RelOff));
return Expr;
}
@@ -1049,10 +1049,17 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS,
std::pair<Thunk *, bool> ThunkCreator::getThunk(SymbolBody &Body,
uint32_t Type) {
- auto res = ThunkedSymbols.insert({&Body, nullptr});
- if (res.second)
- res.first->second = addThunk(Type, Body);
- return std::make_pair(res.first->second, res.second);
+ auto Res = ThunkedSymbols.insert({&Body, std::vector<Thunk *>()});
+ if (!Res.second) {
+ // Check existing Thunks for Body to see if they can be reused
+ for (Thunk *ET : Res.first->second)
+ if (ET->isCompatibleWith(Type))
+ return std::make_pair(ET, false);
+ }
+ // No existing compatible Thunk in range, create a new one
+ Thunk *T = addThunk(Type, Body);
+ Res.first->second.push_back(T);
+ return std::make_pair(T, true);
}
// Call Fn on every executable InputSection accessed via the linker script
@@ -1066,13 +1073,12 @@ void ThunkCreator::forEachExecInputSection(
OutputSection *OS = Cmd->Sec;
if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR))
continue;
- if (OutputSectionCommand *C = Script->getCmd(OS))
- for (BaseCommand *BC : C->Commands)
- if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) {
- CurTS = nullptr;
- for (InputSection* IS : ISD->Sections)
- Fn(OS, &ISD->Sections, IS);
- }
+ for (BaseCommand *BC : Cmd->Commands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) {
+ CurTS = nullptr;
+ for (InputSection *IS : ISD->Sections)
+ Fn(OS, &ISD->Sections, IS);
+ }
}
}
diff --git a/ELF/Relocations.h b/ELF/Relocations.h
index 445308b27cec..fc3e3444ac24 100644
--- a/ELF/Relocations.h
+++ b/ELF/Relocations.h
@@ -144,14 +144,17 @@ private:
std::pair<Thunk *, bool> getThunk(SymbolBody &Body, uint32_t Type);
ThunkSection *addThunkSection(OutputSection *OS,
std::vector<InputSection *> *, uint64_t Off);
- // Track Symbols that already have a Thunk
- llvm::DenseMap<SymbolBody *, Thunk *> ThunkedSymbols;
+ // Record all the available Thunks for a Symbol
+ llvm::DenseMap<SymbolBody *, std::vector<Thunk *>> ThunkedSymbols;
// Find a Thunk from the Thunks symbol definition, we can use this to find
// the Thunk from a relocation to the Thunks symbol definition.
llvm::DenseMap<SymbolBody *, Thunk *> Thunks;
- // Track InputSections that have a ThunkSection placed in front
+ // Track InputSections that have an inline ThunkSection placed in front
+ // an inline ThunkSection may have control fall through to the section below
+ // so we need to make sure that there is only one of them.
+ // The Mips LA25 Thunk is an example of an inline ThunkSection.
llvm::DenseMap<InputSection *, ThunkSection *> ThunkedSections;
// All the ThunkSections that we have created, organised by OutputSection
diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp
index 4a44944fe7ed..72940ca0cfd4 100644
--- a/ELF/ScriptParser.cpp
+++ b/ELF/ScriptParser.cpp
@@ -1191,8 +1191,7 @@ void ScriptParser::readMemory() {
if (It != Script->Opt.MemoryRegions.end())
setError("region '" + Name + "' already defined");
else
- Script->Opt.MemoryRegions[Name] = {Name, Origin, Length,
- Origin, Flags, NegFlags};
+ Script->Opt.MemoryRegions[Name] = {Name, Origin, Length, Flags, NegFlags};
}
}
diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp
index d75b89f17527..c802d74b8ff8 100644
--- a/ELF/SymbolTable.cpp
+++ b/ELF/SymbolTable.cpp
@@ -211,6 +211,13 @@ static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
// Find an existing symbol or create and insert a new one.
template <class ELFT>
std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) {
+ // <name>@@<version> means the symbol is the default version. In that
+ // case symbol <name> must exist and <name>@@<version> will be used to
+ // resolve references to <name>.
+ size_t Pos = Name.find("@@");
+ if (Pos != StringRef::npos)
+ Name = Name.take_front(Pos);
+
auto P = Symtab.insert(
{CachedHashStringRef(Name), SymIndex((int)SymVector.size(), false)});
SymIndex &V = P.first->second;
@@ -319,7 +326,7 @@ static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) {
if (WasInserted)
return 1;
SymbolBody *Body = S->body();
- if (Body->isLazy() || !Body->isInCurrentDSO())
+ if (!Body->isInCurrentDSO())
return 1;
if (Binding == STB_WEAK)
return -1;
@@ -689,6 +696,12 @@ void SymbolTable<ELFT>::assignExactVersion(SymbolVersion Ver, uint16_t VersionId
// Assign the version.
for (SymbolBody *B : Syms) {
+ // Skip symbols containing version info because symbol versions
+ // specified by symbol names take precedence over version scripts.
+ // See parseSymbolVersion().
+ if (B->getName().find('@') != StringRef::npos)
+ continue;
+
Symbol *Sym = B->symbol();
if (Sym->InVersionScript)
warn("duplicate symbol '" + Ver.Name + "' in version script");
@@ -702,47 +715,21 @@ void SymbolTable<ELFT>::assignWildcardVersion(SymbolVersion Ver,
uint16_t VersionId) {
if (!Ver.HasWildcard)
return;
- std::vector<SymbolBody *> Syms = findAllByVersion(Ver);
// Exact matching takes precendence over fuzzy matching,
// so we set a version to a symbol only if no version has been assigned
// to the symbol. This behavior is compatible with GNU.
- for (SymbolBody *B : Syms)
+ for (SymbolBody *B : findAllByVersion(Ver))
if (B->symbol()->VersionId == Config->DefaultSymbolVersion)
B->symbol()->VersionId = VersionId;
}
-static bool isDefaultVersion(SymbolBody *B) {
- return B->isInCurrentDSO() && B->getName().find("@@") != StringRef::npos;
-}
-
// This function processes version scripts by updating VersionId
// member of symbols.
template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
- // Symbol themselves might know their versions because symbols
- // can contain versions in the form of <name>@<version>.
- // Let them parse and update their names to exclude version suffix.
- for (Symbol *Sym : SymVector) {
- SymbolBody *Body = Sym->body();
- bool IsDefault = isDefaultVersion(Body);
- Body->parseSymbolVersion();
-
- if (!IsDefault)
- continue;
-
- // <name>@@<version> means the symbol is the default version. If that's the
- // case, the symbol is not used only to resolve <name> of version <version>
- // but also undefined unversioned symbols with name <name>.
- SymbolBody *S = find(Body->getName());
- if (S && S->isUndefined())
- S->copy(Body);
- }
-
// Handle edge cases first.
handleAnonymousVersion();
- if (Config->VersionDefinitions.empty())
- return;
// Now we have version definitions, so we need to set version ids to symbols.
// Each version definition has a glob pattern, and all symbols that match
@@ -761,6 +748,12 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
for (VersionDefinition &V : llvm::reverse(Config->VersionDefinitions))
for (SymbolVersion &Ver : V.Globals)
assignWildcardVersion(Ver, V.Id);
+
+ // Symbol themselves might know their versions because symbols
+ // can contain versions in the form of <name>@<version>.
+ // Let them parse and update their names to exclude version suffix.
+ for (Symbol *Sym : SymVector)
+ Sym->body()->parseSymbolVersion();
}
template class elf::SymbolTable<ELF32LE>;
diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp
index e8cd662c69ac..1d17f57f0c30 100644
--- a/ELF/Symbols.cpp
+++ b/ELF/Symbols.cpp
@@ -159,19 +159,12 @@ bool SymbolBody::isPreemptible() const {
return true;
}
-// Overwrites all attributes except symbol name with Other's so that
-// this symbol becomes an alias to Other. This is useful for handling
-// some options such as --wrap.
-//
-// The reason why we want to keep the symbol name is because, if we
-// copy symbol names, we'll end up having symbol tables in resulting
-// executables or DSOs containing two or more identical symbols, which
-// is just inconvenient.
+// Overwrites all attributes with Other's so that this symbol becomes
+// an alias to Other. This is useful for handling some options such as
+// --wrap.
void SymbolBody::copy(SymbolBody *Other) {
- StringRef S = Name;
memcpy(symbol()->Body.buffer, Other->symbol()->Body.buffer,
sizeof(Symbol::Body));
- Name = S;
}
uint64_t SymbolBody::getVA(int64_t Addend) const {
@@ -272,7 +265,12 @@ void SymbolBody::parseSymbolVersion() {
}
// It is an error if the specified version is not defined.
- error(toString(File) + ": symbol " + S + " has undefined version " + Verstr);
+ // Usually version script is not provided when linking executable,
+ // but we may still want to override a versioned symbol from DSO,
+ // so we do not report error in this case.
+ if (Config->Shared)
+ error(toString(File) + ": symbol " + S + " has undefined version " +
+ Verstr);
}
Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
diff --git a/ELF/Symbols.h b/ELF/Symbols.h
index 773e1ad9588a..a1b3a6fba911 100644
--- a/ELF/Symbols.h
+++ b/ELF/Symbols.h
@@ -65,7 +65,9 @@ public:
return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
}
bool isShared() const { return SymbolKind == SharedKind; }
- bool isInCurrentDSO() const { return !isUndefined() && !isShared(); }
+ bool isInCurrentDSO() const {
+ return !isUndefined() && !isShared() && !isLazy();
+ }
bool isLocal() const { return IsLocal; }
bool isPreemptible() const;
StringRef getName() const { return Name; }
@@ -218,7 +220,7 @@ public:
Verdef(Verdef), ElfSym(ElfSym) {
// IFuncs defined in DSOs are treated as functions by the static linker.
if (isGnuIFunc())
- Type = llvm::ELF::STT_FUNC;
+ this->Type = llvm::ELF::STT_FUNC;
this->File = File;
}
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp
index 995d05692ee2..fd724fac327c 100644
--- a/ELF/SyntheticSections.cpp
+++ b/ELF/SyntheticSections.cpp
@@ -1071,10 +1071,11 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
return; // Already finalized.
this->Link = InX::DynStrTab->getParent()->SectionIndex;
- if (In<ELFT>::RelaDyn->getParent()->Size > 0) {
+ if (In<ELFT>::RelaDyn->getParent() && !In<ELFT>::RelaDyn->empty()) {
bool IsRela = Config->IsRela;
add({IsRela ? DT_RELA : DT_REL, In<ELFT>::RelaDyn});
- add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->getParent()->Size});
+ add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->getParent(),
+ Entry::SecSize});
add({IsRela ? DT_RELAENT : DT_RELENT,
uint64_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))});
@@ -1087,9 +1088,9 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels});
}
}
- if (In<ELFT>::RelaPlt->getParent()->Size > 0) {
+ if (In<ELFT>::RelaPlt->getParent() && !In<ELFT>::RelaPlt->empty()) {
add({DT_JMPREL, In<ELFT>::RelaPlt});
- add({DT_PLTRELSZ, In<ELFT>::RelaPlt->getParent()->Size});
+ add({DT_PLTRELSZ, In<ELFT>::RelaPlt->getParent(), Entry::SecSize});
switch (Config->EMachine) {
case EM_MIPS:
add({DT_MIPS_PLTGOT, In<ELFT>::GotPlt});
@@ -1699,9 +1700,9 @@ unsigned PltSection::getPltRelocOff() const {
return (HeaderSize == 0) ? InX::Plt->getSize() : 0;
}
-GdbIndexSection::GdbIndexSection()
+GdbIndexSection::GdbIndexSection(std::vector<GdbIndexChunk> &&Chunks)
: SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"),
- StringPool(llvm::StringTableBuilder::ELF) {}
+ StringPool(llvm::StringTableBuilder::ELF), Chunks(std::move(Chunks)) {}
// Iterative hash function for symbol's name is described in .gdb_index format
// specification. Note that we use one for version 5 to 7 here, it is different
@@ -1713,11 +1714,10 @@ static uint32_t hash(StringRef Str) {
return R;
}
-static std::vector<CompilationUnitEntry> readCuList(DWARFContext &Dwarf,
- InputSection *Sec) {
+static std::vector<CompilationUnitEntry> readCuList(DWARFContext &Dwarf) {
std::vector<CompilationUnitEntry> Ret;
for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units())
- Ret.push_back({Sec->OutSecOff + CU->getOffset(), CU->getLength() + 4});
+ Ret.push_back({CU->getOffset(), CU->getLength() + 4});
return Ret;
}
@@ -1764,19 +1764,15 @@ static std::vector<InputSection *> getDebugInfoSections() {
std::vector<InputSection *> Ret;
for (InputSectionBase *S : InputSections)
if (InputSection *IS = dyn_cast<InputSection>(S))
- if (IS->getParent() && IS->Name == ".debug_info")
+ if (IS->Name == ".debug_info")
Ret.push_back(IS);
return Ret;
}
void GdbIndexSection::buildIndex() {
- std::vector<InputSection *> V = getDebugInfoSections();
- if (V.empty())
+ if (Chunks.empty())
return;
- for (InputSection *Sec : V)
- Chunks.push_back(readDwarf(Sec));
-
uint32_t CuId = 0;
for (GdbIndexChunk &D : Chunks) {
for (AddressEntry &E : D.AddressArea)
@@ -1802,23 +1798,33 @@ void GdbIndexSection::buildIndex() {
}
}
-GdbIndexChunk GdbIndexSection::readDwarf(InputSection *Sec) {
- Expected<std::unique_ptr<object::ObjectFile>> Obj =
- object::ObjectFile::createObjectFile(Sec->File->MB);
- if (!Obj) {
- error(toString(Sec->File) + ": error creating DWARF context");
- return {};
- }
-
- DWARFContextInMemory Dwarf(*Obj.get());
-
+static GdbIndexChunk readDwarf(DWARFContextInMemory &Dwarf, InputSection *Sec) {
GdbIndexChunk Ret;
- Ret.CompilationUnits = readCuList(Dwarf, Sec);
+ Ret.DebugInfoSec = Sec;
+ Ret.CompilationUnits = readCuList(Dwarf);
Ret.AddressArea = readAddressArea(Dwarf, Sec);
Ret.NamesAndTypes = readPubNamesAndTypes(Dwarf, Config->IsLE);
return Ret;
}
+template <class ELFT> GdbIndexSection *elf::createGdbIndex() {
+ std::vector<GdbIndexChunk> Chunks;
+ for (InputSection *Sec : getDebugInfoSections()) {
+ InputFile *F = Sec->File;
+ std::error_code EC;
+ ELFObjectFile<ELFT> Obj(F->MB, EC);
+ if (EC)
+ fatal(EC.message());
+ DWARFContextInMemory Dwarf(Obj, nullptr, [&](Error E) {
+ error(toString(F) + ": error parsing DWARF data:\n>>> " +
+ toString(std::move(E)));
+ return ErrorPolicy::Continue;
+ });
+ Chunks.push_back(readDwarf(Dwarf, Sec));
+ }
+ return make<GdbIndexSection>(std::move(Chunks));
+}
+
static size_t getCuSize(std::vector<GdbIndexChunk> &C) {
size_t Ret = 0;
for (GdbIndexChunk &D : C)
@@ -1876,7 +1882,7 @@ void GdbIndexSection::writeTo(uint8_t *Buf) {
// Write the CU list.
for (GdbIndexChunk &D : Chunks) {
for (CompilationUnitEntry &Cu : D.CompilationUnits) {
- write64le(Buf, Cu.CuOffset);
+ write64le(Buf, D.DebugInfoSec->OutSecOff + Cu.CuOffset);
write64le(Buf + 8, Cu.CuLength);
Buf += 16;
}
@@ -2345,6 +2351,11 @@ StringTableSection *InX::ShStrTab;
StringTableSection *InX::StrTab;
SymbolTableBaseSection *InX::SymTab;
+template GdbIndexSection *elf::createGdbIndex<ELF32LE>();
+template GdbIndexSection *elf::createGdbIndex<ELF32BE>();
+template GdbIndexSection *elf::createGdbIndex<ELF64LE>();
+template GdbIndexSection *elf::createGdbIndex<ELF64BE>();
+
template void PltSection::addEntry<ELF32LE>(SymbolBody &Sym);
template void PltSection::addEntry<ELF32BE>(SymbolBody &Sym);
template void PltSection::addEntry<ELF64LE>(SymbolBody &Sym);
diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h
index be9a43c8155b..ddd8ca99a61b 100644
--- a/ELF/SyntheticSections.h
+++ b/ELF/SyntheticSections.h
@@ -503,7 +503,7 @@ class GdbIndexSection final : public SyntheticSection {
const unsigned SymTabEntrySize = 2 * OffsetTypeSize;
public:
- GdbIndexSection();
+ GdbIndexSection(std::vector<GdbIndexChunk> &&Chunks);
void finalizeContents() override;
void writeTo(uint8_t *Buf) override;
size_t getSize() const override;
@@ -524,7 +524,6 @@ public:
std::vector<GdbIndexChunk> Chunks;
private:
- GdbIndexChunk readDwarf(InputSection *Sec);
void buildIndex();
uint32_t CuTypesOffset;
@@ -538,6 +537,8 @@ private:
bool Finalized = false;
};
+template <class ELFT> GdbIndexSection *createGdbIndex();
+
// --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.
diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp
index 752a881d7867..cae31027e557 100644
--- a/ELF/Thunks.cpp
+++ b/ELF/Thunks.cpp
@@ -57,6 +57,7 @@ public:
uint32_t size() const override { return 12; }
void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
void addSymbols(ThunkSection &IS) override;
+ bool isCompatibleWith(uint32_t RelocType) const override;
};
class ARMV7PILongThunk final : public Thunk {
@@ -66,28 +67,31 @@ public:
uint32_t size() const override { return 16; }
void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
void addSymbols(ThunkSection &IS) override;
+ bool isCompatibleWith(uint32_t RelocType) const override;
};
class ThumbV7ABSLongThunk final : public Thunk {
public:
ThumbV7ABSLongThunk(const SymbolBody &Dest) : Thunk(Dest) {
- this->alignment = 2;
+ alignment = 2;
}
uint32_t size() const override { return 10; }
void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
void addSymbols(ThunkSection &IS) override;
+ bool isCompatibleWith(uint32_t RelocType) const override;
};
class ThumbV7PILongThunk final : public Thunk {
public:
ThumbV7PILongThunk(const SymbolBody &Dest) : Thunk(Dest) {
- this->alignment = 2;
+ alignment = 2;
}
uint32_t size() const override { return 12; }
void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
void addSymbols(ThunkSection &IS) override;
+ bool isCompatibleWith(uint32_t RelocType) const override;
};
// MIPS LA25 thunk
@@ -128,6 +132,11 @@ void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) {
addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS);
}
+bool ARMV7ABSLongThunk::isCompatibleWith(uint32_t RelocType) const {
+ // Thumb branch relocations can't use BLX
+ return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24;
+}
+
void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
const uint8_t Data[] = {
0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S
@@ -147,6 +156,12 @@ void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) {
addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS);
}
+bool ThumbV7ABSLongThunk::isCompatibleWith(uint32_t RelocType) const {
+ // ARM branch relocations can't use BLX
+ return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 &&
+ RelocType != R_ARM_PLT32;
+}
+
void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
const uint8_t Data[] = {
0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) +8)
@@ -168,6 +183,11 @@ void ARMV7PILongThunk::addSymbols(ThunkSection &IS) {
addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS);
}
+bool ARMV7PILongThunk::isCompatibleWith(uint32_t RelocType) const {
+ // Thumb branch relocations can't use BLX
+ return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24;
+}
+
void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
const uint8_t Data[] = {
0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4)
@@ -189,9 +209,15 @@ void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) {
addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS);
}
+bool ThumbV7PILongThunk::isCompatibleWith(uint32_t RelocType) const {
+ // ARM branch relocations can't use BLX
+ return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 &&
+ RelocType != R_ARM_PLT32;
+}
+
// Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
void MipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const {
- uint64_t S = this->Destination.getVA();
+ uint64_t S = Destination.getVA();
write32(Buf, 0x3c190000, Config->Endianness); // lui $25, %hi(func)
write32(Buf + 4, 0x08000000 | (S >> 2), Config->Endianness); // j func
write32(Buf + 8, 0x27390000, Config->Endianness); // addiu $25, $25, %lo(func)
diff --git a/ELF/Thunks.h b/ELF/Thunks.h
index 38ee090e75e1..00b6b2cf2994 100644
--- a/ELF/Thunks.h
+++ b/ELF/Thunks.h
@@ -41,6 +41,10 @@ public:
// a branch and fall through to the first Symbol in the Target.
virtual InputSection *getTargetInputSection() const { return nullptr; }
+ // To reuse a Thunk the caller as identified by the RelocType must be
+ // compatible with it.
+ virtual bool isCompatibleWith(uint32_t RelocType) const { return true; }
+
// The alignment requirement for this Thunk, defaults to the size of the
// typical code section alignment.
const SymbolBody &Destination;
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index 080d8e787301..bf43ee5c5f91 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -73,13 +73,12 @@ private:
std::unique_ptr<FileOutputBuffer> Buffer;
- OutputSectionFactory Factory{OutputSections};
+ OutputSectionFactory Factory;
void addRelIpltSymbols();
void addStartEndSymbols();
void addStartStopSymbols(OutputSection *Sec);
uint64_t getEntryAddr();
- OutputSection *findSection(StringRef Name);
OutputSection *findSectionInScript(StringRef Name);
OutputSectionCommand *findSectionCommand(StringRef Name);
@@ -152,10 +151,6 @@ template <class ELFT> static void combineEhFrameSections() {
}
template <class ELFT> void Writer<ELFT>::clearOutputSections() {
- if (Script->Opt.HasSections)
- Script->createOrphanCommands();
- else
- Script->fabricateDefaultCommands();
// Clear the OutputSections to make sure it is not used anymore. Any
// code from this point on should be using the linker script
// commands.
@@ -190,9 +185,10 @@ template <class ELFT> void Writer<ELFT>::run() {
// output sections by default rules. We still need to give the
// linker script a chance to run, because it might contain
// non-SECTIONS commands such as ASSERT.
- createSections();
Script->processCommands(Factory);
+ createSections();
}
+ clearOutputSections();
if (Config->Discard != DiscardPolicy::All)
copyLocalSymbols();
@@ -218,7 +214,8 @@ template <class ELFT> void Writer<ELFT>::run() {
OutputSectionCommands.begin(), OutputSectionCommands.end(),
[](OutputSectionCommand *Cmd) { Cmd->maybeCompress<ELFT>(); });
- Script->assignAddresses(Phdrs);
+ Script->assignAddresses();
+ Script->allocateHeaders(Phdrs);
// Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
// 0 sized region. This has to be done late since only after assignAddresses
@@ -383,7 +380,7 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
Add(InX::IgotPlt);
if (Config->GdbIndex) {
- InX::GdbIndex = make<GdbIndexSection>();
+ InX::GdbIndex = createGdbIndex<ELFT>();
Add(InX::GdbIndex);
}
@@ -499,11 +496,18 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
// Create one STT_SECTION symbol for each output section we might
// have a relocation with.
- for (OutputSection *Sec : OutputSections) {
- if (Sec->Sections.empty())
+ for (BaseCommand *Base : Script->Opt.Commands) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
+ if (!Cmd)
continue;
-
- InputSection *IS = Sec->Sections[0];
+ auto I = llvm::find_if(Cmd->Commands, [](BaseCommand *Base) {
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
+ return !ISD->Sections.empty();
+ return false;
+ });
+ if (I == Cmd->Commands.end())
+ continue;
+ InputSection *IS = cast<InputSectionDescription>(*I)->Sections[0];
if (isa<SyntheticSection>(IS) || IS->Type == SHT_REL ||
IS->Type == SHT_RELA)
continue;
@@ -864,20 +868,19 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
// Sort input sections by section name suffixes for
// __attribute__((init_priority(N))).
-static void sortInitFini(OutputSection *S) {
- if (S)
- reinterpret_cast<OutputSection *>(S)->sortInitFini();
+static void sortInitFini(OutputSectionCommand *Cmd) {
+ if (Cmd)
+ Cmd->sortInitFini();
}
// Sort input sections by the special rule for .ctors and .dtors.
-static void sortCtorsDtors(OutputSection *S) {
- if (S)
- reinterpret_cast<OutputSection *>(S)->sortCtorsDtors();
+static void sortCtorsDtors(OutputSectionCommand *Cmd) {
+ if (Cmd)
+ Cmd->sortCtorsDtors();
}
// Sort input sections using the list provided by --symbol-ordering-file.
-template <class ELFT>
-static void sortBySymbolsOrder(ArrayRef<OutputSection *> OutputSections) {
+template <class ELFT> static void sortBySymbolsOrder() {
if (Config->SymbolOrderingFile.empty())
return;
@@ -902,9 +905,9 @@ static void sortBySymbolsOrder(ArrayRef<OutputSection *> OutputSections) {
}
// Sort sections by priority.
- for (OutputSection *Base : OutputSections)
- if (auto *Sec = dyn_cast<OutputSection>(Base))
- Sec->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); });
+ for (BaseCommand *Base : Script->Opt.Commands)
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+ Cmd->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); });
}
template <class ELFT>
@@ -934,11 +937,12 @@ template <class ELFT> void Writer<ELFT>::createSections() {
if (IS)
Factory.addInputSec(IS, getOutputSectionName(IS->Name));
- sortBySymbolsOrder<ELFT>(OutputSections);
- sortInitFini(findSection(".init_array"));
- sortInitFini(findSection(".fini_array"));
- sortCtorsDtors(findSection(".ctors"));
- sortCtorsDtors(findSection(".dtors"));
+ Script->fabricateDefaultCommands();
+ sortBySymbolsOrder<ELFT>();
+ sortInitFini(findSectionCommand(".init_array"));
+ sortInitFini(findSectionCommand(".fini_array"));
+ sortCtorsDtors(findSectionCommand(".ctors"));
+ sortCtorsDtors(findSectionCommand(".dtors"));
}
// We want to find how similar two ranks are.
@@ -1132,7 +1136,7 @@ static void applySynthetic(const std::vector<SyntheticSection *> &Sections,
// to make them visible from linkescript side. But not all sections are always
// required to be in output. For example we don't need dynamic section content
// sometimes. This function filters out such unused sections from the output.
-static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V) {
+static void removeUnusedSyntheticSections() {
// All input synthetic sections that can be empty are placed after
// all regular ones. We iterate over them all and exit at first
// non-synthetic.
@@ -1145,29 +1149,53 @@ static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V) {
continue;
if ((SS == InX::Got || SS == InX::MipsGot) && ElfSym::GlobalOffsetTable)
continue;
- OS->Sections.erase(std::find(OS->Sections.begin(), OS->Sections.end(), SS));
- SS->Live = false;
+
+ OutputSectionCommand *Cmd = Script->getCmd(OS);
+ std::vector<BaseCommand *>::iterator Empty = Cmd->Commands.end();
+ for (auto I = Cmd->Commands.begin(), E = Cmd->Commands.end(); I != E; ++I) {
+ BaseCommand *B = *I;
+ if (auto *ISD = dyn_cast<InputSectionDescription>(B)) {
+ auto P = std::find(ISD->Sections.begin(), ISD->Sections.end(), SS);
+ if (P != ISD->Sections.end())
+ ISD->Sections.erase(P);
+ if (ISD->Sections.empty())
+ Empty = I;
+ }
+ }
+ if (Empty != Cmd->Commands.end())
+ Cmd->Commands.erase(Empty);
+
// If there are no other sections in the output section, remove it from the
// output.
- if (OS->Sections.empty())
- V.erase(std::find(V.begin(), V.end(), OS));
+ if (Cmd->Commands.empty()) {
+ // Also remove script commands matching the output section.
+ auto &Cmds = Script->Opt.Commands;
+ auto I = std::remove_if(Cmds.begin(), Cmds.end(), [&](BaseCommand *Cmd) {
+ if (auto *OSCmd = dyn_cast<OutputSectionCommand>(Cmd))
+ return OSCmd->Sec == OS;
+ return false;
+ });
+ Cmds.erase(I, Cmds.end());
+ }
}
}
// Create output section objects and add them to OutputSections.
template <class ELFT> void Writer<ELFT>::finalizeSections() {
- Out::DebugInfo = findSection(".debug_info");
- Out::PreinitArray = findSection(".preinit_array");
- Out::InitArray = findSection(".init_array");
- Out::FiniArray = findSection(".fini_array");
+ Out::DebugInfo = findSectionInScript(".debug_info");
+ Out::PreinitArray = findSectionInScript(".preinit_array");
+ Out::InitArray = findSectionInScript(".init_array");
+ Out::FiniArray = findSectionInScript(".fini_array");
// 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 (OutputSection *Sec : OutputSections)
- addStartStopSymbols(Sec);
+ for (BaseCommand *Base : Script->Opt.Commands)
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+ if (Cmd->Sec)
+ addStartStopSymbols(Cmd->Sec);
}
// Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type.
@@ -1218,9 +1246,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
return;
addPredefinedSections();
- removeUnusedSyntheticSections(OutputSections);
+ removeUnusedSyntheticSections();
- clearOutputSections();
sortSections();
// Now that we have the final list, create a list of all the
@@ -1257,12 +1284,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size();
}
- // Compute the size of .rela.dyn and .rela.plt early since we need
- // them to populate .dynamic.
- for (SyntheticSection *SS : {In<ELFT>::RelaDyn, In<ELFT>::RelaPlt})
- if (SS->getParent() && !SS->empty())
- SS->getParent()->assignOffsets();
-
// Dynamic section must be the last one in this list and dynamic
// symbol table section (DynSymTab) must be the first one.
applySynthetic({InX::DynSymTab, InX::Bss, InX::BssRelRo,
@@ -1286,6 +1307,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// are out of range. This will need to turn into a loop that converges
// when no more Thunks are added
ThunkCreator TC;
+ Script->assignAddresses();
if (TC.createThunks(OutputSectionCommands)) {
applySynthetic({InX::MipsGot},
[](SyntheticSection *SS) { SS->updateAllocSize(); });
@@ -1308,21 +1330,18 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
// ARM ABI requires .ARM.exidx to be terminated by some piece of data.
// We have the terminater synthetic section class. Add that at the end.
- auto *OS = dyn_cast_or_null<OutputSection>(findSection(".ARM.exidx"));
- if (!OS || OS->Sections.empty() || Config->Relocatable)
+ OutputSectionCommand *Cmd = findSectionCommand(".ARM.exidx");
+ if (!Cmd || Cmd->Commands.empty() || Config->Relocatable)
return;
auto *Sentinel = make<ARMExidxSentinelSection>();
- OS->addSection(Sentinel);
- // If there are linker script commands existing at this point then add the
- // sentinel to the last of these too.
- if (OutputSectionCommand *C = Script->getCmd(OS)) {
- auto ISD = std::find_if(C->Commands.rbegin(), C->Commands.rend(),
- [](const BaseCommand *Base) {
- return isa<InputSectionDescription>(Base);
- });
- cast<InputSectionDescription>(*ISD)->Sections.push_back(Sentinel);
- }
+ Cmd->Sec->addSection(Sentinel);
+ // Add the sentinel to the last of these too.
+ auto ISD = std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(),
+ [](const BaseCommand *Base) {
+ return isa<InputSectionDescription>(Base);
+ });
+ cast<InputSectionDescription>(*ISD)->Sections.push_back(Sentinel);
}
// The linker is expected to define SECNAME_start and SECNAME_end
@@ -1346,7 +1365,7 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
Define("__init_array_start", "__init_array_end", Out::InitArray);
Define("__fini_array_start", "__fini_array_end", Out::FiniArray);
- if (OutputSection *Sec = findSection(".ARM.exidx"))
+ if (OutputSection *Sec = findSectionInScript(".ARM.exidx"))
Define("__exidx_start", "__exidx_end", Sec);
}
@@ -1366,9 +1385,10 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) {
template <class ELFT>
OutputSectionCommand *Writer<ELFT>::findSectionCommand(StringRef Name) {
- for (OutputSectionCommand *Cmd : OutputSectionCommands)
- if (Cmd->Name == Name)
- return Cmd;
+ for (BaseCommand *Base : Script->Opt.Commands)
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+ if (Cmd->Name == Name)
+ return Cmd;
return nullptr;
}
@@ -1378,13 +1398,6 @@ template <class ELFT> OutputSection *Writer<ELFT>::findSectionInScript(StringRef
return nullptr;
}
-template <class ELFT> OutputSection *Writer<ELFT>::findSection(StringRef Name) {
- for (OutputSection *Sec : OutputSections)
- if (Sec->Name == Name)
- return Sec;
- return nullptr;
-}
-
static bool needsPtLoad(OutputSection *Sec) {
if (!(Sec->Flags & SHF_ALLOC))
return false;
@@ -1446,7 +1459,7 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() {
// different flags or is loaded at a discontiguous address using AT linker
// script command.
uint64_t NewFlags = computeFlags(Sec->getPhdrFlags());
- if (Script->hasLMA(Sec) || Flags != NewFlags) {
+ if (Cmd->LMAExpr || Flags != NewFlags) {
Load = AddHdr(PT_LOAD, NewFlags);
Flags = NewFlags;
}
@@ -1514,7 +1527,7 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() {
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
OutputSection *Sec = Cmd->Sec;
if (Sec->Type == SHT_NOTE) {
- if (!Note || Script->hasLMA(Sec))
+ if (!Note || Cmd->LMAExpr)
Note = AddHdr(PT_NOTE, PF_R);
Note->add(Sec);
} else {
@@ -1528,11 +1541,9 @@ template <class ELFT>
void Writer<ELFT>::addPtArmExid(std::vector<PhdrEntry> &Phdrs) {
if (Config->EMachine != EM_ARM)
return;
- auto I =
- std::find_if(OutputSectionCommands.begin(), OutputSectionCommands.end(),
- [](OutputSectionCommand *Cmd) {
- return Cmd->Sec->Type == SHT_ARM_EXIDX;
- });
+ auto I = llvm::find_if(OutputSectionCommands, [](OutputSectionCommand *Cmd) {
+ return Cmd->Sec->Type == SHT_ARM_EXIDX;
+ });
if (I == OutputSectionCommands.end())
return;