diff options
Diffstat (limited to 'ELF')
-rw-r--r-- | ELF/Config.h | 1 | ||||
-rw-r--r-- | ELF/Driver.cpp | 9 | ||||
-rw-r--r-- | ELF/ICF.cpp | 4 | ||||
-rw-r--r-- | ELF/InputFiles.cpp | 32 | ||||
-rw-r--r-- | ELF/InputSection.cpp | 31 | ||||
-rw-r--r-- | ELF/InputSection.h | 5 | ||||
-rw-r--r-- | ELF/LTO.cpp | 7 | ||||
-rw-r--r-- | ELF/LinkerScript.cpp | 98 | ||||
-rw-r--r-- | ELF/LinkerScript.h | 11 | ||||
-rw-r--r-- | ELF/MapFile.cpp | 17 | ||||
-rw-r--r-- | ELF/Options.td | 1 | ||||
-rw-r--r-- | ELF/OutputSections.cpp | 93 | ||||
-rw-r--r-- | ELF/OutputSections.h | 2 | ||||
-rw-r--r-- | ELF/SyntheticSections.cpp | 44 | ||||
-rw-r--r-- | ELF/SyntheticSections.h | 6 | ||||
-rw-r--r-- | ELF/Writer.cpp | 190 | ||||
-rw-r--r-- | ELF/Writer.h | 2 |
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; |