diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:12:21 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:12:21 +0000 |
commit | eb1ff93d02b5f17b6b409e83c6d9be585f4a04b3 (patch) | |
tree | 7490b4a8943293f251ad733465936e6ec302b3e9 /ELF/InputFiles.cpp | |
parent | bafea25f368c63f0b39789906adfed6e39219e64 (diff) | |
download | src-eb1ff93d02b5f17b6b409e83c6d9be585f4a04b3.tar.gz src-eb1ff93d02b5f17b6b409e83c6d9be585f4a04b3.zip |
Vendor import of lld trunk r321017:vendor/lld/lld-trunk-r321017
Notes
Notes:
svn path=/vendor/lld/dist/; revision=326947
svn path=/vendor/lld/lld-trunk-r321017/; revision=326948; tag=vendor/lld/lld-trunk-r321017
Diffstat (limited to 'ELF/InputFiles.cpp')
-rw-r--r-- | ELF/InputFiles.cpp | 541 |
1 files changed, 292 insertions, 249 deletions
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index c609615fcc2e..1f68340c9428 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -8,13 +8,13 @@ //===----------------------------------------------------------------------===// #include "InputFiles.h" -#include "Error.h" #include "InputSection.h" #include "LinkerScript.h" -#include "Memory.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" @@ -23,6 +23,8 @@ #include "llvm/LTO/LTO.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELFObjectFile.h" +#include "llvm/Support/ARMAttributeParser.h" +#include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/Path.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/raw_ostream.h" @@ -35,26 +37,23 @@ using namespace llvm::sys::fs; using namespace lld; using namespace lld::elf; +std::vector<BinaryFile *> elf::BinaryFiles; +std::vector<BitcodeFile *> elf::BitcodeFiles; +std::vector<InputFile *> elf::ObjectFiles; +std::vector<InputFile *> elf::SharedFiles; + TarWriter *elf::Tar; InputFile::InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} -namespace { -// In ELF object file all section addresses are zero. If we have multiple -// .text sections (when using -ffunction-section or comdat group) then -// LLVM DWARF parser will not be able to parse .debug_line correctly, unless -// we assign each section some unique address. This callback method assigns -// each section an address equal to its offset in ELF object file. -class ObjectInfo : public LoadedObjectInfoHelper<ObjectInfo> { -public: - uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override { - return static_cast<const ELFSectionRef &>(Sec).getOffset(); - } -}; -} - Optional<MemoryBufferRef> elf::readFile(StringRef Path) { + // The --chroot option changes our virtual root directory. + // This is useful when you are dealing with files created by --reproduce. + if (!Config->Chroot.empty() && Path.startswith("/")) + Path = Saver.save(Config->Chroot + Path); + log(Path); + auto MBOrErr = MemoryBuffer::getFile(Path); if (auto EC = MBOrErr.getError()) { error("cannot open " + Path + ": " + EC.message()); @@ -70,28 +69,88 @@ Optional<MemoryBufferRef> elf::readFile(StringRef Path) { return MBRef; } -template <class ELFT> void elf::ObjectFile<ELFT>::initializeDwarfLine() { - std::unique_ptr<object::ObjectFile> Obj = - check(object::ObjectFile::createObjectFile(this->MB), toString(this)); - - ObjectInfo ObjInfo; - DWARFContextInMemory Dwarf(*Obj, &ObjInfo); +template <class ELFT> void ObjFile<ELFT>::initializeDwarf() { + DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(this)); + const DWARFObject &Obj = Dwarf.getDWARFObj(); DwarfLine.reset(new DWARFDebugLine); - DWARFDataExtractor LineData(Dwarf.getLineSection(), Config->IsLE, + DWARFDataExtractor LineData(Obj, Obj.getLineSection(), Config->IsLE, Config->Wordsize); // The second parameter is offset in .debug_line section // for compilation unit (CU) of interest. We have only one // CU (object file), so offset is always 0. - DwarfLine->getOrParseLineTable(LineData, 0); + // FIXME: Provide the associated DWARFUnit if there is one. DWARF v5 + // needs it in order to find indirect strings. + const DWARFDebugLine::LineTable *LT = + DwarfLine->getOrParseLineTable(LineData, 0, nullptr); + + // Return if there is no debug information about CU available. + if (!Dwarf.getNumCompileUnits()) + return; + + // Loop over variable records and insert them to VariableLoc. + DWARFCompileUnit *CU = Dwarf.getCompileUnitAtIndex(0); + for (const auto &Entry : CU->dies()) { + DWARFDie Die(CU, &Entry); + // Skip all tags that are not variables. + if (Die.getTag() != dwarf::DW_TAG_variable) + continue; + + // Skip if a local variable because we don't need them for generating error + // messages. In general, only non-local symbols can fail to be linked. + if (!dwarf::toUnsigned(Die.find(dwarf::DW_AT_external), 0)) + continue; + + // Get the source filename index for the variable. + unsigned File = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_file), 0); + if (!LT->hasFileAtIndex(File)) + continue; + + // Get the line number on which the variable is declared. + unsigned Line = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_line), 0); + + // Get the name of the variable and add the collected information to + // VariableLoc. Usually Name is non-empty, but it can be empty if the input + // object file lacks some debug info. + StringRef Name = dwarf::toString(Die.find(dwarf::DW_AT_name), ""); + if (!Name.empty()) + VariableLoc.insert({Name, {File, Line}}); + } +} + +// Returns the pair of file name and line number describing location of data +// object (variable, array, etc) definition. +template <class ELFT> +Optional<std::pair<std::string, unsigned>> +ObjFile<ELFT>::getVariableLoc(StringRef Name) { + llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); }); + + // There is always only one CU so it's offset is 0. + const DWARFDebugLine::LineTable *LT = DwarfLine->getLineTable(0); + if (!LT) + return None; + + // Return if we have no debug information about data object. + auto It = VariableLoc.find(Name); + if (It == VariableLoc.end()) + return None; + + // Take file name string from line table. + std::string FileName; + if (!LT->getFileNameByIndex( + It->second.first /* File */, nullptr, + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FileName)) + return None; + + return std::make_pair(FileName, It->second.second /*Line*/); } // Returns source line information for a given offset // using DWARF debug info. template <class ELFT> -Optional<DILineInfo> elf::ObjectFile<ELFT>::getDILineInfo(InputSectionBase *S, - uint64_t Offset) { - llvm::call_once(InitDwarfLine, [this]() { initializeDwarfLine(); }); +Optional<DILineInfo> ObjFile<ELFT>::getDILineInfo(InputSectionBase *S, + uint64_t Offset) { + llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); }); // The offset to CU is 0. const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0); @@ -112,8 +171,7 @@ Optional<DILineInfo> elf::ObjectFile<ELFT>::getDILineInfo(InputSectionBase *S, // Returns source line information for a given offset // using DWARF debug info. template <class ELFT> -std::string elf::ObjectFile<ELFT>::getLineInfo(InputSectionBase *S, - uint64_t Offset) { +std::string ObjFile<ELFT>::getLineInfo(InputSectionBase *S, uint64_t Offset) { if (Optional<DILineInfo> Info = getDILineInfo(S, Offset)) return Info->FileName + ":" + std::to_string(Info->Line); return ""; @@ -145,50 +203,41 @@ ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) { } template <class ELFT> -typename ELFT::SymRange ELFFileBase<ELFT>::getGlobalSymbols() { - return makeArrayRef(Symbols.begin() + FirstNonLocal, Symbols.end()); +typename ELFT::SymRange ELFFileBase<ELFT>::getGlobalELFSyms() { + return makeArrayRef(ELFSyms.begin() + FirstNonLocal, ELFSyms.end()); } template <class ELFT> uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const { - return check(getObj().getSectionIndex(&Sym, Symbols, SymtabSHNDX), - toString(this)); + return CHECK(getObj().getSectionIndex(&Sym, ELFSyms, SymtabSHNDX), this); } template <class ELFT> void ELFFileBase<ELFT>::initSymtab(ArrayRef<Elf_Shdr> Sections, const Elf_Shdr *Symtab) { FirstNonLocal = Symtab->sh_info; - Symbols = check(getObj().symbols(Symtab), toString(this)); - if (FirstNonLocal == 0 || FirstNonLocal > Symbols.size()) + ELFSyms = CHECK(getObj().symbols(Symtab), this); + if (FirstNonLocal == 0 || FirstNonLocal > ELFSyms.size()) fatal(toString(this) + ": invalid sh_info in symbol table"); - StringTable = check(getObj().getStringTableForSymtab(*Symtab, Sections), - toString(this)); + StringTable = + CHECK(getObj().getStringTableForSymtab(*Symtab, Sections), this); } template <class ELFT> -elf::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M, StringRef ArchiveName) - : ELFFileBase<ELFT>(Base::ObjectKind, M) { +ObjFile<ELFT>::ObjFile(MemoryBufferRef M, StringRef ArchiveName) + : ELFFileBase<ELFT>(Base::ObjKind, M) { this->ArchiveName = ArchiveName; } -template <class ELFT> -ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getLocalSymbols() { - if (this->SymbolBodies.empty()) - return this->SymbolBodies; - return makeArrayRef(this->SymbolBodies).slice(1, this->FirstNonLocal - 1); -} - -template <class ELFT> -ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getSymbols() { - if (this->SymbolBodies.empty()) - return this->SymbolBodies; - return makeArrayRef(this->SymbolBodies).slice(1); +template <class ELFT> ArrayRef<Symbol *> ObjFile<ELFT>::getLocalSymbols() { + if (this->Symbols.empty()) + return {}; + return makeArrayRef(this->Symbols).slice(1, this->FirstNonLocal - 1); } template <class ELFT> -void elf::ObjectFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) { +void ObjFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) { // Read section and symbol tables. initializeSections(ComdatGroups); initializeSymbols(); @@ -198,19 +247,17 @@ void elf::ObjectFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) { // They are identified and deduplicated by group name. This function // returns a group name. template <class ELFT> -StringRef -elf::ObjectFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections, - const Elf_Shdr &Sec) { +StringRef ObjFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections, + const Elf_Shdr &Sec) { // Group signatures are stored as symbol names in object files. // sh_info contains a symbol index, so we fetch a symbol and read its name. - if (this->Symbols.empty()) + if (this->ELFSyms.empty()) this->initSymtab( - Sections, - check(object::getSection<ELFT>(Sections, Sec.sh_link), toString(this))); + Sections, CHECK(object::getSection<ELFT>(Sections, Sec.sh_link), this)); - const Elf_Sym *Sym = check( - object::getSymbol<ELFT>(this->Symbols, Sec.sh_info), toString(this)); - StringRef Signature = check(Sym->getName(this->StringTable), toString(this)); + const Elf_Sym *Sym = + CHECK(object::getSymbol<ELFT>(this->ELFSyms, Sec.sh_info), this); + StringRef Signature = CHECK(Sym->getName(this->StringTable), this); // As a special case, if a symbol is a section symbol and has no name, // we use a section name as a signature. @@ -225,32 +272,22 @@ elf::ObjectFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections, } template <class ELFT> -ArrayRef<typename elf::ObjectFile<ELFT>::Elf_Word> -elf::ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) { +ArrayRef<typename ObjFile<ELFT>::Elf_Word> +ObjFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) { const ELFFile<ELFT> &Obj = this->getObj(); - ArrayRef<Elf_Word> Entries = check( - Obj.template getSectionContentsAsArray<Elf_Word>(&Sec), toString(this)); + ArrayRef<Elf_Word> Entries = + CHECK(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec), this); if (Entries.empty() || Entries[0] != GRP_COMDAT) fatal(toString(this) + ": unsupported SHT_GROUP format"); return Entries.slice(1); } -template <class ELFT> -bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) { +template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) { // We don't merge sections if -O0 (default is -O1). This makes sometimes // the linker significantly faster, although the output will be bigger. if (Config->Optimize == 0) return false; - // Do not merge sections if generating a relocatable object. It makes - // the code simpler because we do not need to update relocation addends - // to reflect changes introduced by merging. Instead of that we write - // such "merge" sections into separate OutputSections and keep SHF_MERGE - // / SHF_STRINGS flags and sh_entsize value to be able to perform merging - // later during a final linking. - if (Config->Relocatable) - return false; - // A mergeable section with size 0 is useless because they don't have // any data to merge. A mergeable string section with size 0 can be // argued as invalid because it doesn't end with a null character. @@ -276,29 +313,19 @@ bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) { if (Flags & SHF_WRITE) fatal(toString(this) + ": writable SHF_MERGE section is not supported"); - // Don't try to merge if the alignment is larger than the sh_entsize and this - // is not SHF_STRINGS. - // - // Since this is not a SHF_STRINGS, we would need to pad after every entity. - // It would be equivalent for the producer of the .o to just set a larger - // sh_entsize. - if (Flags & SHF_STRINGS) - return true; - - return Sec.sh_addralign <= EntSize; + return true; } template <class ELFT> -void elf::ObjectFile<ELFT>::initializeSections( +void ObjFile<ELFT>::initializeSections( DenseSet<CachedHashStringRef> &ComdatGroups) { const ELFFile<ELFT> &Obj = this->getObj(); - ArrayRef<Elf_Shdr> ObjSections = - check(this->getObj().sections(), toString(this)); + ArrayRef<Elf_Shdr> ObjSections = CHECK(this->getObj().sections(), this); uint64_t Size = ObjSections.size(); this->Sections.resize(Size); this->SectionStringTable = - check(Obj.getSectionStringTable(ObjSections), toString(this)); + CHECK(Obj.getSectionStringTable(ObjSections), this); for (size_t I = 0, E = ObjSections.size(); I < E; I++) { if (this->Sections[I] == &InputSection::Discarded) @@ -344,8 +371,7 @@ void elf::ObjectFile<ELFT>::initializeSections( this->initSymtab(ObjSections, &Sec); break; case SHT_SYMTAB_SHNDX: - this->SymtabSHNDX = - check(Obj.getSHNDXTable(Sec, ObjSections), toString(this)); + this->SymtabSHNDX = CHECK(Obj.getSHNDXTable(Sec, ObjSections), this); break; case SHT_STRTAB: case SHT_NULL: @@ -361,13 +387,55 @@ void elf::ObjectFile<ELFT>::initializeSections( fatal(toString(this) + ": invalid sh_link index: " + Twine(Sec.sh_link)); this->Sections[Sec.sh_link]->DependentSections.push_back( - this->Sections[I]); + cast<InputSection>(this->Sections[I])); } } } +// The ARM support in lld makes some use of instructions that are not available +// on all ARM architectures. Namely: +// - Use of BLX instruction for interworking between ARM and Thumb state. +// - Use of the extended Thumb branch encoding in relocation. +// - Use of the MOVT/MOVW instructions in Thumb Thunks. +// The ARM Attributes section contains information about the architecture chosen +// at compile time. We follow the convention that if at least one input object +// is compiled with an architecture that supports these features then lld is +// permitted to use them. +static void updateSupportedARMFeatures(const ARMAttributeParser &Attributes) { + if (!Attributes.hasAttribute(ARMBuildAttrs::CPU_arch)) + return; + auto Arch = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch); + switch (Arch) { + case ARMBuildAttrs::Pre_v4: + case ARMBuildAttrs::v4: + case ARMBuildAttrs::v4T: + // Architectures prior to v5 do not support BLX instruction + break; + case ARMBuildAttrs::v5T: + case ARMBuildAttrs::v5TE: + case ARMBuildAttrs::v5TEJ: + case ARMBuildAttrs::v6: + case ARMBuildAttrs::v6KZ: + case ARMBuildAttrs::v6K: + Config->ARMHasBlx = true; + // Architectures used in pre-Cortex processors do not support + // The J1 = 1 J2 = 1 Thumb branch range extension, with the exception + // of Architecture v6T2 (arm1156t2-s and arm1156t2f-s) that do. + break; + default: + // All other Architectures have BLX and extended branch encoding + Config->ARMHasBlx = true; + Config->ARMJ1J2BranchEncoding = true; + if (Arch != ARMBuildAttrs::v6_M && Arch != ARMBuildAttrs::v6S_M) + // All Architectures used in Cortex processors with the exception + // of v6-M and v6S-M have the MOVT and MOVW instructions. + Config->ARMHasMovtMovw = true; + break; + } +} + template <class ELFT> -InputSectionBase *elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) { +InputSectionBase *ObjFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) { uint32_t Idx = Sec.sh_info; if (Idx >= this->Sections.size()) fatal(toString(this) + ": invalid relocated section index: " + Twine(Idx)); @@ -394,21 +462,26 @@ InputSectionBase *toRegularSection(MergeInputSection *Sec) { } template <class ELFT> -InputSectionBase * -elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { +InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { StringRef Name = getSectionName(Sec); switch (Sec.sh_type) { - case SHT_ARM_ATTRIBUTES: - // FIXME: ARM meta-data section. Retain the first attribute section - // we see. The eglibc ARM dynamic loaders require the presence of an - // attribute section for dlopen to work. - // In a full implementation we would merge all attribute sections. + case SHT_ARM_ATTRIBUTES: { + if (Config->EMachine != EM_ARM) + break; + ARMAttributeParser Attributes; + ArrayRef<uint8_t> Contents = check(this->getObj().getSectionContents(&Sec)); + Attributes.Parse(Contents, /*isLittle*/Config->EKind == ELF32LEKind); + updateSupportedARMFeatures(Attributes); + // FIXME: Retain the first attribute section we see. The eglibc ARM + // dynamic loaders require the presence of an attribute section for dlopen + // to work. In a full implementation we would merge all attribute sections. if (InX::ARMAttributes == nullptr) { InX::ARMAttributes = make<InputSection>(this, &Sec, Name); return InX::ARMAttributes; } return &InputSection::Discarded; + } case SHT_RELA: case SHT_REL: { // Find the relocation target section and associate this @@ -443,13 +516,12 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { size_t NumRelocations; if (Sec.sh_type == SHT_RELA) { - ArrayRef<Elf_Rela> Rels = - check(this->getObj().relas(&Sec), toString(this)); + ArrayRef<Elf_Rela> Rels = CHECK(this->getObj().relas(&Sec), this); Target->FirstRelocation = Rels.begin(); NumRelocations = Rels.size(); Target->AreRelocsRela = true; } else { - ArrayRef<Elf_Rel> Rels = check(this->getObj().rels(&Sec), toString(this)); + ArrayRef<Elf_Rel> Rels = CHECK(this->getObj().rels(&Sec), this); Target->FirstRelocation = Rels.begin(); NumRelocations = Rels.size(); Target->AreRelocsRela = false; @@ -497,18 +569,6 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { return &InputSection::Discarded; } - if (Config->Strip != StripPolicy::None && Name.startswith(".debug")) - return &InputSection::Discarded; - - // If -gdb-index is given, LLD creates .gdb_index section, and that - // section serves the same purpose as .debug_gnu_pub{names,types} sections. - // If that's the case, we want to eliminate .debug_gnu_pub{names,types} - // because they are redundant and can waste large amount of disk space - // (for example, they are about 400 MiB in total for a clang debug build.) - if (Config->GdbIndex && - (Name == ".debug_gnu_pubnames" || Name == ".debug_gnu_pubtypes")) - return &InputSection::Discarded; - // The linkonce feature is a sort of proto-comdat. Some glibc i386 object // files contain definitions of symbol "__x86.get_pc_thunk.bx" in linkonce // sections. Drop those sections to avoid duplicate symbol errors. @@ -529,46 +589,24 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { } template <class ELFT> -StringRef elf::ObjectFile<ELFT>::getSectionName(const Elf_Shdr &Sec) { - return check(this->getObj().getSectionName(&Sec, SectionStringTable), - toString(this)); -} - -template <class ELFT> void elf::ObjectFile<ELFT>::initializeSymbols() { - SymbolBodies.reserve(this->Symbols.size()); - for (const Elf_Sym &Sym : this->Symbols) - SymbolBodies.push_back(createSymbolBody(&Sym)); +StringRef ObjFile<ELFT>::getSectionName(const Elf_Shdr &Sec) { + return CHECK(this->getObj().getSectionName(&Sec, SectionStringTable), this); } -template <class ELFT> -InputSectionBase *elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const { - uint32_t Index = this->getSectionIndex(Sym); - if (Index >= this->Sections.size()) - fatal(toString(this) + ": invalid section index: " + Twine(Index)); - InputSectionBase *S = this->Sections[Index]; - - // We found that GNU assembler 2.17.50 [FreeBSD] 2007-07-03 could - // generate broken objects. STT_SECTION/STT_NOTYPE symbols can be - // associated with SHT_REL[A]/SHT_SYMTAB/SHT_STRTAB sections. - // In this case it is fine for section to be null here as we do not - // allocate sections of these types. - if (!S) { - if (Index == 0 || Sym.getType() == STT_SECTION || - Sym.getType() == STT_NOTYPE) - return nullptr; - fatal(toString(this) + ": invalid section index: " + Twine(Index)); - } - - if (S == &InputSection::Discarded) - return S; - return S->Repl; +template <class ELFT> void ObjFile<ELFT>::initializeSymbols() { + this->Symbols.reserve(this->ELFSyms.size()); + for (const Elf_Sym &Sym : this->ELFSyms) + this->Symbols.push_back(createSymbol(&Sym)); } -template <class ELFT> -SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) { +template <class ELFT> Symbol *ObjFile<ELFT>::createSymbol(const Elf_Sym *Sym) { int Binding = Sym->getBinding(); - InputSectionBase *Sec = getSection(*Sym); + uint32_t SecIdx = this->getSectionIndex(*Sym); + if (SecIdx >= this->Sections.size()) + fatal(toString(this) + ": invalid section index: " + Twine(SecIdx)); + + InputSectionBase *Sec = this->Sections[SecIdx]; uint8_t StOther = Sym->st_other; uint8_t Type = Sym->getType(); uint64_t Value = Sym->st_value; @@ -576,34 +614,29 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) { if (Binding == STB_LOCAL) { if (Sym->getType() == STT_FILE) - SourceFile = check(Sym->getName(this->StringTable), toString(this)); + SourceFile = CHECK(Sym->getName(this->StringTable), this); if (this->StringTable.size() <= Sym->st_name) fatal(toString(this) + ": invalid symbol name offset"); StringRefZ Name = this->StringTable.data() + Sym->st_name; if (Sym->st_shndx == SHN_UNDEF) - return make<Undefined>(Name, /*IsLocal=*/true, StOther, Type, this); + return make<Undefined>(this, Name, Binding, StOther, Type); - return make<DefinedRegular>(Name, /*IsLocal=*/true, StOther, Type, Value, - Size, Sec, this); + return make<Defined>(this, Name, Binding, StOther, Type, Value, Size, Sec); } - StringRef Name = check(Sym->getName(this->StringTable), toString(this)); + StringRef Name = CHECK(Sym->getName(this->StringTable), this); switch (Sym->st_shndx) { case SHN_UNDEF: - return elf::Symtab<ELFT>::X - ->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type, - /*CanOmitFromDynSym=*/false, this) - ->body(); + return Symtab->addUndefined<ELFT>(Name, Binding, StOther, Type, + /*CanOmitFromDynSym=*/false, this); case SHN_COMMON: if (Value == 0 || Value >= UINT32_MAX) fatal(toString(this) + ": common symbol '" + Name + "' has invalid alignment: " + Twine(Value)); - return elf::Symtab<ELFT>::X - ->addCommon(Name, Size, Value, Binding, StOther, Type, this) - ->body(); + return Symtab->addCommon(Name, Size, Value, Binding, StOther, Type, this); } switch (Binding) { @@ -613,13 +646,10 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) { case STB_WEAK: case STB_GNU_UNIQUE: if (Sec == &InputSection::Discarded) - return elf::Symtab<ELFT>::X - ->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type, - /*CanOmitFromDynSym=*/false, this) - ->body(); - return elf::Symtab<ELFT>::X - ->addRegular(Name, StOther, Type, Value, Size, Binding, Sec, this) - ->body(); + return Symtab->addUndefined<ELFT>(Name, Binding, StOther, Type, + /*CanOmitFromDynSym=*/false, this); + return Symtab->addRegular<ELFT>(Name, StOther, Type, Value, Size, Binding, + Sec, this); } } @@ -630,14 +660,14 @@ ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&File) template <class ELFT> void ArchiveFile::parse() { Symbols.reserve(File->getNumberOfSymbols()); for (const Archive::Symbol &Sym : File->symbols()) - Symbols.push_back(Symtab<ELFT>::X->addLazyArchive(this, Sym)); + Symbols.push_back(Symtab->addLazyArchive<ELFT>(Sym.getName(), this, Sym)); } // Returns a buffer pointing to a member file containing a given symbol. std::pair<MemoryBufferRef, uint64_t> ArchiveFile::getMember(const Archive::Symbol *Sym) { Archive::Child C = - check(Sym->getMember(), toString(this) + + CHECK(Sym->getMember(), toString(this) + ": could not get the member for symbol " + Sym->getName()); @@ -645,14 +675,13 @@ ArchiveFile::getMember(const Archive::Symbol *Sym) { return {MemoryBufferRef(), 0}; MemoryBufferRef Ret = - check(C.getMemoryBufferRef(), + CHECK(C.getMemoryBufferRef(), toString(this) + ": could not get the buffer for the member defining symbol " + Sym->getName()); if (C.getParent()->isThin() && Tar) - Tar->append(relativeToRoot(check(C.getFullName(), toString(this))), - Ret.getBuffer()); + Tar->append(relativeToRoot(CHECK(C.getFullName(), this)), Ret.getBuffer()); if (C.getParent()->isThin()) return {Ret, 0}; return {Ret, C.getChildOffset()}; @@ -661,22 +690,14 @@ ArchiveFile::getMember(const Archive::Symbol *Sym) { template <class ELFT> SharedFile<ELFT>::SharedFile(MemoryBufferRef M, StringRef DefaultSoName) : ELFFileBase<ELFT>(Base::SharedKind, M), SoName(DefaultSoName), - AsNeeded(Config->AsNeeded) {} - -template <class ELFT> -const typename ELFT::Shdr * -SharedFile<ELFT>::getSection(const Elf_Sym &Sym) const { - return check( - this->getObj().getSection(&Sym, this->Symbols, this->SymtabSHNDX), - toString(this)); -} + IsNeeded(!Config->AsNeeded) {} // Partially parse the shared object file so that we can call // getSoName on this object. template <class ELFT> void SharedFile<ELFT>::parseSoName() { const Elf_Shdr *DynamicSec = nullptr; const ELFFile<ELFT> Obj = this->getObj(); - ArrayRef<Elf_Shdr> Sections = check(Obj.sections(), toString(this)); + ArrayRef<Elf_Shdr> Sections = CHECK(Obj.sections(), this); // Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d. for (const Elf_Shdr &Sec : Sections) { @@ -690,8 +711,7 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() { DynamicSec = &Sec; break; case SHT_SYMTAB_SHNDX: - this->SymtabSHNDX = - check(Obj.getSHNDXTable(Sec, Sections), toString(this)); + this->SymtabSHNDX = CHECK(Obj.getSHNDXTable(Sec, Sections), this); break; case SHT_GNU_versym: this->VersymSec = &Sec; @@ -702,15 +722,14 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() { } } - if (this->VersymSec && this->Symbols.empty()) + if (this->VersymSec && this->ELFSyms.empty()) error("SHT_GNU_versym should be associated with symbol table"); // Search for a DT_SONAME tag to initialize this->SoName. if (!DynamicSec) return; ArrayRef<Elf_Dyn> Arr = - check(Obj.template getSectionContentsAsArray<Elf_Dyn>(DynamicSec), - toString(this)); + CHECK(Obj.template getSectionContentsAsArray<Elf_Dyn>(DynamicSec), this); for (const Elf_Dyn &Dyn : Arr) { if (Dyn.d_tag == DT_SONAME) { uint64_t Val = Dyn.getVal(); @@ -767,11 +786,14 @@ SharedFile<ELFT>::parseVerdefs(const Elf_Versym *&Versym) { template <class ELFT> void SharedFile<ELFT>::parseRest() { // Create mapping from version identifiers to Elf_Verdef entries. const Elf_Versym *Versym = nullptr; - std::vector<const Elf_Verdef *> Verdefs = parseVerdefs(Versym); + Verdefs = parseVerdefs(Versym); - Elf_Sym_Range Syms = this->getGlobalSymbols(); + ArrayRef<Elf_Shdr> Sections = CHECK(this->getObj().sections(), this); + + // Add symbols to the symbol table. + Elf_Sym_Range Syms = this->getGlobalELFSyms(); for (const Elf_Sym &Sym : Syms) { - unsigned VersymIndex = 0; + unsigned VersymIndex = VER_NDX_GLOBAL; if (Versym) { VersymIndex = Versym->vs_index; ++Versym; @@ -779,28 +801,54 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() { bool Hidden = VersymIndex & VERSYM_HIDDEN; VersymIndex = VersymIndex & ~VERSYM_HIDDEN; - StringRef Name = check(Sym.getName(this->StringTable), toString(this)); + StringRef Name = CHECK(Sym.getName(this->StringTable), this); if (Sym.isUndefined()) { Undefs.push_back(Name); continue; } - // Ignore local symbols. - if (Versym && VersymIndex == VER_NDX_LOCAL) + if (Sym.getBinding() == STB_LOCAL) { + warn("found local symbol '" + Name + + "' in global part of symbol table in file " + toString(this)); continue; + } + + const Elf_Verdef *Ver = nullptr; + if (VersymIndex != VER_NDX_GLOBAL) { + if (VersymIndex >= Verdefs.size() || VersymIndex == VER_NDX_LOCAL) { + error("corrupt input file: version definition index " + + Twine(VersymIndex) + " for symbol " + Name + + " is out of bounds\n>>> defined in " + toString(this)); + continue; + } + Ver = Verdefs[VersymIndex]; + } else { + VersymIndex = 0; + } - const Elf_Verdef *V = - VersymIndex == VER_NDX_GLOBAL ? nullptr : Verdefs[VersymIndex]; + // We do not usually care about alignments of data in shared object + // files because the loader takes care of it. However, if we promote a + // DSO symbol to point to .bss due to copy relocation, we need to keep + // the original alignment requirements. We infer it here. + uint64_t Alignment = 1; + if (Sym.st_value) + Alignment = 1ULL << countTrailingZeros((uint64_t)Sym.st_value); + if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size()) { + uint64_t SecAlign = Sections[Sym.st_shndx].sh_addralign; + Alignment = std::min(Alignment, SecAlign); + } + if (Alignment > UINT32_MAX) + error(toString(this) + ": alignment too large: " + Name); if (!Hidden) - elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V); + Symtab->addShared(Name, this, Sym, Alignment, VersymIndex); // Also add the symbol with the versioned name to handle undefined symbols // with explicit versions. - if (V) { - StringRef VerName = this->StringTable.data() + V->getAux()->vda_name; + if (Ver) { + StringRef VerName = this->StringTable.data() + Ver->getAux()->vda_name; Name = Saver.save(Name + "@" + VerName); - elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V); + Symtab->addShared(Name, this, Sym, Alignment, VersymIndex); } } } @@ -855,7 +903,7 @@ BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName, MemoryBufferRef MBRef(MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier() + utostr(OffsetInArchive))); - Obj = check(lto::InputFile::create(MBRef), toString(this)); + Obj = CHECK(lto::InputFile::create(MBRef), this); Triple T(Obj->getTargetTriple()); EKind = getBitcodeELFKind(T); @@ -887,22 +935,20 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats, int C = ObjSym.getComdatIndex(); if (C != -1 && !KeptComdats[C]) - return Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding, - Visibility, Type, CanOmitFromDynSym, - F); + return Symtab->addUndefined<ELFT>(NameRef, Binding, Visibility, Type, + CanOmitFromDynSym, F); if (ObjSym.isUndefined()) - return Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding, - Visibility, Type, CanOmitFromDynSym, - F); + return Symtab->addUndefined<ELFT>(NameRef, Binding, Visibility, Type, + CanOmitFromDynSym, F); if (ObjSym.isCommon()) - return Symtab<ELFT>::X->addCommon(NameRef, ObjSym.getCommonSize(), - ObjSym.getCommonAlignment(), Binding, - Visibility, STT_OBJECT, F); + return Symtab->addCommon(NameRef, ObjSym.getCommonSize(), + ObjSym.getCommonAlignment(), Binding, Visibility, + STT_OBJECT, F); - return Symtab<ELFT>::X->addBitcode(NameRef, Binding, Visibility, Type, - CanOmitFromDynSym, F); + return Symtab->addBitcode(NameRef, Binding, Visibility, Type, + CanOmitFromDynSym, F); } template <class ELFT> @@ -947,18 +993,15 @@ template <class ELFT> void BinaryFile::parse() { // characters in a filename are replaced with underscore. std::string S = "_binary_" + MB.getBufferIdentifier().str(); for (size_t I = 0; I < S.size(); ++I) - if (!isalnum(S[I])) + if (!isAlnum(S[I])) S[I] = '_'; - elf::Symtab<ELFT>::X->addRegular(Saver.save(S + "_start"), STV_DEFAULT, - STT_OBJECT, 0, 0, STB_GLOBAL, Section, - nullptr); - elf::Symtab<ELFT>::X->addRegular(Saver.save(S + "_end"), STV_DEFAULT, - STT_OBJECT, Data.size(), 0, STB_GLOBAL, - Section, nullptr); - elf::Symtab<ELFT>::X->addRegular(Saver.save(S + "_size"), STV_DEFAULT, - STT_OBJECT, Data.size(), 0, STB_GLOBAL, - nullptr, nullptr); + Symtab->addRegular<ELFT>(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT, + 0, 0, STB_GLOBAL, Section, nullptr); + Symtab->addRegular<ELFT>(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT, + Data.size(), 0, STB_GLOBAL, Section, nullptr); + Symtab->addRegular<ELFT>(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT, + Data.size(), 0, STB_GLOBAL, nullptr, nullptr); } static bool isBitcode(MemoryBufferRef MB) { @@ -973,13 +1016,13 @@ InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName, switch (getELFKind(MB)) { case ELF32LEKind: - return make<ObjectFile<ELF32LE>>(MB, ArchiveName); + return make<ObjFile<ELF32LE>>(MB, ArchiveName); case ELF32BEKind: - return make<ObjectFile<ELF32BE>>(MB, ArchiveName); + return make<ObjFile<ELF32BE>>(MB, ArchiveName); case ELF64LEKind: - return make<ObjectFile<ELF64LE>>(MB, ArchiveName); + return make<ObjFile<ELF64LE>>(MB, ArchiveName); case ELF64BEKind: - return make<ObjectFile<ELF64BE>>(MB, ArchiveName); + return make<ObjFile<ELF64BE>>(MB, ArchiveName); default: llvm_unreachable("getELFKind"); } @@ -1000,53 +1043,53 @@ InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) { } } -MemoryBufferRef LazyObjectFile::getBuffer() { +MemoryBufferRef LazyObjFile::getBuffer() { if (Seen) return MemoryBufferRef(); Seen = true; return MB; } -InputFile *LazyObjectFile::fetch() { +InputFile *LazyObjFile::fetch() { MemoryBufferRef MBRef = getBuffer(); if (MBRef.getBuffer().empty()) return nullptr; return createObjectFile(MBRef, ArchiveName, OffsetInArchive); } -template <class ELFT> void LazyObjectFile::parse() { - for (StringRef Sym : getSymbols()) - Symtab<ELFT>::X->addLazyObject(Sym, *this); +template <class ELFT> void LazyObjFile::parse() { + for (StringRef Sym : getSymbolNames()) + Symtab->addLazyObject<ELFT>(Sym, *this); } -template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() { +template <class ELFT> std::vector<StringRef> LazyObjFile::getElfSymbols() { typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::SymRange Elf_Sym_Range; - const ELFFile<ELFT> Obj(this->MB.getBuffer()); - ArrayRef<Elf_Shdr> Sections = check(Obj.sections(), toString(this)); + ELFFile<ELFT> Obj = check(ELFFile<ELFT>::create(this->MB.getBuffer())); + ArrayRef<Elf_Shdr> Sections = CHECK(Obj.sections(), this); for (const Elf_Shdr &Sec : Sections) { if (Sec.sh_type != SHT_SYMTAB) continue; - Elf_Sym_Range Syms = check(Obj.symbols(&Sec), toString(this)); + Elf_Sym_Range Syms = CHECK(Obj.symbols(&Sec), this); uint32_t FirstNonLocal = Sec.sh_info; StringRef StringTable = - check(Obj.getStringTableForSymtab(Sec, Sections), toString(this)); + CHECK(Obj.getStringTableForSymtab(Sec, Sections), this); std::vector<StringRef> V; for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal)) if (Sym.st_shndx != SHN_UNDEF) - V.push_back(check(Sym.getName(StringTable), toString(this))); + V.push_back(CHECK(Sym.getName(StringTable), this)); return V; } return {}; } -std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() { +std::vector<StringRef> LazyObjFile::getBitcodeSymbols() { std::unique_ptr<lto::InputFile> Obj = - check(lto::InputFile::create(this->MB), toString(this)); + CHECK(lto::InputFile::create(this->MB), this); std::vector<StringRef> V; for (const lto::InputFile::Symbol &Sym : Obj->symbols()) if (!Sym.isUndefined()) @@ -1055,7 +1098,7 @@ std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() { } // Returns a vector of globally-visible defined symbol names. -std::vector<StringRef> LazyObjectFile::getSymbols() { +std::vector<StringRef> LazyObjFile::getSymbolNames() { if (isBitcode(this->MB)) return getBitcodeSymbols(); @@ -1083,20 +1126,20 @@ template void BitcodeFile::parse<ELF32BE>(DenseSet<CachedHashStringRef> &); template void BitcodeFile::parse<ELF64LE>(DenseSet<CachedHashStringRef> &); template void BitcodeFile::parse<ELF64BE>(DenseSet<CachedHashStringRef> &); -template void LazyObjectFile::parse<ELF32LE>(); -template void LazyObjectFile::parse<ELF32BE>(); -template void LazyObjectFile::parse<ELF64LE>(); -template void LazyObjectFile::parse<ELF64BE>(); +template void LazyObjFile::parse<ELF32LE>(); +template void LazyObjFile::parse<ELF32BE>(); +template void LazyObjFile::parse<ELF64LE>(); +template void LazyObjFile::parse<ELF64BE>(); template class elf::ELFFileBase<ELF32LE>; template class elf::ELFFileBase<ELF32BE>; template class elf::ELFFileBase<ELF64LE>; template class elf::ELFFileBase<ELF64BE>; -template class elf::ObjectFile<ELF32LE>; -template class elf::ObjectFile<ELF32BE>; -template class elf::ObjectFile<ELF64LE>; -template class elf::ObjectFile<ELF64BE>; +template class elf::ObjFile<ELF32LE>; +template class elf::ObjFile<ELF32BE>; +template class elf::ObjFile<ELF64LE>; +template class elf::ObjFile<ELF64BE>; template class elf::SharedFile<ELF32LE>; template class elf::SharedFile<ELF32BE>; |