Index: vendor/lld/dist/ELF/SymbolTable.cpp =================================================================== --- vendor/lld/dist/ELF/SymbolTable.cpp (revision 312631) +++ vendor/lld/dist/ELF/SymbolTable.cpp (revision 312632) @@ -1,700 +1,704 @@ //===- SymbolTable.cpp ----------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Symbol table is a bag of all known symbols. We put all symbols of // all input files to the symbol table. The symbol table is basically // a hash table with the logic to resolve symbol name conflicts using // the symbol types. // //===----------------------------------------------------------------------===// #include "SymbolTable.h" #include "Config.h" #include "Error.h" #include "LinkerScript.h" #include "Memory.h" #include "Symbols.h" #include "llvm/ADT/STLExtras.h" using namespace llvm; using namespace llvm::object; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; // All input object files must be for the same architecture // (e.g. it does not make sense to link x86 object files with // MIPS object files.) This function checks for that error. template static bool isCompatible(InputFile *F) { if (!isa>(F) && !isa(F)) return true; if (F->EKind == Config->EKind && F->EMachine == Config->EMachine) { if (Config->EMachine != EM_MIPS) return true; if (isMipsN32Abi(F) == Config->MipsN32Abi) return true; } if (!Config->Emulation.empty()) error(toString(F) + " is incompatible with " + Config->Emulation); else error(toString(F) + " is incompatible with " + toString(Config->FirstElf)); return false; } // Add symbols in File to the symbol table. template void SymbolTable::addFile(InputFile *File) { if (!isCompatible(File)) return; // Binary file if (auto *F = dyn_cast(File)) { BinaryFiles.push_back(F); F->parse(); return; } // .a file if (auto *F = dyn_cast(File)) { F->parse(); return; } // Lazy object file if (auto *F = dyn_cast(File)) { F->parse(); return; } if (Config->Trace) outs() << toString(File) << "\n"; // .so file if (auto *F = dyn_cast>(File)) { // DSOs are uniquified not by filename but by soname. F->parseSoName(); if (ErrorCount || !SoNames.insert(F->getSoName()).second) return; SharedFiles.push_back(F); F->parseRest(); return; } // LLVM bitcode file if (auto *F = dyn_cast(File)) { BitcodeFiles.push_back(F); F->parse(ComdatGroups); return; } // Regular object file auto *F = cast>(File); ObjectFiles.push_back(F); F->parse(ComdatGroups); } // This function is where all the optimizations of link-time // optimization happens. When LTO is in use, some input files are // not in native object file format but in the LLVM bitcode format. // This function compiles bitcode files into a few big native files // using LLVM functions and replaces bitcode symbols with the results. // Because all bitcode files that consist of a program are passed // to the compiler at once, it can do whole-program optimization. template void SymbolTable::addCombinedLTOObject() { if (BitcodeFiles.empty()) return; // Compile bitcode files and replace bitcode symbols. LTO.reset(new BitcodeCompiler); for (BitcodeFile *F : BitcodeFiles) LTO->add(*F); for (InputFile *File : LTO->compile()) { ObjectFile *Obj = cast>(File); DenseSet DummyGroups; Obj->parse(DummyGroups); ObjectFiles.push_back(Obj); } } template DefinedRegular *SymbolTable::addAbsolute(StringRef Name, uint8_t Visibility, uint8_t Binding) { Symbol *Sym = addRegular(Name, Visibility, STT_NOTYPE, 0, 0, Binding, nullptr, nullptr); return cast>(Sym->body()); } // Add Name as an "ignored" symbol. An ignored symbol is a regular // linker-synthesized defined symbol, but is only defined if needed. template DefinedRegular *SymbolTable::addIgnored(StringRef Name, uint8_t Visibility) { SymbolBody *S = find(Name); - if (!S || !S->isUndefined()) + if (!S || S->isInCurrentDSO()) return nullptr; return addAbsolute(Name, Visibility); } // Set a flag for --trace-symbol so that we can print out a log message // if a new symbol with the same name is inserted into the symbol table. template void SymbolTable::trace(StringRef Name) { Symtab.insert({CachedHashStringRef(Name), {-1, true}}); } // Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM. // Used to implement --wrap. template void SymbolTable::wrap(StringRef Name) { SymbolBody *B = find(Name); if (!B) return; Symbol *Sym = B->symbol(); Symbol *Real = addUndefined(Saver.save("__real_" + Name)); Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name)); // We rename symbols by replacing the old symbol's SymbolBody with the new // symbol's SymbolBody. This causes all SymbolBody pointers referring to the // old symbol to instead refer to the new symbol. memcpy(Real->Body.buffer, Sym->Body.buffer, sizeof(Sym->Body)); memcpy(Sym->Body.buffer, Wrap->Body.buffer, sizeof(Wrap->Body)); } static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { if (VA == STV_DEFAULT) return VB; if (VB == STV_DEFAULT) return VA; return std::min(VA, VB); } // Find an existing symbol or create and insert a new one. template std::pair SymbolTable::insert(StringRef Name) { auto P = Symtab.insert( {CachedHashStringRef(Name), SymIndex((int)SymVector.size(), false)}); SymIndex &V = P.first->second; bool IsNew = P.second; if (V.Idx == -1) { IsNew = true; V = SymIndex((int)SymVector.size(), true); } Symbol *Sym; if (IsNew) { Sym = new (BAlloc) Symbol; Sym->InVersionScript = false; Sym->Binding = STB_WEAK; Sym->Visibility = STV_DEFAULT; Sym->IsUsedInRegularObj = false; Sym->ExportDynamic = false; Sym->Traced = V.Traced; Sym->VersionId = Config->DefaultSymbolVersion; SymVector.push_back(Sym); } else { Sym = SymVector[V.Idx]; } return {Sym, IsNew}; } // Construct a string in the form of "Sym in File1 and File2". // Used to construct an error message. static std::string conflictMsg(SymbolBody *Existing, InputFile *NewFile) { return "'" + toString(*Existing) + "' in " + toString(Existing->File) + " and " + toString(NewFile); } // Find an existing symbol or create and insert a new one, then apply the given // attributes. template std::pair SymbolTable::insert(StringRef Name, uint8_t Type, uint8_t Visibility, bool CanOmitFromDynSym, InputFile *File) { bool IsUsedInRegularObj = !File || File->kind() == InputFile::ObjectKind; Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); // Merge in the new symbol's visibility. S->Visibility = getMinVisibility(S->Visibility, Visibility); if (!CanOmitFromDynSym && (Config->Shared || Config->ExportDynamic)) S->ExportDynamic = true; if (IsUsedInRegularObj) S->IsUsedInRegularObj = true; if (!WasInserted && S->body()->Type != SymbolBody::UnknownType && ((Type == STT_TLS) != S->body()->isTls())) error("TLS attribute mismatch for symbol " + conflictMsg(S->body(), File)); return {S, WasInserted}; } template Symbol *SymbolTable::addUndefined(StringRef Name) { return addUndefined(Name, /*IsLocal=*/false, STB_GLOBAL, STV_DEFAULT, /*Type*/ 0, /*CanOmitFromDynSym*/ false, /*File*/ nullptr); } static uint8_t getVisibility(uint8_t StOther) { return StOther & 3; } template Symbol *SymbolTable::addUndefined(StringRef Name, bool IsLocal, uint8_t Binding, uint8_t StOther, uint8_t Type, bool CanOmitFromDynSym, InputFile *File) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, File); if (WasInserted) { S->Binding = Binding; replaceBody>(S, Name, IsLocal, StOther, Type, File); return S; } if (Binding != STB_WEAK) { if (S->body()->isShared() || S->body()->isLazy()) S->Binding = Binding; if (auto *SS = dyn_cast>(S->body())) SS->file()->IsUsed = true; } if (auto *L = dyn_cast(S->body())) { // An undefined weak will not fetch archive members, but we have to remember // its type. See also comment in addLazyArchive. if (S->isWeak()) L->Type = Type; else if (InputFile *F = L->fetch()) addFile(F); } return S; } // We have a new defined symbol with the specified binding. Return 1 if the new // symbol should win, -1 if the new symbol should lose, or 0 if both symbols are // strong defined symbols. static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) { if (WasInserted) return 1; SymbolBody *Body = S->body(); - if (Body->isLazy() || Body->isUndefined() || Body->isShared()) + if (Body->isLazy() || !Body->isInCurrentDSO()) return 1; if (Binding == STB_WEAK) return -1; if (S->isWeak()) return 1; return 0; } // We have a new non-common defined symbol with the specified binding. Return 1 // if the new symbol should win, -1 if the new symbol should lose, or 0 if there // is a conflict. If the new symbol wins, also update the binding. template static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding, bool IsAbsolute, typename ELFT::uint Value) { if (int Cmp = compareDefined(S, WasInserted, Binding)) { if (Cmp > 0) S->Binding = Binding; return Cmp; } SymbolBody *B = S->body(); if (isa(B)) { // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) warn("common " + S->body()->getName() + " is overridden"); return 1; } else if (auto *R = dyn_cast>(B)) { if (R->Section == nullptr && Binding == STB_GLOBAL && IsAbsolute && R->Value == Value) return -1; } return 0; } template Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint64_t Alignment, uint8_t Binding, uint8_t StOther, uint8_t Type, InputFile *File) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther), /*CanOmitFromDynSym*/ false, File); int Cmp = compareDefined(S, WasInserted, Binding); if (Cmp > 0) { S->Binding = Binding; replaceBody(S, N, Size, Alignment, StOther, Type, File); } else if (Cmp == 0) { auto *C = dyn_cast(S->body()); if (!C) { // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) warn("common " + S->body()->getName() + " is overridden"); return S; } if (Config->WarnCommon) warn("multiple common of " + S->body()->getName()); Alignment = C->Alignment = std::max(C->Alignment, Alignment); if (Size > C->Size) replaceBody(S, N, Size, Alignment, StOther, Type, File); } return S; } static void print(const Twine &Msg) { if (Config->AllowMultipleDefinition) warn(Msg); else error(Msg); } static void reportDuplicate(SymbolBody *Existing, InputFile *NewFile) { print("duplicate symbol " + conflictMsg(Existing, NewFile)); } template static void reportDuplicate(SymbolBody *Existing, InputSectionBase *ErrSec, typename ELFT::uint ErrOffset) { DefinedRegular *D = dyn_cast>(Existing); if (!D || !D->Section || !ErrSec) { reportDuplicate(Existing, ErrSec ? ErrSec->getFile() : nullptr); return; } std::string OldLoc = D->Section->getLocation(D->Value); std::string NewLoc = ErrSec->getLocation(ErrOffset); print(NewLoc + ": duplicate symbol '" + toString(*Existing) + "'"); print(OldLoc + ": previous definition was here"); } template Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type, uintX_t Value, uintX_t Size, uint8_t Binding, InputSectionBase *Section, InputFile *File) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther), /*CanOmitFromDynSym*/ false, File); int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, Section == nullptr, Value); if (Cmp > 0) replaceBody>(S, Name, /*IsLocal=*/false, StOther, Type, Value, Size, Section, File); else if (Cmp == 0) reportDuplicate(S->body(), Section, Value); return S; } template Symbol *SymbolTable::addSynthetic(StringRef N, const OutputSectionBase *Section, uintX_t Value, uint8_t StOther) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N, STT_NOTYPE, getVisibility(StOther), /*CanOmitFromDynSym*/ false, nullptr); int Cmp = compareDefinedNonCommon(S, WasInserted, STB_GLOBAL, /*IsAbsolute*/ false, /*Value*/ 0); if (Cmp > 0) replaceBody(S, N, Value, Section); else if (Cmp == 0) reportDuplicate(S->body(), nullptr); return S; } template void SymbolTable::addShared(SharedFile *F, StringRef Name, const Elf_Sym &Sym, const typename ELFT::Verdef *Verdef) { // DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT // as the visibility, which will leave the visibility in the symbol table // unchanged. Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name, Sym.getType(), STV_DEFAULT, /*CanOmitFromDynSym*/ true, F); // Make sure we preempt DSO symbols with default visibility. - if (Sym.getVisibility() == STV_DEFAULT) { + if (Sym.getVisibility() == STV_DEFAULT) S->ExportDynamic = true; - // Exporting preempting symbols takes precedence over linker scripts. - if (S->VersionId == VER_NDX_LOCAL) - S->VersionId = VER_NDX_GLOBAL; - } if (WasInserted || isa>(S->body())) { replaceBody>(S, F, Name, Sym, Verdef); if (!S->isWeak()) F->IsUsed = true; } } template Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type, bool CanOmitFromDynSym, BitcodeFile *F) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, F); int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, /*IsAbs*/ false, /*Value*/ 0); if (Cmp > 0) replaceBody>(S, Name, /*IsLocal=*/false, StOther, Type, 0, 0, nullptr, F); else if (Cmp == 0) reportDuplicate(S->body(), F); return S; } template SymbolBody *SymbolTable::find(StringRef Name) { auto It = Symtab.find(CachedHashStringRef(Name)); if (It == Symtab.end()) return nullptr; SymIndex V = It->second; if (V.Idx == -1) return nullptr; return SymVector[V.Idx]->body(); +} + +template +SymbolBody *SymbolTable::findInCurrentDSO(StringRef Name) { + if (SymbolBody *S = find(Name)) + if (S->isInCurrentDSO()) + return S; + return nullptr; } template void SymbolTable::addLazyArchive(ArchiveFile *F, const object::Archive::Symbol Sym) { Symbol *S; bool WasInserted; StringRef Name = Sym.getName(); std::tie(S, WasInserted) = insert(Name); if (WasInserted) { replaceBody(S, *F, Sym, SymbolBody::UnknownType); return; } if (!S->body()->isUndefined()) return; // Weak undefined symbols should not fetch members from archives. If we were // to keep old symbol we would not know that an archive member was available // if a strong undefined symbol shows up afterwards in the link. If a strong // undefined symbol never shows up, this lazy symbol will get to the end of // the link and must be treated as the weak undefined one. We already marked // this symbol as used when we added it to the symbol table, but we also need // to preserve its type. FIXME: Move the Type field to Symbol. if (S->isWeak()) { replaceBody(S, *F, Sym, S->body()->Type); return; } std::pair MBInfo = F->getMember(&Sym); if (!MBInfo.first.getBuffer().empty()) addFile(createObjectFile(MBInfo.first, F->getName(), MBInfo.second)); } template void SymbolTable::addLazyObject(StringRef Name, LazyObjectFile &Obj) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); if (WasInserted) { replaceBody(S, Name, Obj, SymbolBody::UnknownType); return; } if (!S->body()->isUndefined()) return; // See comment for addLazyArchive above. if (S->isWeak()) { replaceBody(S, Name, Obj, S->body()->Type); } else { MemoryBufferRef MBRef = Obj.getBuffer(); if (!MBRef.getBuffer().empty()) addFile(createObjectFile(MBRef)); } } // Process undefined (-u) flags by loading lazy symbols named by those flags. template void SymbolTable::scanUndefinedFlags() { for (StringRef S : Config->Undefined) if (auto *L = dyn_cast_or_null(find(S))) if (InputFile *File = L->fetch()) addFile(File); } // This function takes care of the case in which shared libraries depend on // the user program (not the other way, which is usual). Shared libraries // may have undefined symbols, expecting that the user program provides // the definitions for them. An example is BSD's __progname symbol. // We need to put such symbols to the main program's .dynsym so that // shared libraries can find them. // Except this, we ignore undefined symbols in DSOs. template void SymbolTable::scanShlibUndefined() { for (SharedFile *File : SharedFiles) for (StringRef U : File->getUndefinedSymbols()) if (SymbolBody *Sym = find(U)) if (Sym->isDefined()) Sym->symbol()->ExportDynamic = true; } // Initialize DemangledSyms with a map from demangled symbols to symbol // objects. Used to handle "extern C++" directive in version scripts. // // The map will contain all demangled symbols. That can be very large, // and in LLD we generally want to avoid do anything for each symbol. // Then, why are we doing this? Here's why. // // Users can use "extern C++ {}" directive to match against demangled // C++ symbols. For example, you can write a pattern such as // "llvm::*::foo(int, ?)". Obviously, there's no way to handle this // other than trying to match a pattern against all demangled symbols. // So, if "extern C++" feature is used, we need to demangle all known // symbols. template StringMap> &SymbolTable::getDemangledSyms() { if (!DemangledSyms) { DemangledSyms.emplace(); for (Symbol *Sym : SymVector) { SymbolBody *B = Sym->body(); if (B->isUndefined()) continue; if (Optional S = demangle(B->getName())) (*DemangledSyms)[*S].push_back(B); else (*DemangledSyms)[B->getName()].push_back(B); } } return *DemangledSyms; } template std::vector SymbolTable::findByVersion(SymbolVersion Ver) { if (Ver.IsExternCpp) return getDemangledSyms().lookup(Ver.Name); if (SymbolBody *B = find(Ver.Name)) if (!B->isUndefined()) return {B}; return {}; } template std::vector SymbolTable::findAllByVersion(SymbolVersion Ver) { std::vector Res; StringMatcher M(Ver.Name); if (Ver.IsExternCpp) { for (auto &P : getDemangledSyms()) if (M.match(P.first())) Res.insert(Res.end(), P.second.begin(), P.second.end()); return Res; } for (Symbol *Sym : SymVector) { SymbolBody *B = Sym->body(); if (!B->isUndefined() && M.match(B->getName())) Res.push_back(B); } return Res; } // If there's only one anonymous version definition in a version // script file, the script does not actually define any symbol version, // but just specifies symbols visibilities. template void SymbolTable::handleAnonymousVersion() { for (SymbolVersion &Ver : Config->VersionScriptGlobals) assignExactVersion(Ver, VER_NDX_GLOBAL, "global"); for (SymbolVersion &Ver : Config->VersionScriptGlobals) assignWildcardVersion(Ver, VER_NDX_GLOBAL); for (SymbolVersion &Ver : Config->VersionScriptLocals) assignExactVersion(Ver, VER_NDX_LOCAL, "local"); for (SymbolVersion &Ver : Config->VersionScriptLocals) assignWildcardVersion(Ver, VER_NDX_LOCAL); } // Set symbol versions to symbols. This function handles patterns // containing no wildcard characters. template void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId, StringRef VersionName) { if (Ver.HasWildcard) return; // Get a list of symbols which we need to assign the version to. std::vector Syms = findByVersion(Ver); if (Syms.empty()) { if (Config->NoUndefinedVersion) error("version script assignment of '" + VersionName + "' to symbol '" + Ver.Name + "' failed: symbol not defined"); return; } // Assign the version. for (SymbolBody *B : Syms) { Symbol *Sym = B->symbol(); if (Sym->InVersionScript) warn("duplicate symbol '" + Ver.Name + "' in version script"); Sym->VersionId = VersionId; Sym->InVersionScript = true; } } template void SymbolTable::assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId) { if (!Ver.HasWildcard) return; std::vector Syms = findAllByVersion(Ver); // Exact matching takes precendence over fuzzy matching, // so we set a version to a symbol only if no version has been assigned // to the symbol. This behavior is compatible with GNU. for (SymbolBody *B : Syms) if (B->symbol()->VersionId == Config->DefaultSymbolVersion) B->symbol()->VersionId = VersionId; } // This function processes version scripts by updating VersionId // member of symbols. template void SymbolTable::scanVersionScript() { // Symbol themselves might know their versions because symbols // can contain versions in the form of @. // Let them parse their names. if (!Config->VersionDefinitions.empty()) for (Symbol *Sym : SymVector) Sym->body()->parseSymbolVersion(); // Handle edge cases first. handleAnonymousVersion(); if (Config->VersionDefinitions.empty()) return; // Now we have version definitions, so we need to set version ids to symbols. // Each version definition has a glob pattern, and all symbols that match // with the pattern get that version. // First, we assign versions to exact matching symbols, // i.e. version definitions not containing any glob meta-characters. for (VersionDefinition &V : Config->VersionDefinitions) for (SymbolVersion &Ver : V.Globals) assignExactVersion(Ver, V.Id, V.Name); // Next, we assign versions to fuzzy matching symbols, // i.e. version definitions containing glob meta-characters. // Note that because the last match takes precedence over previous matches, // we iterate over the definitions in the reverse order. for (VersionDefinition &V : llvm::reverse(Config->VersionDefinitions)) for (SymbolVersion &Ver : V.Globals) assignWildcardVersion(Ver, V.Id); } template class elf::SymbolTable; template class elf::SymbolTable; template class elf::SymbolTable; template class elf::SymbolTable; Index: vendor/lld/dist/ELF/SymbolTable.h =================================================================== --- vendor/lld/dist/ELF/SymbolTable.h (revision 312631) +++ vendor/lld/dist/ELF/SymbolTable.h (revision 312632) @@ -1,151 +1,152 @@ //===- SymbolTable.h --------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_ELF_SYMBOL_TABLE_H #define LLD_ELF_SYMBOL_TABLE_H #include "InputFiles.h" #include "LTO.h" #include "Strings.h" #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseMap.h" namespace lld { namespace elf { class Lazy; class OutputSectionBase; struct Symbol; // SymbolTable is a bucket of all known symbols, including defined, // undefined, or lazy symbols (the last one is symbols in archive // files whose archive members are not yet loaded). // // We put all symbols of all files to a SymbolTable, and the // SymbolTable selects the "best" symbols if there are name // conflicts. For example, obviously, a defined symbol is better than // an undefined symbol. Or, if there's a conflict between a lazy and a // undefined, it'll read an archive member to read a real definition // to replace the lazy symbol. The logic is implemented in the // add*() functions, which are called by input files as they are parsed. There // is one add* function per symbol type. template class SymbolTable { typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::uint uintX_t; public: void addFile(InputFile *File); void addCombinedLTOObject(); ArrayRef getSymbols() const { return SymVector; } ArrayRef *> getObjectFiles() const { return ObjectFiles; } ArrayRef getBinaryFiles() const { return BinaryFiles; } ArrayRef *> getSharedFiles() const { return SharedFiles; } DefinedRegular *addAbsolute(StringRef Name, uint8_t Visibility = llvm::ELF::STV_HIDDEN, uint8_t Binding = llvm::ELF::STB_GLOBAL); DefinedRegular *addIgnored(StringRef Name, uint8_t Visibility = llvm::ELF::STV_HIDDEN); Symbol *addUndefined(StringRef Name); Symbol *addUndefined(StringRef Name, bool IsLocal, uint8_t Binding, uint8_t StOther, uint8_t Type, bool CanOmitFromDynSym, InputFile *File); Symbol *addRegular(StringRef Name, uint8_t StOther, uint8_t Type, uintX_t Value, uintX_t Size, uint8_t Binding, InputSectionBase *Section, InputFile *File); Symbol *addSynthetic(StringRef N, const OutputSectionBase *Section, uintX_t Value, uint8_t StOther); void addShared(SharedFile *F, StringRef Name, const Elf_Sym &Sym, const typename ELFT::Verdef *Verdef); void addLazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S); void addLazyObject(StringRef Name, LazyObjectFile &Obj); Symbol *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type, bool CanOmitFromDynSym, BitcodeFile *File); Symbol *addCommon(StringRef N, uint64_t Size, uint64_t Alignment, uint8_t Binding, uint8_t StOther, uint8_t Type, InputFile *File); void scanUndefinedFlags(); void scanShlibUndefined(); void scanVersionScript(); SymbolBody *find(StringRef Name); + SymbolBody *findInCurrentDSO(StringRef Name); void trace(StringRef Name); void wrap(StringRef Name); std::vector *> Sections; private: std::pair insert(StringRef Name); std::pair insert(StringRef Name, uint8_t Type, uint8_t Visibility, bool CanOmitFromDynSym, InputFile *File); std::vector findByVersion(SymbolVersion Ver); std::vector findAllByVersion(SymbolVersion Ver); llvm::StringMap> &getDemangledSyms(); void handleAnonymousVersion(); void assignExactVersion(SymbolVersion Ver, uint16_t VersionId, StringRef VersionName); void assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId); struct SymIndex { SymIndex(int Idx, bool Traced) : Idx(Idx), Traced(Traced) {} int Idx : 31; unsigned Traced : 1; }; // The order the global symbols are in is not defined. We can use an arbitrary // order, but it has to be reproducible. That is true even when cross linking. // The default hashing of StringRef produces different results on 32 and 64 // bit systems so we use a map to a vector. That is arbitrary, deterministic // but a bit inefficient. // FIXME: Experiment with passing in a custom hashing or sorting the symbols // once symbol resolution is finished. llvm::DenseMap Symtab; std::vector SymVector; // Comdat groups define "link once" sections. If two comdat groups have the // same name, only one of them is linked, and the other is ignored. This set // is used to uniquify them. llvm::DenseSet ComdatGroups; std::vector *> ObjectFiles; std::vector *> SharedFiles; std::vector BitcodeFiles; std::vector BinaryFiles; // Set of .so files to not link the same shared object file more than once. llvm::DenseSet SoNames; // A map from demangled symbol names to their symbol objects. // This mapping is 1:N because two symbols with different versions // can have the same name. We use this map to handle "extern C++ {}" // directive in version scripts. llvm::Optional>> DemangledSyms; // For LTO. std::unique_ptr LTO; }; template struct Symtab { static SymbolTable *X; }; template SymbolTable *Symtab::X; } // namespace elf } // namespace lld #endif Index: vendor/lld/dist/ELF/Symbols.cpp =================================================================== --- vendor/lld/dist/ELF/Symbols.cpp (revision 312631) +++ vendor/lld/dist/ELF/Symbols.cpp (revision 312632) @@ -1,396 +1,397 @@ //===- Symbols.cpp --------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Symbols.h" #include "Error.h" #include "InputFiles.h" #include "InputSection.h" #include "OutputSections.h" #include "Strings.h" #include "SyntheticSections.h" #include "Target.h" #include "Writer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Path.h" #include using namespace llvm; using namespace llvm::object; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; template static typename ELFT::uint getSymVA(const SymbolBody &Body, typename ELFT::uint &Addend) { typedef typename ELFT::uint uintX_t; switch (Body.kind()) { case SymbolBody::DefinedSyntheticKind: { auto &D = cast(Body); const OutputSectionBase *Sec = D.Section; if (!Sec) return D.Value; if (D.Value == uintX_t(-1)) return Sec->Addr + Sec->Size; return Sec->Addr + D.Value; } case SymbolBody::DefinedRegularKind: { auto &D = cast>(Body); InputSectionBase *IS = D.Section; // According to the ELF spec reference to a local symbol from outside // the group are not allowed. Unfortunately .eh_frame breaks that rule // and must be treated specially. For now we just replace the symbol with // 0. if (IS == &InputSection::Discarded) return 0; // This is an absolute symbol. if (!IS) return D.Value; uintX_t Offset = D.Value; if (D.isSection()) { Offset += Addend; Addend = 0; } uintX_t VA = (IS->OutSec ? IS->OutSec->Addr : 0) + IS->getOffset(Offset); if (D.isTls() && !Config->Relocatable) { if (!Out::TlsPhdr) fatal(toString(D.File) + " has a STT_TLS symbol but doesn't have a PT_TLS section"); return VA - Out::TlsPhdr->p_vaddr; } return VA; } case SymbolBody::DefinedCommonKind: return In::Common->OutSec->Addr + In::Common->OutSecOff + cast(Body).Offset; case SymbolBody::SharedKind: { auto &SS = cast>(Body); if (!SS.NeedsCopyOrPltAddr) return 0; if (SS.isFunc()) return Body.getPltVA(); return SS.getBssSectionForCopy()->Addr + SS.CopyOffset; } case SymbolBody::UndefinedKind: return 0; case SymbolBody::LazyArchiveKind: case SymbolBody::LazyObjectKind: assert(Body.symbol()->IsUsedInRegularObj && "lazy symbol reached writer"); return 0; } llvm_unreachable("invalid symbol kind"); } SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type) : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(IsLocal), IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false), IsInIgot(false), CopyIsInBssRelRo(false), Type(Type), StOther(StOther), Name(Name) {} // Returns true if a symbol can be replaced at load-time by a symbol // with the same name defined in other ELF executable or DSO. bool SymbolBody::isPreemptible() const { if (isLocal()) return false; // Shared symbols resolve to the definition in the DSO. The exceptions are // symbols with copy relocations (which resolve to .bss) or preempt plt // entries (which resolve to that plt entry). if (isShared()) return !NeedsCopyOrPltAddr; // That's all that can be preempted in a non-DSO. if (!Config->Shared) return false; // Only symbols that appear in dynsym can be preempted. if (!symbol()->includeInDynsym()) return false; // Only default visibility symbols can be preempted. if (symbol()->Visibility != STV_DEFAULT) return false; // -Bsymbolic means that definitions are not preempted. if (Config->Bsymbolic || (Config->BsymbolicFunctions && isFunc())) return !isDefined(); return true; } template bool SymbolBody::hasThunk() const { if (auto *DR = dyn_cast>(this)) return DR->ThunkData != nullptr; if (auto *S = dyn_cast>(this)) return S->ThunkData != nullptr; return false; } template typename ELFT::uint SymbolBody::getVA(typename ELFT::uint Addend) const { typename ELFT::uint OutVA = getSymVA(*this, Addend); return OutVA + Addend; } template typename ELFT::uint SymbolBody::getGotVA() const { return In::Got->getVA() + getGotOffset(); } template typename ELFT::uint SymbolBody::getGotOffset() const { return GotIndex * Target->GotEntrySize; } template typename ELFT::uint SymbolBody::getGotPltVA() const { if (this->IsInIgot) return In::IgotPlt->getVA() + getGotPltOffset(); return In::GotPlt->getVA() + getGotPltOffset(); } template typename ELFT::uint SymbolBody::getGotPltOffset() const { return GotPltIndex * Target->GotPltEntrySize; } template typename ELFT::uint SymbolBody::getPltVA() const { if (this->IsInIplt) return In::Iplt->getVA() + PltIndex * Target->PltEntrySize; return In::Plt->getVA() + Target->PltHeaderSize + PltIndex * Target->PltEntrySize; } template typename ELFT::uint SymbolBody::getThunkVA() const { if (const auto *DR = dyn_cast>(this)) return DR->ThunkData->getVA(); if (const auto *S = dyn_cast>(this)) return S->ThunkData->getVA(); if (const auto *S = dyn_cast>(this)) return S->ThunkData->getVA(); fatal("getThunkVA() not supported for Symbol class\n"); } template typename ELFT::uint SymbolBody::getSize() const { if (const auto *C = dyn_cast(this)) return C->Size; if (const auto *DR = dyn_cast>(this)) return DR->Size; if (const auto *S = dyn_cast>(this)) return S->Sym.st_size; return 0; } // If a symbol name contains '@', the characters after that is // a symbol version name. This function parses that. void SymbolBody::parseSymbolVersion() { StringRef S = getName(); size_t Pos = S.find('@'); if (Pos == 0 || Pos == StringRef::npos) return; StringRef Verstr = S.substr(Pos + 1); if (Verstr.empty()) return; // Truncate the symbol name so that it doesn't include the version string. Name = {S.data(), Pos}; - // If this is an undefined or shared symbol it is not a definition. - if (isUndefined() || isShared()) + // If this is not in this DSO, it is not a definition. + if (!isInCurrentDSO()) return; // '@@' in a symbol name means the default version. // It is usually the most recent one. bool IsDefault = (Verstr[0] == '@'); if (IsDefault) Verstr = Verstr.substr(1); for (VersionDefinition &Ver : Config->VersionDefinitions) { if (Ver.Name != Verstr) continue; if (IsDefault) symbol()->VersionId = Ver.Id; else symbol()->VersionId = Ver.Id | VERSYM_HIDDEN; return; } // It is an error if the specified version is not defined. error(toString(File) + ": symbol " + S + " has undefined version " + Verstr); } Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type) : SymbolBody(K, Name, IsLocal, StOther, Type) {} template bool DefinedRegular::isMipsPIC() const { if (!Section || !isFunc()) return false; return (this->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC || (Section->getFile()->getObj().getHeader()->e_flags & EF_MIPS_PIC); } template Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type, InputFile *File) : SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, StOther, Type) { this->File = File; } template OutputSection *SharedSymbol::getBssSectionForCopy() const { assert(needsCopy()); return CopyIsInBssRelRo ? Out::BssRelRo : Out::Bss; } DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint64_t Alignment, uint8_t StOther, uint8_t Type, InputFile *File) : Defined(SymbolBody::DefinedCommonKind, Name, /*IsLocal=*/false, StOther, Type), Alignment(Alignment), Size(Size) { this->File = File; } InputFile *Lazy::fetch() { if (auto *S = dyn_cast(this)) return S->fetch(); return cast(this)->fetch(); } LazyArchive::LazyArchive(ArchiveFile &File, const llvm::object::Archive::Symbol S, uint8_t Type) : Lazy(LazyArchiveKind, S.getName(), Type), Sym(S) { this->File = &File; } LazyObject::LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type) : Lazy(LazyObjectKind, Name, Type) { this->File = &File; } InputFile *LazyArchive::fetch() { std::pair MBInfo = file()->getMember(&Sym); // getMember returns an empty buffer if the member was already // read from the library. if (MBInfo.first.getBuffer().empty()) return nullptr; return createObjectFile(MBInfo.first, file()->getName(), MBInfo.second); } InputFile *LazyObject::fetch() { MemoryBufferRef MBRef = file()->getBuffer(); if (MBRef.getBuffer().empty()) return nullptr; return createObjectFile(MBRef); } uint8_t Symbol::computeBinding() const { if (Config->Relocatable) return Binding; if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) return STB_LOCAL; - if (VersionId == VER_NDX_LOCAL && !body()->isUndefined()) + const SymbolBody *Body = body(); + if (VersionId == VER_NDX_LOCAL && Body->isInCurrentDSO()) return STB_LOCAL; if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE) return STB_GLOBAL; return Binding; } bool Symbol::includeInDynsym() const { if (computeBinding() == STB_LOCAL) return false; return ExportDynamic || body()->isShared() || (body()->isUndefined() && Config->Shared); } // Print out a log message for --trace-symbol. void elf::printTraceSymbol(Symbol *Sym) { SymbolBody *B = Sym->body(); outs() << toString(B->File); if (B->isUndefined()) outs() << ": reference to "; else if (B->isCommon()) outs() << ": common definition of "; else outs() << ": definition of "; outs() << B->getName() << "\n"; } // Returns a symbol for an error message. std::string lld::toString(const SymbolBody &B) { if (Config->Demangle) if (Optional S = demangle(B.getName())) return *S; return B.getName(); } template bool SymbolBody::hasThunk() const; template bool SymbolBody::hasThunk() const; template bool SymbolBody::hasThunk() const; template bool SymbolBody::hasThunk() const; template uint32_t SymbolBody::template getVA(uint32_t) const; template uint32_t SymbolBody::template getVA(uint32_t) const; template uint64_t SymbolBody::template getVA(uint64_t) const; template uint64_t SymbolBody::template getVA(uint64_t) const; template uint32_t SymbolBody::template getGotVA() const; template uint32_t SymbolBody::template getGotVA() const; template uint64_t SymbolBody::template getGotVA() const; template uint64_t SymbolBody::template getGotVA() const; template uint32_t SymbolBody::template getGotOffset() const; template uint32_t SymbolBody::template getGotOffset() const; template uint64_t SymbolBody::template getGotOffset() const; template uint64_t SymbolBody::template getGotOffset() const; template uint32_t SymbolBody::template getGotPltVA() const; template uint32_t SymbolBody::template getGotPltVA() const; template uint64_t SymbolBody::template getGotPltVA() const; template uint64_t SymbolBody::template getGotPltVA() const; template uint32_t SymbolBody::template getThunkVA() const; template uint32_t SymbolBody::template getThunkVA() const; template uint64_t SymbolBody::template getThunkVA() const; template uint64_t SymbolBody::template getThunkVA() const; template uint32_t SymbolBody::template getGotPltOffset() const; template uint32_t SymbolBody::template getGotPltOffset() const; template uint64_t SymbolBody::template getGotPltOffset() const; template uint64_t SymbolBody::template getGotPltOffset() const; template uint32_t SymbolBody::template getPltVA() const; template uint32_t SymbolBody::template getPltVA() const; template uint64_t SymbolBody::template getPltVA() const; template uint64_t SymbolBody::template getPltVA() const; template uint32_t SymbolBody::template getSize() const; template uint32_t SymbolBody::template getSize() const; template uint64_t SymbolBody::template getSize() const; template uint64_t SymbolBody::template getSize() const; template class elf::Undefined; template class elf::Undefined; template class elf::Undefined; template class elf::Undefined; template class elf::SharedSymbol; template class elf::SharedSymbol; template class elf::SharedSymbol; template class elf::SharedSymbol; template class elf::DefinedRegular; template class elf::DefinedRegular; template class elf::DefinedRegular; template class elf::DefinedRegular; Index: vendor/lld/dist/ELF/Symbols.h =================================================================== --- vendor/lld/dist/ELF/Symbols.h (revision 312631) +++ vendor/lld/dist/ELF/Symbols.h (revision 312632) @@ -1,469 +1,470 @@ //===- Symbols.h ------------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // All symbols are handled as SymbolBodies regardless of their types. // This file defines various types of SymbolBodies. // //===----------------------------------------------------------------------===// #ifndef LLD_ELF_SYMBOLS_H #define LLD_ELF_SYMBOLS_H #include "InputSection.h" #include "Strings.h" #include "lld/Core/LLVM.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ELF.h" namespace lld { namespace elf { class ArchiveFile; class BitcodeFile; class InputFile; class LazyObjectFile; template class ObjectFile; template class OutputSection; class OutputSectionBase; template class SharedFile; struct Symbol; // The base class for real symbol classes. class SymbolBody { public: enum Kind { DefinedFirst, DefinedRegularKind = DefinedFirst, SharedKind, DefinedCommonKind, DefinedSyntheticKind, DefinedLast = DefinedSyntheticKind, UndefinedKind, LazyArchiveKind, LazyObjectKind, }; SymbolBody(Kind K) : SymbolKind(K) {} Symbol *symbol(); const Symbol *symbol() const { return const_cast(this)->symbol(); } Kind kind() const { return static_cast(SymbolKind); } bool isUndefined() const { return SymbolKind == UndefinedKind; } bool isDefined() const { return SymbolKind <= DefinedLast; } bool isCommon() const { return SymbolKind == DefinedCommonKind; } bool isLazy() const { return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind; } bool isShared() const { return SymbolKind == SharedKind; } + bool isInCurrentDSO() const { return !isUndefined() && !isShared(); } bool isLocal() const { return IsLocal; } bool isPreemptible() const; StringRef getName() const { return Name; } uint8_t getVisibility() const { return StOther & 0x3; } void parseSymbolVersion(); bool isInGot() const { return GotIndex != -1U; } bool isInPlt() const { return PltIndex != -1U; } template bool hasThunk() const; template typename ELFT::uint getVA(typename ELFT::uint Addend = 0) const; template typename ELFT::uint getGotOffset() const; template typename ELFT::uint getGotVA() const; template typename ELFT::uint getGotPltOffset() const; template typename ELFT::uint getGotPltVA() const; template typename ELFT::uint getPltVA() const; template typename ELFT::uint getThunkVA() const; template typename ELFT::uint getSize() const; // The file from which this symbol was created. InputFile *File = nullptr; uint32_t DynsymIndex = 0; uint32_t GotIndex = -1; uint32_t GotPltIndex = -1; uint32_t PltIndex = -1; uint32_t GlobalDynIndex = -1; protected: SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type); const unsigned SymbolKind : 8; public: // True if the linker has to generate a copy relocation for this shared // symbol or if the symbol should point to its plt entry. unsigned NeedsCopyOrPltAddr : 1; // True if this is a local symbol. unsigned IsLocal : 1; // True if this symbol has an entry in the global part of MIPS GOT. unsigned IsInGlobalMipsGot : 1; // True if this symbol is referenced by 32-bit GOT relocations. unsigned Is32BitMipsGot : 1; // True if this symbol is in the Iplt sub-section of the Plt. unsigned IsInIplt : 1; // True if this symbol is in the Igot sub-section of the .got.plt or .got. unsigned IsInIgot : 1; // True if this is a shared symbol in a read-only segment which requires a // copy relocation. This causes space for the symbol to be allocated in the // .bss.rel.ro section. unsigned CopyIsInBssRelRo : 1; // The following fields have the same meaning as the ELF symbol attributes. uint8_t Type; // symbol type uint8_t StOther; // st_other field value // The Type field may also have this value. It means that we have not yet seen // a non-Lazy symbol with this name, so we don't know what its type is. The // Type field is normally set to this value for Lazy symbols unless we saw a // weak undefined symbol first, in which case we need to remember the original // symbol's type in order to check for TLS mismatches. enum { UnknownType = 255 }; bool isSection() const { return Type == llvm::ELF::STT_SECTION; } bool isTls() const { return Type == llvm::ELF::STT_TLS; } bool isFunc() const { return Type == llvm::ELF::STT_FUNC; } bool isGnuIFunc() const { return Type == llvm::ELF::STT_GNU_IFUNC; } bool isObject() const { return Type == llvm::ELF::STT_OBJECT; } bool isFile() const { return Type == llvm::ELF::STT_FILE; } protected: StringRefZ Name; }; // The base class for any defined symbols. class Defined : public SymbolBody { public: Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type); static bool classof(const SymbolBody *S) { return S->isDefined(); } }; class DefinedCommon : public Defined { public: DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, uint8_t StOther, uint8_t Type, InputFile *File); static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::DefinedCommonKind; } // The output offset of this common symbol in the output bss. Computed by the // writer. uint64_t Offset; // The maximum alignment we have seen for this symbol. uint64_t Alignment; uint64_t Size; }; // Regular defined symbols read from object file symbol tables. template class DefinedRegular : public Defined { typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::uint uintX_t; public: DefinedRegular(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type, uintX_t Value, uintX_t Size, InputSectionBase *Section, InputFile *File) : Defined(SymbolBody::DefinedRegularKind, Name, IsLocal, StOther, Type), Value(Value), Size(Size), Section(Section ? Section->Repl : NullInputSection) { this->File = File; } // Return true if the symbol is a PIC function. bool isMipsPIC() const; static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::DefinedRegularKind; } uintX_t Value; uintX_t Size; // The input section this symbol belongs to. Notice that this is // a reference to a pointer. We are using two levels of indirections // because of ICF. If ICF decides two sections need to be merged, it // manipulates this Section pointers so that they point to the same // section. This is a bit tricky, so be careful to not be confused. // If this is null, the symbol is an absolute symbol. InputSectionBase *&Section; // If non-null the symbol has a Thunk that may be used as an alternative // destination for callers of this Symbol. Thunk *ThunkData = nullptr; private: static InputSectionBase *NullInputSection; }; template InputSectionBase *DefinedRegular::NullInputSection; // DefinedSynthetic is a class to represent linker-generated ELF symbols. // The difference from the regular symbol is that DefinedSynthetic symbols // don't belong to any input files or sections. Thus, its constructor // takes an output section to calculate output VA, etc. // If Section is null, this symbol is relative to the image base. class DefinedSynthetic : public Defined { public: DefinedSynthetic(StringRef Name, uint64_t Value, const OutputSectionBase *Section) : Defined(SymbolBody::DefinedSyntheticKind, Name, /*IsLocal=*/false, llvm::ELF::STV_HIDDEN, 0 /* Type */), Value(Value), Section(Section) {} static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::DefinedSyntheticKind; } uint64_t Value; const OutputSectionBase *Section; }; template class Undefined : public SymbolBody { public: Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type, InputFile *F); static bool classof(const SymbolBody *S) { return S->kind() == UndefinedKind; } // If non-null the symbol has a Thunk that may be used as an alternative // destination for callers of this Symbol. When linking a DSO undefined // symbols are implicitly imported, the symbol lookup will be performed by // the dynamic loader. A call to an undefined symbol will be given a PLT // entry and on ARM this may need a Thunk if the caller is in Thumb state. Thunk *ThunkData = nullptr; InputFile *file() { return this->File; } }; template class SharedSymbol : public Defined { typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::Verdef Elf_Verdef; typedef typename ELFT::uint uintX_t; public: static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::SharedKind; } SharedSymbol(SharedFile *F, StringRef Name, const Elf_Sym &Sym, const Elf_Verdef *Verdef) : Defined(SymbolBody::SharedKind, Name, /*IsLocal=*/false, Sym.st_other, Sym.getType()), Sym(Sym), Verdef(Verdef) { // IFuncs defined in DSOs are treated as functions by the static linker. if (isGnuIFunc()) Type = llvm::ELF::STT_FUNC; this->File = F; } SharedFile *file() { return (SharedFile *)this->File; } const Elf_Sym &Sym; // This field is a pointer to the symbol's version definition. const Elf_Verdef *Verdef; // CopyOffset is significant only when needsCopy() is true. uintX_t CopyOffset = 0; // If non-null the symbol has a Thunk that may be used as an alternative // destination for callers of this Symbol. Thunk *ThunkData = nullptr; bool needsCopy() const { return this->NeedsCopyOrPltAddr && !this->isFunc(); } OutputSection *getBssSectionForCopy() const; }; // This class represents a symbol defined in an archive file. It is // created from an archive file header, and it knows how to load an // object file from an archive to replace itself with a defined // symbol. If the resolver finds both Undefined and Lazy for // the same name, it will ask the Lazy to load a file. class Lazy : public SymbolBody { public: static bool classof(const SymbolBody *S) { return S->isLazy(); } // Returns an object file for this symbol, or a nullptr if the file // was already returned. InputFile *fetch(); protected: Lazy(SymbolBody::Kind K, StringRef Name, uint8_t Type) : SymbolBody(K, Name, /*IsLocal=*/false, llvm::ELF::STV_DEFAULT, Type) {} }; // LazyArchive symbols represents symbols in archive files. class LazyArchive : public Lazy { public: LazyArchive(ArchiveFile &File, const llvm::object::Archive::Symbol S, uint8_t Type); static bool classof(const SymbolBody *S) { return S->kind() == LazyArchiveKind; } ArchiveFile *file() { return (ArchiveFile *)this->File; } InputFile *fetch(); private: const llvm::object::Archive::Symbol Sym; }; // LazyObject symbols represents symbols in object files between // --start-lib and --end-lib options. class LazyObject : public Lazy { public: LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type); static bool classof(const SymbolBody *S) { return S->kind() == LazyObjectKind; } LazyObjectFile *file() { return (LazyObjectFile *)this->File; } InputFile *fetch(); }; // Some linker-generated symbols need to be created as // DefinedRegular symbols. template struct ElfSym { // The content for __ehdr_start symbol. static DefinedRegular *EhdrStart; // The content for _etext and etext symbols. static DefinedRegular *Etext; static DefinedRegular *Etext2; // The content for _edata and edata symbols. static DefinedRegular *Edata; static DefinedRegular *Edata2; // The content for _end and end symbols. static DefinedRegular *End; static DefinedRegular *End2; // The content for _gp_disp/__gnu_local_gp symbols for MIPS target. static DefinedRegular *MipsGpDisp; static DefinedRegular *MipsLocalGp; static DefinedRegular *MipsGp; }; template DefinedRegular *ElfSym::EhdrStart; template DefinedRegular *ElfSym::Etext; template DefinedRegular *ElfSym::Etext2; template DefinedRegular *ElfSym::Edata; template DefinedRegular *ElfSym::Edata2; template DefinedRegular *ElfSym::End; template DefinedRegular *ElfSym::End2; template DefinedRegular *ElfSym::MipsGpDisp; template DefinedRegular *ElfSym::MipsLocalGp; template DefinedRegular *ElfSym::MipsGp; // A real symbol object, SymbolBody, is usually stored within a Symbol. There's // always one Symbol for each symbol name. The resolver updates the SymbolBody // stored in the Body field of this object as it resolves symbols. Symbol also // holds computed properties of symbol names. struct Symbol { // Symbol binding. This is on the Symbol to track changes during resolution. // In particular: // An undefined weak is still weak when it resolves to a shared library. // An undefined weak will not fetch archive members, but we have to remember // it is weak. uint8_t Binding; // Version definition index. uint16_t VersionId; // Symbol visibility. This is the computed minimum visibility of all // observed non-DSO symbols. unsigned Visibility : 2; // True if the symbol was used for linking and thus need to be added to the // output file's symbol table. This is true for all symbols except for // unreferenced DSO symbols and bitcode symbols that are unreferenced except // by other bitcode objects. unsigned IsUsedInRegularObj : 1; // If this flag is true and the symbol has protected or default visibility, it // will appear in .dynsym. This flag is set by interposable DSO symbols in // executables, by most symbols in DSOs and executables built with // --export-dynamic, and by dynamic lists. unsigned ExportDynamic : 1; // True if this symbol is specified by --trace-symbol option. unsigned Traced : 1; // This symbol version was found in a version script. unsigned InVersionScript : 1; bool includeInDynsym() const; uint8_t computeBinding() const; bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; } // This field is used to store the Symbol's SymbolBody. This instantiation of // AlignedCharArrayUnion gives us a struct with a char array field that is // large and aligned enough to store any derived class of SymbolBody. We // assume that the size and alignment of ELF64LE symbols is sufficient for any // ELFT, and we verify this with the static_asserts in replaceBody. llvm::AlignedCharArrayUnion< DefinedCommon, DefinedRegular, DefinedSynthetic, Undefined, SharedSymbol, LazyArchive, LazyObject> Body; SymbolBody *body() { return reinterpret_cast(Body.buffer); } const SymbolBody *body() const { return const_cast(this)->body(); } }; void printTraceSymbol(Symbol *Sym); template void replaceBody(Symbol *S, ArgT &&... Arg) { static_assert(sizeof(T) <= sizeof(S->Body), "Body too small"); static_assert(alignof(T) <= alignof(decltype(S->Body)), "Body not aligned enough"); assert(static_cast(static_cast(nullptr)) == nullptr && "Not a SymbolBody"); new (S->Body.buffer) T(std::forward(Arg)...); // Print out a log message if --trace-symbol was specified. // This is for debugging. if (S->Traced) printTraceSymbol(S); } inline Symbol *SymbolBody::symbol() { assert(!isLocal()); return reinterpret_cast(reinterpret_cast(this) - offsetof(Symbol, Body)); } } // namespace elf std::string toString(const elf::SymbolBody &B); } // namespace lld #endif Index: vendor/lld/dist/ELF/SyntheticSections.cpp =================================================================== --- vendor/lld/dist/ELF/SyntheticSections.cpp (revision 312631) +++ vendor/lld/dist/ELF/SyntheticSections.cpp (revision 312632) @@ -1,1981 +1,1981 @@ //===- SyntheticSections.cpp ----------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains linker-synthesized sections. Currently, // synthetic sections are created either output sections or input sections, // but we are rewriting code so that all synthetic sections are created as // input sections. // //===----------------------------------------------------------------------===// #include "SyntheticSections.h" #include "Config.h" #include "Error.h" #include "InputFiles.h" #include "LinkerScript.h" #include "Memory.h" #include "OutputSections.h" #include "Strings.h" #include "SymbolTable.h" #include "Target.h" #include "Threads.h" #include "Writer.h" #include "lld/Config/Version.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/Endian.h" #include "llvm/Support/MD5.h" #include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Support/SHA1.h" #include "llvm/Support/xxhash.h" #include using namespace llvm; using namespace llvm::dwarf; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support; using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; template static std::vector getCommonSymbols() { std::vector V; for (Symbol *S : Symtab::X->getSymbols()) if (auto *B = dyn_cast(S->body())) V.push_back(B); return V; } // Find all common symbols and allocate space for them. template InputSection *elf::createCommonSection() { auto *Ret = make>(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, 1, ArrayRef(), "COMMON"); Ret->Live = true; // Sort the common symbols by alignment as an heuristic to pack them better. std::vector Syms = getCommonSymbols(); std::stable_sort(Syms.begin(), Syms.end(), [](const DefinedCommon *A, const DefinedCommon *B) { return A->Alignment > B->Alignment; }); // Assign offsets to symbols. size_t Size = 0; size_t Alignment = 1; for (DefinedCommon *Sym : Syms) { Alignment = std::max(Alignment, Sym->Alignment); Size = alignTo(Size, Sym->Alignment); // Compute symbol offset relative to beginning of input section. Sym->Offset = Size; Size += Sym->Size; } Ret->Alignment = Alignment; Ret->Data = makeArrayRef(nullptr, Size); return Ret; } // Returns an LLD version string. static ArrayRef getVersion() { // Check LLD_VERSION first for ease of testing. // You can get consitent output by using the environment variable. // This is only for testing. StringRef S = getenv("LLD_VERSION"); if (S.empty()) S = Saver.save(Twine("Linker: ") + getLLDVersion()); // +1 to include the terminating '\0'. return {(const uint8_t *)S.data(), S.size() + 1}; } // Creates a .comment section containing LLD version info. // With this feature, you can identify LLD-generated binaries easily // by "objdump -s -j .comment ". // The returned object is a mergeable string section. template MergeInputSection *elf::createCommentSection() { typename ELFT::Shdr Hdr = {}; Hdr.sh_flags = SHF_MERGE | SHF_STRINGS; Hdr.sh_type = SHT_PROGBITS; Hdr.sh_entsize = 1; Hdr.sh_addralign = 1; auto *Ret = make>(/*file=*/nullptr, &Hdr, ".comment"); Ret->Data = getVersion(); Ret->splitIntoPieces(); return Ret; } // .MIPS.abiflags section. template MipsAbiFlagsSection::MipsAbiFlagsSection(Elf_Mips_ABIFlags Flags) : SyntheticSection(SHF_ALLOC, SHT_MIPS_ABIFLAGS, 8, ".MIPS.abiflags"), Flags(Flags) {} template void MipsAbiFlagsSection::writeTo(uint8_t *Buf) { memcpy(Buf, &Flags, sizeof(Flags)); } template MipsAbiFlagsSection *MipsAbiFlagsSection::create() { Elf_Mips_ABIFlags Flags = {}; bool Create = false; for (InputSectionBase *Sec : Symtab::X->Sections) { if (!Sec->Live || Sec->Type != SHT_MIPS_ABIFLAGS) continue; Sec->Live = false; Create = true; std::string Filename = toString(Sec->getFile()); const size_t Size = Sec->Data.size(); // Older version of BFD (such as the default FreeBSD linker) concatenate // .MIPS.abiflags instead of merging. To allow for this case (or potential // zero padding) we ignore everything after the first Elf_Mips_ABIFlags if (Size < sizeof(Elf_Mips_ABIFlags)) { error(Filename + ": invalid size of .MIPS.abiflags section: got " + Twine(Size) + " instead of " + Twine(sizeof(Elf_Mips_ABIFlags))); return nullptr; } auto *S = reinterpret_cast(Sec->Data.data()); if (S->version != 0) { error(Filename + ": unexpected .MIPS.abiflags version " + Twine(S->version)); return nullptr; } // LLD checks ISA compatibility in getMipsEFlags(). Here we just // select the highest number of ISA/Rev/Ext. Flags.isa_level = std::max(Flags.isa_level, S->isa_level); Flags.isa_rev = std::max(Flags.isa_rev, S->isa_rev); Flags.isa_ext = std::max(Flags.isa_ext, S->isa_ext); Flags.gpr_size = std::max(Flags.gpr_size, S->gpr_size); Flags.cpr1_size = std::max(Flags.cpr1_size, S->cpr1_size); Flags.cpr2_size = std::max(Flags.cpr2_size, S->cpr2_size); Flags.ases |= S->ases; Flags.flags1 |= S->flags1; Flags.flags2 |= S->flags2; Flags.fp_abi = elf::getMipsFpAbiFlag(Flags.fp_abi, S->fp_abi, Filename); }; if (Create) return make>(Flags); return nullptr; } // .MIPS.options section. template MipsOptionsSection::MipsOptionsSection(Elf_Mips_RegInfo Reginfo) : SyntheticSection(SHF_ALLOC, SHT_MIPS_OPTIONS, 8, ".MIPS.options"), Reginfo(Reginfo) {} template void MipsOptionsSection::writeTo(uint8_t *Buf) { auto *Options = reinterpret_cast(Buf); Options->kind = ODK_REGINFO; Options->size = getSize(); if (!Config->Relocatable) Reginfo.ri_gp_value = In::MipsGot->getGp(); memcpy(Buf + sizeof(Elf_Mips_Options), &Reginfo, sizeof(Reginfo)); } template MipsOptionsSection *MipsOptionsSection::create() { // N64 ABI only. if (!ELFT::Is64Bits) return nullptr; Elf_Mips_RegInfo Reginfo = {}; bool Create = false; for (InputSectionBase *Sec : Symtab::X->Sections) { if (!Sec->Live || Sec->Type != SHT_MIPS_OPTIONS) continue; Sec->Live = false; Create = true; std::string Filename = toString(Sec->getFile()); ArrayRef D = Sec->Data; while (!D.empty()) { if (D.size() < sizeof(Elf_Mips_Options)) { error(Filename + ": invalid size of .MIPS.options section"); break; } auto *Opt = reinterpret_cast(D.data()); if (Opt->kind == ODK_REGINFO) { if (Config->Relocatable && Opt->getRegInfo().ri_gp_value) error(Filename + ": unsupported non-zero ri_gp_value"); Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask; Sec->getFile()->MipsGp0 = Opt->getRegInfo().ri_gp_value; break; } if (!Opt->size) fatal(Filename + ": zero option descriptor size"); D = D.slice(Opt->size); } }; if (Create) return make>(Reginfo); return nullptr; } // MIPS .reginfo section. template MipsReginfoSection::MipsReginfoSection(Elf_Mips_RegInfo Reginfo) : SyntheticSection(SHF_ALLOC, SHT_MIPS_REGINFO, 4, ".reginfo"), Reginfo(Reginfo) {} template void MipsReginfoSection::writeTo(uint8_t *Buf) { if (!Config->Relocatable) Reginfo.ri_gp_value = In::MipsGot->getGp(); memcpy(Buf, &Reginfo, sizeof(Reginfo)); } template MipsReginfoSection *MipsReginfoSection::create() { // Section should be alive for O32 and N32 ABIs only. if (ELFT::Is64Bits) return nullptr; Elf_Mips_RegInfo Reginfo = {}; bool Create = false; for (InputSectionBase *Sec : Symtab::X->Sections) { if (!Sec->Live || Sec->Type != SHT_MIPS_REGINFO) continue; Sec->Live = false; Create = true; if (Sec->Data.size() != sizeof(Elf_Mips_RegInfo)) { error(toString(Sec->getFile()) + ": invalid size of .reginfo section"); return nullptr; } auto *R = reinterpret_cast(Sec->Data.data()); if (Config->Relocatable && R->ri_gp_value) error(toString(Sec->getFile()) + ": unsupported non-zero ri_gp_value"); Reginfo.ri_gprmask |= R->ri_gprmask; Sec->getFile()->MipsGp0 = R->ri_gp_value; }; if (Create) return make>(Reginfo); return nullptr; } template InputSection *elf::createInterpSection() { auto *Ret = make>(SHF_ALLOC, SHT_PROGBITS, 1, ArrayRef(), ".interp"); Ret->Live = true; // StringSaver guarantees that the returned string ends with '\0'. StringRef S = Saver.save(Config->DynamicLinker); Ret->Data = {(const uint8_t *)S.data(), S.size() + 1}; return Ret; } static size_t getHashSize() { switch (Config->BuildId) { case BuildIdKind::Fast: return 8; case BuildIdKind::Md5: case BuildIdKind::Uuid: return 16; case BuildIdKind::Sha1: return 20; case BuildIdKind::Hexstring: return Config->BuildIdVector.size(); default: llvm_unreachable("unknown BuildIdKind"); } } template BuildIdSection::BuildIdSection() : SyntheticSection(SHF_ALLOC, SHT_NOTE, 1, ".note.gnu.build-id"), HashSize(getHashSize()) {} template void BuildIdSection::writeTo(uint8_t *Buf) { const endianness E = ELFT::TargetEndianness; write32(Buf, 4); // Name size write32(Buf + 4, HashSize); // Content size write32(Buf + 8, NT_GNU_BUILD_ID); // Type memcpy(Buf + 12, "GNU", 4); // Name string HashBuf = Buf + 16; } // Split one uint8 array into small pieces of uint8 arrays. static std::vector> split(ArrayRef Arr, size_t ChunkSize) { std::vector> Ret; while (Arr.size() > ChunkSize) { Ret.push_back(Arr.take_front(ChunkSize)); Arr = Arr.drop_front(ChunkSize); } if (!Arr.empty()) Ret.push_back(Arr); return Ret; } // Computes a hash value of Data using a given hash function. // In order to utilize multiple cores, we first split data into 1MB // chunks, compute a hash for each chunk, and then compute a hash value // of the hash values. template void BuildIdSection::computeHash( llvm::ArrayRef Data, std::function Arr)> HashFn) { std::vector> Chunks = split(Data, 1024 * 1024); std::vector Hashes(Chunks.size() * HashSize); // Compute hash values. forLoop(0, Chunks.size(), [&](size_t I) { HashFn(Hashes.data() + I * HashSize, Chunks[I]); }); // Write to the final output buffer. HashFn(HashBuf, Hashes); } template void BuildIdSection::writeBuildId(ArrayRef Buf) { switch (Config->BuildId) { case BuildIdKind::Fast: computeHash(Buf, [](uint8_t *Dest, ArrayRef Arr) { write64le(Dest, xxHash64(toStringRef(Arr))); }); break; case BuildIdKind::Md5: computeHash(Buf, [](uint8_t *Dest, ArrayRef Arr) { memcpy(Dest, MD5::hash(Arr).data(), 16); }); break; case BuildIdKind::Sha1: computeHash(Buf, [](uint8_t *Dest, ArrayRef Arr) { memcpy(Dest, SHA1::hash(Arr).data(), 20); }); break; case BuildIdKind::Uuid: if (getRandomBytes(HashBuf, HashSize)) error("entropy source failure"); break; case BuildIdKind::Hexstring: memcpy(HashBuf, Config->BuildIdVector.data(), Config->BuildIdVector.size()); break; default: llvm_unreachable("unknown BuildIdKind"); } } template GotSection::GotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Target->GotEntrySize, ".got") {} template void GotSection::addEntry(SymbolBody &Sym) { Sym.GotIndex = NumEntries; ++NumEntries; } template bool GotSection::addDynTlsEntry(SymbolBody &Sym) { if (Sym.GlobalDynIndex != -1U) return false; Sym.GlobalDynIndex = NumEntries; // Global Dynamic TLS entries take two GOT slots. NumEntries += 2; return true; } // Reserves TLS entries for a TLS module ID and a TLS block offset. // In total it takes two GOT slots. template bool GotSection::addTlsIndex() { if (TlsIndexOff != uint32_t(-1)) return false; TlsIndexOff = NumEntries * sizeof(uintX_t); NumEntries += 2; return true; } template typename GotSection::uintX_t GotSection::getGlobalDynAddr(const SymbolBody &B) const { return this->getVA() + B.GlobalDynIndex * sizeof(uintX_t); } template typename GotSection::uintX_t GotSection::getGlobalDynOffset(const SymbolBody &B) const { return B.GlobalDynIndex * sizeof(uintX_t); } template void GotSection::finalize() { Size = NumEntries * sizeof(uintX_t); } template bool GotSection::empty() const { // 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 NumEntries == 0 && !HasGotOffRel; } template void GotSection::writeTo(uint8_t *Buf) { this->relocate(Buf, Buf + Size); } template MipsGotSection::MipsGotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, Target->GotEntrySize, ".got") {} template void MipsGotSection::addEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr) { // For "true" local symbols which can be referenced from the same module // only compiler creates two instructions for address loading: // // lw $8, 0($gp) # R_MIPS_GOT16 // addi $8, $8, 0 # R_MIPS_LO16 // // The first instruction loads high 16 bits of the symbol address while // the second adds an offset. That allows to reduce number of required // GOT entries because only one global offset table entry is necessary // for every 64 KBytes of local data. So for local symbols we need to // allocate number of GOT entries to hold all required "page" addresses. // // All global symbols (hidden and regular) considered by compiler uniformly. // It always generates a single `lw` instruction and R_MIPS_GOT16 relocation // to load address of the symbol. So for each such symbol we need to // allocate dedicated GOT entry to store its address. // // If a symbol is preemptible we need help of dynamic linker to get its // final address. The corresponding GOT entries are allocated in the // "global" part of GOT. Entries for non preemptible global symbol allocated // in the "local" part of GOT. // // See "Global Offset Table" in Chapter 5: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf if (Expr == R_MIPS_GOT_LOCAL_PAGE) { // At this point we do not know final symbol value so to reduce number // of allocated GOT entries do the following trick. Save all output // sections referenced by GOT relocations. Then later in the `finalize` // method calculate number of "pages" required to cover all saved output // section and allocate appropriate number of GOT entries. PageIndexMap.insert({cast>(&Sym)->Section->OutSec, 0}); return; } if (Sym.isTls()) { // GOT entries created for MIPS TLS relocations behave like // almost GOT entries from other ABIs. They go to the end // of the global offset table. Sym.GotIndex = TlsEntries.size(); TlsEntries.push_back(&Sym); return; } auto AddEntry = [&](SymbolBody &S, uintX_t A, GotEntries &Items) { if (S.isInGot() && !A) return; size_t NewIndex = Items.size(); if (!EntryIndexMap.insert({{&S, A}, NewIndex}).second) return; Items.emplace_back(&S, A); if (!A) S.GotIndex = NewIndex; }; if (Sym.isPreemptible()) { // Ignore addends for preemptible symbols. They got single GOT entry anyway. AddEntry(Sym, 0, GlobalEntries); Sym.IsInGlobalMipsGot = true; } else if (Expr == R_MIPS_GOT_OFF32) { AddEntry(Sym, Addend, LocalEntries32); Sym.Is32BitMipsGot = true; } else { // Hold local GOT entries accessed via a 16-bit index separately. // That allows to write them in the beginning of the GOT and keep // their indexes as less as possible to escape relocation's overflow. AddEntry(Sym, Addend, LocalEntries); } } template bool MipsGotSection::addDynTlsEntry(SymbolBody &Sym) { if (Sym.GlobalDynIndex != -1U) return false; Sym.GlobalDynIndex = TlsEntries.size(); // Global Dynamic TLS entries take two GOT slots. TlsEntries.push_back(nullptr); TlsEntries.push_back(&Sym); return true; } // Reserves TLS entries for a TLS module ID and a TLS block offset. // In total it takes two GOT slots. template bool MipsGotSection::addTlsIndex() { if (TlsIndexOff != uint32_t(-1)) return false; TlsIndexOff = TlsEntries.size() * sizeof(uintX_t); TlsEntries.push_back(nullptr); TlsEntries.push_back(nullptr); return true; } static uint64_t getMipsPageAddr(uint64_t Addr) { return (Addr + 0x8000) & ~0xffff; } static uint64_t getMipsPageCount(uint64_t Size) { return (Size + 0xfffe) / 0xffff + 1; } template typename MipsGotSection::uintX_t MipsGotSection::getPageEntryOffset(const SymbolBody &B, uintX_t Addend) const { const OutputSectionBase *OutSec = cast>(&B)->Section->OutSec; uintX_t SecAddr = getMipsPageAddr(OutSec->Addr); uintX_t SymAddr = getMipsPageAddr(B.getVA(Addend)); uintX_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff; assert(Index < PageEntriesNum); return (HeaderEntriesNum + Index) * sizeof(uintX_t); } template typename MipsGotSection::uintX_t MipsGotSection::getBodyEntryOffset(const SymbolBody &B, uintX_t Addend) const { // Calculate offset of the GOT entries block: TLS, global, local. uintX_t Index = HeaderEntriesNum + PageEntriesNum; if (B.isTls()) Index += LocalEntries.size() + LocalEntries32.size() + GlobalEntries.size(); else if (B.IsInGlobalMipsGot) Index += LocalEntries.size() + LocalEntries32.size(); else if (B.Is32BitMipsGot) Index += LocalEntries.size(); // Calculate offset of the GOT entry in the block. if (B.isInGot()) Index += B.GotIndex; else { auto It = EntryIndexMap.find({&B, Addend}); assert(It != EntryIndexMap.end()); Index += It->second; } return Index * sizeof(uintX_t); } template typename MipsGotSection::uintX_t MipsGotSection::getTlsOffset() const { return (getLocalEntriesNum() + GlobalEntries.size()) * sizeof(uintX_t); } template typename MipsGotSection::uintX_t MipsGotSection::getGlobalDynOffset(const SymbolBody &B) const { return B.GlobalDynIndex * sizeof(uintX_t); } template const SymbolBody *MipsGotSection::getFirstGlobalEntry() const { return GlobalEntries.empty() ? nullptr : GlobalEntries.front().first; } template unsigned MipsGotSection::getLocalEntriesNum() const { return HeaderEntriesNum + PageEntriesNum + LocalEntries.size() + LocalEntries32.size(); } template void MipsGotSection::finalize() { PageEntriesNum = 0; for (std::pair &P : PageIndexMap) { // For each output section referenced by GOT page relocations calculate // and save into PageIndexMap an upper bound of MIPS GOT entries required // to store page addresses of local symbols. We assume the worst case - // each 64kb page of the output section has at least one GOT relocation // against it. And take in account the case when the section intersects // page boundaries. P.second = PageEntriesNum; PageEntriesNum += getMipsPageCount(P.first->Size); } Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) * sizeof(uintX_t); } template bool MipsGotSection::empty() const { // We add the .got section to the result for dynamic MIPS target because // its address and properties are mentioned in the .dynamic section. return Config->Relocatable; } template typename MipsGotSection::uintX_t MipsGotSection::getGp() const { return ElfSym::MipsGp->template getVA(0); } template static void writeUint(uint8_t *Buf, typename ELFT::uint Val) { typedef typename ELFT::uint uintX_t; write(Buf, Val); } template void MipsGotSection::writeTo(uint8_t *Buf) { // Set the MSB of the second GOT slot. This is not required by any // MIPS ABI documentation, though. // // There is a comment in glibc saying that "The MSB of got[1] of a // gnu object is set to identify gnu objects," and in GNU gold it // says "the second entry will be used by some runtime loaders". // But how this field is being used is unclear. // // We are not really willing to mimic other linkers behaviors // without understanding why they do that, but because all files // generated by GNU tools have this special GOT value, and because // we've been doing this for years, it is probably a safe bet to // keep doing this for now. We really need to revisit this to see // if we had to do this. auto *P = reinterpret_cast(Buf); P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31); Buf += HeaderEntriesNum * sizeof(uintX_t); // Write 'page address' entries to the local part of the GOT. for (std::pair &L : PageIndexMap) { size_t PageCount = getMipsPageCount(L.first->Size); uintX_t FirstPageAddr = getMipsPageAddr(L.first->Addr); for (size_t PI = 0; PI < PageCount; ++PI) { uint8_t *Entry = Buf + (L.second + PI) * sizeof(uintX_t); writeUint(Entry, FirstPageAddr + PI * 0x10000); } } Buf += PageEntriesNum * sizeof(uintX_t); auto AddEntry = [&](const GotEntry &SA) { uint8_t *Entry = Buf; Buf += sizeof(uintX_t); const SymbolBody *Body = SA.first; uintX_t VA = Body->template getVA(SA.second); writeUint(Entry, VA); }; std::for_each(std::begin(LocalEntries), std::end(LocalEntries), AddEntry); std::for_each(std::begin(LocalEntries32), std::end(LocalEntries32), AddEntry); std::for_each(std::begin(GlobalEntries), std::end(GlobalEntries), AddEntry); // Initialize TLS-related GOT entries. If the entry has a corresponding // dynamic relocations, leave it initialized by zero. Write down adjusted // TLS symbol's values otherwise. To calculate the adjustments use offsets // for thread-local storage. // https://www.linux-mips.org/wiki/NPTL if (TlsIndexOff != -1U && !Config->Pic) writeUint(Buf + TlsIndexOff, 1); for (const SymbolBody *B : TlsEntries) { if (!B || B->isPreemptible()) continue; uintX_t VA = B->getVA(); if (B->GotIndex != -1U) { uint8_t *Entry = Buf + B->GotIndex * sizeof(uintX_t); writeUint(Entry, VA - 0x7000); } if (B->GlobalDynIndex != -1U) { uint8_t *Entry = Buf + B->GlobalDynIndex * sizeof(uintX_t); writeUint(Entry, 1); Entry += sizeof(uintX_t); writeUint(Entry, VA - 0x8000); } } } template GotPltSection::GotPltSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Target->GotPltEntrySize, ".got.plt") {} template void GotPltSection::addEntry(SymbolBody &Sym) { Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size(); Entries.push_back(&Sym); } template size_t GotPltSection::getSize() const { return (Target->GotPltHeaderEntriesNum + Entries.size()) * Target->GotPltEntrySize; } template void GotPltSection::writeTo(uint8_t *Buf) { Target->writeGotPltHeader(Buf); Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize; for (const SymbolBody *B : Entries) { Target->writeGotPlt(Buf, *B); Buf += sizeof(uintX_t); } } // On ARM the IgotPltSection is part of the GotSection, on other Targets it is // part of the .got.plt template IgotPltSection::IgotPltSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Target->GotPltEntrySize, Config->EMachine == EM_ARM ? ".got" : ".got.plt") { } template void IgotPltSection::addEntry(SymbolBody &Sym) { Sym.IsInIgot = true; Sym.GotPltIndex = Entries.size(); Entries.push_back(&Sym); } template size_t IgotPltSection::getSize() const { return Entries.size() * Target->GotPltEntrySize; } template void IgotPltSection::writeTo(uint8_t *Buf) { for (const SymbolBody *B : Entries) { Target->writeIgotPlt(Buf, *B); Buf += sizeof(uintX_t); } } template StringTableSection::StringTableSection(StringRef Name, bool Dynamic) : SyntheticSection(Dynamic ? (uintX_t)SHF_ALLOC : 0, SHT_STRTAB, 1, Name), Dynamic(Dynamic) {} // Adds a string to the string table. If HashIt is true we hash and check for // duplicates. It is optional because the name of global symbols are already // uniqued and hashing them again has a big cost for a small value: uniquing // them with some other string that happens to be the same. template unsigned StringTableSection::addString(StringRef S, bool HashIt) { if (HashIt) { auto R = StringMap.insert(std::make_pair(S, this->Size)); if (!R.second) return R.first->second; } unsigned Ret = this->Size; this->Size = this->Size + S.size() + 1; Strings.push_back(S); return Ret; } template void StringTableSection::writeTo(uint8_t *Buf) { // ELF string tables start with NUL byte, so advance the pointer by one. ++Buf; for (StringRef S : Strings) { memcpy(Buf, S.data(), S.size()); Buf += S.size() + 1; } } // Returns the number of version definition entries. Because the first entry // is for the version definition itself, it is the number of versioned symbols // plus one. Note that we don't support multiple versions yet. static unsigned getVerDefNum() { return Config->VersionDefinitions.size() + 1; } template DynamicSection::DynamicSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_DYNAMIC, sizeof(uintX_t), ".dynamic") { this->Entsize = ELFT::Is64Bits ? 16 : 8; // .dynamic section is not writable on MIPS. // See "Special Section" in Chapter 4 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf if (Config->EMachine == EM_MIPS) this->Flags = SHF_ALLOC; addEntries(); } // There are some dynamic entries that don't depend on other sections. // Such entries can be set early. template void DynamicSection::addEntries() { // Add strings to .dynstr early so that .dynstr's size will be // fixed early. for (StringRef S : Config->AuxiliaryList) add({DT_AUXILIARY, In::DynStrTab->addString(S)}); if (!Config->RPath.empty()) add({Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH, In::DynStrTab->addString(Config->RPath)}); for (SharedFile *F : Symtab::X->getSharedFiles()) if (F->isNeeded()) add({DT_NEEDED, In::DynStrTab->addString(F->getSoName())}); if (!Config->SoName.empty()) add({DT_SONAME, In::DynStrTab->addString(Config->SoName)}); // Set DT_FLAGS and DT_FLAGS_1. uint32_t DtFlags = 0; uint32_t DtFlags1 = 0; if (Config->Bsymbolic) DtFlags |= DF_SYMBOLIC; if (Config->ZNodelete) DtFlags1 |= DF_1_NODELETE; if (Config->ZNow) { DtFlags |= DF_BIND_NOW; DtFlags1 |= DF_1_NOW; } if (Config->ZOrigin) { DtFlags |= DF_ORIGIN; DtFlags1 |= DF_1_ORIGIN; } if (DtFlags) add({DT_FLAGS, DtFlags}); if (DtFlags1) add({DT_FLAGS_1, DtFlags1}); if (!Config->Shared && !Config->Relocatable) add({DT_DEBUG, (uint64_t)0}); } // Add remaining entries to complete .dynamic contents. template void DynamicSection::finalize() { if (this->Size) return; // Already finalized. this->Link = In::DynStrTab->OutSec->SectionIndex; if (In::RelaDyn->OutSec->Size > 0) { bool IsRela = Config->Rela; add({IsRela ? DT_RELA : DT_REL, In::RelaDyn}); add({IsRela ? DT_RELASZ : DT_RELSZ, In::RelaDyn->OutSec->Size}); add({IsRela ? DT_RELAENT : DT_RELENT, uintX_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))}); // MIPS dynamic loader does not support RELCOUNT tag. // The problem is in the tight relation between dynamic // relocations and GOT. So do not emit this tag on MIPS. if (Config->EMachine != EM_MIPS) { size_t NumRelativeRels = In::RelaDyn->getRelativeRelocCount(); if (Config->ZCombreloc && NumRelativeRels) add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels}); } } if (In::RelaPlt->OutSec->Size > 0) { add({DT_JMPREL, In::RelaPlt}); add({DT_PLTRELSZ, In::RelaPlt->OutSec->Size}); add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT, In::GotPlt}); add({DT_PLTREL, uint64_t(Config->Rela ? DT_RELA : DT_REL)}); } add({DT_SYMTAB, In::DynSymTab}); add({DT_SYMENT, sizeof(Elf_Sym)}); add({DT_STRTAB, In::DynStrTab}); add({DT_STRSZ, In::DynStrTab->getSize()}); if (In::GnuHashTab) add({DT_GNU_HASH, In::GnuHashTab}); if (In::HashTab) add({DT_HASH, In::HashTab}); if (Out::PreinitArray) { add({DT_PREINIT_ARRAY, Out::PreinitArray}); add({DT_PREINIT_ARRAYSZ, Out::PreinitArray, Entry::SecSize}); } if (Out::InitArray) { add({DT_INIT_ARRAY, Out::InitArray}); add({DT_INIT_ARRAYSZ, Out::InitArray, Entry::SecSize}); } if (Out::FiniArray) { add({DT_FINI_ARRAY, Out::FiniArray}); add({DT_FINI_ARRAYSZ, Out::FiniArray, Entry::SecSize}); } - if (SymbolBody *B = Symtab::X->find(Config->Init)) + if (SymbolBody *B = Symtab::X->findInCurrentDSO(Config->Init)) add({DT_INIT, B}); - if (SymbolBody *B = Symtab::X->find(Config->Fini)) + if (SymbolBody *B = Symtab::X->findInCurrentDSO(Config->Fini)) add({DT_FINI, B}); bool HasVerNeed = In::VerNeed->getNeedNum() != 0; if (HasVerNeed || In::VerDef) add({DT_VERSYM, In::VerSym}); if (In::VerDef) { add({DT_VERDEF, In::VerDef}); add({DT_VERDEFNUM, getVerDefNum()}); } if (HasVerNeed) { add({DT_VERNEED, In::VerNeed}); add({DT_VERNEEDNUM, In::VerNeed->getNeedNum()}); } if (Config->EMachine == EM_MIPS) { add({DT_MIPS_RLD_VERSION, 1}); add({DT_MIPS_FLAGS, RHF_NOTPOT}); add({DT_MIPS_BASE_ADDRESS, Config->ImageBase}); add({DT_MIPS_SYMTABNO, In::DynSymTab->getNumSymbols()}); add({DT_MIPS_LOCAL_GOTNO, In::MipsGot->getLocalEntriesNum()}); if (const SymbolBody *B = In::MipsGot->getFirstGlobalEntry()) add({DT_MIPS_GOTSYM, B->DynsymIndex}); else add({DT_MIPS_GOTSYM, In::DynSymTab->getNumSymbols()}); add({DT_PLTGOT, In::MipsGot}); if (In::MipsRldMap) add({DT_MIPS_RLD_MAP, In::MipsRldMap}); } this->OutSec->Entsize = this->Entsize; this->OutSec->Link = this->Link; // +1 for DT_NULL this->Size = (Entries.size() + 1) * this->Entsize; } template void DynamicSection::writeTo(uint8_t *Buf) { auto *P = reinterpret_cast(Buf); for (const Entry &E : Entries) { P->d_tag = E.Tag; switch (E.Kind) { case Entry::SecAddr: P->d_un.d_ptr = E.OutSec->Addr; break; case Entry::InSecAddr: P->d_un.d_ptr = E.InSec->OutSec->Addr + E.InSec->OutSecOff; break; case Entry::SecSize: P->d_un.d_val = E.OutSec->Size; break; case Entry::SymAddr: P->d_un.d_ptr = E.Sym->template getVA(); break; case Entry::PlainInt: P->d_un.d_val = E.Val; break; } ++P; } } template typename ELFT::uint DynamicReloc::getOffset() const { if (OutputSec) return OutputSec->Addr + OffsetInSec; return InputSec->OutSec->Addr + InputSec->getOffset(OffsetInSec); } template typename ELFT::uint DynamicReloc::getAddend() const { if (UseSymVA) return Sym->getVA(Addend); return Addend; } template uint32_t DynamicReloc::getSymIndex() const { if (Sym && !UseSymVA) return Sym->DynsymIndex; return 0; } template RelocationSection::RelocationSection(StringRef Name, bool Sort) : SyntheticSection(SHF_ALLOC, Config->Rela ? SHT_RELA : SHT_REL, sizeof(uintX_t), Name), Sort(Sort) { this->Entsize = Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); } template void RelocationSection::addReloc(const DynamicReloc &Reloc) { if (Reloc.Type == Target->RelativeRel) ++NumRelativeRelocs; Relocs.push_back(Reloc); } template static bool compRelocations(const RelTy &A, const RelTy &B) { bool AIsRel = A.getType(Config->Mips64EL) == Target->RelativeRel; bool BIsRel = B.getType(Config->Mips64EL) == Target->RelativeRel; if (AIsRel != BIsRel) return AIsRel; return A.getSymbol(Config->Mips64EL) < B.getSymbol(Config->Mips64EL); } template void RelocationSection::writeTo(uint8_t *Buf) { uint8_t *BufBegin = Buf; for (const DynamicReloc &Rel : Relocs) { auto *P = reinterpret_cast(Buf); Buf += Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); if (Config->Rela) P->r_addend = Rel.getAddend(); P->r_offset = Rel.getOffset(); if (Config->EMachine == EM_MIPS && Rel.getInputSec() == In::MipsGot) // Dynamic relocation against MIPS GOT section make deal TLS entries // allocated in the end of the GOT. We need to adjust the offset to take // in account 'local' and 'global' GOT entries. P->r_offset += In::MipsGot->getTlsOffset(); P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->Mips64EL); } if (Sort) { if (Config->Rela) std::stable_sort((Elf_Rela *)BufBegin, (Elf_Rela *)BufBegin + Relocs.size(), compRelocations); else std::stable_sort((Elf_Rel *)BufBegin, (Elf_Rel *)BufBegin + Relocs.size(), compRelocations); } } template unsigned RelocationSection::getRelocOffset() { return this->Entsize * Relocs.size(); } template void RelocationSection::finalize() { this->Link = In::DynSymTab ? In::DynSymTab->OutSec->SectionIndex : In::SymTab->OutSec->SectionIndex; // Set required output section properties. this->OutSec->Link = this->Link; this->OutSec->Entsize = this->Entsize; } template SymbolTableSection::SymbolTableSection( StringTableSection &StrTabSec) : SyntheticSection(StrTabSec.isDynamic() ? (uintX_t)SHF_ALLOC : 0, StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB, sizeof(uintX_t), StrTabSec.isDynamic() ? ".dynsym" : ".symtab"), StrTabSec(StrTabSec) { this->Entsize = sizeof(Elf_Sym); } // Orders symbols according to their positions in the GOT, // in compliance with MIPS ABI rules. // See "Global Offset Table" in Chapter 5 in the following document // for detailed description: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf static bool sortMipsSymbols(const SymbolBody *L, const SymbolBody *R) { // Sort entries related to non-local preemptible symbols by GOT indexes. // All other entries go to the first part of GOT in arbitrary order. bool LIsInLocalGot = !L->IsInGlobalMipsGot; bool RIsInLocalGot = !R->IsInGlobalMipsGot; if (LIsInLocalGot || RIsInLocalGot) return !RIsInLocalGot; return L->GotIndex < R->GotIndex; } template void SymbolTableSection::finalize() { this->OutSec->Link = this->Link = StrTabSec.OutSec->SectionIndex; this->OutSec->Info = this->Info = NumLocals + 1; this->OutSec->Entsize = this->Entsize; if (Config->Relocatable) { size_t I = NumLocals; for (const SymbolTableEntry &S : Symbols) S.Symbol->DynsymIndex = ++I; return; } if (!StrTabSec.isDynamic()) { std::stable_sort( Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &L, const SymbolTableEntry &R) { return L.Symbol->symbol()->computeBinding() == STB_LOCAL && R.Symbol->symbol()->computeBinding() != STB_LOCAL; }); return; } if (In::GnuHashTab) // NB: It also sorts Symbols to meet the GNU hash table requirements. In::GnuHashTab->addSymbols(Symbols); else if (Config->EMachine == EM_MIPS) std::stable_sort(Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &L, const SymbolTableEntry &R) { return sortMipsSymbols(L.Symbol, R.Symbol); }); size_t I = 0; for (const SymbolTableEntry &S : Symbols) S.Symbol->DynsymIndex = ++I; } template void SymbolTableSection::addSymbol(SymbolBody *B) { Symbols.push_back({B, StrTabSec.addString(B->getName(), false)}); } template void SymbolTableSection::writeTo(uint8_t *Buf) { Buf += sizeof(Elf_Sym); // All symbols with STB_LOCAL binding precede the weak and global symbols. // .dynsym only contains global symbols. if (Config->Discard != DiscardPolicy::All && !StrTabSec.isDynamic()) writeLocalSymbols(Buf); writeGlobalSymbols(Buf); } template void SymbolTableSection::writeLocalSymbols(uint8_t *&Buf) { // Iterate over all input object files to copy their local symbols // to the output symbol table pointed by Buf. for (ObjectFile *File : Symtab::X->getObjectFiles()) { for (const std::pair *, size_t> &P : File->KeptLocalSyms) { const DefinedRegular &Body = *P.first; InputSectionBase *Section = Body.Section; auto *ESym = reinterpret_cast(Buf); if (!Section) { ESym->st_shndx = SHN_ABS; ESym->st_value = Body.Value; } else { const OutputSectionBase *OutSec = Section->OutSec; ESym->st_shndx = OutSec->SectionIndex; ESym->st_value = OutSec->Addr + Section->getOffset(Body); } ESym->st_name = P.second; ESym->st_size = Body.template getSize(); ESym->setBindingAndType(STB_LOCAL, Body.Type); Buf += sizeof(*ESym); } } } template void SymbolTableSection::writeGlobalSymbols(uint8_t *Buf) { // Write the internal symbol table contents to the output symbol table // pointed by Buf. auto *ESym = reinterpret_cast(Buf); for (const SymbolTableEntry &S : Symbols) { SymbolBody *Body = S.Symbol; size_t StrOff = S.StrTabOffset; uint8_t Type = Body->Type; uintX_t Size = Body->getSize(); ESym->setBindingAndType(Body->symbol()->computeBinding(), Type); ESym->st_size = Size; ESym->st_name = StrOff; ESym->setVisibility(Body->symbol()->Visibility); ESym->st_value = Body->getVA(); if (const OutputSectionBase *OutSec = getOutputSection(Body)) ESym->st_shndx = OutSec->SectionIndex; else if (isa>(Body)) ESym->st_shndx = SHN_ABS; if (Config->EMachine == EM_MIPS) { // On MIPS we need to mark symbol which has a PLT entry and requires // pointer equality by STO_MIPS_PLT flag. That is necessary to help // dynamic linker distinguish such symbols and MIPS lazy-binding stubs. // https://sourceware.org/ml/binutils/2008-07/txt00000.txt if (Body->isInPlt() && Body->NeedsCopyOrPltAddr) ESym->st_other |= STO_MIPS_PLT; if (Config->Relocatable) { auto *D = dyn_cast>(Body); if (D && D->isMipsPIC()) ESym->st_other |= STO_MIPS_PIC; } } ++ESym; } } template const OutputSectionBase * SymbolTableSection::getOutputSection(SymbolBody *Sym) { switch (Sym->kind()) { case SymbolBody::DefinedSyntheticKind: return cast(Sym)->Section; case SymbolBody::DefinedRegularKind: { auto &D = cast>(*Sym); if (D.Section) return D.Section->OutSec; break; } case SymbolBody::DefinedCommonKind: return In::Common->OutSec; case SymbolBody::SharedKind: { auto &SS = cast>(*Sym); if (SS.needsCopy()) return SS.getBssSectionForCopy(); break; } case SymbolBody::UndefinedKind: case SymbolBody::LazyArchiveKind: case SymbolBody::LazyObjectKind: break; } return nullptr; } template GnuHashTableSection::GnuHashTableSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, sizeof(uintX_t), ".gnu.hash") { this->Entsize = ELFT::Is64Bits ? 0 : 4; } template unsigned GnuHashTableSection::calcNBuckets(unsigned NumHashed) { if (!NumHashed) return 0; // These values are prime numbers which are not greater than 2^(N-1) + 1. // In result, for any particular NumHashed we return a prime number // which is not greater than NumHashed. static const unsigned Primes[] = { 1, 1, 3, 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071}; return Primes[std::min(Log2_32_Ceil(NumHashed), array_lengthof(Primes) - 1)]; } // Bloom filter estimation: at least 8 bits for each hashed symbol. // GNU Hash table requirement: it should be a power of 2, // the minimum value is 1, even for an empty table. // Expected results for a 32-bit target: // calcMaskWords(0..4) = 1 // calcMaskWords(5..8) = 2 // calcMaskWords(9..16) = 4 // For a 64-bit target: // calcMaskWords(0..8) = 1 // calcMaskWords(9..16) = 2 // calcMaskWords(17..32) = 4 template unsigned GnuHashTableSection::calcMaskWords(unsigned NumHashed) { if (!NumHashed) return 1; return NextPowerOf2((NumHashed - 1) / sizeof(Elf_Off)); } template void GnuHashTableSection::finalize() { unsigned NumHashed = Symbols.size(); NBuckets = calcNBuckets(NumHashed); MaskWords = calcMaskWords(NumHashed); // Second hash shift estimation: just predefined values. Shift2 = ELFT::Is64Bits ? 6 : 5; this->OutSec->Entsize = this->Entsize; this->OutSec->Link = this->Link = In::DynSymTab->OutSec->SectionIndex; this->Size = sizeof(Elf_Word) * 4 // Header + sizeof(Elf_Off) * MaskWords // Bloom Filter + sizeof(Elf_Word) * NBuckets // Hash Buckets + sizeof(Elf_Word) * NumHashed; // Hash Values } template void GnuHashTableSection::writeTo(uint8_t *Buf) { writeHeader(Buf); if (Symbols.empty()) return; writeBloomFilter(Buf); writeHashTable(Buf); } template void GnuHashTableSection::writeHeader(uint8_t *&Buf) { auto *P = reinterpret_cast(Buf); *P++ = NBuckets; *P++ = In::DynSymTab->getNumSymbols() - Symbols.size(); *P++ = MaskWords; *P++ = Shift2; Buf = reinterpret_cast(P); } template void GnuHashTableSection::writeBloomFilter(uint8_t *&Buf) { unsigned C = sizeof(Elf_Off) * 8; auto *Masks = reinterpret_cast(Buf); for (const SymbolData &Sym : Symbols) { size_t Pos = (Sym.Hash / C) & (MaskWords - 1); uintX_t V = (uintX_t(1) << (Sym.Hash % C)) | (uintX_t(1) << ((Sym.Hash >> Shift2) % C)); Masks[Pos] |= V; } Buf += sizeof(Elf_Off) * MaskWords; } template void GnuHashTableSection::writeHashTable(uint8_t *Buf) { Elf_Word *Buckets = reinterpret_cast(Buf); Elf_Word *Values = Buckets + NBuckets; int PrevBucket = -1; int I = 0; for (const SymbolData &Sym : Symbols) { int Bucket = Sym.Hash % NBuckets; assert(PrevBucket <= Bucket); if (Bucket != PrevBucket) { Buckets[Bucket] = Sym.Body->DynsymIndex; PrevBucket = Bucket; if (I > 0) Values[I - 1] |= 1; } Values[I] = Sym.Hash & ~1; ++I; } if (I > 0) Values[I - 1] |= 1; } static uint32_t hashGnu(StringRef Name) { uint32_t H = 5381; for (uint8_t C : Name) H = (H << 5) + H + C; return H; } // Add symbols to this symbol hash table. Note that this function // destructively sort a given vector -- which is needed because // GNU-style hash table places some sorting requirements. template void GnuHashTableSection::addSymbols(std::vector &V) { // Ideally this will just be 'auto' but GCC 6.1 is not able // to deduce it correctly. std::vector::iterator Mid = std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) { return S.Symbol->isUndefined(); }); if (Mid == V.end()) return; for (auto I = Mid, E = V.end(); I != E; ++I) { SymbolBody *B = I->Symbol; size_t StrOff = I->StrTabOffset; Symbols.push_back({B, StrOff, hashGnu(B->getName())}); } unsigned NBuckets = calcNBuckets(Symbols.size()); std::stable_sort(Symbols.begin(), Symbols.end(), [&](const SymbolData &L, const SymbolData &R) { return L.Hash % NBuckets < R.Hash % NBuckets; }); V.erase(Mid, V.end()); for (const SymbolData &Sym : Symbols) V.push_back({Sym.Body, Sym.STName}); } template HashTableSection::HashTableSection() : SyntheticSection(SHF_ALLOC, SHT_HASH, sizeof(Elf_Word), ".hash") { this->Entsize = sizeof(Elf_Word); } template void HashTableSection::finalize() { this->OutSec->Link = this->Link = In::DynSymTab->OutSec->SectionIndex; this->OutSec->Entsize = this->Entsize; unsigned NumEntries = 2; // nbucket and nchain. NumEntries += In::DynSymTab->getNumSymbols(); // The chain entries. // Create as many buckets as there are symbols. // FIXME: This is simplistic. We can try to optimize it, but implementing // support for SHT_GNU_HASH is probably even more profitable. NumEntries += In::DynSymTab->getNumSymbols(); this->Size = NumEntries * sizeof(Elf_Word); } template void HashTableSection::writeTo(uint8_t *Buf) { unsigned NumSymbols = In::DynSymTab->getNumSymbols(); auto *P = reinterpret_cast(Buf); *P++ = NumSymbols; // nbucket *P++ = NumSymbols; // nchain Elf_Word *Buckets = P; Elf_Word *Chains = P + NumSymbols; for (const SymbolTableEntry &S : In::DynSymTab->getSymbols()) { SymbolBody *Body = S.Symbol; StringRef Name = Body->getName(); unsigned I = Body->DynsymIndex; uint32_t Hash = hashSysV(Name) % NumSymbols; Chains[I] = Buckets[Hash]; Buckets[Hash] = I; } } template PltSection::PltSection() : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt") {} template void PltSection::writeTo(uint8_t *Buf) { // At beginning of PLT, we have code to call the dynamic linker // to resolve dynsyms at runtime. Write such code. Target->writePltHeader(Buf); size_t Off = Target->PltHeaderSize; for (auto &I : Entries) { const SymbolBody *B = I.first; unsigned RelOff = I.second; uint64_t Got = B->getGotPltVA(); uint64_t Plt = this->getVA() + Off; Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff); Off += Target->PltEntrySize; } } template void PltSection::addEntry(SymbolBody &Sym) { Sym.PltIndex = Entries.size(); unsigned RelOff = In::RelaPlt->getRelocOffset(); Entries.push_back(std::make_pair(&Sym, RelOff)); } template size_t PltSection::getSize() const { return Target->PltHeaderSize + Entries.size() * Target->PltEntrySize; } template IpltSection::IpltSection() : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt") {} template void IpltSection::writeTo(uint8_t *Buf) { // The IRelative relocations do not support lazy binding so no header is // needed size_t Off = 0; for (auto &I : Entries) { const SymbolBody *B = I.first; unsigned RelOff = I.second + In::Plt->getSize(); uint64_t Got = B->getGotPltVA(); uint64_t Plt = this->getVA() + Off; Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff); Off += Target->PltEntrySize; } } template void IpltSection::addEntry(SymbolBody &Sym) { Sym.PltIndex = Entries.size(); Sym.IsInIplt = true; unsigned RelOff = In::RelaIplt->getRelocOffset(); Entries.push_back(std::make_pair(&Sym, RelOff)); } template size_t IpltSection::getSize() const { return Entries.size() * Target->PltEntrySize; } template GdbIndexSection::GdbIndexSection() : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"), StringPool(llvm::StringTableBuilder::ELF) {} template void GdbIndexSection::parseDebugSections() { for (InputSectionBase *S : Symtab::X->Sections) if (InputSection *IS = dyn_cast>(S)) if (IS->OutSec && IS->Name == ".debug_info") readDwarf(IS); } // Iterative hash function for symbol's name is described in .gdb_index format // specification. Note that we use one for version 5 to 7 here, it is different // for version 4. static uint32_t hash(StringRef Str) { uint32_t R = 0; for (uint8_t C : Str) R = R * 67 + tolower(C) - 113; return R; } template void GdbIndexSection::readDwarf(InputSection *I) { GdbIndexBuilder Builder(I); if (ErrorCount) return; size_t CuId = CompilationUnits.size(); std::vector> CuList = Builder.readCUList(); CompilationUnits.insert(CompilationUnits.end(), CuList.begin(), CuList.end()); std::vector> AddrArea = Builder.readAddressArea(CuId); AddressArea.insert(AddressArea.end(), AddrArea.begin(), AddrArea.end()); std::vector> NamesAndTypes = Builder.readPubNamesAndTypes(); for (std::pair &Pair : NamesAndTypes) { uint32_t Hash = hash(Pair.first); size_t Offset = StringPool.add(Pair.first); bool IsNew; GdbSymbol *Sym; std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset); if (IsNew) { Sym->CuVectorIndex = CuVectors.size(); CuVectors.push_back({{CuId, Pair.second}}); continue; } std::vector> &CuVec = CuVectors[Sym->CuVectorIndex]; CuVec.push_back({CuId, Pair.second}); } } template void GdbIndexSection::finalize() { if (Finalized) return; Finalized = true; parseDebugSections(); // GdbIndex header consist from version fields // and 5 more fields with different kinds of offsets. CuTypesOffset = CuListOffset + CompilationUnits.size() * CompilationUnitSize; SymTabOffset = CuTypesOffset + AddressArea.size() * AddressEntrySize; ConstantPoolOffset = SymTabOffset + SymbolTable.getCapacity() * SymTabEntrySize; for (std::vector> &CuVec : CuVectors) { CuVectorsOffset.push_back(CuVectorsSize); CuVectorsSize += OffsetTypeSize * (CuVec.size() + 1); } StringPoolOffset = ConstantPoolOffset + CuVectorsSize; StringPool.finalizeInOrder(); } template size_t GdbIndexSection::getSize() const { const_cast *>(this)->finalize(); return StringPoolOffset + StringPool.getSize(); } template void GdbIndexSection::writeTo(uint8_t *Buf) { write32le(Buf, 7); // Write version. write32le(Buf + 4, CuListOffset); // CU list offset. write32le(Buf + 8, CuTypesOffset); // Types CU list offset. write32le(Buf + 12, CuTypesOffset); // Address area offset. write32le(Buf + 16, SymTabOffset); // Symbol table offset. write32le(Buf + 20, ConstantPoolOffset); // Constant pool offset. Buf += 24; // Write the CU list. for (std::pair CU : CompilationUnits) { write64le(Buf, CU.first); write64le(Buf + 8, CU.second); Buf += 16; } // Write the address area. for (AddressEntry &E : AddressArea) { uintX_t BaseAddr = E.Section->OutSec->Addr + E.Section->getOffset(0); write64le(Buf, BaseAddr + E.LowAddress); write64le(Buf + 8, BaseAddr + E.HighAddress); write32le(Buf + 16, E.CuIndex); Buf += 20; } // Write the symbol table. for (size_t I = 0; I < SymbolTable.getCapacity(); ++I) { GdbSymbol *Sym = SymbolTable.getSymbol(I); if (Sym) { size_t NameOffset = Sym->NameOffset + StringPoolOffset - ConstantPoolOffset; size_t CuVectorOffset = CuVectorsOffset[Sym->CuVectorIndex]; write32le(Buf, NameOffset); write32le(Buf + 4, CuVectorOffset); } Buf += 8; } // Write the CU vectors into the constant pool. for (std::vector> &CuVec : CuVectors) { write32le(Buf, CuVec.size()); Buf += 4; for (std::pair &P : CuVec) { uint32_t Index = P.first; uint8_t Flags = P.second; Index |= Flags << 24; write32le(Buf, Index); Buf += 4; } } StringPool.write(Buf); } template bool GdbIndexSection::empty() const { return !Out::DebugInfo; } template EhFrameHeader::EhFrameHeader() : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame_hdr") {} // .eh_frame_hdr contains a binary search table of pointers to FDEs. // Each entry of the search table consists of two values, // the starting PC from where FDEs covers, and the FDE's address. // It is sorted by PC. template void EhFrameHeader::writeTo(uint8_t *Buf) { const endianness E = ELFT::TargetEndianness; // Sort the FDE list by their PC and uniqueify. Usually there is only // one FDE for a PC (i.e. function), but if ICF merges two functions // into one, there can be more than one FDEs pointing to the address. auto Less = [](const FdeData &A, const FdeData &B) { return A.Pc < B.Pc; }; std::stable_sort(Fdes.begin(), Fdes.end(), Less); auto Eq = [](const FdeData &A, const FdeData &B) { return A.Pc == B.Pc; }; Fdes.erase(std::unique(Fdes.begin(), Fdes.end(), Eq), Fdes.end()); Buf[0] = 1; Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; Buf[2] = DW_EH_PE_udata4; Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; write32(Buf + 4, Out::EhFrame->Addr - this->getVA() - 4); write32(Buf + 8, Fdes.size()); Buf += 12; uintX_t VA = this->getVA(); for (FdeData &Fde : Fdes) { write32(Buf, Fde.Pc - VA); write32(Buf + 4, Fde.FdeVA - VA); Buf += 8; } } template size_t EhFrameHeader::getSize() const { // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs. return 12 + Out::EhFrame->NumFdes * 8; } template void EhFrameHeader::addFde(uint32_t Pc, uint32_t FdeVA) { Fdes.push_back({Pc, FdeVA}); } template bool EhFrameHeader::empty() const { return Out::EhFrame->empty(); } template VersionDefinitionSection::VersionDefinitionSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t), ".gnu.version_d") {} static StringRef getFileDefName() { if (!Config->SoName.empty()) return Config->SoName; return Config->OutputFile; } template void VersionDefinitionSection::finalize() { FileDefNameOff = In::DynStrTab->addString(getFileDefName()); for (VersionDefinition &V : Config->VersionDefinitions) V.NameOff = In::DynStrTab->addString(V.Name); this->OutSec->Link = this->Link = In::DynStrTab->OutSec->SectionIndex; // sh_info should be set to the number of definitions. This fact is missed in // documentation, but confirmed by binutils community: // https://sourceware.org/ml/binutils/2014-11/msg00355.html this->OutSec->Info = this->Info = getVerDefNum(); } template void VersionDefinitionSection::writeOne(uint8_t *Buf, uint32_t Index, StringRef Name, size_t NameOff) { auto *Verdef = reinterpret_cast(Buf); Verdef->vd_version = 1; Verdef->vd_cnt = 1; Verdef->vd_aux = sizeof(Elf_Verdef); Verdef->vd_next = sizeof(Elf_Verdef) + sizeof(Elf_Verdaux); Verdef->vd_flags = (Index == 1 ? VER_FLG_BASE : 0); Verdef->vd_ndx = Index; Verdef->vd_hash = hashSysV(Name); auto *Verdaux = reinterpret_cast(Buf + sizeof(Elf_Verdef)); Verdaux->vda_name = NameOff; Verdaux->vda_next = 0; } template void VersionDefinitionSection::writeTo(uint8_t *Buf) { writeOne(Buf, 1, getFileDefName(), FileDefNameOff); for (VersionDefinition &V : Config->VersionDefinitions) { Buf += sizeof(Elf_Verdef) + sizeof(Elf_Verdaux); writeOne(Buf, V.Id, V.Name, V.NameOff); } // Need to terminate the last version definition. Elf_Verdef *Verdef = reinterpret_cast(Buf); Verdef->vd_next = 0; } template size_t VersionDefinitionSection::getSize() const { return (sizeof(Elf_Verdef) + sizeof(Elf_Verdaux)) * getVerDefNum(); } template VersionTableSection::VersionTableSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t), ".gnu.version") {} template void VersionTableSection::finalize() { this->OutSec->Entsize = this->Entsize = sizeof(Elf_Versym); // At the moment of june 2016 GNU docs does not mention that sh_link field // should be set, but Sun docs do. Also readelf relies on this field. this->OutSec->Link = this->Link = In::DynSymTab->OutSec->SectionIndex; } template size_t VersionTableSection::getSize() const { return sizeof(Elf_Versym) * (In::DynSymTab->getSymbols().size() + 1); } template void VersionTableSection::writeTo(uint8_t *Buf) { auto *OutVersym = reinterpret_cast(Buf) + 1; for (const SymbolTableEntry &S : In::DynSymTab->getSymbols()) { OutVersym->vs_index = S.Symbol->symbol()->VersionId; ++OutVersym; } } template bool VersionTableSection::empty() const { return !In::VerDef && In::VerNeed->empty(); } template VersionNeedSection::VersionNeedSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t), ".gnu.version_r") { // Identifiers in verneed section start at 2 because 0 and 1 are reserved // for VER_NDX_LOCAL and VER_NDX_GLOBAL. // First identifiers are reserved by verdef section if it exist. NextIndex = getVerDefNum() + 1; } template void VersionNeedSection::addSymbol(SharedSymbol *SS) { if (!SS->Verdef) { SS->symbol()->VersionId = VER_NDX_GLOBAL; return; } SharedFile *F = SS->file(); // If we don't already know that we need an Elf_Verneed for this DSO, prepare // to create one by adding it to our needed list and creating a dynstr entry // for the soname. if (F->VerdefMap.empty()) Needed.push_back({F, In::DynStrTab->addString(F->getSoName())}); typename SharedFile::NeededVer &NV = F->VerdefMap[SS->Verdef]; // If we don't already know that we need an Elf_Vernaux for this Elf_Verdef, // prepare to create one by allocating a version identifier and creating a // dynstr entry for the version name. if (NV.Index == 0) { NV.StrTab = In::DynStrTab->addString( SS->file()->getStringTable().data() + SS->Verdef->getAux()->vda_name); NV.Index = NextIndex++; } SS->symbol()->VersionId = NV.Index; } template void VersionNeedSection::writeTo(uint8_t *Buf) { // The Elf_Verneeds need to appear first, followed by the Elf_Vernauxs. auto *Verneed = reinterpret_cast(Buf); auto *Vernaux = reinterpret_cast(Verneed + Needed.size()); for (std::pair *, size_t> &P : Needed) { // Create an Elf_Verneed for this DSO. Verneed->vn_version = 1; Verneed->vn_cnt = P.first->VerdefMap.size(); Verneed->vn_file = P.second; Verneed->vn_aux = reinterpret_cast(Vernaux) - reinterpret_cast(Verneed); Verneed->vn_next = sizeof(Elf_Verneed); ++Verneed; // Create the Elf_Vernauxs for this Elf_Verneed. The loop iterates over // VerdefMap, which will only contain references to needed version // definitions. Each Elf_Vernaux is based on the information contained in // the Elf_Verdef in the source DSO. This loop iterates over a std::map of // pointers, but is deterministic because the pointers refer to Elf_Verdef // data structures within a single input file. for (auto &NV : P.first->VerdefMap) { Vernaux->vna_hash = NV.first->vd_hash; Vernaux->vna_flags = 0; Vernaux->vna_other = NV.second.Index; Vernaux->vna_name = NV.second.StrTab; Vernaux->vna_next = sizeof(Elf_Vernaux); ++Vernaux; } Vernaux[-1].vna_next = 0; } Verneed[-1].vn_next = 0; } template void VersionNeedSection::finalize() { this->OutSec->Link = this->Link = In::DynStrTab->OutSec->SectionIndex; this->OutSec->Info = this->Info = Needed.size(); } template size_t VersionNeedSection::getSize() const { unsigned Size = Needed.size() * sizeof(Elf_Verneed); for (const std::pair *, size_t> &P : Needed) Size += P.first->VerdefMap.size() * sizeof(Elf_Vernaux); return Size; } template bool VersionNeedSection::empty() const { return getNeedNum() == 0; } template MipsRldMapSection::MipsRldMapSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, sizeof(typename ELFT::uint), ".rld_map") {} template void MipsRldMapSection::writeTo(uint8_t *Buf) { // Apply filler from linker script. uint64_t Filler = Script::X->getFiller(this->Name); Filler = (Filler << 32) | Filler; memcpy(Buf, &Filler, getSize()); } template ARMExidxSentinelSection::ARMExidxSentinelSection() : SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX, sizeof(typename ELFT::uint), ".ARM.exidx") {} // Write a terminating sentinel entry to the end of the .ARM.exidx table. // This section will have been sorted last in the .ARM.exidx table. // This table entry will have the form: // | PREL31 upper bound of code that has exception tables | EXIDX_CANTUNWIND | template void ARMExidxSentinelSection::writeTo(uint8_t *Buf) { // Get the InputSection before us, we are by definition last auto RI = cast>(this->OutSec)->Sections.rbegin(); InputSection *LE = *(++RI); InputSection *LC = cast>(LE->getLinkOrderDep()); uint64_t S = LC->OutSec->Addr + LC->getOffset(LC->getSize()); uint64_t P = this->getVA(); Target->relocateOne(Buf, R_ARM_PREL31, S - P); write32le(Buf + 4, 0x1); } template InputSection *elf::createCommonSection(); template InputSection *elf::createCommonSection(); template InputSection *elf::createCommonSection(); template InputSection *elf::createCommonSection(); template InputSection *elf::createInterpSection(); template InputSection *elf::createInterpSection(); template InputSection *elf::createInterpSection(); template InputSection *elf::createInterpSection(); template MergeInputSection *elf::createCommentSection(); template MergeInputSection *elf::createCommentSection(); template MergeInputSection *elf::createCommentSection(); template MergeInputSection *elf::createCommentSection(); template class elf::MipsAbiFlagsSection; template class elf::MipsAbiFlagsSection; template class elf::MipsAbiFlagsSection; template class elf::MipsAbiFlagsSection; template class elf::MipsOptionsSection; template class elf::MipsOptionsSection; template class elf::MipsOptionsSection; template class elf::MipsOptionsSection; template class elf::MipsReginfoSection; template class elf::MipsReginfoSection; template class elf::MipsReginfoSection; template class elf::MipsReginfoSection; template class elf::BuildIdSection; template class elf::BuildIdSection; template class elf::BuildIdSection; template class elf::BuildIdSection; template class elf::GotSection; template class elf::GotSection; template class elf::GotSection; template class elf::GotSection; template class elf::MipsGotSection; template class elf::MipsGotSection; template class elf::MipsGotSection; template class elf::MipsGotSection; template class elf::GotPltSection; template class elf::GotPltSection; template class elf::GotPltSection; template class elf::GotPltSection; template class elf::IgotPltSection; template class elf::IgotPltSection; template class elf::IgotPltSection; template class elf::IgotPltSection; template class elf::StringTableSection; template class elf::StringTableSection; template class elf::StringTableSection; template class elf::StringTableSection; template class elf::DynamicSection; template class elf::DynamicSection; template class elf::DynamicSection; template class elf::DynamicSection; template class elf::RelocationSection; template class elf::RelocationSection; template class elf::RelocationSection; template class elf::RelocationSection; template class elf::SymbolTableSection; template class elf::SymbolTableSection; template class elf::SymbolTableSection; template class elf::SymbolTableSection; template class elf::GnuHashTableSection; template class elf::GnuHashTableSection; template class elf::GnuHashTableSection; template class elf::GnuHashTableSection; template class elf::HashTableSection; template class elf::HashTableSection; template class elf::HashTableSection; template class elf::HashTableSection; template class elf::PltSection; template class elf::PltSection; template class elf::PltSection; template class elf::PltSection; template class elf::IpltSection; template class elf::IpltSection; template class elf::IpltSection; template class elf::IpltSection; template class elf::GdbIndexSection; template class elf::GdbIndexSection; template class elf::GdbIndexSection; template class elf::GdbIndexSection; template class elf::EhFrameHeader; template class elf::EhFrameHeader; template class elf::EhFrameHeader; template class elf::EhFrameHeader; template class elf::VersionTableSection; template class elf::VersionTableSection; template class elf::VersionTableSection; template class elf::VersionTableSection; template class elf::VersionNeedSection; template class elf::VersionNeedSection; template class elf::VersionNeedSection; template class elf::VersionNeedSection; template class elf::VersionDefinitionSection; template class elf::VersionDefinitionSection; template class elf::VersionDefinitionSection; template class elf::VersionDefinitionSection; template class elf::MipsRldMapSection; template class elf::MipsRldMapSection; template class elf::MipsRldMapSection; template class elf::MipsRldMapSection; template class elf::ARMExidxSentinelSection; template class elf::ARMExidxSentinelSection; template class elf::ARMExidxSentinelSection; template class elf::ARMExidxSentinelSection; Index: vendor/lld/dist/ELF/Writer.cpp =================================================================== --- vendor/lld/dist/ELF/Writer.cpp (revision 312631) +++ vendor/lld/dist/ELF/Writer.cpp (revision 312632) @@ -1,1742 +1,1742 @@ //===- Writer.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Writer.h" #include "Config.h" #include "LinkerScript.h" #include "Memory.h" #include "OutputSections.h" #include "Relocations.h" #include "Strings.h" #include "SymbolTable.h" #include "SyntheticSections.h" #include "Target.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" #include #include using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support; using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; namespace { // The writer writes a SymbolTable result to a file. template class Writer { public: typedef typename ELFT::uint uintX_t; typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Ehdr Elf_Ehdr; typedef typename ELFT::Phdr Elf_Phdr; typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::SymRange Elf_Sym_Range; typedef typename ELFT::Rela Elf_Rela; void run(); private: void createSyntheticSections(); void copyLocalSymbols(); void addReservedSymbols(); void addInputSec(InputSectionBase *S); void createSections(); void forEachRelSec(std::function &)> Fn); void sortSections(); void finalizeSections(); void addPredefinedSections(); std::vector createPhdrs(); void removeEmptyPTLoad(); void addPtArmExid(std::vector &Phdrs); void assignAddresses(); void assignFileOffsets(); void assignFileOffsetsBinary(); void setPhdrs(); void fixHeaders(); void fixSectionAlignments(); void fixAbsoluteSymbols(); void openFile(); void writeHeader(); void writeSections(); void writeSectionsBinary(); void writeBuildId(); std::unique_ptr Buffer; std::vector OutputSections; OutputSectionFactory Factory; void addRelIpltSymbols(); void addStartEndSymbols(); void addStartStopSymbols(OutputSectionBase *Sec); uintX_t getEntryAddr(); OutputSectionBase *findSection(StringRef Name); std::vector Phdrs; uintX_t FileSize; uintX_t SectionHeaderOff; bool AllocateHeader = true; }; } // anonymous namespace StringRef elf::getOutputSectionName(StringRef Name) { if (Config->Relocatable) return Name; for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.", ".gcc_except_table.", ".tdata.", ".ARM.exidx."}) { StringRef Prefix = V.drop_back(); if (Name.startswith(V) || Name == Prefix) return Prefix; } // CommonSection is identified as "COMMON" in linker scripts. // By default, it should go to .bss section. if (Name == "COMMON") return ".bss"; // ".zdebug_" is a prefix for ZLIB-compressed sections. // Because we decompressed input sections, we want to remove 'z'. if (Name.startswith(".zdebug_")) return Saver.save(Twine(".") + Name.substr(2)); return Name; } template void elf::reportDiscarded(InputSectionBase *IS) { if (!Config->PrintGcSections) return; errs() << "removing unused section from '" << IS->Name << "' in file '" << IS->getFile()->getName() << "'\n"; } template static bool needsInterpSection() { return !Symtab::X->getSharedFiles().empty() && !Config->DynamicLinker.empty() && !Script::X->ignoreInterpSection(); } template void elf::writeResult() { Writer().run(); } template void Writer::removeEmptyPTLoad() { auto I = std::remove_if(Phdrs.begin(), Phdrs.end(), [&](const PhdrEntry &P) { if (P.p_type != PT_LOAD) return false; if (!P.First) return true; uintX_t Size = P.Last->Addr + P.Last->Size - P.First->Addr; return Size == 0; }); Phdrs.erase(I, Phdrs.end()); } // The main function of the writer. template void Writer::run() { // Create linker-synthesized sections such as .got or .plt. // Such sections are of type input section. createSyntheticSections(); // We need to create some reserved symbols such as _end. Create them. if (!Config->Relocatable) addReservedSymbols(); // Some architectures use small displacements for jump instructions. // It is linker's responsibility to create thunks containing long // jump instructions if jump targets are too far. Create thunks. if (Target->NeedsThunks) forEachRelSec(createThunks); // Create output sections. Script::X->OutputSections = &OutputSections; if (ScriptConfig->HasSections) { // If linker script contains SECTIONS commands, let it create sections. Script::X->processCommands(Factory); // Linker scripts may have left some input sections unassigned. // Assign such sections using the default rule. Script::X->addOrphanSections(Factory); } else { // If linker script does not contain SECTIONS commands, create // output sections by default rules. We still need to give the // linker script a chance to run, because it might contain // non-SECTIONS commands such as ASSERT. createSections(); Script::X->processCommands(Factory); } if (Config->Discard != DiscardPolicy::All) copyLocalSymbols(); // Now that we have a complete set of output sections. This function // completes section contents. For example, we need to add strings // to the string table, and add entries to .got and .plt. // finalizeSections does that. finalizeSections(); if (ErrorCount) return; if (Config->Relocatable) { assignFileOffsets(); } else { if (ScriptConfig->HasSections) { Script::X->assignAddresses(Phdrs); } else { fixSectionAlignments(); assignAddresses(); } // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a // 0 sized region. This has to be done late since only after assignAddresses // we know the size of the sections. removeEmptyPTLoad(); if (!Config->OFormatBinary) assignFileOffsets(); else assignFileOffsetsBinary(); setPhdrs(); fixAbsoluteSymbols(); } // Write the result down to a file. openFile(); if (ErrorCount) return; if (!Config->OFormatBinary) { writeHeader(); writeSections(); } else { writeSectionsBinary(); } // 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. writeBuildId(); if (ErrorCount) return; if (auto EC = Buffer->commit()) error(EC, "failed to write to the output file"); // Flush the output streams and exit immediately. A full shutdown // is a good test that we are keeping track of all allocated memory, // but actually freeing it is a waste of time in a regular linker run. if (Config->ExitEarly) exitLld(0); } // Initialize Out members. template void Writer::createSyntheticSections() { // Initialize all pointers with NULL. This is needed because // you can call lld::elf::main more than once as a library. memset(&Out::First, 0, sizeof(Out)); // Create singleton output sections. Out::Bss = make>(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); Out::BssRelRo = make>(".bss.rel.ro", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); In::DynStrTab = make>(".dynstr", true); In::Dynamic = make>(); Out::EhFrame = make>(); In::RelaDyn = make>( Config->Rela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc); In::ShStrTab = make>(".shstrtab", false); Out::ElfHeader = make("", 0, SHF_ALLOC); Out::ElfHeader->Size = sizeof(Elf_Ehdr); Out::ProgramHeaders = make("", 0, SHF_ALLOC); Out::ProgramHeaders->updateAlignment(sizeof(uintX_t)); if (needsInterpSection()) { In::Interp = createInterpSection(); Symtab::X->Sections.push_back(In::Interp); } else { In::Interp = nullptr; } if (!Config->Relocatable) Symtab::X->Sections.push_back(createCommentSection()); if (Config->Strip != StripPolicy::All) { In::StrTab = make>(".strtab", false); In::SymTab = make>(*In::StrTab); } if (Config->BuildId != BuildIdKind::None) { In::BuildId = make>(); Symtab::X->Sections.push_back(In::BuildId); } InputSection *Common = createCommonSection(); if (!Common->Data.empty()) { In::Common = Common; Symtab::X->Sections.push_back(Common); } // Add MIPS-specific sections. bool HasDynSymTab = !Symtab::X->getSharedFiles().empty() || Config->Pic; if (Config->EMachine == EM_MIPS) { if (!Config->Shared && HasDynSymTab) { In::MipsRldMap = make>(); Symtab::X->Sections.push_back(In::MipsRldMap); } if (auto *Sec = MipsAbiFlagsSection::create()) Symtab::X->Sections.push_back(Sec); if (auto *Sec = MipsOptionsSection::create()) Symtab::X->Sections.push_back(Sec); if (auto *Sec = MipsReginfoSection::create()) Symtab::X->Sections.push_back(Sec); } if (HasDynSymTab) { In::DynSymTab = make>(*In::DynStrTab); Symtab::X->Sections.push_back(In::DynSymTab); In::VerSym = make>(); Symtab::X->Sections.push_back(In::VerSym); if (!Config->VersionDefinitions.empty()) { In::VerDef = make>(); Symtab::X->Sections.push_back(In::VerDef); } In::VerNeed = make>(); Symtab::X->Sections.push_back(In::VerNeed); if (Config->GnuHash) { In::GnuHashTab = make>(); Symtab::X->Sections.push_back(In::GnuHashTab); } if (Config->SysvHash) { In::HashTab = make>(); Symtab::X->Sections.push_back(In::HashTab); } Symtab::X->Sections.push_back(In::Dynamic); Symtab::X->Sections.push_back(In::DynStrTab); Symtab::X->Sections.push_back(In::RelaDyn); } // Add .got. MIPS' .got is so different from the other archs, // it has its own class. if (Config->EMachine == EM_MIPS) { In::MipsGot = make>(); Symtab::X->Sections.push_back(In::MipsGot); } else { In::Got = make>(); Symtab::X->Sections.push_back(In::Got); } In::GotPlt = make>(); Symtab::X->Sections.push_back(In::GotPlt); In::IgotPlt = make>(); Symtab::X->Sections.push_back(In::IgotPlt); if (Config->GdbIndex) { In::GdbIndex = make>(); Symtab::X->Sections.push_back(In::GdbIndex); } // We always need to add rel[a].plt to output if it has entries. // Even for static linking it can contain R_[*]_IRELATIVE relocations. In::RelaPlt = make>( Config->Rela ? ".rela.plt" : ".rel.plt", false /*Sort*/); Symtab::X->Sections.push_back(In::RelaPlt); // The RelaIplt immediately follows .rel.plt (.rel.dyn for ARM) to ensure // that the IRelative relocations are processed last by the dynamic loader In::RelaIplt = make>( (Config->EMachine == EM_ARM) ? ".rel.dyn" : In::RelaPlt->Name, false /*Sort*/); Symtab::X->Sections.push_back(In::RelaIplt); In::Plt = make>(); Symtab::X->Sections.push_back(In::Plt); In::Iplt = make>(); Symtab::X->Sections.push_back(In::Iplt); if (Config->EhFrameHdr) { In::EhFrameHdr = make>(); Symtab::X->Sections.push_back(In::EhFrameHdr); } } template static bool shouldKeepInSymtab(InputSectionBase *Sec, StringRef SymName, const SymbolBody &B) { if (B.isFile()) return false; // We keep sections in symtab for relocatable output. if (B.isSection()) return Config->Relocatable; // If sym references a section in a discarded group, don't keep it. if (Sec == &InputSection::Discarded) return false; if (Config->Discard == DiscardPolicy::None) return true; // In ELF assembly .L symbols are normally discarded by the assembler. // If the assembler fails to do so, the linker discards them if // * --discard-locals is used. // * The symbol is in a SHF_MERGE section, which is normally the reason for // the assembler keeping the .L symbol. if (!SymName.startswith(".L") && !SymName.empty()) return true; if (Config->Discard == DiscardPolicy::Locals) return false; return !Sec || !(Sec->Flags & SHF_MERGE); } template static bool includeInSymtab(const SymbolBody &B) { if (!B.isLocal() && !B.symbol()->IsUsedInRegularObj) return false; // If --retain-symbols-file is given, we'll keep only symbols listed in that // file. if (Config->Discard == DiscardPolicy::RetainFile && !Config->RetainSymbolsFile.count(B.getName())) return false; if (auto *D = dyn_cast>(&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>(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 void Writer::copyLocalSymbols() { if (!In::SymTab) return; for (elf::ObjectFile *F : Symtab::X->getObjectFiles()) { for (SymbolBody *B : F->getLocalSymbols()) { if (!B->IsLocal) fatal(toString(F) + ": broken object: getLocalSymbols returns a non-local symbol"); auto *DR = dyn_cast>(B); // No reason to keep local undefined symbol in symtab. if (!DR) continue; if (!includeInSymtab(*B)) continue; InputSectionBase *Sec = DR->Section; if (!shouldKeepInSymtab(Sec, B->getName(), *B)) continue; ++In::SymTab->NumLocals; if (Config->Relocatable) B->DynsymIndex = In::SymTab->NumLocals; F->KeptLocalSyms.push_back(std::make_pair( DR, In::SymTab->StrTabSec.addString(B->getName()))); } } } // PPC64 has a number of special SHT_PROGBITS+SHF_ALLOC+SHF_WRITE sections that // we would like to make sure appear is a specific order to maximize their // coverage by a single signed 16-bit offset from the TOC base pointer. // Conversely, the special .tocbss section should be first among all SHT_NOBITS // sections. This will put it next to the loaded special PPC64 sections (and, // thus, within reach of the TOC base pointer). static int getPPC64SectionRank(StringRef SectionName) { return StringSwitch(SectionName) .Case(".tocbss", 0) .Case(".branch_lt", 2) .Case(".toc", 3) .Case(".toc1", 4) .Case(".opd", 5) .Default(1); } template bool elf::isRelroSection(const OutputSectionBase *Sec) { if (!Config->ZRelro) return false; uint64_t Flags = Sec->Flags; if (!(Flags & SHF_ALLOC) || !(Flags & SHF_WRITE)) return false; if (Flags & SHF_TLS) return true; uint32_t Type = Sec->Type; if (Type == SHT_INIT_ARRAY || Type == SHT_FINI_ARRAY || Type == SHT_PREINIT_ARRAY) return true; if (Sec == In::GotPlt->OutSec) return Config->ZNow; if (Sec == In::Dynamic->OutSec) return true; if (In::Got && Sec == In::Got->OutSec) return true; if (In::MipsGot && Sec == In::MipsGot->OutSec) return true; if (Sec == Out::BssRelRo) return true; StringRef S = Sec->getName(); return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" || S == ".eh_frame" || S == ".openbsd.randomdata"; } template static bool compareSectionsNonScript(const OutputSectionBase *A, const OutputSectionBase *B) { // Put .interp first because some loaders want to see that section // on the first page of the executable file when loaded into memory. bool AIsInterp = A->getName() == ".interp"; bool BIsInterp = B->getName() == ".interp"; if (AIsInterp != BIsInterp) return AIsInterp; // Allocatable sections go first to reduce the total PT_LOAD size and // so debug info doesn't change addresses in actual code. bool AIsAlloc = A->Flags & SHF_ALLOC; bool BIsAlloc = B->Flags & SHF_ALLOC; if (AIsAlloc != BIsAlloc) return AIsAlloc; // We don't have any special requirements for the relative order of two non // allocatable sections. if (!AIsAlloc) return false; // We want to put section specified by -T option first, so we // can start assigning VA starting from them later. auto AAddrSetI = Config->SectionStartMap.find(A->getName()); auto BAddrSetI = Config->SectionStartMap.find(B->getName()); bool AHasAddrSet = AAddrSetI != Config->SectionStartMap.end(); bool BHasAddrSet = BAddrSetI != Config->SectionStartMap.end(); if (AHasAddrSet != BHasAddrSet) return AHasAddrSet; if (AHasAddrSet) return AAddrSetI->second < BAddrSetI->second; // We want the read only sections first so that they go in the PT_LOAD // covering the program headers at the start of the file. bool AIsWritable = A->Flags & SHF_WRITE; bool BIsWritable = B->Flags & SHF_WRITE; if (AIsWritable != BIsWritable) return BIsWritable; if (!Config->SingleRoRx) { // 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. bool AIsExec = A->Flags & SHF_EXECINSTR; bool BIsExec = B->Flags & SHF_EXECINSTR; if (AIsExec != BIsExec) return BIsExec; } // If we got here we know that both A and B are in the same PT_LOAD. bool AIsTls = A->Flags & SHF_TLS; bool BIsTls = B->Flags & SHF_TLS; bool AIsNoBits = A->Type == SHT_NOBITS; bool BIsNoBits = B->Type == SHT_NOBITS; // The first requirement we have is to put (non-TLS) nobits sections last. The // reason is that the only thing the dynamic linker will see about them is a // p_memsz that is larger than p_filesz. Seeing that it zeros the end of the // PT_LOAD, so that has to correspond to the nobits sections. bool AIsNonTlsNoBits = AIsNoBits && !AIsTls; bool BIsNonTlsNoBits = BIsNoBits && !BIsTls; if (AIsNonTlsNoBits != BIsNonTlsNoBits) return BIsNonTlsNoBits; // We place nobits RelRo sections before plain r/w ones, and non-nobits RelRo // sections after r/w ones, so that the RelRo sections are contiguous. bool AIsRelRo = isRelroSection(A); bool BIsRelRo = isRelroSection(B); if (AIsRelRo != BIsRelRo) return AIsNonTlsNoBits ? AIsRelRo : BIsRelRo; // The TLS initialization block needs to be a single contiguous block in a R/W // PT_LOAD, so stick TLS sections directly before the other RelRo R/W // sections. The TLS NOBITS sections are placed here as they don't take up // virtual address space in the PT_LOAD. if (AIsTls != BIsTls) return AIsTls; // Within the TLS initialization block, the non-nobits sections need to appear // first. if (AIsNoBits != BIsNoBits) return BIsNoBits; // Some architectures have additional ordering restrictions for sections // within the same PT_LOAD. if (Config->EMachine == EM_PPC64) return getPPC64SectionRank(A->getName()) < getPPC64SectionRank(B->getName()); return false; } // Output section ordering is determined by this function. template static bool compareSections(const OutputSectionBase *A, const OutputSectionBase *B) { // For now, put sections mentioned in a linker script first. int AIndex = Script::X->getSectionIndex(A->getName()); int BIndex = Script::X->getSectionIndex(B->getName()); bool AInScript = AIndex != INT_MAX; bool BInScript = BIndex != INT_MAX; if (AInScript != BInScript) return AInScript; // If both are in the script, use that order. if (AInScript) return AIndex < BIndex; return compareSectionsNonScript(A, B); } // Program header entry PhdrEntry::PhdrEntry(unsigned Type, unsigned Flags) { p_type = Type; p_flags = Flags; } void PhdrEntry::add(OutputSectionBase *Sec) { Last = Sec; if (!First) First = Sec; p_align = std::max(p_align, Sec->Addralign); if (p_type == PT_LOAD) Sec->FirstInPtLoad = First; } template static void addOptionalSynthetic(StringRef Name, OutputSectionBase *Sec, typename ELFT::uint Val, uint8_t StOther = STV_HIDDEN) { if (SymbolBody *S = Symtab::X->find(Name)) - if (S->isUndefined() || S->isShared()) + if (!S->isInCurrentDSO()) Symtab::X->addSynthetic(Name, Sec, Val, StOther); } template static Symbol *addRegular(StringRef Name, InputSectionBase *Sec, typename ELFT::uint Value) { // The linker generated symbols are added as STB_WEAK to allow user defined // ones to override them. return Symtab::X->addRegular(Name, STV_HIDDEN, STT_NOTYPE, Value, /*Size=*/0, STB_WEAK, Sec, /*File=*/nullptr); } template static Symbol *addOptionalRegular(StringRef Name, InputSectionBase *IS, typename ELFT::uint Value) { SymbolBody *S = Symtab::X->find(Name); if (!S) return nullptr; - if (!S->isUndefined() && !S->isShared()) + if (S->isInCurrentDSO()) return S->symbol(); return addRegular(Name, IS, Value); } // The beginning and the ending of .rel[a].plt section are marked // with __rel[a]_iplt_{start,end} symbols if it is a statically linked // executable. The runtime needs these symbols in order to resolve // all IRELATIVE relocs on startup. For dynamic executables, we don't // need these symbols, since IRELATIVE relocs are resolved through GOT // and PLT. For details, see http://www.airs.com/blog/archives/403. template void Writer::addRelIpltSymbols() { if (In::DynSymTab) return; StringRef S = Config->Rela ? "__rela_iplt_start" : "__rel_iplt_start"; addOptionalRegular(S, In::RelaIplt, 0); S = Config->Rela ? "__rela_iplt_end" : "__rel_iplt_end"; addOptionalRegular(S, In::RelaIplt, -1); } // The linker is expected to define some symbols depending on // the linking result. This function defines such symbols. template void Writer::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 by default is relative // to GOT. Default offset is 0x7ff0. // See "Global Data Symbols" in Chapter 6 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf ElfSym::MipsGp = Symtab::X->addAbsolute("_gp", STV_HIDDEN, STB_LOCAL); // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between // start of function and 'gp' pointer into GOT. To simplify relocation // calculation we assign _gp value to it and calculate corresponding // relocations as relative to this value. if (Symtab::X->find("_gp_disp")) ElfSym::MipsGpDisp = Symtab::X->addAbsolute("_gp_disp", STV_HIDDEN, STB_LOCAL); // 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 if (Symtab::X->find("__gnu_local_gp")) ElfSym::MipsLocalGp = Symtab::X->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_LOCAL); } // 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. Symtab::X->addIgnored("_GLOBAL_OFFSET_TABLE_"); // __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For // static linking the linker is required to optimize away any references to // __tls_get_addr, so it's not defined anywhere. Create a hidden definition // to avoid the undefined symbol error. As usual special cases are ARM and // MIPS - the libc for these targets defines __tls_get_addr itself because // there are no TLS optimizations for these targets. if (!In::DynSymTab && (Config->EMachine != EM_MIPS && Config->EMachine != EM_ARM)) Symtab::X->addIgnored("__tls_get_addr"); // If linker script do layout we do not need to create any standart symbols. if (ScriptConfig->HasSections) return; ElfSym::EhdrStart = Symtab::X->addIgnored("__ehdr_start"); auto Define = [this](StringRef S, DefinedRegular *&Sym1, DefinedRegular *&Sym2) { Sym1 = Symtab::X->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::X->find(S)) if (B->isUndefined()) Sym2 = Symtab::X->addAbsolute(S, STV_DEFAULT); }; Define("_end", ElfSym::End, ElfSym::End2); Define("_etext", ElfSym::Etext, ElfSym::Etext2); Define("_edata", ElfSym::Edata, ElfSym::Edata2); } // Sort input sections by section name suffixes for // __attribute__((init_priority(N))). template static void sortInitFini(OutputSectionBase *S) { if (S) reinterpret_cast *>(S)->sortInitFini(); } // Sort input sections by the special rule for .ctors and .dtors. template static void sortCtorsDtors(OutputSectionBase *S) { if (S) reinterpret_cast *>(S)->sortCtorsDtors(); } // Sort input sections using the list provided by --symbol-ordering-file. template static void sortBySymbolsOrder(ArrayRef OutputSections) { if (Config->SymbolOrderingFile.empty()) return; // Build a map from symbols to their priorities. Symbols that didn't // appear in the symbol ordering file have the lowest priority 0. // All explicitly mentioned symbols have negative (higher) priorities. DenseMap SymbolOrder; int Priority = -Config->SymbolOrderingFile.size(); for (StringRef S : Config->SymbolOrderingFile) SymbolOrder.insert({S, Priority++}); // Build a map from sections to their priorities. DenseMap *, int> SectionOrder; for (elf::ObjectFile *File : Symtab::X->getObjectFiles()) { for (SymbolBody *Body : File->getSymbols()) { auto *D = dyn_cast>(Body); if (!D || !D->Section) continue; int &Priority = SectionOrder[D->Section]; Priority = std::min(Priority, SymbolOrder.lookup(D->getName())); } } // Sort sections by priority. for (OutputSectionBase *Base : OutputSections) if (auto *Sec = dyn_cast>(Base)) Sec->sort([&](InputSection *S) { return SectionOrder.lookup(S); }); } template void Writer::forEachRelSec( std::function &)> Fn) { for (InputSectionBase *IS : Symtab::X->Sections) { if (!IS->Live) continue; // Scan all relocations. Each relocation goes through a series // of tests to determine if it needs special treatment, such as // creating GOT, PLT, copy relocations, etc. // Note that relocations for non-alloc sections are directly // processed by InputSection::relocateNonAlloc. if (!(IS->Flags & SHF_ALLOC)) continue; if (isa>(IS) || isa>(IS)) Fn(*IS); } } template void Writer::addInputSec(InputSectionBase *IS) { if (!IS) return; if (!IS->Live) { reportDiscarded(IS); return; } OutputSectionBase *Sec; bool IsNew; StringRef OutsecName = getOutputSectionName(IS->Name); std::tie(Sec, IsNew) = Factory.create(IS, OutsecName); if (IsNew) OutputSections.push_back(Sec); Sec->addSection(IS); } template void Writer::createSections() { for (InputSectionBase *IS : Symtab::X->Sections) addInputSec(IS); sortBySymbolsOrder(OutputSections); sortInitFini(findSection(".init_array")); sortInitFini(findSection(".fini_array")); sortCtorsDtors(findSection(".ctors")); sortCtorsDtors(findSection(".dtors")); for (OutputSectionBase *Sec : OutputSections) Sec->assignOffsets(); } template static bool canSharePtLoad(const OutputSectionBase &S1, const OutputSectionBase &S2) { if (!(S1.Flags & SHF_ALLOC) || !(S2.Flags & SHF_ALLOC)) return false; bool S1IsWrite = S1.Flags & SHF_WRITE; bool S2IsWrite = S2.Flags & SHF_WRITE; if (S1IsWrite != S2IsWrite) return false; if (!S1IsWrite) return true; // RO and RX share a PT_LOAD with linker scripts. return (S1.Flags & SHF_EXECINSTR) == (S2.Flags & SHF_EXECINSTR); } template void Writer::sortSections() { // Don't sort if using -r. It is not necessary and we want to preserve the // relative order for SHF_LINK_ORDER sections. if (Config->Relocatable) return; if (!ScriptConfig->HasSections) { std::stable_sort(OutputSections.begin(), OutputSections.end(), compareSectionsNonScript); return; } Script::X->adjustSectionsBeforeSorting(); // The order of the sections in the script is arbitrary and may not agree with // compareSectionsNonScript. This means that we cannot easily define a // strict weak ordering. To see why, consider a comparison of a section in the // script and one not in the script. We have a two simple options: // * Make them equivalent (a is not less than b, and b is not less than a). // The problem is then that equivalence has to be transitive and we can // have sections a, b and c with only b in a script and a less than c // which breaks this property. // * Use compareSectionsNonScript. Given that the script order doesn't have // to match, we can end up with sections a, b, c, d where b and c are in the // script and c is compareSectionsNonScript less than b. In which case d // can be equivalent to c, a to b and d < a. As a concrete example: // .a (rx) # not in script // .b (rx) # in script // .c (ro) # in script // .d (ro) # not in script // // The way we define an order then is: // * First put script sections at the start and sort the script and // non-script sections independently. // * Move each non-script section to its preferred position. We try // to put each section in the last position where it it can share // a PT_LOAD. std::stable_sort(OutputSections.begin(), OutputSections.end(), compareSections); auto I = OutputSections.begin(); auto E = OutputSections.end(); auto NonScriptI = std::find_if(OutputSections.begin(), E, [](OutputSectionBase *S) { return Script::X->getSectionIndex(S->getName()) == INT_MAX; }); while (NonScriptI != E) { auto BestPos = std::max_element( I, NonScriptI, [&](OutputSectionBase *&A, OutputSectionBase *&B) { bool ACanSharePtLoad = canSharePtLoad(**NonScriptI, *A); bool BCanSharePtLoad = canSharePtLoad(**NonScriptI, *B); if (ACanSharePtLoad != BCanSharePtLoad) return BCanSharePtLoad; bool ACmp = compareSectionsNonScript(*NonScriptI, A); bool BCmp = compareSectionsNonScript(*NonScriptI, B); if (ACmp != BCmp) return BCmp; // FIXME: missing test size_t PosA = &A - &OutputSections[0]; size_t PosB = &B - &OutputSections[0]; return ACmp ? PosA > PosB : PosA < PosB; }); // max_element only returns NonScriptI if the range is empty. If the range // is not empty we should consider moving the the element forward one // position. if (BestPos != NonScriptI && !compareSectionsNonScript(*NonScriptI, *BestPos)) ++BestPos; std::rotate(BestPos, NonScriptI, NonScriptI + 1); ++NonScriptI; } Script::X->adjustSectionsAfterSorting(); } template static void finalizeSynthetic(const std::vector *> &Sections) { for (SyntheticSection *SS : Sections) if (SS && SS->OutSec && !SS->empty()) { SS->finalize(); SS->OutSec->Size = 0; SS->OutSec->assignOffsets(); } } // We need to add input synthetic sections early in createSyntheticSections() // to make them visible from linkescript side. But not all sections are always // required to be in output. For example we don't need dynamic section content // sometimes. This function filters out such unused sections from output. template static void removeUnusedSyntheticSections(std::vector &V) { // Input synthetic sections are placed after all regular ones. We iterate over // them all and exit at first non-synthetic. for (InputSectionBase *S : llvm::reverse(Symtab::X->Sections)) { SyntheticSection *SS = dyn_cast>(S); if (!SS) return; if (!SS->empty() || !SS->OutSec) continue; OutputSection *OutSec = cast>(SS->OutSec); OutSec->Sections.erase( std::find(OutSec->Sections.begin(), OutSec->Sections.end(), SS)); // If there is no other sections in output section, remove it from output. if (OutSec->Sections.empty()) V.erase(std::find(V.begin(), V.end(), OutSec)); } } // Create output section objects and add them to OutputSections. template void Writer::finalizeSections() { Out::DebugInfo = findSection(".debug_info"); Out::PreinitArray = findSection(".preinit_array"); Out::InitArray = findSection(".init_array"); Out::FiniArray = findSection(".fini_array"); // The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop // symbols for sections, so that the runtime can get the start and end // addresses of each section by section name. Add such symbols. if (!Config->Relocatable) { addStartEndSymbols(); for (OutputSectionBase *Sec : OutputSections) 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 (In::DynSymTab) addRegular("_DYNAMIC", In::Dynamic, 0); // Define __rel[a]_iplt_{start,end} symbols if needed. addRelIpltSymbols(); if (!Out::EhFrame->empty()) { OutputSections.push_back(Out::EhFrame); Out::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. forEachRelSec(scanRelocations); // Now that we have defined all possible symbols including linker- // synthesized ones. Visit all symbols to give the finishing touches. for (Symbol *S : Symtab::X->getSymbols()) { SymbolBody *Body = S->body(); if (!includeInSymtab(*Body)) continue; if (In::SymTab) In::SymTab->addSymbol(Body); if (In::DynSymTab && S->includeInDynsym()) { In::DynSymTab->addSymbol(Body); if (auto *SS = dyn_cast>(Body)) if (SS->file()->isNeeded()) In::VerNeed->addSymbol(SS); } } // Do not proceed if there was an undefined symbol. if (ErrorCount) return; // So far we have added sections from input object files. // This function adds linker-created Out::* sections. addPredefinedSections(); removeUnusedSyntheticSections(OutputSections); sortSections(); unsigned I = 1; for (OutputSectionBase *Sec : OutputSections) { Sec->SectionIndex = I++; Sec->ShName = In::ShStrTab->addString(Sec->getName()); } // Binary and relocatable output does not have PHDRS. // The headers have to be created before finalize as that can influence the // image base and the dynamic section on mips includes the image base. if (!Config->Relocatable && !Config->OFormatBinary) { Phdrs = Script::X->hasPhdrsCommands() ? Script::X->createPhdrs() : createPhdrs(); addPtArmExid(Phdrs); fixHeaders(); } // Fill other section headers. The dynamic table is finalized // at the end because some tags like RELSZ depend on result // of finalizing other sections. for (OutputSectionBase *Sec : OutputSections) Sec->finalize(); // Dynamic section must be the last one in this list and dynamic // symbol table section (DynSymTab) must be the first one. finalizeSynthetic( {In::DynSymTab, In::GnuHashTab, In::HashTab, In::SymTab, In::ShStrTab, In::StrTab, In::VerDef, In::DynStrTab, In::GdbIndex, In::Got, In::MipsGot, In::IgotPlt, In::GotPlt, In::RelaDyn, In::RelaIplt, In::RelaPlt, In::Plt, In::Iplt, In::Plt, In::EhFrameHdr, In::VerSym, In::VerNeed, In::Dynamic}); } template void Writer::addPredefinedSections() { if (Out::Bss->Size > 0) OutputSections.push_back(Out::Bss); if (Out::BssRelRo->Size > 0) OutputSections.push_back(Out::BssRelRo); auto OS = dyn_cast_or_null>(findSection(".ARM.exidx")); if (OS && !OS->Sections.empty() && !Config->Relocatable) OS->addSection(make>()); addInputSec(In::SymTab); addInputSec(In::ShStrTab); addInputSec(In::StrTab); } // The linker is expected to define SECNAME_start and SECNAME_end // symbols for a few sections. This function defines them. template void Writer::addStartEndSymbols() { auto Define = [&](StringRef Start, StringRef End, OutputSectionBase *OS) { // These symbols resolve to the image base if the section does not exist. // A special value -1 indicates end of the section. addOptionalSynthetic(Start, OS, 0); addOptionalSynthetic(End, OS, OS ? -1 : 0); }; Define("__preinit_array_start", "__preinit_array_end", Out::PreinitArray); Define("__init_array_start", "__init_array_end", Out::InitArray); Define("__fini_array_start", "__fini_array_end", Out::FiniArray); if (OutputSectionBase *Sec = findSection(".ARM.exidx")) Define("__exidx_start", "__exidx_end", Sec); } // If a section name is valid as a C identifier (which is rare because of // the leading '.'), linkers are expected to define __start_ and // __stop_ symbols. They are at beginning and end of the section, // respectively. This is not requested by the ELF standard, but GNU ld and // gold provide the feature, and used by many programs. template void Writer::addStartStopSymbols(OutputSectionBase *Sec) { StringRef S = Sec->getName(); if (!isValidCIdentifier(S)) return; addOptionalSynthetic(Saver.save("__start_" + S), Sec, 0, STV_DEFAULT); addOptionalSynthetic(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT); } template OutputSectionBase *Writer::findSection(StringRef Name) { for (OutputSectionBase *Sec : OutputSections) if (Sec->getName() == Name) return Sec; return nullptr; } template static bool needsPtLoad(OutputSectionBase *Sec) { if (!(Sec->Flags & 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->Flags & SHF_TLS && Sec->Type == SHT_NOBITS) return false; return true; } // Linker scripts are responsible for aligning addresses. Unfortunately, most // linker scripts are designed for creating two PT_LOADs only, one RX and one // RW. This means that there is no alignment in the RO to RX transition and we // cannot create a PT_LOAD there. template static typename ELFT::uint computeFlags(typename ELFT::uint F) { if (Config->OMagic) return PF_R | PF_W | PF_X; if (Config->SingleRoRx && !(F & PF_W)) return F | PF_X; return F; } // Decide which program headers to create and which sections to include in each // one. template std::vector Writer::createPhdrs() { std::vector Ret; auto AddHdr = [&](unsigned Type, unsigned Flags) -> PhdrEntry * { Ret.emplace_back(Type, Flags); return &Ret.back(); }; // The first phdr entry is PT_PHDR which describes the program header itself. PhdrEntry &Hdr = *AddHdr(PT_PHDR, PF_R); Hdr.add(Out::ProgramHeaders); // PT_INTERP must be the second entry if exists. if (OutputSectionBase *Sec = findSection(".interp")) { PhdrEntry &Hdr = *AddHdr(PT_INTERP, Sec->getPhdrFlags()); Hdr.add(Sec); } // Add the first PT_LOAD segment for regular output sections. uintX_t Flags = computeFlags(PF_R); PhdrEntry *Load = AddHdr(PT_LOAD, Flags); PhdrEntry TlsHdr(PT_TLS, PF_R); PhdrEntry RelRo(PT_GNU_RELRO, PF_R); PhdrEntry Note(PT_NOTE, PF_R); for (OutputSectionBase *Sec : OutputSections) { if (!(Sec->Flags & SHF_ALLOC)) break; // If we meet TLS section then we create TLS header // and put all TLS sections inside for further use when // assign addresses. if (Sec->Flags & SHF_TLS) TlsHdr.add(Sec); if (!needsPtLoad(Sec)) continue; // Segments are contiguous memory regions that has the same attributes // (e.g. executable or writable). There is one phdr for each segment. // Therefore, we need to create a new phdr when the next section has // different flags or is loaded at a discontiguous address using AT linker // script command. uintX_t NewFlags = computeFlags(Sec->getPhdrFlags()); if (Script::X->hasLMA(Sec->getName()) || Flags != NewFlags) { Load = AddHdr(PT_LOAD, NewFlags); Flags = NewFlags; } Load->add(Sec); if (isRelroSection(Sec)) RelRo.add(Sec); if (Sec->Type == SHT_NOTE) Note.add(Sec); } // Add the TLS segment unless it's empty. if (TlsHdr.First) Ret.push_back(std::move(TlsHdr)); // Add an entry for .dynamic. if (In::DynSymTab) { PhdrEntry &H = *AddHdr(PT_DYNAMIC, In::Dynamic->OutSec->getPhdrFlags()); H.add(In::Dynamic->OutSec); } // PT_GNU_RELRO includes all sections that should be marked as // read-only by dynamic linker after proccessing relocations. if (RelRo.First) Ret.push_back(std::move(RelRo)); // PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr. if (!Out::EhFrame->empty() && In::EhFrameHdr) { PhdrEntry &Hdr = *AddHdr(PT_GNU_EH_FRAME, In::EhFrameHdr->OutSec->getPhdrFlags()); Hdr.add(In::EhFrameHdr->OutSec); } // PT_OPENBSD_RANDOMIZE specifies the location and size of a part of the // memory image of the program that must be filled with random data before any // code in the object is executed. if (OutputSectionBase *Sec = findSection(".openbsd.randomdata")) { PhdrEntry &Hdr = *AddHdr(PT_OPENBSD_RANDOMIZE, Sec->getPhdrFlags()); Hdr.add(Sec); } // PT_GNU_STACK is a special section to tell the loader to make the // pages for the stack non-executable. if (!Config->ZExecstack) { PhdrEntry &Hdr = *AddHdr(PT_GNU_STACK, PF_R | PF_W); if (Config->ZStackSize != uint64_t(-1)) Hdr.p_memsz = Config->ZStackSize; } // PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable // is expected to perform W^X violations, such as calling mprotect(2) or // mmap(2) with PROT_WRITE | PROT_EXEC, which is prohibited by default on // OpenBSD. if (Config->ZWxneeded) AddHdr(PT_OPENBSD_WXNEEDED, PF_X); if (Note.First) Ret.push_back(std::move(Note)); return Ret; } template void Writer::addPtArmExid(std::vector &Phdrs) { if (Config->EMachine != EM_ARM) return; auto I = std::find_if( OutputSections.begin(), OutputSections.end(), [](OutputSectionBase *Sec) { return Sec->Type == SHT_ARM_EXIDX; }); if (I == OutputSections.end()) return; // PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME PhdrEntry ARMExidx(PT_ARM_EXIDX, PF_R); ARMExidx.add(*I); Phdrs.push_back(ARMExidx); } // The first section of each PT_LOAD, the first section in PT_GNU_RELRO and the // first section after PT_GNU_RELRO have to be page aligned so that the dynamic // linker can set the permissions. template void Writer::fixSectionAlignments() { for (const PhdrEntry &P : Phdrs) if (P.p_type == PT_LOAD && P.First) P.First->PageAlign = true; for (const PhdrEntry &P : Phdrs) { if (P.p_type != PT_GNU_RELRO) continue; if (P.First) P.First->PageAlign = true; // 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 *Sec = *(I + 1); if (needsPtLoad(Sec)) Sec->PageAlign = true; } } template void elf::allocateHeaders(MutableArrayRef Phdrs, ArrayRef OutputSections) { auto FirstPTLoad = std::find_if(Phdrs.begin(), Phdrs.end(), [](const PhdrEntry &E) { return E.p_type == PT_LOAD; }); if (FirstPTLoad == Phdrs.end()) return; if (FirstPTLoad->First) for (OutputSectionBase *Sec : OutputSections) if (Sec->FirstInPtLoad == FirstPTLoad->First) Sec->FirstInPtLoad = Out::ElfHeader; FirstPTLoad->First = Out::ElfHeader; if (!FirstPTLoad->Last) FirstPTLoad->Last = Out::ProgramHeaders; } // 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 void Writer::fixHeaders() { Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size(); // If the script has SECTIONS, assignAddresses will compute the values. if (ScriptConfig->HasSections) return; uintX_t HeaderSize = getHeaderSize(); // When -T
option is specified, lower the base to make room for those // sections. if (!Config->SectionStartMap.empty()) { uint64_t Min = -1; for (const auto &P : Config->SectionStartMap) Min = std::min(Min, P.second); if (HeaderSize < Min) Min -= HeaderSize; else AllocateHeader = false; if (Min < Config->ImageBase) Config->ImageBase = alignDown(Min, Config->MaxPageSize); } if (AllocateHeader) allocateHeaders(Phdrs, OutputSections); uintX_t BaseVA = Config->ImageBase; Out::ElfHeader->Addr = BaseVA; Out::ProgramHeaders->Addr = BaseVA + Out::ElfHeader->Size; } // Assign VAs (addresses at run-time) to output sections. template void Writer::assignAddresses() { uintX_t VA = Config->ImageBase; if (AllocateHeader) VA += getHeaderSize(); uintX_t ThreadBssOffset = 0; for (OutputSectionBase *Sec : OutputSections) { uintX_t Alignment = Sec->Addralign; if (Sec->PageAlign) Alignment = std::max(Alignment, Config->MaxPageSize); auto I = Config->SectionStartMap.find(Sec->getName()); if (I != Config->SectionStartMap.end()) VA = I->second; // We only assign VAs to allocated sections. if (needsPtLoad(Sec)) { VA = alignTo(VA, Alignment); Sec->Addr = VA; VA += Sec->Size; } else if (Sec->Flags & SHF_TLS && Sec->Type == SHT_NOBITS) { uintX_t TVA = VA + ThreadBssOffset; TVA = alignTo(TVA, Alignment); Sec->Addr = TVA; ThreadBssOffset = TVA - VA + Sec->Size; } } } // 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 static uintX_t getFileAlignment(uintX_t Off, OutputSectionBase *Sec) { OutputSectionBase *First = Sec->FirstInPtLoad; // If the section is not in a PT_LOAD, we just have to align it. if (!First) return alignTo(Off, Sec->Addralign); // The first section in a PT_LOAD has to have congruent offset and address // module the page size. if (Sec == First) return alignTo(Off, Config->MaxPageSize, Sec->Addr); // If two sections share the same PT_LOAD the file offset is calculated // using this formula: Off2 = Off1 + (VA2 - VA1). return First->Offset + Sec->Addr - First->Addr; } template void setOffset(OutputSectionBase *Sec, uintX_t &Off) { if (Sec->Type == SHT_NOBITS) { Sec->Offset = Off; return; } Off = getFileAlignment(Off, Sec); Sec->Offset = Off; Off += Sec->Size; } template void Writer::assignFileOffsetsBinary() { uintX_t Off = 0; for (OutputSectionBase *Sec : OutputSections) if (Sec->Flags & SHF_ALLOC) setOffset(Sec, Off); FileSize = alignTo(Off, sizeof(uintX_t)); } // Assign file offsets to output sections. template void Writer::assignFileOffsets() { uintX_t Off = 0; setOffset(Out::ElfHeader, Off); setOffset(Out::ProgramHeaders, Off); for (OutputSectionBase *Sec : OutputSections) setOffset(Sec, Off); SectionHeaderOff = alignTo(Off, sizeof(uintX_t)); FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr); } // Finalize the program headers. We call this function after we assign // file offsets and VAs to all sections. template void Writer::setPhdrs() { for (PhdrEntry &P : Phdrs) { OutputSectionBase *First = P.First; OutputSectionBase *Last = P.Last; if (First) { P.p_filesz = Last->Offset - First->Offset; if (Last->Type != SHT_NOBITS) P.p_filesz += Last->Size; P.p_memsz = Last->Addr + Last->Size - First->Addr; P.p_offset = First->Offset; P.p_vaddr = First->Addr; if (!P.HasLMA) P.p_paddr = First->getLMA(); } if (P.p_type == PT_LOAD) P.p_align = Config->MaxPageSize; else if (P.p_type == PT_GNU_RELRO) { P.p_align = 1; // The glibc dynamic loader rounds the size down, so we need to round up // to protect the last page. This is a no-op on FreeBSD which always // rounds up. P.p_memsz = alignTo(P.p_memsz, Config->MaxPageSize); } // 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 (P.p_type == PT_TLS) { Out::TlsPhdr = &P; if (P.p_memsz) P.p_memsz = alignTo(P.p_memsz, P.p_align); } } } // The entry point address is chosen in the following ways. // // 1. the '-e' entry command-line option; // 2. the ENTRY(symbol) command in a linker control script; // 3. the value of the symbol start, if present; // 4. the address of the first byte of the .text section, if present; // 5. the address 0. template typename ELFT::uint Writer::getEntryAddr() { // Case 1, 2 or 3. As a special case, if the symbol is actually // a number, we'll use that number as an address. if (SymbolBody *B = Symtab::X->find(Config->Entry)) return B->getVA(); uint64_t Addr; if (!Config->Entry.getAsInteger(0, Addr)) return Addr; // Case 4 if (OutputSectionBase *Sec = findSection(".text")) { if (Config->WarnMissingEntry) warn("cannot find entry symbol " + Config->Entry + "; defaulting to 0x" + utohexstr(Sec->Addr)); return Sec->Addr; } // Case 5 if (Config->WarnMissingEntry) warn("cannot find entry symbol " + Config->Entry + "; not setting start address"); return 0; } template 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 void Writer::fixAbsoluteSymbols() { // __ehdr_start is the location of program headers. if (ElfSym::EhdrStart) ElfSym::EhdrStart->Value = Out::ProgramHeaders->Addr; auto Set = [](DefinedRegular *S1, DefinedRegular *S2, uintX_t V) { if (S1) S1->Value = V; if (S2) S2->Value = V; }; // _etext is the first location after the last read-only loadable segment. // _edata is the first location after the last read-write loadable segment. // _end is the first location after the uninitialized data region. for (PhdrEntry &P : Phdrs) { if (P.p_type != PT_LOAD) continue; Set(ElfSym::End, ElfSym::End2, P.p_vaddr + P.p_memsz); uintX_t Val = P.p_vaddr + P.p_filesz; if (P.p_flags & PF_W) Set(ElfSym::Edata, ElfSym::Edata2, Val); else Set(ElfSym::Etext, ElfSym::Etext2, Val); } // Setup MIPS _gp_disp/__gnu_local_gp symbols which should // be equal to the _gp symbol's value. if (Config->EMachine == EM_MIPS) { if (!ElfSym::MipsGp->Value) { // Find GP-relative section with the lowest address // and use this address to calculate default _gp value. uintX_t Gp = -1; for (const OutputSectionBase * OS : OutputSections) if ((OS->Flags & SHF_MIPS_GPREL) && OS->Addr < Gp) Gp = OS->Addr; if (Gp != (uintX_t)-1) ElfSym::MipsGp->Value = Gp + 0x7ff0; } if (ElfSym::MipsGpDisp) ElfSym::MipsGpDisp->Value = ElfSym::MipsGp->Value; if (ElfSym::MipsLocalGp) ElfSym::MipsLocalGp->Value = ElfSym::MipsGp->Value; } } template void Writer::writeHeader() { uint8_t *Buf = Buffer->getBufferStart(); memcpy(Buf, "\177ELF", 4); // Write the ELF header. auto *EHdr = reinterpret_cast(Buf); EHdr->e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32; EHdr->e_ident[EI_DATA] = getELFEncoding(); EHdr->e_ident[EI_VERSION] = EV_CURRENT; EHdr->e_ident[EI_OSABI] = Config->OSABI; EHdr->e_type = getELFType(); EHdr->e_machine = Config->EMachine; EHdr->e_version = EV_CURRENT; EHdr->e_entry = getEntryAddr(); EHdr->e_shoff = SectionHeaderOff; EHdr->e_ehsize = sizeof(Elf_Ehdr); EHdr->e_phnum = Phdrs.size(); EHdr->e_shentsize = sizeof(Elf_Shdr); EHdr->e_shnum = OutputSections.size() + 1; EHdr->e_shstrndx = In::ShStrTab->OutSec->SectionIndex; if (Config->EMachine == EM_ARM) // We don't currently use any features incompatible with EF_ARM_EABI_VER5, // but we don't have any firm guarantees of conformance. Linux AArch64 // kernels (as of 2016) require an EABI version to be set. EHdr->e_flags = EF_ARM_EABI_VER5; else if (Config->EMachine == EM_MIPS) EHdr->e_flags = getMipsEFlags(); if (!Config->Relocatable) { EHdr->e_phoff = sizeof(Elf_Ehdr); EHdr->e_phentsize = sizeof(Elf_Phdr); } // Write the program header table. auto *HBuf = reinterpret_cast(Buf + EHdr->e_phoff); for (PhdrEntry &P : Phdrs) { HBuf->p_type = P.p_type; HBuf->p_flags = P.p_flags; HBuf->p_offset = P.p_offset; HBuf->p_vaddr = P.p_vaddr; HBuf->p_paddr = P.p_paddr; HBuf->p_filesz = P.p_filesz; HBuf->p_memsz = P.p_memsz; HBuf->p_align = P.p_align; ++HBuf; } // Write the section header table. Note that the first table entry is null. auto *SHdrs = reinterpret_cast(Buf + EHdr->e_shoff); for (OutputSectionBase *Sec : OutputSections) Sec->writeHeaderTo(++SHdrs); } // Removes a given file asynchronously. This is a performance hack, // so remove this when operating systems are improved. // // On Linux (and probably on other Unix-like systems), unlink(2) is a // noticeably slow system call. As of 2016, unlink takes 250 // milliseconds to remove a 1 GB file on ext4 filesystem on my machine. // // To create a new result file, we first remove existing file. So, if // you repeatedly link a 1 GB program in a regular compile-link-debug // cycle, every cycle wastes 250 milliseconds only to remove a file. // Since LLD can link a 1 GB binary in about 5 seconds, that waste // actually counts. // // This function spawns a background thread to call unlink. // The calling thread returns almost immediately. static void unlinkAsync(StringRef Path) { if (!Config->Threads || !sys::fs::exists(Config->OutputFile)) return; // First, rename Path to avoid race condition. We cannot remove // Path from a different thread because we are now going to create // Path as a new file. If we do that in a different thread, the new // thread can remove the new file. SmallString<128> TempPath; if (sys::fs::createUniqueFile(Path + "tmp%%%%%%%%", TempPath)) return; if (sys::fs::rename(Path, TempPath)) { sys::fs::remove(TempPath); return; } // Remove TempPath in background. std::thread([=] { ::remove(TempPath.str().str().c_str()); }).detach(); } // Open a result file. template void Writer::openFile() { unlinkAsync(Config->OutputFile); ErrorOr> 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); } template void Writer::writeSectionsBinary() { uint8_t *Buf = Buffer->getBufferStart(); for (OutputSectionBase *Sec : OutputSections) if (Sec->Flags & SHF_ALLOC) Sec->writeTo(Buf + Sec->Offset); } // Write section contents to a mmap'ed file. template void Writer::writeSections() { uint8_t *Buf = Buffer->getBufferStart(); // PPC64 needs to process relocations in the .opd section // before processing relocations in code-containing sections. Out::Opd = findSection(".opd"); if (Out::Opd) { Out::OpdBuf = Buf + Out::Opd->Offset; Out::Opd->writeTo(Buf + Out::Opd->Offset); } OutputSectionBase *EhFrameHdr = In::EhFrameHdr ? In::EhFrameHdr->OutSec : nullptr; for (OutputSectionBase *Sec : OutputSections) if (Sec != Out::Opd && Sec != EhFrameHdr) Sec->writeTo(Buf + Sec->Offset); // The .eh_frame_hdr depends on .eh_frame section contents, therefore // it should be written after .eh_frame is written. if (!Out::EhFrame->empty() && EhFrameHdr) EhFrameHdr->writeTo(Buf + EhFrameHdr->Offset); } template void Writer::writeBuildId() { if (!In::BuildId || !In::BuildId->OutSec) return; // Compute a hash of all sections of the output file. uint8_t *Start = Buffer->getBufferStart(); uint8_t *End = Start + FileSize; In::BuildId->writeBuildId({Start, End}); } template void elf::writeResult(); template void elf::writeResult(); template void elf::writeResult(); template void elf::writeResult(); template void elf::allocateHeaders(MutableArrayRef, ArrayRef); template void elf::allocateHeaders(MutableArrayRef, ArrayRef); template void elf::allocateHeaders(MutableArrayRef, ArrayRef); template void elf::allocateHeaders(MutableArrayRef, ArrayRef); template bool elf::isRelroSection(const OutputSectionBase *); template bool elf::isRelroSection(const OutputSectionBase *); template bool elf::isRelroSection(const OutputSectionBase *); template bool elf::isRelroSection(const OutputSectionBase *); template void elf::reportDiscarded(InputSectionBase *); template void elf::reportDiscarded(InputSectionBase *); template void elf::reportDiscarded(InputSectionBase *); template void elf::reportDiscarded(InputSectionBase *); Index: vendor/lld/dist/test/ELF/Inputs/resolution-end.s =================================================================== --- vendor/lld/dist/test/ELF/Inputs/resolution-end.s (nonexistent) +++ vendor/lld/dist/test/ELF/Inputs/resolution-end.s (revision 312632) @@ -0,0 +1,2 @@ +.data + .quad _end Property changes on: vendor/lld/dist/test/ELF/Inputs/resolution-end.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/ELF/gc-sections-shared.s =================================================================== --- vendor/lld/dist/test/ELF/gc-sections-shared.s (revision 312631) +++ vendor/lld/dist/test/ELF/gc-sections-shared.s (revision 312632) @@ -1,68 +1,59 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o # RUN: ld.lld -shared %t2.o -o %t2.so # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o # RUN: ld.lld --gc-sections --export-dynamic-symbol foo -o %t %t.o --as-needed %t2.so # RUN: llvm-readobj --dynamic-table --dyn-symbols %t | FileCheck %s # This test the property that we have a needed line for every undefined. # It would also be OK to drop bar2 and the need for the .so # CHECK: DynamicSymbols [ # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: # CHECK-NEXT: Value: # CHECK-NEXT: Size: # CHECK-NEXT: Binding: Local # CHECK-NEXT: Type: # CHECK-NEXT: Other: # CHECK-NEXT: Section: Undefined (0x0) # CHECK-NEXT: } # CHECK-NEXT: Symbol { -# CHECK-NEXT: Name: bar -# CHECK-NEXT: Value: -# CHECK-NEXT: Size: -# CHECK-NEXT: Binding: Global -# CHECK-NEXT: Type: -# CHECK-NEXT: Other: -# CHECK-NEXT: Section: .text -# CHECK-NEXT: } -# CHECK-NEXT: Symbol { # CHECK-NEXT: Name: bar2 # CHECK-NEXT: Value: # CHECK-NEXT: Size: # CHECK-NEXT: Binding: Global # CHECK-NEXT: Type: # CHECK-NEXT: Other: # CHECK-NEXT: Section: Undefined # CHECK-NEXT: } # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: foo # CHECK-NEXT: Value: # CHECK-NEXT: Size: # CHECK-NEXT: Binding: Global # CHECK-NEXT: Type: # CHECK-NEXT: Other: # CHECK-NEXT: Section: .text # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK: NEEDED SharedLibrary ({{.*}}.so) .section .text.foo, "ax" .globl foo foo: call bar .section .text.bar, "ax" .globl bar bar: ret .section .text._start, "ax" .globl _start _start: ret .section .text.unused, "ax" call bar2 Index: vendor/lld/dist/test/ELF/init-fini.s =================================================================== --- vendor/lld/dist/test/ELF/init-fini.s (revision 312631) +++ vendor/lld/dist/test/ELF/init-fini.s (revision 312632) @@ -1,43 +1,54 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t // Should use "_init" and "_fini" by default when fills dynamic table // RUN: ld.lld -shared %t -o %t2 // RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=BYDEF %s // BYDEF: INIT 0x11010 // BYDEF: FINI 0x11020 // -init and -fini override symbols to use // RUN: ld.lld -shared %t -o %t2 -init _foo -fini _bar // RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=OVR %s // OVR: INIT 0x11030 // OVR: FINI 0x11040 // Check aliases as well // RUN: ld.lld -shared %t -o %t2 -init=_foo -fini=_bar // RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=OVR %s -// Should add a dynamic table entry even if a given symbol stay undefined +// Don't add an entry for undef. The freebsd dynamic linker doesn't +// check if the value is null. If it is, it will just call the +// load address. // RUN: ld.lld -shared %t -o %t2 -init=_undef -fini=_undef // RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=UNDEF %s -// UNDEF: INIT 0x0 -// UNDEF: FINI 0x0 +// UNDEF-NOT: INIT +// UNDEF-NOT: FINI + +// Don't add an entry for shared. For the same reason as undef. +// RUN: ld.lld -shared %t -o %t.so +// RUN: echo > %t.s +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t.s -o %t2.o +// RUN: ld.lld -shared %t2.o %t.so -o %t2 +// RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=SHARED %s +// SHARED-NOT: INIT +// SHARED-NOT: FINI // Should not add new entries to the symbol table // and should not require given symbols to be resolved // RUN: ld.lld -shared %t -o %t2 -init=_unknown -fini=_unknown // RUN: llvm-readobj -symbols -dynamic-table %t2 | FileCheck --check-prefix=NOENTRY %s // NOENTRY: Symbols [ // NOENTRY-NOT: Name: _unknown // NOENTRY: ] // NOENTRY: DynamicSection [ // NOENTRY-NOT: INIT // NOENTRY-NOT: FINI // NOENTRY: ] .global _start,_init,_fini,_foo,_bar,_undef _start: _init = 0x11010 _fini = 0x11020 _foo = 0x11030 _bar = 0x11040 Index: vendor/lld/dist/test/ELF/resolution-end.s =================================================================== --- vendor/lld/dist/test/ELF/resolution-end.s (nonexistent) +++ vendor/lld/dist/test/ELF/resolution-end.s (revision 312632) @@ -0,0 +1,39 @@ +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/resolution-end.s -o %t2.o +# RUN: ld.lld -shared -o %t2.so %t2.o +# RUN: ld.lld %t1.o %t2.so -o %t +# RUN: llvm-readobj -t -s -section-data %t | FileCheck %s +# REQUIRES: x86 + +# Test that we resolve _end to the this executable. + +# CHECK: Name: .text +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_EXECINSTR +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 80202000 00000000 +# CHECK-NEXT: ) + +# CHECK: Symbol { +# CHECK: Name: _end +# CHECK-NEXT: Value: 0x202080 +# CHECK-NEXT: Size: +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: +# CHECK-NEXT: Other: +# CHECK-NEXT: Section: +# CHECK-NEXT: } + +.global _start +_start: +.quad _end Property changes on: vendor/lld/dist/test/ELF/resolution-end.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/ELF/version-script-hide-so-symbol.s =================================================================== --- vendor/lld/dist/test/ELF/version-script-hide-so-symbol.s (nonexistent) +++ vendor/lld/dist/test/ELF/version-script-hide-so-symbol.s (revision 312632) @@ -0,0 +1,28 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld -shared %t.o -o %t2.so +# RUN: echo "{ local: *; };" > %t.script +# RUN: ld.lld --version-script %t.script -shared %t.o %t2.so -o %t.so +# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s + +# The symbol foo must be hidden. This matches bfd and gold and is +# required to make it possible for a c++ library to hide its own +# operator delete. + +# CHECK: DynamicSymbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: @ (0) +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined +# CHECK-NEXT: } +# CHECK-NEXT: ] + + .global foo +foo: + nop + Property changes on: vendor/lld/dist/test/ELF/version-script-hide-so-symbol.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property