diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:03:39 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:03:39 +0000 |
commit | d2d3ebb81992e107edf95c1c136d7a342d9b1418 (patch) | |
tree | bb1af8fff2b1400cf240e3b2532a1e5d22a121da /ELF/InputFiles.cpp | |
parent | 16787c9ce0b96aaa669d7fab3a495916b35ce758 (diff) |
Notes
Diffstat (limited to 'ELF/InputFiles.cpp')
-rw-r--r-- | ELF/InputFiles.cpp | 373 |
1 files changed, 215 insertions, 158 deletions
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index f3afb1c34562..d651fbcad253 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -16,7 +16,6 @@ #include "Symbols.h" #include "SyntheticSections.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/Bitcode/BitcodeReader.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/IR/LLVMContext.h" @@ -38,6 +37,8 @@ using namespace lld::elf; 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 @@ -56,14 +57,13 @@ public: } Optional<MemoryBufferRef> elf::readFile(StringRef Path) { - if (Config->Verbose) - outs() << Path << "\n"; - + log(Path); auto MBOrErr = MemoryBuffer::getFile(Path); if (auto EC = MBOrErr.getError()) { - error(EC, "cannot open " + Path); + error("cannot open " + Path + ": " + EC.message()); return None; } + std::unique_ptr<MemoryBuffer> &MB = *MBOrErr; MemoryBufferRef MBRef = MB->getMemBufferRef(); make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership @@ -75,15 +75,13 @@ Optional<MemoryBufferRef> elf::readFile(StringRef Path) { template <class ELFT> void elf::ObjectFile<ELFT>::initializeDwarfLine() { std::unique_ptr<object::ObjectFile> Obj = - check(object::ObjectFile::createObjectFile(this->MB), - "createObjectFile failed"); + check(object::ObjectFile::createObjectFile(this->MB), toString(this)); ObjectInfo ObjInfo; DWARFContextInMemory Dwarf(*Obj, &ObjInfo); DwarfLine.reset(new DWARFDebugLine(&Dwarf.getLineSection().Relocs)); - DataExtractor LineData(Dwarf.getLineSection().Data, - ELFT::TargetEndianness == support::little, - ELFT::Is64Bits ? 8 : 4); + DataExtractor LineData(Dwarf.getLineSection().Data, Config->IsLE, + Config->Wordsize); // The second parameter is offset in .debug_line section // for compilation unit (CU) of interest. We have only one @@ -94,34 +92,49 @@ template <class ELFT> void elf::ObjectFile<ELFT>::initializeDwarfLine() { // Returns source line information for a given offset // using DWARF debug info. template <class ELFT> -std::string elf::ObjectFile<ELFT>::getLineInfo(InputSectionBase<ELFT> *S, - uintX_t Offset) { +Optional<DILineInfo> elf::ObjectFile<ELFT>::getDILineInfo(InputSectionBase *S, + uint64_t Offset) { if (!DwarfLine) initializeDwarfLine(); // The offset to CU is 0. const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0); if (!Tbl) - return ""; + return None; // Use fake address calcuated by adding section file offset and offset in // section. See comments for ObjectInfo class. DILineInfo Info; Tbl->getFileLineInfoForAddress( - S->Offset + Offset, nullptr, + S->getOffsetInFile() + Offset, nullptr, DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info); if (Info.Line == 0) - return ""; - return Info.FileName + ":" + std::to_string(Info.Line); + return None; + return Info; +} + +// 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) { + if (Optional<DILineInfo> Info = getDILineInfo(S, Offset)) + return Info->FileName + ":" + std::to_string(Info->Line); + return ""; } // Returns "(internal)", "foo.a(bar.o)" or "baz.o". std::string lld::toString(const InputFile *F) { if (!F) return "(internal)"; - if (!F->ArchiveName.empty()) - return (F->ArchiveName + "(" + F->getName() + ")").str(); - return F->getName(); + + if (F->ToStringCache.empty()) { + if (F->ArchiveName.empty()) + F->ToStringCache = F->getName(); + else + F->ToStringCache = (F->ArchiveName + "(" + F->getName() + ")").str(); + } + return F->ToStringCache; } template <class ELFT> static ELFKind getELFKind() { @@ -144,18 +157,20 @@ typename ELFT::SymRange ELFFileBase<ELFT>::getGlobalSymbols() { template <class ELFT> uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const { - return check(getObj().getSectionIndex(&Sym, Symbols, SymtabSHNDX)); + return check(getObj().getSectionIndex(&Sym, Symbols, SymtabSHNDX), + toString(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)); + Symbols = check(getObj().symbols(Symtab), toString(this)); if (FirstNonLocal == 0 || FirstNonLocal > Symbols.size()) fatal(toString(this) + ": invalid sh_info in symbol table"); - StringTable = check(getObj().getStringTableForSymtab(*Symtab, Sections)); + StringTable = check(getObj().getStringTableForSymtab(*Symtab, Sections), + toString(this)); } template <class ELFT> @@ -163,11 +178,6 @@ elf::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M) : ELFFileBase<ELFT>(Base::ObjectKind, M) {} template <class ELFT> -ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getNonLocalSymbols() { - return makeArrayRef(this->SymbolBodies).slice(this->FirstNonLocal); -} - -template <class ELFT> ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getLocalSymbols() { if (this->SymbolBodies.empty()) return this->SymbolBodies; @@ -196,19 +206,20 @@ StringRef elf::ObjectFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections, const Elf_Shdr &Sec) { if (this->Symbols.empty()) - this->initSymtab(Sections, - check(object::getSection<ELFT>(Sections, Sec.sh_link))); - const Elf_Sym *Sym = - check(object::getSymbol<ELFT>(this->Symbols, Sec.sh_info)); - return check(Sym->getName(this->StringTable)); + this->initSymtab( + Sections, + check(object::getSection<ELFT>(Sections, Sec.sh_link), toString(this))); + const Elf_Sym *Sym = check( + object::getSymbol<ELFT>(this->Symbols, Sec.sh_info), toString(this)); + return check(Sym->getName(this->StringTable), toString(this)); } template <class ELFT> ArrayRef<typename elf::ObjectFile<ELFT>::Elf_Word> elf::ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) { const ELFFile<ELFT> &Obj = this->getObj(); - ArrayRef<Elf_Word> Entries = - check(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec)); + ArrayRef<Elf_Word> Entries = check( + Obj.template getSectionContentsAsArray<Elf_Word>(&Sec), toString(this)); if (Entries.empty() || Entries[0] != GRP_COMDAT) fatal(toString(this) + ": unsupported SHT_GROUP format"); return Entries.slice(1); @@ -242,14 +253,14 @@ bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) { // the section does not hold a table of fixed-size entries". We know // that Rust 1.13 produces a string mergeable section with a zero // sh_entsize. Here we just accept it rather than being picky about it. - uintX_t EntSize = Sec.sh_entsize; + uint64_t EntSize = Sec.sh_entsize; if (EntSize == 0) return false; if (Sec.sh_size % EntSize) fatal(toString(this) + ": SHF_MERGE section size must be a multiple of sh_entsize"); - uintX_t Flags = Sec.sh_flags; + uint64_t Flags = Sec.sh_flags; if (!(Flags & SHF_MERGE)) return false; if (Flags & SHF_WRITE) @@ -270,76 +281,79 @@ bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) { template <class ELFT> void elf::ObjectFile<ELFT>::initializeSections( DenseSet<CachedHashStringRef> &ComdatGroups) { - ArrayRef<Elf_Shdr> ObjSections = check(this->getObj().sections()); + ArrayRef<Elf_Shdr> ObjSections = + check(this->getObj().sections(), toString(this)); const ELFFile<ELFT> &Obj = this->getObj(); uint64_t Size = ObjSections.size(); - Sections.resize(Size); + this->Sections.resize(Size); unsigned I = -1; - StringRef SectionStringTable = check(Obj.getSectionStringTable(ObjSections)); + StringRef SectionStringTable = + check(Obj.getSectionStringTable(ObjSections), toString(this)); for (const Elf_Shdr &Sec : ObjSections) { ++I; - if (Sections[I] == &InputSection<ELFT>::Discarded) + if (this->Sections[I] == &InputSection::Discarded) continue; // SHF_EXCLUDE'ed sections are discarded by the linker. However, // if -r is given, we'll let the final link discard such sections. // This is compatible with GNU. if ((Sec.sh_flags & SHF_EXCLUDE) && !Config->Relocatable) { - Sections[I] = &InputSection<ELFT>::Discarded; + this->Sections[I] = &InputSection::Discarded; continue; } switch (Sec.sh_type) { case SHT_GROUP: - Sections[I] = &InputSection<ELFT>::Discarded; - if (ComdatGroups.insert(CachedHashStringRef( - getShtGroupSignature(ObjSections, Sec))) + this->Sections[I] = &InputSection::Discarded; + if (ComdatGroups + .insert( + CachedHashStringRef(getShtGroupSignature(ObjSections, Sec))) .second) continue; for (uint32_t SecIndex : getShtGroupEntries(Sec)) { if (SecIndex >= Size) - fatal(toString(this) + ": invalid section index in group: " + - Twine(SecIndex)); - Sections[SecIndex] = &InputSection<ELFT>::Discarded; + fatal(toString(this) + + ": invalid section index in group: " + Twine(SecIndex)); + this->Sections[SecIndex] = &InputSection::Discarded; } break; case SHT_SYMTAB: this->initSymtab(ObjSections, &Sec); break; case SHT_SYMTAB_SHNDX: - this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec, ObjSections)); + this->SymtabSHNDX = + check(Obj.getSHNDXTable(Sec, ObjSections), toString(this)); break; case SHT_STRTAB: case SHT_NULL: break; default: - Sections[I] = createInputSection(Sec, SectionStringTable); + this->Sections[I] = createInputSection(Sec, SectionStringTable); } // .ARM.exidx sections have a reverse dependency on the InputSection they // have a SHF_LINK_ORDER dependency, this is identified by the sh_link. if (Sec.sh_flags & SHF_LINK_ORDER) { - if (Sec.sh_link >= Sections.size()) + if (Sec.sh_link >= this->Sections.size()) fatal(toString(this) + ": invalid sh_link index: " + Twine(Sec.sh_link)); - auto *IS = cast<InputSection<ELFT>>(Sections[Sec.sh_link]); - IS->DependentSection = Sections[I]; + this->Sections[Sec.sh_link]->DependentSections.push_back( + this->Sections[I]); } } } template <class ELFT> -InputSectionBase<ELFT> * -elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) { +InputSectionBase *elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) { uint32_t Idx = Sec.sh_info; - if (Idx >= Sections.size()) + if (Idx >= this->Sections.size()) fatal(toString(this) + ": invalid relocated section index: " + Twine(Idx)); - InputSectionBase<ELFT> *Target = Sections[Idx]; + InputSectionBase *Target = this->Sections[Idx]; // Strictly speaking, a relocation section must be included in the // group of the section it relocates. However, LLVM 3.3 and earlier // would fail to do so, so we gracefully handle that case. - if (Target == &InputSection<ELFT>::Discarded) + if (Target == &InputSection::Discarded) return nullptr; if (!Target) @@ -348,11 +362,11 @@ elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) { } template <class ELFT> -InputSectionBase<ELFT> * +InputSectionBase * elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec, StringRef SectionStringTable) { - StringRef Name = - check(this->getObj().getSectionName(&Sec, SectionStringTable)); + StringRef Name = check( + this->getObj().getSectionName(&Sec, SectionStringTable), toString(this)); switch (Sec.sh_type) { case SHT_ARM_ATTRIBUTES: @@ -361,62 +375,91 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec, // attribute section for dlopen to work. // In a full implementation we would merge all attribute sections. if (In<ELFT>::ARMAttributes == nullptr) { - In<ELFT>::ARMAttributes = make<InputSection<ELFT>>(this, &Sec, Name); + In<ELFT>::ARMAttributes = make<InputSection>(this, &Sec, Name); return In<ELFT>::ARMAttributes; } - return &InputSection<ELFT>::Discarded; + return &InputSection::Discarded; case SHT_RELA: case SHT_REL: { + // Find the relocation target section and associate this + // section with it. Target can be discarded, for example + // if it is a duplicated member of SHT_GROUP section, we + // do not create or proccess relocatable sections then. + InputSectionBase *Target = getRelocTarget(Sec); + if (!Target) + return nullptr; + // This section contains relocation information. // If -r is given, we do not interpret or apply relocation // but just copy relocation sections to output. if (Config->Relocatable) - return make<InputSection<ELFT>>(this, &Sec, Name); + return make<InputSection>(this, &Sec, Name); - // Find the relocation target section and associate this - // section with it. - InputSectionBase<ELFT> *Target = getRelocTarget(Sec); - if (!Target) - return nullptr; if (Target->FirstRelocation) fatal(toString(this) + ": multiple relocation sections to one section are not supported"); - if (!isa<InputSection<ELFT>>(Target) && !isa<EhInputSection<ELFT>>(Target)) + if (isa<MergeInputSection>(Target)) fatal(toString(this) + ": relocations pointing to SHF_MERGE are not supported"); size_t NumRelocations; if (Sec.sh_type == SHT_RELA) { - ArrayRef<Elf_Rela> Rels = check(this->getObj().relas(&Sec)); + ArrayRef<Elf_Rela> Rels = + check(this->getObj().relas(&Sec), toString(this)); Target->FirstRelocation = Rels.begin(); NumRelocations = Rels.size(); Target->AreRelocsRela = true; } else { - ArrayRef<Elf_Rel> Rels = check(this->getObj().rels(&Sec)); + ArrayRef<Elf_Rel> Rels = check(this->getObj().rels(&Sec), toString(this)); Target->FirstRelocation = Rels.begin(); NumRelocations = Rels.size(); Target->AreRelocsRela = false; } assert(isUInt<31>(NumRelocations)); Target->NumRelocations = NumRelocations; + + // Relocation sections processed by the linker are usually removed + // from the output, so returning `nullptr` for the normal case. + // However, if -emit-relocs is given, we need to leave them in the output. + // (Some post link analysis tools need this information.) + if (Config->EmitRelocs) { + InputSection *RelocSec = make<InputSection>(this, &Sec, Name); + // We will not emit relocation section if target was discarded. + Target->DependentSections.push_back(RelocSec); + return RelocSec; + } return nullptr; } } - // .note.GNU-stack is a marker section to control the presence of - // PT_GNU_STACK segment in outputs. Since the presence of the segment - // is controlled only by the command line option (-z execstack) in LLD, - // .note.GNU-stack is ignored. + // The GNU linker uses .note.GNU-stack section as a marker indicating + // that the code in the object file does not expect that the stack is + // executable (in terms of NX bit). If all input files have the marker, + // the GNU linker adds a PT_GNU_STACK segment to tells the loader to + // make the stack non-executable. Most object files have this section as + // of 2017. + // + // But making the stack non-executable is a norm today for security + // reasons. Failure to do so may result in a serious security issue. + // Therefore, we make LLD always add PT_GNU_STACK unless it is + // explicitly told to do otherwise (by -z execstack). Because the stack + // executable-ness is controlled solely by command line options, + // .note.GNU-stack sections are simply ignored. if (Name == ".note.GNU-stack") - return &InputSection<ELFT>::Discarded; + return &InputSection::Discarded; + // Split stacks is a feature to support a discontiguous stack. At least + // as of 2017, it seems that the feature is not being used widely. + // Only GNU gold supports that. We don't. For the details about that, + // see https://gcc.gnu.org/wiki/SplitStacks if (Name == ".note.GNU-split-stack") { - error("objects using splitstacks are not supported"); - return &InputSection<ELFT>::Discarded; + error(toString(this) + + ": object file compiled with -fsplit-stack is not supported"); + return &InputSection::Discarded; } if (Config->Strip != StripPolicy::None && Name.startswith(".debug")) - return &InputSection<ELFT>::Discarded; + 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 @@ -424,17 +467,17 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec, // FIXME: This is glibc PR20543, we should remove this hack once that has been // fixed for a while. if (Name.startswith(".gnu.linkonce.")) - return &InputSection<ELFT>::Discarded; + return &InputSection::Discarded; // The linker merges EH (exception handling) frames and creates a // .eh_frame_hdr section for runtime. So we handle them with a special // class. For relocatable outputs, they are just passed through. if (Name == ".eh_frame" && !Config->Relocatable) - return make<EhInputSection<ELFT>>(this, &Sec, Name); + return make<EhInputSection>(this, &Sec, Name); if (shouldMerge(Sec)) - return make<MergeInputSection<ELFT>>(this, &Sec, Name); - return make<InputSection<ELFT>>(this, &Sec, Name); + return make<MergeInputSection>(this, &Sec, Name); + return make<InputSection>(this, &Sec, Name); } template <class ELFT> void elf::ObjectFile<ELFT>::initializeSymbols() { @@ -444,12 +487,11 @@ template <class ELFT> void elf::ObjectFile<ELFT>::initializeSymbols() { } template <class ELFT> -InputSectionBase<ELFT> * -elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const { +InputSectionBase *elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const { uint32_t Index = this->getSectionIndex(Sym); - if (Index >= Sections.size()) + if (Index >= this->Sections.size()) fatal(toString(this) + ": invalid section index: " + Twine(Index)); - InputSectionBase<ELFT> *S = Sections[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 @@ -463,7 +505,7 @@ elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const { fatal(toString(this) + ": invalid section index: " + Twine(Index)); } - if (S == &InputSection<ELFT>::Discarded) + if (S == &InputSection::Discarded) return S; return S->Repl; } @@ -471,30 +513,29 @@ elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const { template <class ELFT> SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) { int Binding = Sym->getBinding(); - InputSectionBase<ELFT> *Sec = getSection(*Sym); + InputSectionBase *Sec = getSection(*Sym); uint8_t StOther = Sym->st_other; uint8_t Type = Sym->getType(); - uintX_t Value = Sym->st_value; - uintX_t Size = Sym->st_size; + uint64_t Value = Sym->st_value; + uint64_t Size = Sym->st_size; if (Binding == STB_LOCAL) { if (Sym->getType() == STT_FILE) - SourceFile = check(Sym->getName(this->StringTable)); + SourceFile = check(Sym->getName(this->StringTable), toString(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 new (BAlloc) - Undefined<ELFT>(Name, /*IsLocal=*/true, StOther, Type, this); + return make<Undefined>(Name, /*IsLocal=*/true, StOther, Type, this); - return new (BAlloc) DefinedRegular<ELFT>(Name, /*IsLocal=*/true, StOther, - Type, Value, Size, Sec, this); + return make<DefinedRegular>(Name, /*IsLocal=*/true, StOther, Type, Value, + Size, Sec, this); } - StringRef Name = check(Sym->getName(this->StringTable)); + StringRef Name = check(Sym->getName(this->StringTable), toString(this)); switch (Sym->st_shndx) { case SHN_UNDEF: @@ -517,7 +558,7 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) { case STB_GLOBAL: case STB_WEAK: case STB_GNU_UNIQUE: - if (Sec == &InputSection<ELFT>::Discarded) + if (Sec == &InputSection::Discarded) return elf::Symtab<ELFT>::X ->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type, /*CanOmitFromDynSym=*/false, this) @@ -533,27 +574,34 @@ template <class ELFT> void ArchiveFile::parse() { MB.getBufferIdentifier() + ": failed to parse archive"); // Read the symbol table to construct Lazy objects. - for (const Archive::Symbol &Sym : File->symbols()) + for (const Archive::Symbol &Sym : File->symbols()) { Symtab<ELFT>::X->addLazyArchive(this, Sym); + } + + if (File->symbols().begin() == File->symbols().end()) + Config->ArchiveWithoutSymbolsSeen = true; } // 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(), - "could not get the member for symbol " + Sym->getName()); + check(Sym->getMember(), toString(this) + + ": could not get the member for symbol " + + Sym->getName()); if (!Seen.insert(C.getChildOffset()).second) return {MemoryBufferRef(), 0}; MemoryBufferRef Ret = check(C.getMemoryBufferRef(), - "could not get the buffer for the member defining symbol " + + 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())), Ret.getBuffer()); + Tar->append(relativeToRoot(check(C.getFullName(), toString(this))), + Ret.getBuffer()); if (C.getParent()->isThin()) return {Ret, 0}; return {Ret, C.getChildOffset()}; @@ -567,16 +615,24 @@ 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)); + this->getObj().getSection(&Sym, this->Symbols, this->SymtabSHNDX), + toString(this)); +} + +template <class ELFT> StringRef SharedFile<ELFT>::getSoName() const { + if (SoName.empty()) + return this->DefaultSoName; + return SoName; } // 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()); + ArrayRef<Elf_Shdr> Sections = check(Obj.sections(), toString(this)); + + // Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d. for (const Elf_Shdr &Sec : Sections) { switch (Sec.sh_type) { default: @@ -588,7 +644,8 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() { DynamicSec = &Sec; break; case SHT_SYMTAB_SHNDX: - this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec, Sections)); + this->SymtabSHNDX = + check(Obj.getSHNDXTable(Sec, Sections), toString(this)); break; case SHT_GNU_versym: this->VersymSec = &Sec; @@ -602,20 +659,15 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() { if (this->VersymSec && this->Symbols.empty()) error("SHT_GNU_versym should be associated with symbol table"); - // DSOs are identified by soname, and they usually contain - // DT_SONAME tag in their header. But if they are missing, - // filenames are used as default sonames. - SoName = sys::path::filename(this->getName()); - + // 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) + ": getSectionContentsAsArray failed"); + toString(this)); for (const Elf_Dyn &Dyn : Arr) { if (Dyn.d_tag == DT_SONAME) { - uintX_t Val = Dyn.getVal(); + uint64_t Val = Dyn.getVal(); if (Val >= this->StringTable.size()) fatal(toString(this) + ": invalid DT_SONAME entry"); SoName = StringRef(this->StringTable.data() + Val); @@ -681,7 +733,7 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() { bool Hidden = VersymIndex & VERSYM_HIDDEN; VersymIndex = VersymIndex & ~VERSYM_HIDDEN; - StringRef Name = check(Sym.getName(this->StringTable)); + StringRef Name = check(Sym.getName(this->StringTable), toString(this)); if (Sym.isUndefined()) { Undefs.push_back(Name); continue; @@ -707,19 +759,18 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() { } } -static ELFKind getBitcodeELFKind(MemoryBufferRef MB) { - Triple T(check(getBitcodeTargetTriple(MB))); +static ELFKind getBitcodeELFKind(const Triple &T) { if (T.isLittleEndian()) return T.isArch64Bit() ? ELF64LEKind : ELF32LEKind; return T.isArch64Bit() ? ELF64BEKind : ELF32BEKind; } -static uint8_t getBitcodeMachineKind(MemoryBufferRef MB) { - Triple T(check(getBitcodeTargetTriple(MB))); +static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) { switch (T.getArch()) { case Triple::aarch64: return EM_AARCH64; case Triple::arm: + case Triple::thumb: return EM_ARM; case Triple::mips: case Triple::mipsel: @@ -735,14 +786,32 @@ static uint8_t getBitcodeMachineKind(MemoryBufferRef MB) { case Triple::x86_64: return EM_X86_64; default: - fatal(MB.getBufferIdentifier() + - ": could not infer e_machine from bitcode target triple " + T.str()); + fatal(Path + ": could not infer e_machine from bitcode target triple " + + T.str()); } } -BitcodeFile::BitcodeFile(MemoryBufferRef MB) : InputFile(BitcodeKind, MB) { - EKind = getBitcodeELFKind(MB); - EMachine = getBitcodeMachineKind(MB); +BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName, + uint64_t OffsetInArchive) + : InputFile(BitcodeKind, MB) { + this->ArchiveName = ArchiveName; + + // Here we pass a new MemoryBufferRef which is identified by ArchiveName + // (the fully resolved path of the archive) + member name + offset of the + // member in the archive. + // ThinLTO uses the MemoryBufferRef identifier to access its internal + // data structures and if two archives define two members with the same name, + // this causes a collision which result in only one of the objects being + // taken into consideration at LTO time (which very likely causes undefined + // symbols later in the link stage). + MemoryBufferRef MBRef(MB.getBuffer(), + Saver.save(ArchiveName + MB.getBufferIdentifier() + + utostr(OffsetInArchive))); + Obj = check(lto::InputFile::create(MBRef), toString(this)); + + Triple T(Obj->getTargetTriple()); + EKind = getBitcodeELFKind(T); + EMachine = getBitcodeMachineKind(MB.getBufferIdentifier(), T); } static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) { @@ -762,25 +831,24 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats, const lto::InputFile::Symbol &ObjSym, BitcodeFile *F) { StringRef NameRef = Saver.save(ObjSym.getName()); - uint32_t Flags = ObjSym.getFlags(); - uint32_t Binding = (Flags & BasicSymbolRef::SF_Weak) ? STB_WEAK : STB_GLOBAL; + uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL; uint8_t Type = ObjSym.isTLS() ? STT_TLS : STT_NOTYPE; uint8_t Visibility = mapVisibility(ObjSym.getVisibility()); bool CanOmitFromDynSym = ObjSym.canBeOmittedFromSymbolTable(); - int C = check(ObjSym.getComdatIndex()); + int C = ObjSym.getComdatIndex(); if (C != -1 && !KeptComdats[C]) return Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding, Visibility, Type, CanOmitFromDynSym, F); - if (Flags & BasicSymbolRef::SF_Undefined) + if (ObjSym.isUndefined()) return Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding, Visibility, Type, CanOmitFromDynSym, F); - if (Flags & BasicSymbolRef::SF_Common) + if (ObjSym.isCommon()) return Symtab<ELFT>::X->addCommon(NameRef, ObjSym.getCommonSize(), ObjSym.getCommonAlignment(), Binding, Visibility, STT_OBJECT, F); @@ -791,24 +859,9 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats, template <class ELFT> void BitcodeFile::parse(DenseSet<CachedHashStringRef> &ComdatGroups) { - - // Here we pass a new MemoryBufferRef which is identified by ArchiveName - // (the fully resolved path of the archive) + member name + offset of the - // member in the archive. - // ThinLTO uses the MemoryBufferRef identifier to access its internal - // data structures and if two archives define two members with the same name, - // this causes a collision which result in only one of the objects being - // taken into consideration at LTO time (which very likely causes undefined - // symbols later in the link stage). - Obj = check(lto::InputFile::create(MemoryBufferRef( - MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier() + - utostr(OffsetInArchive))))); - std::vector<bool> KeptComdats; - for (StringRef S : Obj->getComdatTable()) { - StringRef N = Saver.save(S); - KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(N)).second); - } + for (StringRef S : Obj->getComdatTable()) + KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(S)).second); for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, this)); @@ -857,8 +910,8 @@ template <class ELFT> void BinaryFile::parse() { StringRef EndName = Saver.save(Twine(Filename) + "_end"); StringRef SizeName = Saver.save(Twine(Filename) + "_size"); - auto *Section = make<InputSection<ELFT>>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, - 8, Data, ".data"); + auto *Section = + make<InputSection>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 8, Data, ".data"); Sections.push_back(Section); elf::Symtab<ELFT>::X->addRegular(StartName, STV_DEFAULT, STT_OBJECT, 0, 0, @@ -878,10 +931,10 @@ static bool isBitcode(MemoryBufferRef MB) { InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName, uint64_t OffsetInArchive) { - InputFile *F = - isBitcode(MB) ? make<BitcodeFile>(MB) : createELFFile<ObjectFile>(MB); + InputFile *F = isBitcode(MB) + ? make<BitcodeFile>(MB, ArchiveName, OffsetInArchive) + : createELFFile<ObjectFile>(MB); F->ArchiveName = ArchiveName; - F->OffsetInArchive = OffsetInArchive; return F; } @@ -907,27 +960,31 @@ template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() { typedef typename ELFT::SymRange Elf_Sym_Range; const ELFFile<ELFT> Obj(this->MB.getBuffer()); - ArrayRef<Elf_Shdr> Sections = check(Obj.sections()); + ArrayRef<Elf_Shdr> Sections = check(Obj.sections(), toString(this)); for (const Elf_Shdr &Sec : Sections) { if (Sec.sh_type != SHT_SYMTAB) continue; - Elf_Sym_Range Syms = check(Obj.symbols(&Sec)); + + Elf_Sym_Range Syms = check(Obj.symbols(&Sec), toString(this)); uint32_t FirstNonLocal = Sec.sh_info; - StringRef StringTable = check(Obj.getStringTableForSymtab(Sec, Sections)); + StringRef StringTable = + check(Obj.getStringTableForSymtab(Sec, Sections), toString(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))); + V.push_back(check(Sym.getName(StringTable), toString(this))); return V; } return {}; } std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() { - std::unique_ptr<lto::InputFile> Obj = check(lto::InputFile::create(this->MB)); + std::unique_ptr<lto::InputFile> Obj = + check(lto::InputFile::create(this->MB), toString(this)); std::vector<StringRef> V; for (const lto::InputFile::Symbol &Sym : Obj->symbols()) - if (!(Sym.getFlags() & BasicSymbolRef::SF_Undefined)) + if (!Sym.isUndefined()) V.push_back(Saver.save(Sym.getName())); return V; } |