aboutsummaryrefslogtreecommitdiff
path: root/ELF/Writer.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-07-23 20:48:50 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-07-23 20:48:50 +0000
commit1c98619801a5705c688e683be3ef9d70169a0686 (patch)
tree8422105cd1a94c368315f2db16b9ac746cf7c000 /ELF/Writer.cpp
parentf4f3ce4613680903220815690ad79fc7ba0a2e26 (diff)
downloadsrc-1c98619801a5705c688e683be3ef9d70169a0686.tar.gz
src-1c98619801a5705c688e683be3ef9d70169a0686.zip
Vendor import of lld release_39 branch r276489:vendor/lld/lld-release_39-r276489
Notes
Notes: svn path=/vendor/lld/dist/; revision=303239 svn path=/vendor/lld/lld-release_39-r276489/; revision=303240; tag=vendor/lld/lld-release_39-r276489
Diffstat (limited to 'ELF/Writer.cpp')
-rw-r--r--ELF/Writer.cpp1564
1 files changed, 769 insertions, 795 deletions
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index fbecfc601ac1..387bec3d8fb2 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -9,362 +9,353 @@
#include "Writer.h"
#include "Config.h"
+#include "LinkerScript.h"
#include "OutputSections.h"
+#include "Relocations.h"
+#include "Strings.h"
#include "SymbolTable.h"
#include "Target.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace lld;
-using namespace lld::elf2;
+using namespace lld::elf;
namespace {
// The writer writes a SymbolTable result to a file.
template <class ELFT> class Writer {
public:
- typedef typename ELFFile<ELFT>::uintX_t uintX_t;
- typedef typename ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
- typedef typename ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr;
- typedef typename ELFFile<ELFT>::Elf_Phdr Elf_Phdr;
- typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
- typedef typename ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
- typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
+ typedef typename ELFT::uint uintX_t;
+ typedef typename ELFT::Shdr Elf_Shdr;
+ typedef typename ELFT::Ehdr Elf_Ehdr;
+ typedef typename ELFT::Phdr Elf_Phdr;
+ typedef typename ELFT::Sym Elf_Sym;
+ typedef typename ELFT::SymRange Elf_Sym_Range;
+ typedef typename ELFT::Rela Elf_Rela;
Writer(SymbolTable<ELFT> &S) : Symtab(S) {}
void run();
private:
+ // This describes a program header entry.
+ // Each contains type, access flags and range of output sections that will be
+ // placed in it.
+ struct Phdr {
+ Phdr(unsigned Type, unsigned Flags) {
+ H.p_type = Type;
+ H.p_flags = Flags;
+ }
+ Elf_Phdr H = {};
+ OutputSectionBase<ELFT> *First = nullptr;
+ OutputSectionBase<ELFT> *Last = nullptr;
+ };
+
void copyLocalSymbols();
void addReservedSymbols();
void createSections();
void addPredefinedSections();
+ bool needsGot();
- template <bool isRela>
- void scanRelocs(InputSectionBase<ELFT> &C,
- iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels);
-
- void scanRelocs(InputSection<ELFT> &C);
- void scanRelocs(InputSectionBase<ELFT> &S, const Elf_Shdr &RelSec);
- void updateRelro(Elf_Phdr *Cur, Elf_Phdr *GnuRelroPhdr, uintX_t VA);
+ void createPhdrs();
void assignAddresses();
- void buildSectionMap();
+ void assignFileOffsets();
+ void setPhdrs();
+ void fixHeaders();
+ void fixSectionAlignments();
void fixAbsoluteSymbols();
- void openFile(StringRef OutputPath);
+ void openFile();
void writeHeader();
void writeSections();
- bool isDiscarded(InputSectionBase<ELFT> *IS) const;
- StringRef getOutputSectionName(StringRef S) const;
+ void writeBuildId();
bool needsInterpSection() const {
return !Symtab.getSharedFiles().empty() && !Config->DynamicLinker.empty();
}
bool isOutputDynamic() const {
- return !Symtab.getSharedFiles().empty() || Config->Shared;
+ return !Symtab.getSharedFiles().empty() || Config->Pic;
}
- int getPhdrsNum() const;
- OutputSection<ELFT> *getBss();
void addCommonSymbols(std::vector<DefinedCommon *> &Syms);
- void addCopyRelSymbols(std::vector<SharedSymbol<ELFT> *> &Syms);
- std::unique_ptr<llvm::FileOutputBuffer> Buffer;
+ std::unique_ptr<FileOutputBuffer> Buffer;
BumpPtrAllocator Alloc;
std::vector<OutputSectionBase<ELFT> *> OutputSections;
std::vector<std::unique_ptr<OutputSectionBase<ELFT>>> OwningSections;
- unsigned getNumSections() const { return OutputSections.size() + 1; }
void addRelIpltSymbols();
void addStartEndSymbols();
void addStartStopSymbols(OutputSectionBase<ELFT> *Sec);
- void setPhdr(Elf_Phdr *PH, uint32_t Type, uint32_t Flags, uintX_t FileOff,
- uintX_t VA, uintX_t Size, uintX_t Align);
- void copyPhdr(Elf_Phdr *PH, OutputSectionBase<ELFT> *From);
- bool HasRelro = false;
SymbolTable<ELFT> &Symtab;
- std::vector<Elf_Phdr> Phdrs;
+ std::vector<Phdr> Phdrs;
uintX_t FileSize;
uintX_t SectionHeaderOff;
-
- llvm::StringMap<llvm::StringRef> InputToOutputSection;
};
} // anonymous namespace
-template <class ELFT> static bool shouldUseRela() { return ELFT::Is64Bits; }
+template <class ELFT>
+StringRef elf::getOutputSectionName(InputSectionBase<ELFT> *S) {
+ StringRef Dest = Script<ELFT>::X->getOutputSection(S);
+ if (!Dest.empty())
+ return Dest;
+
+ StringRef Name = S->getSectionName();
+ for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.",
+ ".init_array.", ".fini_array.", ".ctors.", ".dtors.",
+ ".tbss.", ".gcc_except_table.", ".tdata."})
+ if (Name.startswith(V))
+ return V.drop_back();
+ return Name;
+}
-template <class ELFT> void elf2::writeResult(SymbolTable<ELFT> *Symtab) {
- // Initialize output sections that are handled by Writer specially.
- // Don't reorder because the order of initialization matters.
- InterpSection<ELFT> Interp;
- Out<ELFT>::Interp = &Interp;
- StringTableSection<ELFT> ShStrTab(".shstrtab", false);
- Out<ELFT>::ShStrTab = &ShStrTab;
- StringTableSection<ELFT> StrTab(".strtab", false);
- if (!Config->StripAll)
- Out<ELFT>::StrTab = &StrTab;
- StringTableSection<ELFT> DynStrTab(".dynstr", true);
- Out<ELFT>::DynStrTab = &DynStrTab;
+template <class ELFT>
+void elf::reportDiscarded(InputSectionBase<ELFT> *IS,
+ const std::unique_ptr<elf::ObjectFile<ELFT>> &File) {
+ if (!Config->PrintGcSections || !IS || IS->Live)
+ return;
+ errs() << "removing unused section from '" << IS->getSectionName()
+ << "' in file '" << File->getName() << "'\n";
+}
+
+template <class ELFT> void elf::writeResult(SymbolTable<ELFT> *Symtab) {
+ typedef typename ELFT::uint uintX_t;
+ typedef typename ELFT::Ehdr Elf_Ehdr;
+
+ // Create singleton output sections.
+ OutputSection<ELFT> Bss(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
+ DynamicSection<ELFT> Dynamic;
+ EhOutputSection<ELFT> EhFrame;
GotSection<ELFT> Got;
- Out<ELFT>::Got = &Got;
- GotPltSection<ELFT> GotPlt;
- if (Target->supportsLazyRelocations())
- Out<ELFT>::GotPlt = &GotPlt;
+ InterpSection<ELFT> Interp;
PltSection<ELFT> Plt;
- Out<ELFT>::Plt = &Plt;
- std::unique_ptr<SymbolTableSection<ELFT>> SymTab;
+ RelocationSection<ELFT> RelaDyn(Config->Rela ? ".rela.dyn" : ".rel.dyn",
+ Config->ZCombreloc);
+ StringTableSection<ELFT> DynStrTab(".dynstr", true);
+ StringTableSection<ELFT> ShStrTab(".shstrtab", false);
+ SymbolTableSection<ELFT> DynSymTab(DynStrTab);
+ VersionTableSection<ELFT> VerSym;
+ VersionNeedSection<ELFT> VerNeed;
+
+ OutputSectionBase<ELFT> ElfHeader("", 0, SHF_ALLOC);
+ ElfHeader.setSize(sizeof(Elf_Ehdr));
+ OutputSectionBase<ELFT> ProgramHeaders("", 0, SHF_ALLOC);
+ ProgramHeaders.updateAlignment(sizeof(uintX_t));
+
+ // Instantiate optional output sections if they are needed.
+ std::unique_ptr<BuildIdSection<ELFT>> BuildId;
+ std::unique_ptr<EhFrameHeader<ELFT>> EhFrameHdr;
+ std::unique_ptr<GnuHashTableSection<ELFT>> GnuHashTab;
+ std::unique_ptr<GotPltSection<ELFT>> GotPlt;
+ std::unique_ptr<HashTableSection<ELFT>> HashTab;
+ std::unique_ptr<RelocationSection<ELFT>> RelaPlt;
+ std::unique_ptr<StringTableSection<ELFT>> StrTab;
+ std::unique_ptr<SymbolTableSection<ELFT>> SymTabSec;
+ std::unique_ptr<OutputSection<ELFT>> MipsRldMap;
+ std::unique_ptr<VersionDefinitionSection<ELFT>> VerDef;
+
+ if (Config->BuildId == BuildIdKind::Fnv1)
+ BuildId.reset(new BuildIdFnv1<ELFT>);
+ else if (Config->BuildId == BuildIdKind::Md5)
+ BuildId.reset(new BuildIdMd5<ELFT>);
+ else if (Config->BuildId == BuildIdKind::Sha1)
+ BuildId.reset(new BuildIdSha1<ELFT>);
+ else if (Config->BuildId == BuildIdKind::Hexstring)
+ BuildId.reset(new BuildIdHexstring<ELFT>);
+
+ if (Config->EhFrameHdr)
+ EhFrameHdr.reset(new EhFrameHeader<ELFT>);
+
+ if (Config->GnuHash)
+ GnuHashTab.reset(new GnuHashTableSection<ELFT>);
+ if (Config->SysvHash)
+ HashTab.reset(new HashTableSection<ELFT>);
+ StringRef S = Config->Rela ? ".rela.plt" : ".rel.plt";
+ GotPlt.reset(new GotPltSection<ELFT>);
+ RelaPlt.reset(new RelocationSection<ELFT>(S, false /*Sort*/));
if (!Config->StripAll) {
- SymTab.reset(new SymbolTableSection<ELFT>(*Symtab, *Out<ELFT>::StrTab));
- Out<ELFT>::SymTab = SymTab.get();
+ StrTab.reset(new StringTableSection<ELFT>(".strtab", false));
+ SymTabSec.reset(new SymbolTableSection<ELFT>(*StrTab));
}
- SymbolTableSection<ELFT> DynSymTab(*Symtab, *Out<ELFT>::DynStrTab);
+ if (Config->EMachine == EM_MIPS && !Config->Shared) {
+ // This is a MIPS specific section to hold a space within the data segment
+ // of executable file which is pointed to by the DT_MIPS_RLD_MAP entry.
+ // See "Dynamic section" in Chapter 5 in the following document:
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ MipsRldMap.reset(new OutputSection<ELFT>(".rld_map", SHT_PROGBITS,
+ SHF_ALLOC | SHF_WRITE));
+ MipsRldMap->setSize(sizeof(uintX_t));
+ MipsRldMap->updateAlignment(sizeof(uintX_t));
+ }
+ if (!Config->VersionDefinitions.empty())
+ VerDef.reset(new VersionDefinitionSection<ELFT>());
+
+ Out<ELFT>::Bss = &Bss;
+ Out<ELFT>::BuildId = BuildId.get();
+ Out<ELFT>::DynStrTab = &DynStrTab;
Out<ELFT>::DynSymTab = &DynSymTab;
- HashTableSection<ELFT> HashTab;
- if (Config->SysvHash)
- Out<ELFT>::HashTab = &HashTab;
- GnuHashTableSection<ELFT> GnuHashTab;
- if (Config->GnuHash)
- Out<ELFT>::GnuHashTab = &GnuHashTab;
- bool IsRela = shouldUseRela<ELFT>();
- RelocationSection<ELFT> RelaDyn(IsRela ? ".rela.dyn" : ".rel.dyn", IsRela);
- Out<ELFT>::RelaDyn = &RelaDyn;
- RelocationSection<ELFT> RelaPlt(IsRela ? ".rela.plt" : ".rel.plt", IsRela);
- if (Target->supportsLazyRelocations())
- Out<ELFT>::RelaPlt = &RelaPlt;
- DynamicSection<ELFT> Dynamic(*Symtab);
Out<ELFT>::Dynamic = &Dynamic;
+ Out<ELFT>::EhFrame = &EhFrame;
+ Out<ELFT>::EhFrameHdr = EhFrameHdr.get();
+ Out<ELFT>::GnuHashTab = GnuHashTab.get();
+ Out<ELFT>::Got = &Got;
+ Out<ELFT>::GotPlt = GotPlt.get();
+ Out<ELFT>::HashTab = HashTab.get();
+ Out<ELFT>::Interp = &Interp;
+ Out<ELFT>::Plt = &Plt;
+ Out<ELFT>::RelaDyn = &RelaDyn;
+ Out<ELFT>::RelaPlt = RelaPlt.get();
+ Out<ELFT>::ShStrTab = &ShStrTab;
+ Out<ELFT>::StrTab = StrTab.get();
+ Out<ELFT>::SymTab = SymTabSec.get();
+ Out<ELFT>::VerDef = VerDef.get();
+ Out<ELFT>::VerSym = &VerSym;
+ Out<ELFT>::VerNeed = &VerNeed;
+ Out<ELFT>::MipsRldMap = MipsRldMap.get();
+ Out<ELFT>::Opd = nullptr;
+ Out<ELFT>::OpdBuf = nullptr;
+ Out<ELFT>::TlsPhdr = nullptr;
+ Out<ELFT>::ElfHeader = &ElfHeader;
+ Out<ELFT>::ProgramHeaders = &ProgramHeaders;
Writer<ELFT>(*Symtab).run();
}
// The main function of the writer.
template <class ELFT> void Writer<ELFT>::run() {
- buildSectionMap();
if (!Config->DiscardAll)
copyLocalSymbols();
addReservedSymbols();
createSections();
- assignAddresses();
- fixAbsoluteSymbols();
- openFile(Config->OutputFile);
- writeHeader();
- writeSections();
- error(Buffer->commit());
-}
+ if (HasError)
+ return;
-namespace {
-template <bool Is64Bits> struct SectionKey {
- typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t;
- StringRef Name;
- uint32_t Type;
- uintX_t Flags;
- uintX_t EntSize;
-};
-}
-namespace llvm {
-template <bool Is64Bits> struct DenseMapInfo<SectionKey<Is64Bits>> {
- static SectionKey<Is64Bits> getEmptyKey() {
- return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0,
- 0};
- }
- static SectionKey<Is64Bits> getTombstoneKey() {
- return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0,
- 0, 0};
- }
- static unsigned getHashValue(const SectionKey<Is64Bits> &Val) {
- return hash_combine(Val.Name, Val.Type, Val.Flags, Val.EntSize);
- }
- static bool isEqual(const SectionKey<Is64Bits> &LHS,
- const SectionKey<Is64Bits> &RHS) {
- return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) &&
- LHS.Type == RHS.Type && LHS.Flags == RHS.Flags &&
- LHS.EntSize == RHS.EntSize;
+ if (Config->Relocatable) {
+ assignFileOffsets();
+ } else {
+ createPhdrs();
+ fixHeaders();
+ if (ScriptConfig->DoLayout) {
+ Script<ELFT>::X->assignAddresses(OutputSections);
+ } else {
+ fixSectionAlignments();
+ assignAddresses();
+ }
+ assignFileOffsets();
+ setPhdrs();
+ fixAbsoluteSymbols();
}
-};
+
+ openFile();
+ if (HasError)
+ return;
+ writeHeader();
+ writeSections();
+ writeBuildId();
+ if (HasError)
+ return;
+ if (auto EC = Buffer->commit())
+ error(EC, "failed to write to the output file");
}
-// The reason we have to do this early scan is as follows
-// * To mmap the output file, we need to know the size
-// * For that, we need to know how many dynamic relocs we will have.
-// It might be possible to avoid this by outputting the file with write:
-// * Write the allocated output sections, computing addresses.
-// * Apply relocations, recording which ones require a dynamic reloc.
-// * Write the dynamic relocations.
-// * Write the rest of the file.
template <class ELFT>
-template <bool isRela>
-void Writer<ELFT>::scanRelocs(
- InputSectionBase<ELFT> &C,
- iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels) {
- typedef Elf_Rel_Impl<ELFT, isRela> RelType;
- const ObjectFile<ELFT> &File = *C.getFile();
- for (const RelType &RI : Rels) {
- uint32_t SymIndex = RI.getSymbol(Config->Mips64EL);
- SymbolBody *Body = File.getSymbolBody(SymIndex);
- uint32_t Type = RI.getType(Config->Mips64EL);
-
- if (Target->isGotRelative(Type))
- HasGotOffRel = true;
-
- if (Target->isTlsLocalDynamicReloc(Type)) {
- if (Target->isTlsOptimized(Type, nullptr))
- continue;
- if (Out<ELFT>::Got->addCurrentModuleTlsIndex())
- Out<ELFT>::RelaDyn->addReloc({&C, &RI});
- continue;
- }
-
- // Set "used" bit for --as-needed.
- if (Body && Body->isUndefined() && !Body->isWeak())
- if (auto *S = dyn_cast<SharedSymbol<ELFT>>(Body->repl()))
- S->File->IsUsed = true;
-
- if (Body)
- Body = Body->repl();
-
- if (Body && Body->isTls() && Target->isTlsGlobalDynamicReloc(Type)) {
- bool Opt = Target->isTlsOptimized(Type, Body);
- if (!Opt && Out<ELFT>::Got->addDynTlsEntry(Body)) {
- Out<ELFT>::RelaDyn->addReloc({&C, &RI});
- Out<ELFT>::RelaDyn->addReloc({nullptr, nullptr});
- Body->setUsedInDynamicReloc();
- continue;
- }
- if (!canBePreempted(Body, true))
- continue;
- }
-
- if (Body && Body->isTls() && !Target->isTlsDynReloc(Type, *Body))
- continue;
+static void reportUndefined(SymbolTable<ELFT> &Symtab, SymbolBody *Sym) {
+ if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore)
+ return;
- if (Target->relocNeedsDynRelative(Type)) {
- RelType *Rel = new (Alloc) RelType;
- Rel->setSymbolAndType(0, Target->getRelativeReloc(), Config->Mips64EL);
- Rel->r_offset = RI.r_offset;
- Out<ELFT>::RelaDyn->addReloc({&C, Rel});
- }
+ if (Config->Shared && Sym->symbol()->Visibility == STV_DEFAULT &&
+ Config->UnresolvedSymbols != UnresolvedPolicy::NoUndef)
+ return;
- bool NeedsGot = false;
- bool NeedsPlt = false;
- if (Body) {
- if (auto *E = dyn_cast<SharedSymbol<ELFT>>(Body)) {
- if (E->NeedsCopy)
- continue;
- if (Target->needsCopyRel(Type, *Body))
- E->NeedsCopy = true;
- }
- NeedsPlt = Target->relocNeedsPlt(Type, *Body);
- if (NeedsPlt) {
- if (Body->isInPlt())
- continue;
- Out<ELFT>::Plt->addEntry(Body);
- }
- NeedsGot = Target->relocNeedsGot(Type, *Body);
- if (NeedsGot) {
- if (NeedsPlt && Target->supportsLazyRelocations()) {
- Out<ELFT>::GotPlt->addEntry(Body);
- } else {
- if (Body->isInGot())
- continue;
- Out<ELFT>::Got->addEntry(Body);
- }
- }
- }
+ std::string Msg = "undefined symbol: " + Sym->getName().str();
+ if (Sym->File)
+ Msg += " in " + getFilename(Sym->File);
+ if (Config->UnresolvedSymbols == UnresolvedPolicy::Warn)
+ warning(Msg);
+ else
+ error(Msg);
+}
- // An STT_GNU_IFUNC symbol always uses a PLT entry, and all references
- // to the symbol go through the PLT. This is true even for a local
- // symbol, although local symbols normally do not require PLT entries.
- if (Body && isGnuIFunc<ELFT>(*Body)) {
- Body->setUsedInDynamicReloc();
- Out<ELFT>::RelaPlt->addReloc({&C, &RI});
- continue;
- }
+template <class ELFT>
+static bool shouldKeepInSymtab(InputSectionBase<ELFT> *Sec, StringRef SymName,
+ const SymbolBody &B) {
+ if (B.isFile())
+ return false;
- if (Config->EMachine == EM_MIPS) {
- if (NeedsGot) {
- // MIPS ABI has special rules to process GOT entries
- // and doesn't require relocation entries for them.
- // See "Global Offset Table" in Chapter 5 in the following document
- // for detailed description:
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- Body->setUsedInDynamicReloc();
- continue;
- }
- if (Body == Config->MipsGpDisp)
- // MIPS _gp_disp designates offset between start of function and gp
- // pointer into GOT therefore any relocations against it do not require
- // dynamic relocation.
- continue;
- }
+ // We keep sections in symtab for relocatable output.
+ if (B.isSection())
+ return Config->Relocatable;
- // Here we are creating a relocation for the dynamic linker based on
- // a relocation from an object file, but some relocations need no
- // load-time fixup. Skip such relocation.
- bool CBP = canBePreempted(Body, NeedsGot);
- bool NoDynrel = Target->isRelRelative(Type) || Target->isSizeReloc(Type);
- if (!CBP && (NoDynrel || !Config->Shared))
- continue;
+ // If sym references a section in a discarded group, don't keep it.
+ if (Sec == &InputSection<ELFT>::Discarded)
+ return false;
- if (CBP)
- Body->setUsedInDynamicReloc();
- if (NeedsPlt && Target->supportsLazyRelocations())
- Out<ELFT>::RelaPlt->addReloc({&C, &RI});
- else
- Out<ELFT>::RelaDyn->addReloc({&C, &RI});
- }
-}
+ if (Config->DiscardNone)
+ return true;
-template <class ELFT> void Writer<ELFT>::scanRelocs(InputSection<ELFT> &C) {
- if (!(C.getSectionHdr()->sh_flags & SHF_ALLOC))
- return;
+ // In ELF assembly .L symbols are normally discarded by the assembler.
+ // If the assembler fails to do so, the linker discards them if
+ // * --discard-locals is used.
+ // * The symbol is in a SHF_MERGE section, which is normally the reason for
+ // the assembler keeping the .L symbol.
+ if (!SymName.startswith(".L") && !SymName.empty())
+ return true;
- for (const Elf_Shdr *RelSec : C.RelocSections)
- scanRelocs(C, *RelSec);
-}
+ if (Config->DiscardLocals)
+ return false;
-template <class ELFT>
-void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &S,
- const Elf_Shdr &RelSec) {
- ELFFile<ELFT> &EObj = S.getFile()->getObj();
- if (RelSec.sh_type == SHT_RELA)
- scanRelocs(S, EObj.relas(&RelSec));
- else
- scanRelocs(S, EObj.rels(&RelSec));
+ return !(Sec->getSectionHdr()->sh_flags & SHF_MERGE);
}
-template <class ELFT>
-static void reportUndefined(SymbolTable<ELFT> &Symtab, SymbolBody *Sym) {
- if (Config->Shared && !Config->NoUndefined)
- return;
+template <class ELFT> static bool includeInSymtab(const SymbolBody &B) {
+ if (!B.isLocal() && !B.symbol()->IsUsedInRegularObj)
+ return false;
- std::string Msg = "undefined symbol: " + Sym->getName().str();
- if (ELFFileBase<ELFT> *File = Symtab.findFile(Sym))
- Msg += " in " + File->getName().str();
- if (Config->NoInhibitExec)
- warning(Msg);
- else
- error(Msg);
+ if (auto *D = dyn_cast<DefinedRegular<ELFT>>(&B)) {
+ // Always include absolute symbols.
+ if (!D->Section)
+ return true;
+ // Exclude symbols pointing to garbage-collected sections.
+ if (!D->Section->Live)
+ return false;
+ if (auto *S = dyn_cast<MergeInputSection<ELFT>>(D->Section))
+ if (!S->getSectionPiece(D->Value)->Live)
+ return false;
+ }
+ return true;
}
// Local symbols are not in the linker's symbol table. This function scans
// each object file's symbol table to copy local symbols to the output.
template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
- for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
- for (const Elf_Sym &Sym : F->getLocalSymbols()) {
- ErrorOr<StringRef> SymNameOrErr = Sym.getName(F->getStringTable());
- error(SymNameOrErr);
- StringRef SymName = *SymNameOrErr;
- if (!shouldKeepInSymtab<ELFT>(*F, SymName, Sym))
+ if (!Out<ELFT>::SymTab)
+ return;
+ for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
+ Symtab.getObjectFiles()) {
+ const char *StrTab = F->getStringTable().data();
+ for (SymbolBody *B : F->getLocalSymbols()) {
+ auto *DR = dyn_cast<DefinedRegular<ELFT>>(B);
+ // No reason to keep local undefined symbol in symtab.
+ if (!DR)
continue;
- if (Out<ELFT>::SymTab)
- Out<ELFT>::SymTab->addLocalSymbol(SymName);
+ if (!includeInSymtab<ELFT>(*B))
+ continue;
+ StringRef SymName(StrTab + B->getNameOffset());
+ InputSectionBase<ELFT> *Sec = DR->Section;
+ if (!shouldKeepInSymtab<ELFT>(Sec, SymName, *B))
+ continue;
+ ++Out<ELFT>::SymTab->NumLocals;
+ if (Config->Relocatable)
+ B->DynsymIndex = Out<ELFT>::SymTab->NumLocals;
+ F->KeptLocalSyms.push_back(
+ std::make_pair(DR, Out<ELFT>::SymTab->StrTabSec.addString(SymName)));
}
}
}
@@ -377,16 +368,18 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
// thus, within reach of the TOC base pointer).
static int getPPC64SectionRank(StringRef SectionName) {
return StringSwitch<int>(SectionName)
- .Case(".tocbss", 0)
- .Case(".branch_lt", 2)
- .Case(".toc", 3)
- .Case(".toc1", 4)
- .Case(".opd", 5)
- .Default(1);
+ .Case(".tocbss", 0)
+ .Case(".branch_lt", 2)
+ .Case(".toc", 3)
+ .Case(".toc1", 4)
+ .Case(".opd", 5)
+ .Default(1);
}
template <class ELFT> static bool isRelroSection(OutputSectionBase<ELFT> *Sec) {
- typename OutputSectionBase<ELFT>::uintX_t Flags = Sec->getFlags();
+ if (!Config->ZRelro)
+ return false;
+ typename ELFT::uint Flags = Sec->getFlags();
if (!(Flags & SHF_ALLOC) || !(Flags & SHF_WRITE))
return false;
if (Flags & SHF_TLS)
@@ -406,9 +399,13 @@ template <class ELFT> static bool isRelroSection(OutputSectionBase<ELFT> *Sec) {
// Output section ordering is determined by this function.
template <class ELFT>
-static bool compareOutputSections(OutputSectionBase<ELFT> *A,
- OutputSectionBase<ELFT> *B) {
- typedef typename ELFFile<ELFT>::uintX_t uintX_t;
+static bool compareSections(OutputSectionBase<ELFT> *A,
+ OutputSectionBase<ELFT> *B) {
+ typedef typename ELFT::uint uintX_t;
+
+ int Comp = Script<ELFT>::X->compareSections(A->getName(), B->getName());
+ if (Comp != 0)
+ return Comp < 0;
uintX_t AFlags = A->getFlags();
uintX_t BFlags = B->getFlags();
@@ -475,16 +472,6 @@ static bool compareOutputSections(OutputSectionBase<ELFT> *A,
return false;
}
-template <class ELFT> OutputSection<ELFT> *Writer<ELFT>::getBss() {
- if (!Out<ELFT>::Bss) {
- Out<ELFT>::Bss =
- new OutputSection<ELFT>(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
- OwningSections.emplace_back(Out<ELFT>::Bss);
- OutputSections.push_back(Out<ELFT>::Bss);
- }
- return Out<ELFT>::Bss;
-}
-
// Until this function is called, common symbols do not belong to any section.
// This function adds them to end of BSS section.
template <class ELFT>
@@ -495,12 +482,13 @@ void Writer<ELFT>::addCommonSymbols(std::vector<DefinedCommon *> &Syms) {
// Sort the common symbols by alignment as an heuristic to pack them better.
std::stable_sort(Syms.begin(), Syms.end(),
[](const DefinedCommon *A, const DefinedCommon *B) {
- return A->MaxAlignment > B->MaxAlignment;
+ return A->Alignment > B->Alignment;
});
- uintX_t Off = getBss()->getSize();
+ uintX_t Off = Out<ELFT>::Bss->getSize();
for (DefinedCommon *C : Syms) {
- Off = align(Off, C->MaxAlignment);
+ Off = alignTo(Off, C->Alignment);
+ Out<ELFT>::Bss->updateAlignment(C->Alignment);
C->OffsetInBss = Off;
Off += C->Size;
}
@@ -508,75 +496,16 @@ void Writer<ELFT>::addCommonSymbols(std::vector<DefinedCommon *> &Syms) {
Out<ELFT>::Bss->setSize(Off);
}
-// Reserve space in .bss for copy relocations.
-template <class ELFT>
-void Writer<ELFT>::addCopyRelSymbols(std::vector<SharedSymbol<ELFT> *> &Syms) {
- if (Syms.empty())
- return;
- uintX_t Off = getBss()->getSize();
- for (SharedSymbol<ELFT> *C : Syms) {
- const Elf_Sym &Sym = C->Sym;
- const Elf_Shdr *Sec = C->File->getSection(Sym);
- uintX_t SecAlign = Sec->sh_addralign;
- unsigned TrailingZeros =
- std::min(countTrailingZeros(SecAlign),
- countTrailingZeros((uintX_t)Sym.st_value));
- uintX_t Align = 1 << TrailingZeros;
- Out<ELFT>::Bss->updateAlign(Align);
- Off = align(Off, Align);
- C->OffsetInBss = Off;
- Off += Sym.st_size;
- }
- Out<ELFT>::Bss->setSize(Off);
-}
-
-template <class ELFT>
-StringRef Writer<ELFT>::getOutputSectionName(StringRef S) const {
- auto It = InputToOutputSection.find(S);
- if (It != std::end(InputToOutputSection))
- return It->second;
-
- if (S.startswith(".text."))
- return ".text";
- if (S.startswith(".rodata."))
- return ".rodata";
- if (S.startswith(".data.rel.ro"))
- return ".data.rel.ro";
- if (S.startswith(".data."))
- return ".data";
- if (S.startswith(".bss."))
- return ".bss";
- return S;
-}
-
-template <class ELFT>
-void reportDiscarded(InputSectionBase<ELFT> *IS,
- const std::unique_ptr<ObjectFile<ELFT>> &File) {
- if (!Config->PrintGcSections || !IS || IS->isLive())
- return;
- llvm::errs() << "removing unused section from '" << IS->getSectionName()
- << "' in file '" << File->getName() << "'\n";
-}
-
template <class ELFT>
-bool Writer<ELFT>::isDiscarded(InputSectionBase<ELFT> *IS) const {
- if (!IS || !IS->isLive() || IS == &InputSection<ELFT>::Discarded)
- return true;
- return InputToOutputSection.lookup(IS->getSectionName()) == "/DISCARD/";
-}
-
-template <class ELFT>
-static bool compareSections(OutputSectionBase<ELFT> *A,
- OutputSectionBase<ELFT> *B) {
- auto ItA = Config->OutputSections.find(A->getName());
- auto ItEnd = std::end(Config->OutputSections);
- if (ItA == ItEnd)
- return compareOutputSections(A, B);
- auto ItB = Config->OutputSections.find(B->getName());
- if (ItB == ItEnd)
- return compareOutputSections(A, B);
-
- return std::distance(ItA, ItB) > 0;
+static Symbol *addOptionalSynthetic(SymbolTable<ELFT> &Table, StringRef Name,
+ OutputSectionBase<ELFT> *Sec,
+ typename ELFT::uint Val) {
+ SymbolBody *S = Table.find(Name);
+ if (!S)
+ return nullptr;
+ if (!S->isUndefined() && !S->isShared())
+ return S->symbol();
+ return Table.addSynthetic(Name, Sec, Val);
}
// The beginning and the ending of .rel[a].plt section are marked
@@ -585,125 +514,57 @@ static bool compareSections(OutputSectionBase<ELFT> *A,
// all IRELATIVE relocs on startup. For dynamic executables, we don't
// need these symbols, since IRELATIVE relocs are resolved through GOT
// and PLT. For details, see http://www.airs.com/blog/archives/403.
-template <class ELFT>
-void Writer<ELFT>::addRelIpltSymbols() {
+template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
if (isOutputDynamic() || !Out<ELFT>::RelaPlt)
return;
- bool IsRela = shouldUseRela<ELFT>();
-
- StringRef S = IsRela ? "__rela_iplt_start" : "__rel_iplt_start";
- if (Symtab.find(S))
- Symtab.addAbsolute(S, ElfSym<ELFT>::RelaIpltStart);
-
- S = IsRela ? "__rela_iplt_end" : "__rel_iplt_end";
- if (Symtab.find(S))
- Symtab.addAbsolute(S, ElfSym<ELFT>::RelaIpltEnd);
-}
-
-template <class ELFT> static bool includeInSymtab(const SymbolBody &B) {
- if (!B.isUsedInRegularObj())
- return false;
-
- // Don't include synthetic symbols like __init_array_start in every output.
- if (auto *U = dyn_cast<DefinedRegular<ELFT>>(&B))
- if (&U->Sym == &ElfSym<ELFT>::IgnoredWeak ||
- &U->Sym == &ElfSym<ELFT>::Ignored)
- return false;
+ StringRef S = Config->Rela ? "__rela_iplt_start" : "__rel_iplt_start";
+ addOptionalSynthetic(Symtab, S, Out<ELFT>::RelaPlt, 0);
- return true;
-}
-
-static bool includeInDynamicSymtab(const SymbolBody &B) {
- uint8_t V = B.getVisibility();
- if (V != STV_DEFAULT && V != STV_PROTECTED)
- return false;
- if (Config->ExportDynamic || Config->Shared)
- return true;
- return B.isUsedInDynamicReloc();
-}
-
-// This class knows how to create an output section for a given
-// input section. Output section type is determined by various
-// factors, including input section's sh_flags, sh_type and
-// linker scripts.
-namespace {
-template <class ELFT> class OutputSectionFactory {
- typedef typename ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
- typedef typename ELFFile<ELFT>::uintX_t uintX_t;
-
-public:
- std::pair<OutputSectionBase<ELFT> *, bool> create(InputSectionBase<ELFT> *C,
- StringRef OutsecName);
-
- OutputSectionBase<ELFT> *lookup(StringRef Name, uint32_t Type, uintX_t Flags);
-
-private:
- SectionKey<ELFT::Is64Bits> createKey(InputSectionBase<ELFT> *C,
- StringRef OutsecName);
-
- SmallDenseMap<SectionKey<ELFT::Is64Bits>, OutputSectionBase<ELFT> *> Map;
-};
-}
-
-template <class ELFT>
-std::pair<OutputSectionBase<ELFT> *, bool>
-OutputSectionFactory<ELFT>::create(InputSectionBase<ELFT> *C,
- StringRef OutsecName) {
- SectionKey<ELFT::Is64Bits> Key = createKey(C, OutsecName);
- OutputSectionBase<ELFT> *&Sec = Map[Key];
- if (Sec)
- return {Sec, false};
-
- switch (C->SectionKind) {
- case InputSectionBase<ELFT>::Regular:
- Sec = new OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
- break;
- case InputSectionBase<ELFT>::EHFrame:
- Sec = new EHOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
- break;
- case InputSectionBase<ELFT>::Merge:
- Sec = new MergeOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
- break;
- case InputSectionBase<ELFT>::MipsReginfo:
- Sec = new MipsReginfoOutputSection<ELFT>();
- break;
- }
- return {Sec, true};
-}
-
-template <class ELFT>
-OutputSectionBase<ELFT> *OutputSectionFactory<ELFT>::lookup(StringRef Name,
- uint32_t Type,
- uintX_t Flags) {
- return Map.lookup({Name, Type, Flags, 0});
-}
-
-template <class ELFT>
-SectionKey<ELFT::Is64Bits>
-OutputSectionFactory<ELFT>::createKey(InputSectionBase<ELFT> *C,
- StringRef OutsecName) {
- const Elf_Shdr *H = C->getSectionHdr();
- uintX_t Flags = H->sh_flags & ~SHF_GROUP;
-
- // For SHF_MERGE we create different output sections for each sh_entsize.
- // This makes each output section simple and keeps a single level
- // mapping from input to output.
- uintX_t EntSize = isa<MergeInputSection<ELFT>>(C) ? H->sh_entsize : 0;
-
- // GNU as can give .eh_frame secion type SHT_PROGBITS or SHT_X86_64_UNWIND
- // depending on the construct. We want to canonicalize it so that
- // there is only one .eh_frame in the end.
- uint32_t Type = H->sh_type;
- if (Type == SHT_PROGBITS && Config->EMachine == EM_X86_64 &&
- isa<EHInputSection<ELFT>>(C))
- Type = SHT_X86_64_UNWIND;
-
- return SectionKey<ELFT::Is64Bits>{OutsecName, Type, Flags, EntSize};
+ S = Config->Rela ? "__rela_iplt_end" : "__rel_iplt_end";
+ addOptionalSynthetic(Symtab, S, Out<ELFT>::RelaPlt,
+ DefinedSynthetic<ELFT>::SectionEnd);
}
// The linker is expected to define some symbols depending on
// the linking result. This function defines such symbols.
template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
+ if (Config->EMachine == EM_MIPS) {
+ // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer
+ // so that it points to an absolute address which is relative to GOT.
+ // See "Global Data Symbols" in Chapter 6 in the following document:
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ Symtab.addSynthetic("_gp", Out<ELFT>::Got, MipsGPOffset);
+
+ // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
+ // start of function and 'gp' pointer into GOT.
+ Symbol *Sym =
+ addOptionalSynthetic(Symtab, "_gp_disp", Out<ELFT>::Got, MipsGPOffset);
+ if (Sym)
+ ElfSym<ELFT>::MipsGpDisp = Sym->body();
+
+ // The __gnu_local_gp is a magic symbol equal to the current value of 'gp'
+ // pointer. This symbol is used in the code generated by .cpload pseudo-op
+ // in case of using -mno-shared option.
+ // https://sourceware.org/ml/binutils/2004-12/msg00094.html
+ addOptionalSynthetic(Symtab, "__gnu_local_gp", Out<ELFT>::Got,
+ MipsGPOffset);
+ }
+
+ // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
+ // is magical and is used to produce a R_386_GOTPC relocation.
+ // The R_386_GOTPC relocation value doesn't actually depend on the
+ // symbol value, so it could use an index of STN_UNDEF which, according
+ // to the spec, means the symbol value is 0.
+ // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in
+ // the object file.
+ // The situation is even stranger on x86_64 where the assembly doesn't
+ // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as
+ // an undefined symbol in the .o files.
+ // Given that the symbol is effectively unused, we just create a dummy
+ // hidden one to avoid the undefined symbol error.
+ if (!Config->Relocatable)
+ Symtab.addIgnored("_GLOBAL_OFFSET_TABLE_");
+
// __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For
// static linking the linker is required to optimize away any references to
// __tls_get_addr, so it's not defined anywhere. Create a hidden definition
@@ -711,35 +572,44 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
if (!isOutputDynamic())
Symtab.addIgnored("__tls_get_addr");
- // If the "_end" symbol is referenced, it is expected to point to the address
- // right after the data segment. Usually, this symbol points to the end
- // of .bss section or to the end of .data section if .bss section is absent.
- // The order of the sections can be affected by linker script,
- // so it is hard to predict which section will be the last one.
- // So, if this symbol is referenced, we just add the placeholder here
- // and update its value later.
- if (Symtab.find("_end"))
- Symtab.addAbsolute("_end", ElfSym<ELFT>::End);
-
- // If there is an undefined symbol "end", we should initialize it
- // with the same value as "_end". In any other case it should stay intact,
- // because it is an allowable name for a user symbol.
- if (SymbolBody *B = Symtab.find("end"))
- if (B->isUndefined())
- Symtab.addAbsolute("end", ElfSym<ELFT>::End);
+ auto Define = [this](StringRef S, DefinedRegular<ELFT> *&Sym1,
+ DefinedRegular<ELFT> *&Sym2) {
+ Sym1 = Symtab.addIgnored(S, STV_DEFAULT);
+
+ // The name without the underscore is not a reserved name,
+ // so it is defined only when there is a reference against it.
+ assert(S.startswith("_"));
+ S = S.substr(1);
+ if (SymbolBody *B = Symtab.find(S))
+ if (B->isUndefined())
+ Sym2 = Symtab.addAbsolute(S, STV_DEFAULT);
+ };
+
+ Define("_end", ElfSym<ELFT>::End, ElfSym<ELFT>::End2);
+ Define("_etext", ElfSym<ELFT>::Etext, ElfSym<ELFT>::Etext2);
+ Define("_edata", ElfSym<ELFT>::Edata, ElfSym<ELFT>::Edata2);
+}
+
+// Sort input sections by section name suffixes for
+// __attribute__((init_priority(N))).
+template <class ELFT> static void sortInitFini(OutputSectionBase<ELFT> *S) {
+ if (S)
+ reinterpret_cast<OutputSection<ELFT> *>(S)->sortInitFini();
+}
+
+// Sort input sections by the special rule for .ctors and .dtors.
+template <class ELFT> static void sortCtorsDtors(OutputSectionBase<ELFT> *S) {
+ if (S)
+ reinterpret_cast<OutputSection<ELFT> *>(S)->sortCtorsDtors();
}
// Create output section objects and add them to OutputSections.
template <class ELFT> void Writer<ELFT>::createSections() {
- // Add .interp first because some loaders want to see that section
- // on the first page of the executable file when loaded into memory.
- if (needsInterpSection())
- OutputSections.push_back(Out<ELFT>::Interp);
-
// Create output sections for input object file sections.
std::vector<OutputSectionBase<ELFT> *> RegularSections;
OutputSectionFactory<ELFT> Factory;
- for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
+ for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
+ Symtab.getObjectFiles()) {
for (InputSectionBase<ELFT> *C : F->getSections()) {
if (isDiscarded(C)) {
reportDiscarded(C, F);
@@ -747,8 +617,7 @@ template <class ELFT> void Writer<ELFT>::createSections() {
}
OutputSectionBase<ELFT> *Sec;
bool IsNew;
- std::tie(Sec, IsNew) =
- Factory.create(C, getOutputSectionName(C->getSectionName()));
+ std::tie(Sec, IsNew) = Factory.create(C, getOutputSectionName(C));
if (IsNew) {
OwningSections.emplace_back(Sec);
OutputSections.push_back(Sec);
@@ -758,9 +627,6 @@ template <class ELFT> void Writer<ELFT>::createSections() {
}
}
- Out<ELFT>::Bss = static_cast<OutputSection<ELFT> *>(
- Factory.lookup(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE));
-
// If we have a .opd section (used under PPC64 for function descriptors),
// store a pointer to it here so that we can use it later when processing
// relocations.
@@ -773,56 +639,92 @@ template <class ELFT> void Writer<ELFT>::createSections() {
Out<ELFT>::Dynamic->FiniArraySec =
Factory.lookup(".fini_array", SHT_FINI_ARRAY, SHF_WRITE | SHF_ALLOC);
+ // Sort section contents for __attribute__((init_priority(N)).
+ sortInitFini(Out<ELFT>::Dynamic->InitArraySec);
+ sortInitFini(Out<ELFT>::Dynamic->FiniArraySec);
+ sortCtorsDtors(Factory.lookup(".ctors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC));
+ sortCtorsDtors(Factory.lookup(".dtors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC));
+
// The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop
// symbols for sections, so that the runtime can get the start and end
// addresses of each section by section name. Add such symbols.
- addStartEndSymbols();
- for (OutputSectionBase<ELFT> *Sec : RegularSections)
- addStartStopSymbols(Sec);
+ if (!Config->Relocatable) {
+ addStartEndSymbols();
+ for (OutputSectionBase<ELFT> *Sec : RegularSections)
+ addStartStopSymbols(Sec);
+ }
+
+ // Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type.
+ // It should be okay as no one seems to care about the type.
+ // Even the author of gold doesn't remember why gold behaves that way.
+ // https://sourceware.org/ml/binutils/2002-03/msg00360.html
+ if (isOutputDynamic())
+ Symtab.addSynthetic("_DYNAMIC", Out<ELFT>::Dynamic, 0);
+
+ // Define __rel[a]_iplt_{start,end} symbols if needed.
+ addRelIpltSymbols();
+
+ // Add scripted symbols with zero values now.
+ // Real values will be assigned later
+ Script<ELFT>::X->addScriptedSymbols();
+
+ if (!Out<ELFT>::EhFrame->empty()) {
+ OutputSections.push_back(Out<ELFT>::EhFrame);
+ Out<ELFT>::EhFrame->finalize();
+ }
// Scan relocations. This must be done after every symbol is declared so that
// we can correctly decide if a dynamic relocation is needed.
- for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
+ for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
+ Symtab.getObjectFiles()) {
for (InputSectionBase<ELFT> *C : F->getSections()) {
if (isDiscarded(C))
continue;
- if (auto *S = dyn_cast<InputSection<ELFT>>(C))
- scanRelocs(*S);
- else if (auto *S = dyn_cast<EHInputSection<ELFT>>(C))
+ if (auto *S = dyn_cast<InputSection<ELFT>>(C)) {
+ scanRelocations(*S);
+ continue;
+ }
+ if (auto *S = dyn_cast<EhInputSection<ELFT>>(C))
if (S->RelocSection)
- scanRelocs(*S, *S->RelocSection);
+ scanRelocations(*S, *S->RelocSection);
}
}
- // Define __rel[a]_iplt_{start,end} symbols if needed.
- addRelIpltSymbols();
+ for (OutputSectionBase<ELFT> *Sec : OutputSections)
+ Sec->assignOffsets();
// Now that we have defined all possible symbols including linker-
// synthesized ones. Visit all symbols to give the finishing touches.
std::vector<DefinedCommon *> CommonSymbols;
- std::vector<SharedSymbol<ELFT> *> CopyRelSymbols;
- for (auto &P : Symtab.getSymbols()) {
- SymbolBody *Body = P.second->Body;
- if (auto *U = dyn_cast<Undefined>(Body))
- if (!U->isWeak() && !U->canKeepUndefined())
- reportUndefined<ELFT>(Symtab, Body);
+ for (Symbol *S : Symtab.getSymbols()) {
+ SymbolBody *Body = S->body();
+
+ // We only report undefined symbols in regular objects. This means that we
+ // will accept an undefined reference in bitcode if it can be optimized out.
+ if (S->IsUsedInRegularObj && Body->isUndefined() && !S->isWeak())
+ reportUndefined<ELFT>(Symtab, Body);
if (auto *C = dyn_cast<DefinedCommon>(Body))
CommonSymbols.push_back(C);
- if (auto *SC = dyn_cast<SharedSymbol<ELFT>>(Body))
- if (SC->NeedsCopy)
- CopyRelSymbols.push_back(SC);
if (!includeInSymtab<ELFT>(*Body))
continue;
if (Out<ELFT>::SymTab)
Out<ELFT>::SymTab->addSymbol(Body);
- if (isOutputDynamic() && includeInDynamicSymtab(*Body))
+ if (isOutputDynamic() && S->includeInDynsym()) {
Out<ELFT>::DynSymTab->addSymbol(Body);
+ if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(Body))
+ if (SS->file()->isNeeded())
+ Out<ELFT>::VerNeed->addSymbol(SS);
+ }
}
+
+ // Do not proceed if there was an undefined symbol.
+ if (HasError)
+ return;
+
addCommonSymbols(CommonSymbols);
- addCopyRelSymbols(CopyRelSymbols);
// So far we have added sections from input object files.
// This function adds linker-created Out<ELFT>::* sections.
@@ -831,25 +733,47 @@ template <class ELFT> void Writer<ELFT>::createSections() {
std::stable_sort(OutputSections.begin(), OutputSections.end(),
compareSections<ELFT>);
- for (unsigned I = 0, N = OutputSections.size(); I < N; ++I) {
- OutputSections[I]->SectionIndex = I + 1;
- HasRelro |= (Config->ZRelro && isRelroSection(OutputSections[I]));
+ unsigned I = 1;
+ for (OutputSectionBase<ELFT> *Sec : OutputSections) {
+ Sec->SectionIndex = I++;
+ Sec->setSHName(Out<ELFT>::ShStrTab->addString(Sec->getName()));
}
- for (OutputSectionBase<ELFT> *Sec : OutputSections)
- Out<ELFT>::ShStrTab->reserve(Sec->getName());
-
// Finalizers fix each section's size.
- // .dynamic section's finalizer may add strings to .dynstr,
- // so finalize that early.
- // Likewise, .dynsym is finalized early since that may fill up .gnu.hash.
- Out<ELFT>::Dynamic->finalize();
+ // .dynsym is finalized early since that may fill up .gnu.hash.
if (isOutputDynamic())
Out<ELFT>::DynSymTab->finalize();
- // Fill other section headers.
+ // Fill other section headers. The dynamic table is finalized
+ // at the end because some tags like RELSZ depend on result
+ // of finalizing other sections. The dynamic string table is
+ // finalized once the .dynamic finalizer has added a few last
+ // strings. See DynamicSection::finalize()
+ for (OutputSectionBase<ELFT> *Sec : OutputSections)
+ if (Sec != Out<ELFT>::DynStrTab && Sec != Out<ELFT>::Dynamic)
+ Sec->finalize();
+
+ if (isOutputDynamic())
+ Out<ELFT>::Dynamic->finalize();
+
+ // Now that all output offsets are fixed. Finalize mergeable sections
+ // to fix their maps from input offsets to output offsets.
for (OutputSectionBase<ELFT> *Sec : OutputSections)
- Sec->finalize();
+ Sec->finalizePieces();
+}
+
+template <class ELFT> bool Writer<ELFT>::needsGot() {
+ if (!Out<ELFT>::Got->empty())
+ return true;
+
+ // We add the .got section to the result for dynamic MIPS target because
+ // its address and properties are mentioned in the .dynamic section.
+ if (Config->EMachine == EM_MIPS)
+ return true;
+
+ // If we have a relocation that is relative to GOT (such as GOTOFFREL),
+ // we need to emit a GOT even if it's empty.
+ return Out<ELFT>::Got->HasGotOffRel;
}
// This function add Out<ELFT>::* sections to OutputSections.
@@ -859,6 +783,17 @@ template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
OutputSections.push_back(C);
};
+ // A core file does not usually contain unmodified segments except
+ // the first page of the executable. Add the build ID section to beginning of
+ // the file so that the section is included in the first page.
+ if (Out<ELFT>::BuildId)
+ OutputSections.insert(OutputSections.begin(), Out<ELFT>::BuildId);
+
+ // Add .interp at first because some loaders want to see that section
+ // on the first page of the executable file when loaded into memory.
+ if (needsInterpSection())
+ OutputSections.insert(OutputSections.begin(), Out<ELFT>::Interp);
+
// This order is not the same as the final output order
// because we sort the sections using their attributes below.
Add(Out<ELFT>::SymTab);
@@ -866,25 +801,21 @@ template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
Add(Out<ELFT>::StrTab);
if (isOutputDynamic()) {
Add(Out<ELFT>::DynSymTab);
+
+ bool HasVerNeed = Out<ELFT>::VerNeed->getNeedNum() != 0;
+ if (Out<ELFT>::VerDef || HasVerNeed)
+ Add(Out<ELFT>::VerSym);
+ Add(Out<ELFT>::VerDef);
+ if (HasVerNeed)
+ Add(Out<ELFT>::VerNeed);
+
Add(Out<ELFT>::GnuHashTab);
Add(Out<ELFT>::HashTab);
Add(Out<ELFT>::Dynamic);
Add(Out<ELFT>::DynStrTab);
if (Out<ELFT>::RelaDyn->hasRelocs())
Add(Out<ELFT>::RelaDyn);
-
- // This is a MIPS specific section to hold a space within the data segment
- // of executable file which is pointed to by the DT_MIPS_RLD_MAP entry.
- // See "Dynamic section" in Chapter 5 in the following document:
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- if (Config->EMachine == EM_MIPS && !Config->Shared) {
- Out<ELFT>::MipsRldMap = new OutputSection<ELFT>(".rld_map", SHT_PROGBITS,
- SHF_ALLOC | SHF_WRITE);
- Out<ELFT>::MipsRldMap->setSize(ELFT::Is64Bits ? 8 : 4);
- Out<ELFT>::MipsRldMap->updateAlign(ELFT::Is64Bits ? 8 : 4);
- OwningSections.emplace_back(Out<ELFT>::MipsRldMap);
- Add(Out<ELFT>::MipsRldMap);
- }
+ Add(Out<ELFT>::MipsRldMap);
}
// We always need to add rel[a].plt to output if it has entries.
@@ -894,22 +825,16 @@ template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
Out<ELFT>::RelaPlt->Static = !isOutputDynamic();
}
- bool needsGot = !Out<ELFT>::Got->empty();
- // We add the .got section to the result for dynamic MIPS target because
- // its address and properties are mentioned in the .dynamic section.
- if (Config->EMachine == EM_MIPS)
- needsGot |= isOutputDynamic();
- // If we have a relocation that is relative to GOT (such as GOTOFFREL),
- // we need to emit a GOT even if it's empty.
- if (HasGotOffRel)
- needsGot = true;
-
- if (needsGot)
+ if (needsGot())
Add(Out<ELFT>::Got);
if (Out<ELFT>::GotPlt && !Out<ELFT>::GotPlt->empty())
Add(Out<ELFT>::GotPlt);
if (!Out<ELFT>::Plt->empty())
Add(Out<ELFT>::Plt);
+ if (!Out<ELFT>::EhFrame->empty())
+ Add(Out<ELFT>::EhFrameHdr);
+ if (Out<ELFT>::Bss->getSize() > 0)
+ Add(Out<ELFT>::Bss);
}
// The linker is expected to define SECNAME_start and SECNAME_end
@@ -918,11 +843,13 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
auto Define = [&](StringRef Start, StringRef End,
OutputSectionBase<ELFT> *OS) {
if (OS) {
- Symtab.addSynthetic(Start, *OS, 0);
- Symtab.addSynthetic(End, *OS, OS->getSize());
+ this->Symtab.addSynthetic(Start, OS, 0);
+ this->Symtab.addSynthetic(End, OS, DefinedSynthetic<ELFT>::SectionEnd);
} else {
- Symtab.addIgnored(Start);
- Symtab.addIgnored(End);
+ addOptionalSynthetic(this->Symtab, Start,
+ (OutputSectionBase<ELFT> *)nullptr, 0);
+ addOptionalSynthetic(this->Symtab, End,
+ (OutputSectionBase<ELFT> *)nullptr, 0);
}
};
@@ -934,19 +861,6 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
Out<ELFT>::Dynamic->FiniArraySec);
}
-static bool isAlpha(char C) {
- return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z') || C == '_';
-}
-
-static bool isAlnum(char C) { return isAlpha(C) || ('0' <= C && C <= '9'); }
-
-// Returns true if S is valid as a C language identifier.
-static bool isValidCIdentifier(StringRef S) {
- if (S.empty() || !isAlpha(S[0]))
- return false;
- return std::all_of(S.begin() + 1, S.end(), isAlnum);
-}
-
// If a section name is valid as a C identifier (which is rare because of
// the leading '.'), linkers are expected to define __start_<secname> and
// __stop_<secname> symbols. They are at beginning and end of the section,
@@ -962,14 +876,22 @@ void Writer<ELFT>::addStartStopSymbols(OutputSectionBase<ELFT> *Sec) {
StringRef Stop = Saver.save("__stop_" + S);
if (SymbolBody *B = Symtab.find(Start))
if (B->isUndefined())
- Symtab.addSynthetic(Start, *Sec, 0);
+ Symtab.addSynthetic(Start, Sec, 0);
if (SymbolBody *B = Symtab.find(Stop))
if (B->isUndefined())
- Symtab.addSynthetic(Stop, *Sec, Sec->getSize());
+ Symtab.addSynthetic(Stop, Sec, DefinedSynthetic<ELFT>::SectionEnd);
}
-template <class ELFT> static bool needsPhdr(OutputSectionBase<ELFT> *Sec) {
- return Sec->getFlags() & SHF_ALLOC;
+template <class ELFT> static bool needsPtLoad(OutputSectionBase<ELFT> *Sec) {
+ if (!(Sec->getFlags() & SHF_ALLOC))
+ return false;
+
+ // Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is
+ // responsible for allocating space for them, not the PT_LOAD that
+ // contains the TLS initialization image.
+ if (Sec->getFlags() & SHF_TLS && Sec->getType() == SHT_NOBITS)
+ return false;
+ return true;
}
static uint32_t toPhdrFlags(uint64_t Flags) {
@@ -981,269 +903,341 @@ static uint32_t toPhdrFlags(uint64_t Flags) {
return Ret;
}
-/// For AMDGPU we need to use custom segment kinds in order to specify which
-/// address space data should be loaded into.
-template <class ELFT>
-static uint32_t getAmdgpuPhdr(OutputSectionBase<ELFT> *Sec) {
- uint32_t Flags = Sec->getFlags();
- if (Flags & SHF_AMDGPU_HSA_CODE)
- return PT_AMDGPU_HSA_LOAD_CODE_AGENT;
- if ((Flags & SHF_AMDGPU_HSA_GLOBAL) && !(Flags & SHF_AMDGPU_HSA_AGENT))
- return PT_AMDGPU_HSA_LOAD_GLOBAL_PROGRAM;
- return PT_LOAD;
-}
-
-template <class ELFT>
-void Writer<ELFT>::updateRelro(Elf_Phdr *Cur, Elf_Phdr *GnuRelroPhdr,
- uintX_t VA) {
- if (!GnuRelroPhdr->p_type)
- setPhdr(GnuRelroPhdr, PT_GNU_RELRO, PF_R, Cur->p_offset, Cur->p_vaddr,
- VA - Cur->p_vaddr, 1 /*p_align*/);
- GnuRelroPhdr->p_filesz = VA - Cur->p_vaddr;
- GnuRelroPhdr->p_memsz = VA - Cur->p_vaddr;
-}
-
-// Visits all sections to create PHDRs and to assign incremental,
-// non-overlapping addresses to output sections.
-template <class ELFT> void Writer<ELFT>::assignAddresses() {
- uintX_t VA = Target->getVAStart() + sizeof(Elf_Ehdr);
- uintX_t FileOff = sizeof(Elf_Ehdr);
+// Decide which program headers to create and which sections to include in each
+// one.
+template <class ELFT> void Writer<ELFT>::createPhdrs() {
+ auto AddHdr = [this](unsigned Type, unsigned Flags) {
+ return &*Phdrs.emplace(Phdrs.end(), Type, Flags);
+ };
- // Calculate and reserve the space for the program header first so that
- // the first section can start right after the program header.
- Phdrs.resize(getPhdrsNum());
- size_t PhdrSize = sizeof(Elf_Phdr) * Phdrs.size();
+ auto AddSec = [](Phdr &Hdr, OutputSectionBase<ELFT> *Sec) {
+ Hdr.Last = Sec;
+ if (!Hdr.First)
+ Hdr.First = Sec;
+ Hdr.H.p_align = std::max<uintX_t>(Hdr.H.p_align, Sec->getAlignment());
+ };
// The first phdr entry is PT_PHDR which describes the program header itself.
- setPhdr(&Phdrs[0], PT_PHDR, PF_R, FileOff, VA, PhdrSize, /*Align=*/8);
- FileOff += PhdrSize;
- VA += PhdrSize;
+ Phdr &Hdr = *AddHdr(PT_PHDR, PF_R);
+ AddSec(Hdr, Out<ELFT>::ProgramHeaders);
// PT_INTERP must be the second entry if exists.
- int PhdrIdx = 0;
- Elf_Phdr *Interp = nullptr;
- if (needsInterpSection())
- Interp = &Phdrs[++PhdrIdx];
+ if (needsInterpSection()) {
+ Phdr &Hdr = *AddHdr(PT_INTERP, toPhdrFlags(Out<ELFT>::Interp->getFlags()));
+ AddSec(Hdr, Out<ELFT>::Interp);
+ }
// Add the first PT_LOAD segment for regular output sections.
- setPhdr(&Phdrs[++PhdrIdx], PT_LOAD, PF_R, 0, Target->getVAStart(), FileOff,
- Target->getPageSize());
-
- Elf_Phdr GnuRelroPhdr = {};
- Elf_Phdr TlsPhdr{};
- bool RelroAligned = false;
- uintX_t ThreadBssOffset = 0;
- // Create phdrs as we assign VAs and file offsets to all output sections.
+ uintX_t Flags = PF_R;
+ Phdr *Load = AddHdr(PT_LOAD, Flags);
+ AddSec(*Load, Out<ELFT>::ElfHeader);
+ AddSec(*Load, Out<ELFT>::ProgramHeaders);
+
+ Phdr TlsHdr(PT_TLS, PF_R);
+ Phdr RelRo(PT_GNU_RELRO, PF_R);
+ Phdr Note(PT_NOTE, PF_R);
for (OutputSectionBase<ELFT> *Sec : OutputSections) {
- Elf_Phdr *PH = &Phdrs[PhdrIdx];
- if (needsPhdr<ELFT>(Sec)) {
- uintX_t Flags = toPhdrFlags(Sec->getFlags());
- bool InRelRo = Config->ZRelro && (Flags & PF_W) && isRelroSection(Sec);
- bool FirstNonRelRo = GnuRelroPhdr.p_type && !InRelRo && !RelroAligned;
- if (FirstNonRelRo || PH->p_flags != Flags) {
- VA = align(VA, Target->getPageSize());
- FileOff = align(FileOff, Target->getPageSize());
- if (FirstNonRelRo)
- RelroAligned = true;
- }
+ if (!(Sec->getFlags() & SHF_ALLOC))
+ break;
- if (PH->p_flags != Flags) {
- // Flags changed. Create a new PT_LOAD.
- PH = &Phdrs[++PhdrIdx];
- uint32_t PTType = (Config->EMachine != EM_AMDGPU) ? (uint32_t)PT_LOAD
- : getAmdgpuPhdr(Sec);
- setPhdr(PH, PTType, Flags, FileOff, VA, 0, Target->getPageSize());
- }
+ // If we meet TLS section then we create TLS header
+ // and put all TLS sections inside for futher use when
+ // assign addresses.
+ if (Sec->getFlags() & SHF_TLS)
+ AddSec(TlsHdr, Sec);
- if (Sec->getFlags() & SHF_TLS) {
- if (!TlsPhdr.p_vaddr)
- setPhdr(&TlsPhdr, PT_TLS, PF_R, FileOff, VA, 0, Sec->getAlign());
- if (Sec->getType() != SHT_NOBITS)
- VA = align(VA, Sec->getAlign());
- uintX_t TVA = align(VA + ThreadBssOffset, Sec->getAlign());
- Sec->setVA(TVA);
- TlsPhdr.p_memsz += Sec->getSize();
- if (Sec->getType() == SHT_NOBITS) {
- ThreadBssOffset = TVA - VA + Sec->getSize();
- } else {
- TlsPhdr.p_filesz += Sec->getSize();
- VA += Sec->getSize();
- }
- TlsPhdr.p_align = std::max<uintX_t>(TlsPhdr.p_align, Sec->getAlign());
- } else {
- VA = align(VA, Sec->getAlign());
- Sec->setVA(VA);
- VA += Sec->getSize();
- if (InRelRo)
- updateRelro(PH, &GnuRelroPhdr, VA);
- }
- }
+ if (!needsPtLoad<ELFT>(Sec))
+ continue;
- FileOff = align(FileOff, Sec->getAlign());
- Sec->setFileOffset(FileOff);
- if (Sec->getType() != SHT_NOBITS)
- FileOff += Sec->getSize();
- if (needsPhdr<ELFT>(Sec)) {
- PH->p_filesz = FileOff - PH->p_offset;
- PH->p_memsz = VA - PH->p_vaddr;
+ // If flags changed then we want new load segment.
+ uintX_t NewFlags = toPhdrFlags(Sec->getFlags());
+ if (Flags != NewFlags) {
+ Load = AddHdr(PT_LOAD, NewFlags);
+ Flags = NewFlags;
}
- }
- if (TlsPhdr.p_vaddr) {
- // The TLS pointer goes after PT_TLS. At least glibc will align it,
- // so round up the size to make sure the offsets are correct.
- TlsPhdr.p_memsz = align(TlsPhdr.p_memsz, TlsPhdr.p_align);
- Phdrs[++PhdrIdx] = TlsPhdr;
- Out<ELFT>::TlsPhdr = &Phdrs[PhdrIdx];
+ AddSec(*Load, Sec);
+
+ if (isRelroSection(Sec))
+ AddSec(RelRo, Sec);
+ if (Sec->getType() == SHT_NOTE)
+ AddSec(Note, Sec);
}
+ // Add the TLS segment unless it's empty.
+ if (TlsHdr.First)
+ Phdrs.push_back(std::move(TlsHdr));
+
// Add an entry for .dynamic.
if (isOutputDynamic()) {
- Elf_Phdr *PH = &Phdrs[++PhdrIdx];
- PH->p_type = PT_DYNAMIC;
- copyPhdr(PH, Out<ELFT>::Dynamic);
+ Phdr &H = *AddHdr(PT_DYNAMIC, toPhdrFlags(Out<ELFT>::Dynamic->getFlags()));
+ AddSec(H, Out<ELFT>::Dynamic);
}
- if (HasRelro) {
- Elf_Phdr *PH = &Phdrs[++PhdrIdx];
- *PH = GnuRelroPhdr;
+ // PT_GNU_RELRO includes all sections that should be marked as
+ // read-only by dynamic linker after proccessing relocations.
+ if (RelRo.First)
+ Phdrs.push_back(std::move(RelRo));
+
+ // PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr.
+ if (!Out<ELFT>::EhFrame->empty() && Out<ELFT>::EhFrameHdr) {
+ Phdr &Hdr = *AddHdr(PT_GNU_EH_FRAME,
+ toPhdrFlags(Out<ELFT>::EhFrameHdr->getFlags()));
+ AddSec(Hdr, Out<ELFT>::EhFrameHdr);
}
// PT_GNU_STACK is a special section to tell the loader to make the
// pages for the stack non-executable.
- if (!Config->ZExecStack) {
- Elf_Phdr *PH = &Phdrs[++PhdrIdx];
- PH->p_type = PT_GNU_STACK;
- PH->p_flags = PF_R | PF_W;
+ if (!Config->ZExecStack)
+ AddHdr(PT_GNU_STACK, PF_R | PF_W);
+
+ if (Note.First)
+ Phdrs.push_back(std::move(Note));
+
+ Out<ELFT>::ProgramHeaders->setSize(sizeof(Elf_Phdr) * Phdrs.size());
+}
+
+// The first section of each PT_LOAD and the first section after PT_GNU_RELRO
+// have to be page aligned so that the dynamic linker can set the permissions.
+template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
+ for (const Phdr &P : Phdrs)
+ if (P.H.p_type == PT_LOAD)
+ P.First->PageAlign = true;
+
+ for (const Phdr &P : Phdrs) {
+ if (P.H.p_type != PT_GNU_RELRO)
+ continue;
+ // Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we
+ // have to align it to a page.
+ auto End = OutputSections.end();
+ auto I = std::find(OutputSections.begin(), End, P.Last);
+ if (I == End || (I + 1) == End)
+ continue;
+ OutputSectionBase<ELFT> *Sec = *(I + 1);
+ if (needsPtLoad(Sec))
+ Sec->PageAlign = true;
}
+}
- // Fix up PT_INTERP as we now know the address of .interp section.
- if (Interp) {
- Interp->p_type = PT_INTERP;
- copyPhdr(Interp, Out<ELFT>::Interp);
+// We should set file offsets and VAs for elf header and program headers
+// sections. These are special, we do not include them into output sections
+// list, but have them to simplify the code.
+template <class ELFT> void Writer<ELFT>::fixHeaders() {
+ uintX_t BaseVA = ScriptConfig->DoLayout ? 0 : Config->ImageBase;
+ Out<ELFT>::ElfHeader->setVA(BaseVA);
+ uintX_t Off = Out<ELFT>::ElfHeader->getSize();
+ Out<ELFT>::ProgramHeaders->setVA(Off + BaseVA);
+}
+
+// Assign VAs (addresses at run-time) to output sections.
+template <class ELFT> void Writer<ELFT>::assignAddresses() {
+ uintX_t VA = Config->ImageBase + Out<ELFT>::ElfHeader->getSize() +
+ Out<ELFT>::ProgramHeaders->getSize();
+
+ uintX_t ThreadBssOffset = 0;
+ for (OutputSectionBase<ELFT> *Sec : OutputSections) {
+ uintX_t Alignment = Sec->getAlignment();
+ if (Sec->PageAlign)
+ Alignment = std::max<uintX_t>(Alignment, Target->PageSize);
+
+ // We only assign VAs to allocated sections.
+ if (needsPtLoad<ELFT>(Sec)) {
+ VA = alignTo(VA, Alignment);
+ Sec->setVA(VA);
+ VA += Sec->getSize();
+ } else if (Sec->getFlags() & SHF_TLS && Sec->getType() == SHT_NOBITS) {
+ uintX_t TVA = VA + ThreadBssOffset;
+ TVA = alignTo(TVA, Alignment);
+ Sec->setVA(TVA);
+ ThreadBssOffset = TVA - VA + Sec->getSize();
+ }
}
+}
+
+// Adjusts the file alignment for a given output section and returns
+// its new file offset. The file offset must be the same with its
+// virtual address (modulo the page size) so that the loader can load
+// executables without any address adjustment.
+template <class ELFT, class uintX_t>
+static uintX_t getFileAlignment(uintX_t Off, OutputSectionBase<ELFT> *Sec) {
+ uintX_t Alignment = Sec->getAlignment();
+ if (Sec->PageAlign)
+ Alignment = std::max<uintX_t>(Alignment, Target->PageSize);
+ Off = alignTo(Off, Alignment);
+
+ // Relocatable output does not have program headers
+ // and does not need any other offset adjusting.
+ if (Config->Relocatable || !(Sec->getFlags() & SHF_ALLOC))
+ return Off;
+ return alignTo(Off, Target->PageSize, Sec->getVA());
+}
+
+// Assign file offsets to output sections.
+template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
+ uintX_t Off = 0;
- // Add space for section headers.
- SectionHeaderOff = align(FileOff, ELFT::Is64Bits ? 8 : 4);
- FileSize = SectionHeaderOff + getNumSections() * sizeof(Elf_Shdr);
+ auto Set = [&](OutputSectionBase<ELFT> *Sec) {
+ if (Sec->getType() == SHT_NOBITS) {
+ Sec->setFileOffset(Off);
+ return;
+ }
- // Update "_end" and "end" symbols so that they
- // point to the end of the data segment.
- ElfSym<ELFT>::End.st_value = VA;
+ Off = getFileAlignment<ELFT>(Off, Sec);
+ Sec->setFileOffset(Off);
+ Off += Sec->getSize();
+ };
+
+ Set(Out<ELFT>::ElfHeader);
+ Set(Out<ELFT>::ProgramHeaders);
+ for (OutputSectionBase<ELFT> *Sec : OutputSections)
+ Set(Sec);
+
+ SectionHeaderOff = alignTo(Off, sizeof(uintX_t));
+ FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr);
}
-// Returns the number of PHDR entries.
-template <class ELFT> int Writer<ELFT>::getPhdrsNum() const {
- bool Tls = false;
- int I = 2; // 2 for PT_PHDR and first PT_LOAD
- if (needsInterpSection())
- ++I;
- if (isOutputDynamic())
- ++I;
- if (!Config->ZExecStack)
- ++I;
- uintX_t Last = PF_R;
- for (OutputSectionBase<ELFT> *Sec : OutputSections) {
- if (!needsPhdr<ELFT>(Sec))
- continue;
- if (Sec->getFlags() & SHF_TLS)
- Tls = true;
- uintX_t Flags = toPhdrFlags(Sec->getFlags());
- if (Last != Flags) {
- Last = Flags;
- ++I;
+// Finalize the program headers. We call this function after we assign
+// file offsets and VAs to all sections.
+template <class ELFT> void Writer<ELFT>::setPhdrs() {
+ for (Phdr &P : Phdrs) {
+ Elf_Phdr &H = P.H;
+ OutputSectionBase<ELFT> *First = P.First;
+ OutputSectionBase<ELFT> *Last = P.Last;
+ if (First) {
+ H.p_filesz = Last->getFileOff() - First->getFileOff();
+ if (Last->getType() != SHT_NOBITS)
+ H.p_filesz += Last->getSize();
+ H.p_memsz = Last->getVA() + Last->getSize() - First->getVA();
+ H.p_offset = First->getFileOff();
+ H.p_vaddr = First->getVA();
+ }
+ if (H.p_type == PT_LOAD)
+ H.p_align = Target->PageSize;
+ else if (H.p_type == PT_GNU_RELRO)
+ H.p_align = 1;
+ H.p_paddr = H.p_vaddr;
+
+ // The TLS pointer goes after PT_TLS. At least glibc will align it,
+ // so round up the size to make sure the offsets are correct.
+ if (H.p_type == PT_TLS) {
+ Out<ELFT>::TlsPhdr = &H;
+ H.p_memsz = alignTo(H.p_memsz, H.p_align);
}
}
- if (Tls)
- ++I;
- if (HasRelro)
- ++I;
- return I;
}
-static uint32_t getELFFlags() {
- if (Config->EMachine != EM_MIPS)
- return 0;
+static uint32_t getMipsEFlags(bool Is64Bits) {
// FIXME: In fact ELF flags depends on ELF flags of input object files
// and selected emulation. For now just use hard coded values.
- uint32_t V = EF_MIPS_ABI_O32 | EF_MIPS_CPIC | EF_MIPS_ARCH_32R2;
+ if (Is64Bits)
+ return EF_MIPS_CPIC | EF_MIPS_PIC | EF_MIPS_ARCH_64R2;
+
+ uint32_t V = EF_MIPS_CPIC | EF_MIPS_ABI_O32 | EF_MIPS_ARCH_32R2;
if (Config->Shared)
V |= EF_MIPS_PIC;
return V;
}
-template <class ELFT>
-static typename ELFFile<ELFT>::uintX_t getEntryAddr() {
- if (Config->EntrySym) {
- if (SymbolBody *E = Config->EntrySym->repl())
- return getSymVA<ELFT>(*E);
- return 0;
- }
+template <class ELFT> static typename ELFT::uint getEntryAddr() {
+ if (Symbol *S = Config->EntrySym)
+ return S->body()->getVA<ELFT>();
if (Config->EntryAddr != uint64_t(-1))
return Config->EntryAddr;
return 0;
}
+template <class ELFT> static uint8_t getELFEncoding() {
+ if (ELFT::TargetEndianness == llvm::support::little)
+ return ELFDATA2LSB;
+ return ELFDATA2MSB;
+}
+
+static uint16_t getELFType() {
+ if (Config->Pic)
+ return ET_DYN;
+ if (Config->Relocatable)
+ return ET_REL;
+ return ET_EXEC;
+}
+
// This function is called after we have assigned address and size
// to each section. This function fixes some predefined absolute
// symbol values that depend on section address and size.
template <class ELFT> void Writer<ELFT>::fixAbsoluteSymbols() {
- // Update __rel[a]_iplt_{start,end} symbols so that they point
- // to beginning or ending of .rela.plt section, respectively.
- if (Out<ELFT>::RelaPlt) {
- uintX_t Start = Out<ELFT>::RelaPlt->getVA();
- ElfSym<ELFT>::RelaIpltStart.st_value = Start;
- ElfSym<ELFT>::RelaIpltEnd.st_value = Start + Out<ELFT>::RelaPlt->getSize();
- }
+ auto Set = [](DefinedRegular<ELFT> *S1, DefinedRegular<ELFT> *S2, uintX_t V) {
+ if (S1)
+ S1->Value = V;
+ if (S2)
+ S2->Value = V;
+ };
- // Update MIPS _gp absolute symbol so that it points to the static data.
- if (Config->EMachine == EM_MIPS)
- ElfSym<ELFT>::MipsGp.st_value = getMipsGpAddr<ELFT>();
+ // _etext is the first location after the last read-only loadable segment.
+ // _edata is the first location after the last read-write loadable segment.
+ // _end is the first location after the uninitialized data region.
+ for (Phdr &P : Phdrs) {
+ Elf_Phdr &H = P.H;
+ if (H.p_type != PT_LOAD)
+ continue;
+ Set(ElfSym<ELFT>::End, ElfSym<ELFT>::End2, H.p_vaddr + H.p_memsz);
+
+ uintX_t Val = H.p_vaddr + H.p_filesz;
+ if (H.p_flags & PF_W)
+ Set(ElfSym<ELFT>::Edata, ElfSym<ELFT>::Edata2, Val);
+ else
+ Set(ElfSym<ELFT>::Etext, ElfSym<ELFT>::Etext2, Val);
+ }
}
template <class ELFT> void Writer<ELFT>::writeHeader() {
uint8_t *Buf = Buffer->getBufferStart();
memcpy(Buf, "\177ELF", 4);
+ auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf);
+
// Write the ELF header.
auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
EHdr->e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
- EHdr->e_ident[EI_DATA] = ELFT::TargetEndianness == llvm::support::little
- ? ELFDATA2LSB
- : ELFDATA2MSB;
+ EHdr->e_ident[EI_DATA] = getELFEncoding<ELFT>();
EHdr->e_ident[EI_VERSION] = EV_CURRENT;
-
- auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf);
EHdr->e_ident[EI_OSABI] = FirstObj.getOSABI();
-
- EHdr->e_type = Config->Shared ? ET_DYN : ET_EXEC;
- EHdr->e_machine = FirstObj.getEMachine();
+ EHdr->e_type = getELFType();
+ EHdr->e_machine = FirstObj.EMachine;
EHdr->e_version = EV_CURRENT;
EHdr->e_entry = getEntryAddr<ELFT>();
- EHdr->e_phoff = sizeof(Elf_Ehdr);
EHdr->e_shoff = SectionHeaderOff;
- EHdr->e_flags = getELFFlags();
EHdr->e_ehsize = sizeof(Elf_Ehdr);
- EHdr->e_phentsize = sizeof(Elf_Phdr);
EHdr->e_phnum = Phdrs.size();
EHdr->e_shentsize = sizeof(Elf_Shdr);
- EHdr->e_shnum = getNumSections();
+ EHdr->e_shnum = OutputSections.size() + 1;
EHdr->e_shstrndx = Out<ELFT>::ShStrTab->SectionIndex;
+ if (Config->EMachine == EM_MIPS)
+ EHdr->e_flags = getMipsEFlags(ELFT::Is64Bits);
+
+ if (!Config->Relocatable) {
+ EHdr->e_phoff = sizeof(Elf_Ehdr);
+ EHdr->e_phentsize = sizeof(Elf_Phdr);
+ }
+
// Write the program header table.
- memcpy(Buf + EHdr->e_phoff, &Phdrs[0], Phdrs.size() * sizeof(Phdrs[0]));
+ auto *HBuf = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff);
+ for (Phdr &P : Phdrs)
+ *HBuf++ = P.H;
// Write the section header table. Note that the first table entry is null.
- auto SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
+ auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
for (OutputSectionBase<ELFT> *Sec : OutputSections)
Sec->writeHeaderTo(++SHdrs);
}
-template <class ELFT> void Writer<ELFT>::openFile(StringRef Path) {
+template <class ELFT> void Writer<ELFT>::openFile() {
ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
- FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable);
- error(BufferOrErr, "failed to open " + Path);
- Buffer = std::move(*BufferOrErr);
+ FileOutputBuffer::create(Config->OutputFile, FileSize,
+ FileOutputBuffer::F_executable);
+ if (auto EC = BufferOrErr.getError())
+ error(EC, "failed to open " + Config->OutputFile);
+ else
+ Buffer = std::move(*BufferOrErr);
}
// Write section contents to a mmap'ed file.
@@ -1257,53 +1251,33 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
Sec->writeTo(Buf + Sec->getFileOff());
}
- // Write all sections but string table sections. We know the sizes of the
- // string tables already, but they may not have actual strings yet (only
- // room may be reserved), because writeTo() is allowed to add actual
- // strings to the string tables.
for (OutputSectionBase<ELFT> *Sec : OutputSections)
- if (Sec != Out<ELFT>::Opd && Sec->getType() != SHT_STRTAB)
+ if (Sec != Out<ELFT>::Opd)
Sec->writeTo(Buf + Sec->getFileOff());
-
- // Write string table sections.
- for (OutputSectionBase<ELFT> *Sec : OutputSections)
- if (Sec != Out<ELFT>::Opd && Sec->getType() == SHT_STRTAB)
- Sec->writeTo(Buf + Sec->getFileOff());
-}
-
-template <class ELFT>
-void Writer<ELFT>::setPhdr(Elf_Phdr *PH, uint32_t Type, uint32_t Flags,
- uintX_t FileOff, uintX_t VA, uintX_t Size,
- uintX_t Align) {
- PH->p_type = Type;
- PH->p_flags = Flags;
- PH->p_offset = FileOff;
- PH->p_vaddr = VA;
- PH->p_paddr = VA;
- PH->p_filesz = Size;
- PH->p_memsz = Size;
- PH->p_align = Align;
}
-template <class ELFT>
-void Writer<ELFT>::copyPhdr(Elf_Phdr *PH, OutputSectionBase<ELFT> *From) {
- PH->p_flags = toPhdrFlags(From->getFlags());
- PH->p_offset = From->getFileOff();
- PH->p_vaddr = From->getVA();
- PH->p_paddr = From->getVA();
- PH->p_filesz = From->getSize();
- PH->p_memsz = From->getSize();
- PH->p_align = From->getAlign();
-}
+template <class ELFT> void Writer<ELFT>::writeBuildId() {
+ if (!Out<ELFT>::BuildId)
+ return;
-template <class ELFT> void Writer<ELFT>::buildSectionMap() {
- for (const std::pair<StringRef, std::vector<StringRef>> &OutSec :
- Config->OutputSections)
- for (StringRef Name : OutSec.second)
- InputToOutputSection[Name] = OutSec.first;
+ // Compute a hash of all sections except .debug_* sections.
+ // We skip debug sections because they tend to be very large
+ // and their contents are very likely to be the same as long as
+ // other sections are the same.
+ uint8_t *Start = Buffer->getBufferStart();
+ uint8_t *Last = Start;
+ std::vector<ArrayRef<uint8_t>> Regions;
+ for (OutputSectionBase<ELFT> *Sec : OutputSections) {
+ uint8_t *End = Start + Sec->getFileOff();
+ if (!Sec->getName().startswith(".debug_"))
+ Regions.push_back({Last, End});
+ Last = End;
+ }
+ Regions.push_back({Last, Start + FileSize});
+ Out<ELFT>::BuildId->writeBuildId(Regions);
}
-template void elf2::writeResult<ELF32LE>(SymbolTable<ELF32LE> *Symtab);
-template void elf2::writeResult<ELF32BE>(SymbolTable<ELF32BE> *Symtab);
-template void elf2::writeResult<ELF64LE>(SymbolTable<ELF64LE> *Symtab);
-template void elf2::writeResult<ELF64BE>(SymbolTable<ELF64BE> *Symtab);
+template void elf::writeResult<ELF32LE>(SymbolTable<ELF32LE> *Symtab);
+template void elf::writeResult<ELF32BE>(SymbolTable<ELF32BE> *Symtab);
+template void elf::writeResult<ELF64LE>(SymbolTable<ELF64LE> *Symtab);
+template void elf::writeResult<ELF64BE>(SymbolTable<ELF64BE> *Symtab);