summaryrefslogtreecommitdiff
path: root/ELF
diff options
context:
space:
mode:
Diffstat (limited to 'ELF')
-rw-r--r--ELF/Config.h1
-rw-r--r--ELF/Driver.cpp9
-rw-r--r--ELF/ICF.cpp4
-rw-r--r--ELF/InputFiles.cpp32
-rw-r--r--ELF/InputSection.cpp31
-rw-r--r--ELF/InputSection.h5
-rw-r--r--ELF/LTO.cpp7
-rw-r--r--ELF/LinkerScript.cpp98
-rw-r--r--ELF/LinkerScript.h11
-rw-r--r--ELF/MapFile.cpp17
-rw-r--r--ELF/Options.td1
-rw-r--r--ELF/OutputSections.cpp93
-rw-r--r--ELF/OutputSections.h2
-rw-r--r--ELF/SyntheticSections.cpp44
-rw-r--r--ELF/SyntheticSections.h6
-rw-r--r--ELF/Writer.cpp190
-rw-r--r--ELF/Writer.h2
17 files changed, 331 insertions, 222 deletions
diff --git a/ELF/Config.h b/ELF/Config.h
index 57a0e5a5ec73e..54f6dc2acc7cf 100644
--- a/ELF/Config.h
+++ b/ELF/Config.h
@@ -145,6 +145,7 @@ struct Configuration {
bool ZNow;
bool ZOrigin;
bool ZRelro;
+ bool ZRodynamic;
bool ZText;
bool ExitEarly;
bool ZWxneeded;
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index 737c6a6bf1147..325404447b24b 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -572,10 +572,14 @@ static std::pair<bool, bool> getHashStyle(opt::InputArgList &Args) {
// -build-id=sha1 are actually tree hashes for performance reasons.
static std::pair<BuildIdKind, std::vector<uint8_t>>
getBuildId(opt::InputArgList &Args) {
- if (Args.hasArg(OPT_build_id))
+ auto *Arg = Args.getLastArg(OPT_build_id, OPT_build_id_eq);
+ if (!Arg)
+ return {BuildIdKind::None, {}};
+
+ if (Arg->getOption().getID() == OPT_build_id)
return {BuildIdKind::Fast, {}};
- StringRef S = getString(Args, OPT_build_id_eq, "none");
+ StringRef S = Arg->getValue();
if (S == "md5")
return {BuildIdKind::Md5, {}};
if (S == "sha1" || S == "tree")
@@ -688,6 +692,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->ZNow = hasZOption(Args, "now");
Config->ZOrigin = hasZOption(Args, "origin");
Config->ZRelro = !hasZOption(Args, "norelro");
+ Config->ZRodynamic = hasZOption(Args, "rodynamic");
Config->ZStackSize = getZOptionValue(Args, "stack-size", 0);
Config->ZText = !hasZOption(Args, "notext");
Config->ZWxneeded = hasZOption(Args, "wxneeded");
diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp
index 3722d4e3ed2f8..419ae68163282 100644
--- a/ELF/ICF.cpp
+++ b/ELF/ICF.cpp
@@ -326,9 +326,9 @@ void ICF<ELFT>::forEachClass(std::function<void(size_t, size_t)> Fn) {
size_t NumShards = 256;
size_t Step = Sections.size() / NumShards;
parallelForEachN(0, NumShards, [&](size_t I) {
- forEachClassRange(I * Step, (I + 1) * Step, Fn);
+ size_t End = (I == NumShards - 1) ? Sections.size() : (I + 1) * Step;
+ forEachClassRange(I * Step, End, Fn);
});
- forEachClassRange(Step * NumShards, Sections.size(), Fn);
++Cnt;
}
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index fe036a644f417..98189825ccbf6 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -281,18 +281,20 @@ bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
template <class ELFT>
void elf::ObjectFile<ELFT>::initializeSections(
DenseSet<CachedHashStringRef> &ComdatGroups) {
+ const ELFFile<ELFT> &Obj = this->getObj();
+
ArrayRef<Elf_Shdr> ObjSections =
check(this->getObj().sections(), toString(this));
- const ELFFile<ELFT> &Obj = this->getObj();
uint64_t Size = ObjSections.size();
this->Sections.resize(Size);
- unsigned I = -1;
+
StringRef SectionStringTable =
check(Obj.getSectionStringTable(ObjSections), toString(this));
- for (const Elf_Shdr &Sec : ObjSections) {
- ++I;
+
+ for (size_t I = 0, E = ObjSections.size(); I < E; I++) {
if (this->Sections[I] == &InputSection::Discarded)
continue;
+ const Elf_Shdr &Sec = ObjSections[I];
// SHF_EXCLUDE'ed sections are discarded by the linker. However,
// if -r is given, we'll let the final link discard such sections.
@@ -303,13 +305,22 @@ void elf::ObjectFile<ELFT>::initializeSections(
}
switch (Sec.sh_type) {
- case SHT_GROUP:
- this->Sections[I] = &InputSection::Discarded;
- if (ComdatGroups
- .insert(
- CachedHashStringRef(getShtGroupSignature(ObjSections, Sec)))
- .second)
+ case SHT_GROUP: {
+ // We discard comdat sections usually. When -r we should not do that. We
+ // still do deduplication in this case to simplify implementation, because
+ // otherwise merging group sections together would requre additional
+ // regeneration of its contents.
+ bool New = ComdatGroups
+ .insert(CachedHashStringRef(
+ getShtGroupSignature(ObjSections, Sec)))
+ .second;
+ if (New && Config->Relocatable)
+ this->Sections[I] = createInputSection(Sec, SectionStringTable);
+ else
+ this->Sections[I] = &InputSection::Discarded;
+ if (New)
continue;
+
for (uint32_t SecIndex : getShtGroupEntries(Sec)) {
if (SecIndex >= Size)
fatal(toString(this) +
@@ -317,6 +328,7 @@ void elf::ObjectFile<ELFT>::initializeSections(
this->Sections[SecIndex] = &InputSection::Discarded;
}
break;
+ }
case SHT_SYMTAB:
this->initSymtab(ObjSections, &Sec);
break;
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
index e8cfd21c4c49d..466656efbf085 100644
--- a/ELF/InputSection.cpp
+++ b/ELF/InputSection.cpp
@@ -23,6 +23,7 @@
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Threading.h"
#include <mutex>
using namespace llvm;
@@ -172,7 +173,8 @@ void InputSectionBase::uncompress() {
if (Error E = Dec.decompress({OutputBuf, Size}))
fatal(toString(this) +
": decompress failed: " + llvm::toString(std::move(E)));
- Data = ArrayRef<uint8_t>((uint8_t *)OutputBuf, Size);
+ this->Data = ArrayRef<uint8_t>((uint8_t *)OutputBuf, Size);
+ this->Flags &= ~(uint64_t)SHF_COMPRESSED;
}
uint64_t SectionBase::getOffset(const DefinedRegular &Sym) const {
@@ -293,6 +295,24 @@ bool InputSectionBase::classof(const SectionBase *S) {
return S->kind() != Output;
}
+void InputSection::copyShtGroup(uint8_t *Buf) {
+ assert(this->Type == SHT_GROUP);
+
+ ArrayRef<uint32_t> From = getDataAs<uint32_t>();
+ uint32_t *To = reinterpret_cast<uint32_t *>(Buf);
+
+ // First entry is a flag word, we leave it unchanged.
+ *To++ = From[0];
+
+ // Here we adjust indices of sections that belong to group as it
+ // might change during linking.
+ ArrayRef<InputSectionBase *> Sections = this->File->getSections();
+ for (uint32_t Val : From.slice(1)) {
+ uint32_t Index = read32(&Val, Config->Endianness);
+ write32(To++, Sections[Index]->OutSec->SectionIndex, Config->Endianness);
+ }
+}
+
InputSectionBase *InputSection::getRelocatedSection() {
assert(this->Type == SHT_RELA || this->Type == SHT_REL);
ArrayRef<InputSectionBase *> Sections = this->File->getSections();
@@ -678,6 +698,13 @@ template <class ELFT> void InputSection::writeTo(uint8_t *Buf) {
return;
}
+ // If -r is given, linker should keep SHT_GROUP sections. We should fixup
+ // them, see copyShtGroup().
+ if (this->Type == SHT_GROUP) {
+ copyShtGroup(Buf + OutSecOff);
+ return;
+ }
+
// Copy section contents from source object file to output file
// and then apply relocations.
memcpy(Buf + OutSecOff, Data.data(), Data.size());
@@ -866,7 +893,7 @@ const SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) const {
// it is not just an addition to a base output offset.
uint64_t MergeInputSection::getOffset(uint64_t Offset) const {
// Initialize OffsetMap lazily.
- std::call_once(InitOffsetMap, [&] {
+ llvm::call_once(InitOffsetMap, [&] {
OffsetMap.reserve(Pieces.size());
for (const SectionPiece &Piece : Pieces)
OffsetMap[Piece.InputOff] = Piece.OutputOff;
diff --git a/ELF/InputSection.h b/ELF/InputSection.h
index 303c398b58cd4..4ef4328e8a5d1 100644
--- a/ELF/InputSection.h
+++ b/ELF/InputSection.h
@@ -18,6 +18,7 @@
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Object/ELF.h"
+#include "llvm/Support/Threading.h"
#include <mutex>
namespace lld {
@@ -248,7 +249,7 @@ private:
std::vector<uint32_t> Hashes;
mutable llvm::DenseMap<uint64_t, uint64_t> OffsetMap;
- mutable std::once_flag InitOffsetMap;
+ mutable llvm::once_flag InitOffsetMap;
llvm::DenseSet<uint64_t> LiveOffsets;
};
@@ -318,6 +319,8 @@ public:
private:
template <class ELFT, class RelTy>
void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
+
+ void copyShtGroup(uint8_t *Buf);
};
// The list of all input sections.
diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp
index dd435173101a5..6915d9713891d 100644
--- a/ELF/LTO.cpp
+++ b/ELF/LTO.cpp
@@ -73,7 +73,12 @@ static std::unique_ptr<lto::LTO> createLTO() {
Conf.Options = InitTargetOptionsFromCodeGenFlags();
Conf.Options.RelaxELFRelocations = true;
- Conf.RelocModel = Config->Pic ? Reloc::PIC_ : Reloc::Static;
+ if (Config->Relocatable)
+ Conf.RelocModel = None;
+ else if (Config->Pic)
+ Conf.RelocModel = Reloc::PIC_;
+ else
+ Conf.RelocModel = Reloc::Static;
Conf.CodeModel = GetCodeModelFromCMModel();
Conf.DisableVerify = Config->DisableVerify;
Conf.DiagHandler = diagnosticHandler;
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index c303f0524ad44..492b81c1fa762 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -20,6 +20,8 @@
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
+#include "Target.h"
+#include "Threads.h"
#include "Writer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
@@ -198,6 +200,15 @@ bool OutputSectionCommand::classof(const BaseCommand *C) {
return C->Kind == OutputSectionKind;
}
+// Fill [Buf, Buf + Size) with Filler.
+// This is used for linker script "=fillexp" command.
+static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) {
+ size_t I = 0;
+ for (; I + 4 < Size; I += 4)
+ memcpy(Buf + I, &Filler, 4);
+ memcpy(Buf + I, &Filler, Size - I);
+}
+
bool InputSectionDescription::classof(const BaseCommand *C) {
return C->Kind == InputSectionKind;
}
@@ -263,16 +274,16 @@ static bool matchConstraints(ArrayRef<InputSectionBase *> Sections,
(!IsRW && Kind == ConstraintKind::ReadOnly);
}
-static void sortSections(InputSectionBase **Begin, InputSectionBase **End,
+static void sortSections(InputSection **Begin, InputSection **End,
SortSectionPolicy K) {
if (K != SortSectionPolicy::Default && K != SortSectionPolicy::None)
std::stable_sort(Begin, End, getComparator(K));
}
// Compute and remember which sections the InputSectionDescription matches.
-std::vector<InputSectionBase *>
+std::vector<InputSection *>
LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
- std::vector<InputSectionBase *> Ret;
+ std::vector<InputSection *> Ret;
// Collects all sections that satisfy constraints of Cmd.
for (const SectionPattern &Pat : Cmd->SectionPatterns) {
@@ -294,7 +305,7 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
!Pat.SectionPat.match(Sec->Name))
continue;
- Ret.push_back(Sec);
+ Ret.push_back(cast<InputSection>(Sec));
Sec->Assigned = true;
}
@@ -309,8 +320,8 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
// --sort-section is handled as an inner SORT command.
// 3. If one SORT command is given, and if it is SORT_NONE, don't sort.
// 4. If no SORT command is given, sort according to --sort-section.
- InputSectionBase **Begin = Ret.data() + SizeBefore;
- InputSectionBase **End = Ret.data() + Ret.size();
+ InputSection **Begin = Ret.data() + SizeBefore;
+ InputSection **End = Ret.data() + Ret.size();
if (Pat.SortOuter != SortSectionPolicy::None) {
if (Pat.SortInner == SortSectionPolicy::Default)
sortSections(Begin, End, Config->SortSection);
@@ -493,7 +504,7 @@ void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
Sec->SectionIndex = Index;
}
auto *ISD = make<InputSectionDescription>("");
- ISD->Sections.push_back(S);
+ ISD->Sections.push_back(cast<InputSection>(S));
Cmd->Commands.push_back(ISD);
}
}
@@ -684,7 +695,6 @@ void LinkerScript::adjustSectionsBeforeSorting() {
// '.' is assigned to, but creating these section should not have any bad
// consequeces and gives us a section to put the symbol in.
uint64_t Flags = SHF_ALLOC;
- uint32_t Type = SHT_PROGBITS;
for (int I = 0, E = Opt.Commands.size(); I != E; ++I) {
auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I]);
@@ -692,14 +702,13 @@ void LinkerScript::adjustSectionsBeforeSorting() {
continue;
if (OutputSection *Sec = Cmd->Sec) {
Flags = Sec->Flags;
- Type = Sec->Type;
continue;
}
if (isAllSectionDescription(*Cmd))
continue;
- auto *OutSec = make<OutputSection>(Cmd->Name, Type, Flags);
+ auto *OutSec = make<OutputSection>(Cmd->Name, SHT_PROGBITS, Flags);
OutSec->SectionIndex = I;
OutputSections->push_back(OutSec);
Cmd->Sec = OutSec;
@@ -875,20 +884,20 @@ void LinkerScript::synchronize() {
if (!Cmd)
continue;
ArrayRef<InputSection *> Sections = Cmd->Sec->Sections;
- std::vector<InputSectionBase **> ScriptSections;
- DenseSet<InputSectionBase *> ScriptSectionsSet;
+ std::vector<InputSection **> ScriptSections;
+ DenseSet<InputSection *> ScriptSectionsSet;
for (BaseCommand *Base : Cmd->Commands) {
auto *ISD = dyn_cast<InputSectionDescription>(Base);
if (!ISD)
continue;
- for (InputSectionBase *&IS : ISD->Sections) {
+ for (InputSection *&IS : ISD->Sections) {
if (IS->Live) {
ScriptSections.push_back(&IS);
ScriptSectionsSet.insert(IS);
}
}
}
- std::vector<InputSectionBase *> Missing;
+ std::vector<InputSection *> Missing;
for (InputSection *IS : Sections)
if (!ScriptSectionsSet.count(IS))
Missing.push_back(IS);
@@ -896,7 +905,7 @@ void LinkerScript::synchronize() {
auto ISD = make<InputSectionDescription>("");
ISD->Sections = Missing;
Cmd->Commands.push_back(ISD);
- for (InputSectionBase *&IS : ISD->Sections)
+ for (InputSection *&IS : ISD->Sections)
if (IS->Live)
ScriptSections.push_back(&IS);
}
@@ -1034,10 +1043,12 @@ OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const {
return I->second;
}
-Optional<uint32_t> LinkerScript::getFiller(OutputSection *Sec) {
- if (OutputSectionCommand *Cmd = getCmd(Sec))
- return Cmd->Filler;
- return None;
+uint32_t OutputSectionCommand::getFiller() {
+ if (Filler)
+ return *Filler;
+ if (Sec->Flags & SHF_EXECINSTR)
+ return Target->TrapInstr;
+ return 0;
}
static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
@@ -1053,11 +1064,45 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
llvm_unreachable("unsupported Size argument");
}
-void LinkerScript::writeDataBytes(OutputSection *Sec, uint8_t *Buf) {
- if (OutputSectionCommand *Cmd = getCmd(Sec))
- for (BaseCommand *Base : Cmd->Commands)
- if (auto *Data = dyn_cast<BytesDataCommand>(Base))
- writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size);
+template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) {
+ Sec->Loc = Buf;
+
+ // We may have already rendered compressed content when using
+ // -compress-debug-sections option. Write it together with header.
+ if (!Sec->CompressedData.empty()) {
+ memcpy(Buf, Sec->ZDebugHeader.data(), Sec->ZDebugHeader.size());
+ memcpy(Buf + Sec->ZDebugHeader.size(), Sec->CompressedData.data(),
+ Sec->CompressedData.size());
+ return;
+ }
+
+ // Write leading padding.
+ ArrayRef<InputSection *> Sections = Sec->Sections;
+ uint32_t Filler = getFiller();
+ if (Filler)
+ fill(Buf, Sections.empty() ? Sec->Size : Sections[0]->OutSecOff, Filler);
+
+ parallelForEachN(0, Sections.size(), [=](size_t I) {
+ InputSection *IS = Sections[I];
+ IS->writeTo<ELFT>(Buf);
+
+ // Fill gaps between sections.
+ if (Filler) {
+ uint8_t *Start = Buf + IS->OutSecOff + IS->getSize();
+ uint8_t *End;
+ if (I + 1 == Sections.size())
+ End = Buf + Sec->Size;
+ else
+ End = Buf + Sections[I + 1]->OutSecOff;
+ fill(Start, End - Start, Filler);
+ }
+ });
+
+ // Linker scripts may have BYTE()-family commands with which you
+ // can write arbitrary bytes to the output. Process them if any.
+ for (BaseCommand *Base : Commands)
+ if (auto *Data = dyn_cast<BytesDataCommand>(Base))
+ writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size);
}
bool LinkerScript::hasLMA(OutputSection *Sec) {
@@ -1104,3 +1149,8 @@ size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) {
error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS");
return 0;
}
+
+template void OutputSectionCommand::writeTo<ELF32LE>(uint8_t *Buf);
+template void OutputSectionCommand::writeTo<ELF32BE>(uint8_t *Buf);
+template void OutputSectionCommand::writeTo<ELF64LE>(uint8_t *Buf);
+template void OutputSectionCommand::writeTo<ELF64BE>(uint8_t *Buf);
diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h
index d0a4d83d72b05..e56e569d4e72b 100644
--- a/ELF/LinkerScript.h
+++ b/ELF/LinkerScript.h
@@ -130,6 +130,9 @@ struct OutputSectionCommand : BaseCommand {
ConstraintKind Constraint = ConstraintKind::NoConstraint;
std::string Location;
std::string MemoryRegionName;
+
+ template <class ELFT> void writeTo(uint8_t *Buf);
+ uint32_t getFiller();
};
// This struct represents one section match pattern in SECTIONS() command.
@@ -157,7 +160,7 @@ struct InputSectionDescription : BaseCommand {
// will be associated with this InputSectionDescription.
std::vector<SectionPattern> SectionPatterns;
- std::vector<InputSectionBase *> Sections;
+ std::vector<InputSection *> Sections;
};
// Represents an ASSERT().
@@ -213,11 +216,10 @@ struct ScriptConfiguration {
class LinkerScript final {
llvm::DenseMap<OutputSection *, OutputSectionCommand *> SecToCommand;
- OutputSectionCommand *getCmd(OutputSection *Sec) const;
void assignSymbol(SymbolAssignment *Cmd, bool InSec);
void setDot(Expr E, const Twine &Loc, bool InSec);
- std::vector<InputSectionBase *>
+ std::vector<InputSection *>
computeInputSections(const InputSectionDescription *);
std::vector<InputSectionBase *>
@@ -244,6 +246,7 @@ class LinkerScript final {
MemoryRegion *CurMemRegion = nullptr;
public:
+ OutputSectionCommand *getCmd(OutputSection *Sec) const;
bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); }
uint64_t getDot() { return Dot; }
OutputSection *getOutputSection(const Twine &Loc, StringRef S);
@@ -263,7 +266,6 @@ public:
std::vector<PhdrEntry> createPhdrs();
bool ignoreInterpSection();
- llvm::Optional<uint32_t> getFiller(OutputSection *Sec);
bool hasLMA(OutputSection *Sec);
bool shouldKeep(InputSectionBase *S);
void assignOffsets(OutputSectionCommand *Cmd);
@@ -272,7 +274,6 @@ public:
void synchronize();
void assignAddresses(std::vector<PhdrEntry> &Phdrs);
- void writeDataBytes(OutputSection *Sec, uint8_t *Buf);
void addSymbol(SymbolAssignment *Cmd);
void processCommands(OutputSectionFactory &Factory);
diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp
index 7b82eceba02a5..806e99e3d9dd9 100644
--- a/ELF/MapFile.cpp
+++ b/ELF/MapFile.cpp
@@ -132,12 +132,17 @@ void elf::writeMapFile(llvm::ArrayRef<BaseCommand *> Script) {
OS << OSec->Name << '\n';
// Dump symbols for each input section.
- for (InputSection *IS : OSec->Sections) {
- writeHeader<ELFT>(OS, OSec->Addr + IS->OutSecOff, IS->getSize(),
- IS->Alignment);
- OS << indent(1) << toString(IS) << '\n';
- for (DefinedRegular *Sym : SectionSyms[IS])
- OS << SymStr[Sym] << '\n';
+ for (BaseCommand *Base : Cmd->Commands) {
+ auto *ISD = dyn_cast<InputSectionDescription>(Base);
+ if (!ISD)
+ continue;
+ for (InputSection *IS : ISD->Sections) {
+ writeHeader<ELFT>(OS, OSec->Addr + IS->OutSecOff, IS->getSize(),
+ IS->Alignment);
+ OS << indent(1) << toString(IS) << '\n';
+ for (DefinedRegular *Sym : SectionSyms[IS])
+ OS << SymStr[Sym] << '\n';
+ }
}
}
}
diff --git a/ELF/Options.td b/ELF/Options.td
index 65a0e72d23200..335c7ade6db22 100644
--- a/ELF/Options.td
+++ b/ELF/Options.td
@@ -313,6 +313,7 @@ def alias_o_output2 : Separate<["--"], "output">, Alias<o>;
def alias_pie_pic_executable: F<"pic-executable">, Alias<pie>;
def alias_print_map_M: Flag<["-"], "M">, Alias<print_map>;
def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>;
+def alias_reproduce_eq: J<"reproduce=">, Alias<reproduce>;
def alias_retain_symbols_file: S<"retain-symbols-file">, Alias<retain_symbols_file>;
def alias_rpath_R: JoinedOrSeparate<["-"], "R">, Alias<rpath>;
def alias_rpath_rpath: J<"rpath=">, Alias<rpath>;
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
index dcefd03766d79..d82fdcdc31ba0 100644
--- a/ELF/OutputSections.cpp
+++ b/ELF/OutputSections.cpp
@@ -103,7 +103,7 @@ template <class ELFT> void OutputSection::maybeCompress() {
// Write section contents to a temporary buffer and compress it.
std::vector<uint8_t> Buf(Size);
- writeTo<ELFT>(Buf.data());
+ Script->getCmd(this)->writeTo<ELFT>(Buf.data());
if (Error E = zlib::compress(toStringRef(Buf), CompressedData))
fatal("compress failed: " + llvm::toString(std::move(E)));
@@ -112,6 +112,19 @@ template <class ELFT> void OutputSection::maybeCompress() {
Flags |= SHF_COMPRESSED;
}
+template <class ELFT> static void finalizeShtGroup(OutputSection *Sec) {
+ // sh_link field for SHT_GROUP sections should contain the section index of
+ // the symbol table.
+ Sec->Link = InX::SymTab->OutSec->SectionIndex;
+
+ // sh_link then contain index of an entry in symbol table section which
+ // provides signature of the section group.
+ elf::ObjectFile<ELFT> *Obj = Sec->Sections[0]->getFile<ELFT>();
+ assert(Config->Relocatable && Sec->Sections.size() == 1);
+ ArrayRef<SymbolBody *> Symbols = Obj->getSymbols();
+ Sec->Info = InX::SymTab->getSymbolIndex(Symbols[Sec->Sections[0]->Info - 1]);
+}
+
template <class ELFT> void OutputSection::finalize() {
if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) {
std::sort(Sections.begin(), Sections.end(), compareByFilePosition);
@@ -126,6 +139,11 @@ template <class ELFT> void OutputSection::finalize() {
}
uint32_t Type = this->Type;
+ if (Type == SHT_GROUP) {
+ finalizeShtGroup<ELFT>(this);
+ return;
+ }
+
if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL))
return;
@@ -259,69 +277,6 @@ void OutputSection::sortCtorsDtors() {
std::stable_sort(Sections.begin(), Sections.end(), compCtors);
}
-// Fill [Buf, Buf + Size) with Filler.
-// This is used for linker script "=fillexp" command.
-static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) {
- size_t I = 0;
- for (; I + 4 < Size; I += 4)
- memcpy(Buf + I, &Filler, 4);
- memcpy(Buf + I, &Filler, Size - I);
-}
-
-uint32_t OutputSection::getFiller() {
- // Determine what to fill gaps between InputSections with, as specified by the
- // linker script. If nothing is specified and this is an executable section,
- // fall back to trap instructions to prevent bad diassembly and detect invalid
- // jumps to padding.
- if (Optional<uint32_t> Filler = Script->getFiller(this))
- return *Filler;
- if (Flags & SHF_EXECINSTR)
- return Target->TrapInstr;
- return 0;
-}
-
-template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) {
- Loc = Buf;
-
- // We may have already rendered compressed content when using
- // -compress-debug-sections option. Write it together with header.
- if (!CompressedData.empty()) {
- memcpy(Buf, ZDebugHeader.data(), ZDebugHeader.size());
- memcpy(Buf + ZDebugHeader.size(), CompressedData.data(),
- CompressedData.size());
- return;
- }
-
- // Write leading padding.
- uint32_t Filler = getFiller();
- if (Filler)
- fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler);
-
- parallelForEachN(0, Sections.size(), [=](size_t I) {
- InputSection *Sec = Sections[I];
- Sec->writeTo<ELFT>(Buf);
-
- // Fill gaps between sections.
- if (Filler) {
- uint8_t *Start = Buf + Sec->OutSecOff + Sec->getSize();
- uint8_t *End;
- if (I + 1 == Sections.size())
- End = Buf + Size;
- else
- End = Buf + Sections[I + 1]->OutSecOff;
- fill(Start, End - Start, Filler);
- }
- });
-
- // Linker scripts may have BYTE()-family commands with which you
- // can write arbitrary bytes to the output. Process them if any.
- Script->writeDataBytes(this, Buf);
-}
-
-static uint64_t getOutFlags(InputSectionBase *S) {
- return S->Flags & ~SHF_GROUP & ~SHF_COMPRESSED;
-}
-
static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) {
// The ELF spec just says
// ----------------------------------------------------------------
@@ -418,7 +373,10 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS,
return;
}
- uint64_t Flags = getOutFlags(IS);
+ uint64_t Flags = IS->Flags;
+ if (!Config->Relocatable)
+ Flags &= ~(uint64_t)SHF_GROUP;
+
if (Sec) {
if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags))
error("incompatible section flags for " + Sec->Name +
@@ -484,8 +442,3 @@ template void OutputSection::maybeCompress<ELF32LE>();
template void OutputSection::maybeCompress<ELF32BE>();
template void OutputSection::maybeCompress<ELF64LE>();
template void OutputSection::maybeCompress<ELF64BE>();
-
-template void OutputSection::writeTo<ELF32LE>(uint8_t *Buf);
-template void OutputSection::writeTo<ELF32BE>(uint8_t *Buf);
-template void OutputSection::writeTo<ELF64LE>(uint8_t *Buf);
-template void OutputSection::writeTo<ELF64BE>(uint8_t *Buf);
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h
index 413871b60cf70..08655a9ed67b5 100644
--- a/ELF/OutputSections.h
+++ b/ELF/OutputSections.h
@@ -82,8 +82,6 @@ public:
void sort(std::function<int(InputSectionBase *S)> Order);
void sortInitFini();
void sortCtorsDtors();
- uint32_t getFiller();
- template <class ELFT> void writeTo(uint8_t *Buf);
template <class ELFT> void finalize();
template <class ELFT> void maybeCompress();
void assignOffsets();
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp
index 599f1441a47fe..d3db32613a8a5 100644
--- a/ELF/SyntheticSections.cpp
+++ b/ELF/SyntheticSections.cpp
@@ -1005,10 +1005,11 @@ DynamicSection<ELFT>::DynamicSection()
".dynamic") {
this->Entsize = ELFT::Is64Bits ? 16 : 8;
- // .dynamic section is not writable on MIPS.
+ // .dynamic section is not writable on MIPS and on Fuchsia OS
+ // which passes -z rodynamic.
// 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)
+ if (Config->EMachine == EM_MIPS || Config->ZRodynamic)
this->Flags = SHF_ALLOC;
addEntries();
@@ -1053,7 +1054,15 @@ template <class ELFT> void DynamicSection<ELFT>::addEntries() {
if (DtFlags1)
add({DT_FLAGS_1, DtFlags1});
- if (!Config->Shared && !Config->Relocatable)
+ // DT_DEBUG is a pointer to debug informaion used by debuggers at runtime. We
+ // need it for each process, so we don't write it for DSOs. The loader writes
+ // the pointer into this entry.
+ //
+ // DT_DEBUG is the only .dynamic entry that needs to be written to. Some
+ // systems (currently only Fuchsia OS) provide other means to give the
+ // debugger this information. Such systems may choose make .dynamic read-only.
+ // If the target is such a system (used -z rodynamic) don't write DT_DEBUG.
+ if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic)
add({DT_DEBUG, (uint64_t)0});
}
@@ -1778,11 +1787,10 @@ void GdbIndexSection::readDwarf(InputSection *Sec) {
std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset);
if (IsNew) {
Sym->CuVectorIndex = CuVectors.size();
- CuVectors.push_back({{CuId, Pair.second}});
- continue;
+ CuVectors.resize(CuVectors.size() + 1);
}
- CuVectors[Sym->CuVectorIndex].push_back({CuId, Pair.second});
+ CuVectors[Sym->CuVectorIndex].insert((Pair.second << 24) | (uint32_t)CuId);
}
}
@@ -1806,7 +1814,7 @@ void GdbIndexSection::finalizeContents() {
ConstantPoolOffset =
SymTabOffset + SymbolTable.getCapacity() * SymTabEntrySize;
- for (std::vector<std::pair<uint32_t, uint8_t>> &CuVec : CuVectors) {
+ for (std::set<uint32_t> &CuVec : CuVectors) {
CuVectorsOffset.push_back(CuVectorsSize);
CuVectorsSize += OffsetTypeSize * (CuVec.size() + 1);
}
@@ -1859,14 +1867,11 @@ void GdbIndexSection::writeTo(uint8_t *Buf) {
}
// Write the CU vectors into the constant pool.
- for (std::vector<std::pair<uint32_t, uint8_t>> &CuVec : CuVectors) {
+ for (std::set<uint32_t> &CuVec : CuVectors) {
write32le(Buf, CuVec.size());
Buf += 4;
- for (std::pair<uint32_t, uint8_t> &P : CuVec) {
- uint32_t Index = P.first;
- uint8_t Flags = P.second;
- Index |= Flags << 24;
- write32le(Buf, Index);
+ for (uint32_t Val : CuVec) {
+ write32le(Buf, Val);
Buf += 4;
}
}
@@ -2173,17 +2178,6 @@ MipsRldMapSection::MipsRldMapSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize,
".rld_map") {}
-void MipsRldMapSection::writeTo(uint8_t *Buf) {
- // Apply filler from linker script.
- Optional<uint32_t> Fill = Script->getFiller(this->OutSec);
- if (!Fill || *Fill == 0)
- return;
-
- uint64_t Filler = *Fill;
- Filler = (Filler << 32) | Filler;
- memcpy(Buf, &Filler, getSize());
-}
-
ARMExidxSentinelSection::ARMExidxSentinelSection()
: SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX,
Config->Wordsize, ".ARM.exidx") {}
@@ -2194,7 +2188,7 @@ ARMExidxSentinelSection::ARMExidxSentinelSection()
// | PREL31 upper bound of code that has exception tables | EXIDX_CANTUNWIND |
void ARMExidxSentinelSection::writeTo(uint8_t *Buf) {
// Get the InputSection before us, we are by definition last
- auto RI = cast<OutputSection>(this->OutSec)->Sections.rbegin();
+ auto RI = this->OutSec->Sections.rbegin();
InputSection *LE = *(++RI);
InputSection *LC = cast<InputSection>(LE->getLinkOrderDep());
uint64_t S = LC->OutSec->Addr + LC->getOffset(LC->getSize());
diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h
index c5ffb88c13666..61cc03de222eb 100644
--- a/ELF/SyntheticSections.h
+++ b/ELF/SyntheticSections.h
@@ -27,6 +27,8 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/MC/StringTableBuilder.h"
+#include <set>
+
namespace lld {
namespace elf {
@@ -515,7 +517,7 @@ public:
GdbHashTab SymbolTable;
// The CU vector portion of the constant pool.
- std::vector<std::vector<std::pair<uint32_t, uint8_t>>> CuVectors;
+ std::vector<std::set<uint32_t>> CuVectors;
std::vector<AddressEntry> AddressArea;
@@ -709,7 +711,7 @@ class MipsRldMapSection : public SyntheticSection {
public:
MipsRldMapSection();
size_t getSize() const override { return Config->Wordsize; }
- void writeTo(uint8_t *Buf) override;
+ void writeTo(uint8_t *Buf) override {}
};
class ARMExidxSentinelSection : public SyntheticSection {
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index 7a21d2b9f13da..e539d8ffce6ee 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -46,6 +46,7 @@ public:
void run();
private:
+ void clearOutputSections();
void createSyntheticSections();
void copyLocalSymbols();
void addSectionSymbols();
@@ -80,6 +81,8 @@ private:
void addStartStopSymbols(OutputSection *Sec);
uint64_t getEntryAddr();
OutputSection *findSection(StringRef Name);
+ OutputSection *findSectionInScript(StringRef Name);
+ OutputSectionCommand *findSectionCommand(StringRef Name);
std::vector<PhdrEntry> Phdrs;
@@ -161,7 +164,7 @@ static void combineMergableSections() {
continue;
StringRef OutsecName = getOutputSectionName(MS->Name);
- uint64_t Flags = MS->Flags & ~(uint64_t)(SHF_GROUP | SHF_COMPRESSED);
+ uint64_t Flags = MS->Flags & ~(uint64_t)SHF_GROUP;
uint32_t Alignment = std::max<uint32_t>(MS->Alignment, MS->Entsize);
auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) {
@@ -198,6 +201,15 @@ template <class ELFT> static void combineEhFrameSections() {
V.erase(std::remove(V.begin(), V.end(), nullptr), V.end());
}
+template <class ELFT> void Writer<ELFT>::clearOutputSections() {
+ // Clear the OutputSections to make sure it is not used anymore. Any
+ // code from this point on should be using the linker script
+ // commands.
+ for (OutputSection *Sec : OutputSections)
+ Sec->Sections.clear();
+ OutputSections.clear();
+}
+
// The main function of the writer.
template <class ELFT> void Writer<ELFT>::run() {
// Create linker-synthesized sections such as .got or .plt.
@@ -244,13 +256,21 @@ template <class ELFT> void Writer<ELFT>::run() {
if (ErrorCount)
return;
+ if (!Script->Opt.HasSections) {
+ if (!Config->Relocatable)
+ fixSectionAlignments();
+ Script->fabricateDefaultCommands();
+ }
+
+ // If -compressed-debug-sections is specified, we need to compress
+ // .debug_* sections. Do it right now because it changes the size of
+ // output sections.
+ parallelForEach(OutputSections.begin(), OutputSections.end(),
+ [](OutputSection *S) { S->maybeCompress<ELFT>(); });
+
if (Config->Relocatable) {
assignFileOffsets();
} else {
- if (!Script->Opt.HasSections) {
- fixSectionAlignments();
- Script->fabricateDefaultCommands();
- }
Script->synchronize();
Script->assignAddresses(Phdrs);
@@ -281,6 +301,7 @@ template <class ELFT> void Writer<ELFT>::run() {
} else {
writeSectionsBinary();
}
+ clearOutputSections();
// Backfill .note.gnu.build-id section content. This is done at last
// because the content is usually a hash value of the entire output file.
@@ -288,10 +309,6 @@ template <class ELFT> void Writer<ELFT>::run() {
if (ErrorCount)
return;
- // Clear the OutputSections to make sure it is not used anymore. Any
- // code from this point on should be using the linker script
- // commands.
- OutputSections.clear();
// Handle -Map option.
writeMapFile<ELFT>(Script->Opt.Commands);
@@ -631,10 +648,11 @@ bool elf::isRelroSection(const OutputSection *Sec) {
// * It is easy to check if a give branch was taken.
// * It is easy two see how similar two ranks are (see getRankProximity).
enum RankFlags {
- RF_NOT_ADDR_SET = 1 << 15,
- RF_NOT_INTERP = 1 << 14,
- RF_NOT_ALLOC = 1 << 13,
- RF_WRITE = 1 << 12,
+ RF_NOT_ADDR_SET = 1 << 16,
+ RF_NOT_INTERP = 1 << 15,
+ RF_NOT_ALLOC = 1 << 14,
+ RF_WRITE = 1 << 13,
+ RF_EXEC_WRITE = 1 << 12,
RF_EXEC = 1 << 11,
RF_NON_TLS_BSS = 1 << 10,
RF_NON_TLS_BSS_RO = 1 << 9,
@@ -669,19 +687,29 @@ static unsigned getSectionRank(const OutputSection *Sec) {
if (!(Sec->Flags & SHF_ALLOC))
return Rank | RF_NOT_ALLOC;
- // 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.
- if (Sec->Flags & SHF_WRITE)
- Rank |= RF_WRITE;
-
- if (Sec->Flags & SHF_EXECINSTR) {
- // For a corresponding reason, put non exec sections first (the program
- // header PT_LOAD is not executable).
- // We only do that if we are not using linker scripts, since with linker
- // scripts ro and rx sections are in the same PT_LOAD, so their relative
- // order is not important. The same applies for -no-rosegment.
- if ((Rank & RF_WRITE) || !Config->SingleRoRx)
+ // Sort sections based on their access permission in the following
+ // order: R, RX, RWX, RW. This order is based on the following
+ // considerations:
+ // * Read-only sections come first such that they go in the
+ // PT_LOAD covering the program headers at the start of the file.
+ // * Read-only, executable sections come next, unless the
+ // -no-rosegment option is used.
+ // * Writable, executable sections follow such that .plt on
+ // architectures where it needs to be writable will be placed
+ // between .text and .data.
+ // * Writable sections come last, such that .bss lands at the very
+ // end of the last PT_LOAD.
+ bool IsExec = Sec->Flags & SHF_EXECINSTR;
+ bool IsWrite = Sec->Flags & SHF_WRITE;
+
+ if (IsExec) {
+ if (IsWrite)
+ Rank |= RF_EXEC_WRITE;
+ else if (!Config->SingleRoRx)
Rank |= RF_EXEC;
+ } else {
+ if (IsWrite)
+ Rank |= RF_WRITE;
}
// If we got here we know that both A and B are in the same PT_LOAD.
@@ -778,12 +806,6 @@ static bool compareSections(const OutputSection *A, const OutputSection *B) {
return compareSectionsNonScript(A, B);
}
-// Program header entry
-PhdrEntry::PhdrEntry(unsigned Type, unsigned Flags) {
- p_type = Type;
- p_flags = Flags;
-}
-
void PhdrEntry::add(OutputSection *Sec) {
Last = Sec;
if (!First)
@@ -1239,12 +1261,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
for (OutputSection *Sec : OutputSections)
Sec->finalize<ELFT>();
- // If -compressed-debug-sections is specified, we need to compress
- // .debug_* sections. Do it right now because it changes the size of
- // output sections.
- parallelForEach(OutputSections.begin(), OutputSections.end(),
- [](OutputSection *S) { S->maybeCompress<ELFT>(); });
-
// createThunks may have added local symbols to the static symbol table
applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab},
[](SyntheticSection *SS) { SS->postThunkContents(); });
@@ -1297,6 +1313,21 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) {
addOptionalRegular<ELFT>(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT);
}
+template <class ELFT>
+OutputSectionCommand *Writer<ELFT>::findSectionCommand(StringRef Name) {
+ for (BaseCommand *Base : Script->Opt.Commands)
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+ if (Cmd->Name == Name)
+ return Cmd;
+ return nullptr;
+}
+
+template <class ELFT> OutputSection *Writer<ELFT>::findSectionInScript(StringRef Name) {
+ if (OutputSectionCommand *Cmd = findSectionCommand(Name))
+ return Cmd->Sec;
+ return nullptr;
+}
+
template <class ELFT> OutputSection *Writer<ELFT>::findSection(StringRef Name) {
for (OutputSection *Sec : OutputSections)
if (Sec->Name == Name)
@@ -1583,7 +1614,7 @@ template <class ELFT> uint64_t Writer<ELFT>::getEntryAddr() {
return Addr;
// Case 4
- if (OutputSection *Sec = findSection(".text")) {
+ if (OutputSection *Sec = findSectionInScript(".text")) {
if (Config->WarnMissingEntry)
warn("cannot find entry symbol " + Config->Entry + "; defaulting to 0x" +
utohexstr(Sec->Addr));
@@ -1609,18 +1640,6 @@ static uint16_t getELFType() {
// to each section. This function fixes some predefined
// symbol values that depend on section address and size.
template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() {
- auto Set = [](DefinedRegular *S1, DefinedRegular *S2, OutputSection *Sec,
- uint64_t Value) {
- if (S1) {
- S1->Section = Sec;
- S1->Value = Value;
- }
- if (S2) {
- S2->Section = Sec;
- S2->Value = Value;
- }
- };
-
// _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.
@@ -1636,15 +1655,29 @@ template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() {
else
LastRO = &P;
}
- if (Last)
- Set(ElfSym::End1, ElfSym::End2, Last->First, Last->p_memsz);
- if (LastRO)
- Set(ElfSym::Etext1, ElfSym::Etext2, LastRO->First, LastRO->p_filesz);
- if (LastRW)
- Set(ElfSym::Edata1, ElfSym::Edata2, LastRW->First, LastRW->p_filesz);
+
+ auto Set = [](DefinedRegular *S, OutputSection *Sec, uint64_t Value) {
+ if (S) {
+ S->Section = Sec;
+ S->Value = Value;
+ }
+ };
+
+ if (Last) {
+ Set(ElfSym::End1, Last->First, Last->p_memsz);
+ Set(ElfSym::End2, Last->First, Last->p_memsz);
+ }
+ if (LastRO) {
+ Set(ElfSym::Etext1, LastRO->First, LastRO->p_filesz);
+ Set(ElfSym::Etext2, LastRO->First, LastRO->p_filesz);
+ }
+ if (LastRW) {
+ Set(ElfSym::Edata1, LastRW->First, LastRW->p_filesz);
+ Set(ElfSym::Edata2, LastRW->First, LastRW->p_filesz);
+ }
if (ElfSym::Bss)
- ElfSym::Bss->Section = findSection(".bss");
+ ElfSym::Bss->Section = findSectionInScript(".bss");
// Setup MIPS _gp_disp/__gnu_local_gp symbols which should
// be equal to the _gp symbol's value.
@@ -1736,9 +1769,14 @@ template <class ELFT> void Writer<ELFT>::openFile() {
template <class ELFT> void Writer<ELFT>::writeSectionsBinary() {
uint8_t *Buf = Buffer->getBufferStart();
- for (OutputSection *Sec : OutputSections)
+ for (BaseCommand *Base : Script->Opt.Commands) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
+ if (!Cmd)
+ continue;
+ OutputSection *Sec = Cmd->Sec;
if (Sec->Flags & SHF_ALLOC)
- Sec->writeTo<ELFT>(Buf + Sec->Offset);
+ Cmd->writeTo<ELFT>(Buf + Sec->Offset);
+ }
}
// Write section contents to a mmap'ed file.
@@ -1747,31 +1785,45 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
// PPC64 needs to process relocations in the .opd section
// before processing relocations in code-containing sections.
- Out::Opd = findSection(".opd");
- if (Out::Opd) {
+ if (auto *OpdCmd = findSectionCommand(".opd")) {
+ Out::Opd = OpdCmd->Sec;
Out::OpdBuf = Buf + Out::Opd->Offset;
- Out::Opd->template writeTo<ELFT>(Buf + Out::Opd->Offset);
+ OpdCmd->template writeTo<ELFT>(Buf + Out::Opd->Offset);
}
OutputSection *EhFrameHdr =
- In<ELFT>::EhFrameHdr ? In<ELFT>::EhFrameHdr->OutSec : nullptr;
+ (In<ELFT>::EhFrameHdr && !In<ELFT>::EhFrameHdr->empty())
+ ? In<ELFT>::EhFrameHdr->OutSec
+ : nullptr;
// In -r or -emit-relocs mode, write the relocation sections first as in
// ELf_Rel targets we might find out that we need to modify the relocated
// section while doing it.
- for (OutputSection *Sec : OutputSections)
+ for (BaseCommand *Base : Script->Opt.Commands) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
+ if (!Cmd)
+ continue;
+ OutputSection *Sec = Cmd->Sec;
if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA)
- Sec->writeTo<ELFT>(Buf + Sec->Offset);
+ Cmd->writeTo<ELFT>(Buf + Sec->Offset);
+ }
- for (OutputSection *Sec : OutputSections)
+ for (BaseCommand *Base : Script->Opt.Commands) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
+ if (!Cmd)
+ continue;
+ OutputSection *Sec = Cmd->Sec;
if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL &&
Sec->Type != SHT_RELA)
- Sec->writeTo<ELFT>(Buf + Sec->Offset);
+ Cmd->writeTo<ELFT>(Buf + Sec->Offset);
+ }
// The .eh_frame_hdr depends on .eh_frame section contents, therefore
// it should be written after .eh_frame is written.
- if (EhFrameHdr && !EhFrameHdr->Sections.empty())
- EhFrameHdr->writeTo<ELFT>(Buf + EhFrameHdr->Offset);
+ if (EhFrameHdr) {
+ OutputSectionCommand *Cmd = Script->getCmd(EhFrameHdr);
+ Cmd->writeTo<ELFT>(Buf + EhFrameHdr->Offset);
+ }
}
template <class ELFT> void Writer<ELFT>::writeBuildId() {
diff --git a/ELF/Writer.h b/ELF/Writer.h
index 17fbda394a204..e935b6419de67 100644
--- a/ELF/Writer.h
+++ b/ELF/Writer.h
@@ -30,7 +30,7 @@ bool isRelroSection(const OutputSection *Sec);
// Each contains type, access flags and range of output sections that will be
// placed in it.
struct PhdrEntry {
- PhdrEntry(unsigned Type, unsigned Flags);
+ PhdrEntry(unsigned Type, unsigned Flags) : p_type(Type), p_flags(Flags) {}
void add(OutputSection *Sec);
uint64_t p_paddr = 0;