Index: head/contrib/llvm/tools/lld/ELF/InputFiles.cpp =================================================================== --- head/contrib/llvm/tools/lld/ELF/InputFiles.cpp (revision 331730) +++ head/contrib/llvm/tools/lld/ELF/InputFiles.cpp (revision 331731) @@ -1,1198 +1,1202 @@ //===- InputFiles.cpp -----------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "InputFiles.h" #include "InputSection.h" #include "LinkerScript.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" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #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" using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::sys; using namespace llvm::sys::fs; using namespace lld; using namespace lld::elf; std::vector elf::BinaryFiles; std::vector elf::BitcodeFiles; std::vector elf::ObjectFiles; std::vector elf::SharedFiles; TarWriter *elf::Tar; InputFile::InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} Optional 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()); return None; } std::unique_ptr &MB = *MBOrErr; MemoryBufferRef MBRef = MB->getMemBufferRef(); make>(std::move(MB)); // take MB ownership if (Tar) Tar->append(relativeToRoot(Path), MBRef.getBuffer()); return MBRef; } // Concatenates arguments to construct a string representing an error location. static std::string createFileLineMsg(StringRef Path, unsigned Line) { std::string Filename = path::filename(Path); std::string Lineno = ":" + std::to_string(Line); if (Filename == Path) return Filename + Lineno; return Filename + Lineno + " (" + Path.str() + Lineno + ")"; } template static std::string getSrcMsgAux(ObjFile &File, const Symbol &Sym, InputSectionBase &Sec, uint64_t Offset) { // In DWARF, functions and variables are stored to different places. // First, lookup a function for a given offset. if (Optional Info = File.getDILineInfo(&Sec, Offset)) return createFileLineMsg(Info->FileName, Info->Line); // If it failed, lookup again as a variable. if (Optional> FileLine = File.getVariableLoc(Sym.getName())) return createFileLineMsg(FileLine->first, FileLine->second); // File.SourceFile contains STT_FILE symbol, and that is a last resort. return File.SourceFile; } std::string InputFile::getSrcMsg(const Symbol &Sym, InputSectionBase &Sec, uint64_t Offset) { if (kind() != ObjKind) return ""; switch (Config->EKind) { default: llvm_unreachable("Invalid kind"); case ELF32LEKind: return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); case ELF32BEKind: return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); case ELF64LEKind: return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); case ELF64BEKind: return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); } } template void ObjFile::initializeDwarf() { DWARFContext Dwarf(make_unique>(this)); const DWARFObject &Obj = Dwarf.getDWARFObj(); DwarfLine.reset(new DWARFDebugLine); 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. // 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 Optional> ObjFile::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 Optional ObjFile::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); if (!Tbl) 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->getOffsetInFile() + Offset, nullptr, DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info); if (Info.Line == 0) return None; return Info; } // Returns source line information for a given offset // using DWARF debug info. template std::string ObjFile::getLineInfo(InputSectionBase *S, uint64_t Offset) { if (Optional Info = getDILineInfo(S, Offset)) return Info->FileName + ":" + std::to_string(Info->Line); return ""; } // Returns "", "foo.a(bar.o)" or "baz.o". std::string lld::toString(const InputFile *F) { if (!F) return ""; if (F->ToStringCache.empty()) { if (F->ArchiveName.empty()) F->ToStringCache = F->getName(); else F->ToStringCache = (F->ArchiveName + "(" + F->getName() + ")").str(); } return F->ToStringCache; } template ELFFileBase::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) { if (ELFT::TargetEndianness == support::little) EKind = ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind; else EKind = ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind; EMachine = getObj().getHeader()->e_machine; OSABI = getObj().getHeader()->e_ident[llvm::ELF::EI_OSABI]; } template typename ELFT::SymRange ELFFileBase::getGlobalELFSyms() { return makeArrayRef(ELFSyms.begin() + FirstNonLocal, ELFSyms.end()); } template uint32_t ELFFileBase::getSectionIndex(const Elf_Sym &Sym) const { return CHECK(getObj().getSectionIndex(&Sym, ELFSyms, SymtabSHNDX), this); } template void ELFFileBase::initSymtab(ArrayRef Sections, const Elf_Shdr *Symtab) { FirstNonLocal = Symtab->sh_info; 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), this); } template ObjFile::ObjFile(MemoryBufferRef M, StringRef ArchiveName) : ELFFileBase(Base::ObjKind, M) { this->ArchiveName = ArchiveName; } template ArrayRef ObjFile::getLocalSymbols() { if (this->Symbols.empty()) return {}; return makeArrayRef(this->Symbols).slice(1, this->FirstNonLocal - 1); } +template ArrayRef ObjFile::getGlobalSymbols() { + return makeArrayRef(this->Symbols).slice(this->FirstNonLocal); +} + template void ObjFile::parse(DenseSet &ComdatGroups) { // Read section and symbol tables. initializeSections(ComdatGroups); initializeSymbols(); } // Sections with SHT_GROUP and comdat bits define comdat section groups. // They are identified and deduplicated by group name. This function // returns a group name. template StringRef ObjFile::getShtGroupSignature(ArrayRef 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->ELFSyms.empty()) this->initSymtab( Sections, CHECK(object::getSection(Sections, Sec.sh_link), this)); const Elf_Sym *Sym = CHECK(object::getSymbol(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. // // Such SHT_GROUP sections are invalid from the perspective of the ELF // standard, but GNU gold 1.14 (the neweset version as of July 2017) or // older produce such sections as outputs for the -r option, so we need // a bug-compatibility. if (Signature.empty() && Sym->getType() == STT_SECTION) return getSectionName(Sec); return Signature; } template ArrayRef::Elf_Word> ObjFile::getShtGroupEntries(const Elf_Shdr &Sec) { const ELFFile &Obj = this->getObj(); ArrayRef Entries = CHECK(Obj.template getSectionContentsAsArray(&Sec), this); if (Entries.empty() || Entries[0] != GRP_COMDAT) fatal(toString(this) + ": unsupported SHT_GROUP format"); return Entries.slice(1); } template bool ObjFile::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; // 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. // We'll avoid a mess by handling them as if they were non-mergeable. if (Sec.sh_size == 0) return false; // Check for sh_entsize. The ELF spec is not clear about the zero // sh_entsize. It says that "the member [sh_entsize] contains 0 if // 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. 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"); uint64_t Flags = Sec.sh_flags; if (!(Flags & SHF_MERGE)) return false; if (Flags & SHF_WRITE) fatal(toString(this) + ": writable SHF_MERGE section is not supported"); return true; } template void ObjFile::initializeSections( DenseSet &ComdatGroups) { const ELFFile &Obj = this->getObj(); ArrayRef ObjSections = CHECK(this->getObj().sections(), this); uint64_t Size = ObjSections.size(); this->Sections.resize(Size); this->SectionStringTable = CHECK(Obj.getSectionStringTable(ObjSections), this); for (size_t I = 0, E = ObjSections.size(); I < E; I++) { if (this->Sections[I] == &InputSection::Discarded) continue; const Elf_Shdr &Sec = ObjSections[I]; // SHF_EXCLUDE'ed sections are discarded by the linker. However, // if -r is given, we'll let the final link discard such sections. // This is compatible with GNU. if ((Sec.sh_flags & SHF_EXCLUDE) && !Config->Relocatable) { this->Sections[I] = &InputSection::Discarded; continue; } switch (Sec.sh_type) { case SHT_GROUP: { // De-duplicate section groups by their signatures. StringRef Signature = getShtGroupSignature(ObjSections, Sec); bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second; this->Sections[I] = &InputSection::Discarded; // If it is a new section group, we want to keep group members. // Group leader sections, which contain indices of group members, are // discarded because they are useless beyond this point. The only // exception is the -r option because in order to produce re-linkable // object files, we want to pass through basically everything. if (IsNew) { if (Config->Relocatable) this->Sections[I] = createInputSection(Sec); continue; } // Otherwise, discard group members. for (uint32_t SecIndex : getShtGroupEntries(Sec)) { if (SecIndex >= Size) 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); break; case SHT_STRTAB: case SHT_NULL: break; default: this->Sections[I] = createInputSection(Sec); } // .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 >= this->Sections.size()) fatal(toString(this) + ": invalid sh_link index: " + Twine(Sec.sh_link)); this->Sections[Sec.sh_link]->DependentSections.push_back( cast(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 InputSectionBase *ObjFile::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)); 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::Discarded) return nullptr; if (!Target) fatal(toString(this) + ": unsupported relocation reference"); return Target; } // Create a regular InputSection class that has the same contents // as a given section. static InputSection *toRegularSection(MergeInputSection *Sec) { return make(Sec->File, Sec->Flags, Sec->Type, Sec->Alignment, Sec->Data, Sec->Name); } template InputSectionBase *ObjFile::createInputSection(const Elf_Shdr &Sec) { StringRef Name = getSectionName(Sec); switch (Sec.sh_type) { case SHT_ARM_ATTRIBUTES: { if (Config->EMachine != EM_ARM) break; ARMAttributeParser Attributes; ArrayRef 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(*this, Sec, Name); return InX::ARMAttributes; } 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(*this, Sec, Name); if (Target->FirstRelocation) fatal(toString(this) + ": multiple relocation sections to one section are not supported"); // Mergeable sections with relocations are tricky because relocations // need to be taken into account when comparing section contents for // merging. It's not worth supporting such mergeable sections because // they are rare and it'd complicates the internal design (we usually // have to determine if two sections are mergeable early in the link // process much before applying relocations). We simply handle mergeable // sections with relocations as non-mergeable. if (auto *MS = dyn_cast(Target)) { Target = toRegularSection(MS); this->Sections[Sec.sh_info] = Target; } size_t NumRelocations; if (Sec.sh_type == SHT_RELA) { ArrayRef Rels = CHECK(this->getObj().relas(&Sec), this); Target->FirstRelocation = Rels.begin(); NumRelocations = Rels.size(); Target->AreRelocsRela = true; } else { ArrayRef Rels = CHECK(this->getObj().rels(&Sec), 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(*this, Sec, Name); // We will not emit relocation section if target was discarded. Target->DependentSections.push_back(RelocSec); return RelocSec; } return nullptr; } } // 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::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(toString(this) + ": object file compiled with -fsplit-stack is not supported"); 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. // 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::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(*this, Sec, Name); if (shouldMerge(Sec)) return make(*this, Sec, Name); return make(*this, Sec, Name); } template StringRef ObjFile::getSectionName(const Elf_Shdr &Sec) { return CHECK(this->getObj().getSectionName(&Sec, SectionStringTable), this); } template void ObjFile::initializeSymbols() { this->Symbols.reserve(this->ELFSyms.size()); for (const Elf_Sym &Sym : this->ELFSyms) this->Symbols.push_back(createSymbol(&Sym)); } template Symbol *ObjFile::createSymbol(const Elf_Sym *Sym) { int Binding = Sym->getBinding(); 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; uint64_t Size = Sym->st_size; if (Binding == STB_LOCAL) { if (Sym->getType() == STT_FILE) 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(this, Name, Binding, StOther, Type); return make(this, Name, Binding, StOther, Type, Value, Size, Sec); } StringRef Name = CHECK(Sym->getName(this->StringTable), this); switch (Sym->st_shndx) { case SHN_UNDEF: return Symtab->addUndefined(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 Symtab->addCommon(Name, Size, Value, Binding, StOther, Type, *this); } switch (Binding) { default: fatal(toString(this) + ": unexpected binding: " + Twine(Binding)); case STB_GLOBAL: case STB_WEAK: case STB_GNU_UNIQUE: if (Sec == &InputSection::Discarded) return Symtab->addUndefined(Name, Binding, StOther, Type, /*CanOmitFromDynSym=*/false, this); return Symtab->addRegular(Name, StOther, Type, Value, Size, Binding, Sec, this); } } ArchiveFile::ArchiveFile(std::unique_ptr &&File) : InputFile(ArchiveKind, File->getMemoryBufferRef()), File(std::move(File)) {} template void ArchiveFile::parse() { Symbols.reserve(File->getNumberOfSymbols()); for (const Archive::Symbol &Sym : File->symbols()) Symbols.push_back(Symtab->addLazyArchive(Sym.getName(), *this, Sym)); } // Returns a buffer pointing to a member file containing a given symbol. std::pair ArchiveFile::getMember(const Archive::Symbol *Sym) { Archive::Child C = 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(), 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(), this)), Ret.getBuffer()); if (C.getParent()->isThin()) return {Ret, 0}; return {Ret, C.getChildOffset()}; } template SharedFile::SharedFile(MemoryBufferRef M, StringRef DefaultSoName) : ELFFileBase(Base::SharedKind, M), SoName(DefaultSoName), IsNeeded(!Config->AsNeeded) {} // Partially parse the shared object file so that we can call // getSoName on this object. template void SharedFile::parseSoName() { const Elf_Shdr *DynamicSec = nullptr; const ELFFile Obj = this->getObj(); ArrayRef Sections = CHECK(Obj.sections(), this); // Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d. for (const Elf_Shdr &Sec : Sections) { switch (Sec.sh_type) { default: continue; case SHT_DYNSYM: this->initSymtab(Sections, &Sec); break; case SHT_DYNAMIC: DynamicSec = &Sec; break; case SHT_SYMTAB_SHNDX: this->SymtabSHNDX = CHECK(Obj.getSHNDXTable(Sec, Sections), this); break; case SHT_GNU_versym: this->VersymSec = &Sec; break; case SHT_GNU_verdef: this->VerdefSec = &Sec; break; } } 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 Arr = CHECK(Obj.template getSectionContentsAsArray(DynamicSec), this); for (const Elf_Dyn &Dyn : Arr) { if (Dyn.d_tag == DT_SONAME) { uint64_t Val = Dyn.getVal(); if (Val >= this->StringTable.size()) fatal(toString(this) + ": invalid DT_SONAME entry"); SoName = this->StringTable.data() + Val; return; } } } // Parse the version definitions in the object file if present. Returns a vector // whose nth element contains a pointer to the Elf_Verdef for version identifier // n. Version identifiers that are not definitions map to nullptr. The array // always has at least length 1. template std::vector SharedFile::parseVerdefs(const Elf_Versym *&Versym) { std::vector Verdefs(1); // We only need to process symbol versions for this DSO if it has both a // versym and a verdef section, which indicates that the DSO contains symbol // version definitions. if (!VersymSec || !VerdefSec) return Verdefs; // The location of the first global versym entry. const char *Base = this->MB.getBuffer().data(); Versym = reinterpret_cast(Base + VersymSec->sh_offset) + this->FirstNonLocal; // We cannot determine the largest verdef identifier without inspecting // every Elf_Verdef, but both bfd and gold assign verdef identifiers // sequentially starting from 1, so we predict that the largest identifier // will be VerdefCount. unsigned VerdefCount = VerdefSec->sh_info; Verdefs.resize(VerdefCount + 1); // Build the Verdefs array by following the chain of Elf_Verdef objects // from the start of the .gnu.version_d section. const char *Verdef = Base + VerdefSec->sh_offset; for (unsigned I = 0; I != VerdefCount; ++I) { auto *CurVerdef = reinterpret_cast(Verdef); Verdef += CurVerdef->vd_next; unsigned VerdefIndex = CurVerdef->vd_ndx; if (Verdefs.size() <= VerdefIndex) Verdefs.resize(VerdefIndex + 1); Verdefs[VerdefIndex] = CurVerdef; } return Verdefs; } // Fully parse the shared object file. This must be called after parseSoName(). template void SharedFile::parseRest() { // Create mapping from version identifiers to Elf_Verdef entries. const Elf_Versym *Versym = nullptr; Verdefs = parseVerdefs(Versym); ArrayRef 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 = VER_NDX_GLOBAL; if (Versym) { VersymIndex = Versym->vs_index; ++Versym; } bool Hidden = VersymIndex & VERSYM_HIDDEN; VersymIndex = VersymIndex & ~VERSYM_HIDDEN; StringRef Name = CHECK(Sym.getName(this->StringTable), this); if (Sym.isUndefined()) { Undefs.push_back(Name); continue; } if (Sym.getBinding() == STB_LOCAL) { warn("found local symbol '" + Name + "' in global part of symbol table in file " + toString(this)); continue; } if (Config->EMachine == EM_MIPS) { // FIXME: MIPS BFD linker puts _gp_disp symbol into DSO files // and incorrectly assigns VER_NDX_LOCAL to this section global // symbol. Here is a workaround for this bug. if (Versym && VersymIndex == VER_NDX_LOCAL && Name == "_gp_disp") 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; } // 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) Symtab->addShared(Name, *this, Sym, Alignment, VersymIndex); // Also add the symbol with the versioned name to handle undefined symbols // with explicit versions. if (Ver) { StringRef VerName = this->StringTable.data() + Ver->getAux()->vda_name; Name = Saver.save(Name + "@" + VerName); Symtab->addShared(Name, *this, Sym, Alignment, VersymIndex); } } } static ELFKind getBitcodeELFKind(const Triple &T) { if (T.isLittleEndian()) return T.isArch64Bit() ? ELF64LEKind : ELF32LEKind; return T.isArch64Bit() ? ELF64BEKind : ELF32BEKind; } 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::avr: return EM_AVR; case Triple::mips: case Triple::mipsel: case Triple::mips64: case Triple::mips64el: return EM_MIPS; case Triple::ppc: return EM_PPC; case Triple::ppc64: return EM_PPC64; case Triple::x86: return T.isOSIAMCU() ? EM_IAMCU : EM_386; case Triple::x86_64: return EM_X86_64; default: fatal(Path + ": could not infer e_machine from bitcode target triple " + T.str()); } } 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), this); Triple T(Obj->getTargetTriple()); EKind = getBitcodeELFKind(T); EMachine = getBitcodeMachineKind(MB.getBufferIdentifier(), T); } static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) { switch (GvVisibility) { case GlobalValue::DefaultVisibility: return STV_DEFAULT; case GlobalValue::HiddenVisibility: return STV_HIDDEN; case GlobalValue::ProtectedVisibility: return STV_PROTECTED; } llvm_unreachable("unknown visibility"); } template static Symbol *createBitcodeSymbol(const std::vector &KeptComdats, const lto::InputFile::Symbol &ObjSym, BitcodeFile &F) { StringRef NameRef = Saver.save(ObjSym.getName()); 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 = ObjSym.getComdatIndex(); if (C != -1 && !KeptComdats[C]) return Symtab->addUndefined(NameRef, Binding, Visibility, Type, CanOmitFromDynSym, &F); if (ObjSym.isUndefined()) return Symtab->addUndefined(NameRef, Binding, Visibility, Type, CanOmitFromDynSym, &F); if (ObjSym.isCommon()) return Symtab->addCommon(NameRef, ObjSym.getCommonSize(), ObjSym.getCommonAlignment(), Binding, Visibility, STT_OBJECT, F); return Symtab->addBitcode(NameRef, Binding, Visibility, Type, CanOmitFromDynSym, F); } template void BitcodeFile::parse(DenseSet &ComdatGroups) { std::vector KeptComdats; 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(KeptComdats, ObjSym, *this)); } static ELFKind getELFKind(MemoryBufferRef MB) { unsigned char Size; unsigned char Endian; std::tie(Size, Endian) = getElfArchType(MB.getBuffer()); if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB) fatal(MB.getBufferIdentifier() + ": invalid data encoding"); if (Size != ELFCLASS32 && Size != ELFCLASS64) fatal(MB.getBufferIdentifier() + ": invalid file class"); size_t BufSize = MB.getBuffer().size(); if ((Size == ELFCLASS32 && BufSize < sizeof(Elf32_Ehdr)) || (Size == ELFCLASS64 && BufSize < sizeof(Elf64_Ehdr))) fatal(MB.getBufferIdentifier() + ": file is too short"); if (Size == ELFCLASS32) return (Endian == ELFDATA2LSB) ? ELF32LEKind : ELF32BEKind; return (Endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind; } void BinaryFile::parse() { ArrayRef Data = toArrayRef(MB.getBuffer()); auto *Section = make(nullptr, SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 8, Data, ".data"); Sections.push_back(Section); // For each input file foo that is embedded to a result as a binary // blob, we define _binary_foo_{start,end,size} symbols, so that // user programs can access blobs by name. Non-alphanumeric // 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])) S[I] = '_'; Symtab->addRegular(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT, 0, 0, STB_GLOBAL, Section, nullptr); Symtab->addRegular(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT, Data.size(), 0, STB_GLOBAL, Section, nullptr); Symtab->addRegular(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT, Data.size(), 0, STB_GLOBAL, nullptr, nullptr); } static bool isBitcode(MemoryBufferRef MB) { using namespace sys::fs; return identify_magic(MB.getBuffer()) == file_magic::bitcode; } InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName, uint64_t OffsetInArchive) { if (isBitcode(MB)) return make(MB, ArchiveName, OffsetInArchive); switch (getELFKind(MB)) { case ELF32LEKind: return make>(MB, ArchiveName); case ELF32BEKind: return make>(MB, ArchiveName); case ELF64LEKind: return make>(MB, ArchiveName); case ELF64BEKind: return make>(MB, ArchiveName); default: llvm_unreachable("getELFKind"); } } InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) { switch (getELFKind(MB)) { case ELF32LEKind: return make>(MB, DefaultSoName); case ELF32BEKind: return make>(MB, DefaultSoName); case ELF64LEKind: return make>(MB, DefaultSoName); case ELF64BEKind: return make>(MB, DefaultSoName); default: llvm_unreachable("getELFKind"); } } MemoryBufferRef LazyObjFile::getBuffer() { if (Seen) return MemoryBufferRef(); Seen = true; return MB; } InputFile *LazyObjFile::fetch() { MemoryBufferRef MBRef = getBuffer(); if (MBRef.getBuffer().empty()) return nullptr; return createObjectFile(MBRef, ArchiveName, OffsetInArchive); } template void LazyObjFile::parse() { for (StringRef Sym : getSymbolNames()) Symtab->addLazyObject(Sym, *this); } template std::vector LazyObjFile::getElfSymbols() { typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::SymRange Elf_Sym_Range; ELFFile Obj = check(ELFFile::create(this->MB.getBuffer())); ArrayRef 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), this); uint32_t FirstNonLocal = Sec.sh_info; StringRef StringTable = CHECK(Obj.getStringTableForSymtab(Sec, Sections), this); std::vector V; for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal)) if (Sym.st_shndx != SHN_UNDEF) V.push_back(CHECK(Sym.getName(StringTable), this)); return V; } return {}; } std::vector LazyObjFile::getBitcodeSymbols() { std::unique_ptr Obj = CHECK(lto::InputFile::create(this->MB), this); std::vector V; for (const lto::InputFile::Symbol &Sym : Obj->symbols()) if (!Sym.isUndefined()) V.push_back(Saver.save(Sym.getName())); return V; } // Returns a vector of globally-visible defined symbol names. std::vector LazyObjFile::getSymbolNames() { if (isBitcode(this->MB)) return getBitcodeSymbols(); switch (getELFKind(this->MB)) { case ELF32LEKind: return getElfSymbols(); case ELF32BEKind: return getElfSymbols(); case ELF64LEKind: return getElfSymbols(); case ELF64BEKind: return getElfSymbols(); default: llvm_unreachable("getELFKind"); } } template void ArchiveFile::parse(); template void ArchiveFile::parse(); template void ArchiveFile::parse(); template void ArchiveFile::parse(); template void BitcodeFile::parse(DenseSet &); template void BitcodeFile::parse(DenseSet &); template void BitcodeFile::parse(DenseSet &); template void BitcodeFile::parse(DenseSet &); template void LazyObjFile::parse(); template void LazyObjFile::parse(); template void LazyObjFile::parse(); template void LazyObjFile::parse(); template class elf::ELFFileBase; template class elf::ELFFileBase; template class elf::ELFFileBase; template class elf::ELFFileBase; template class elf::ObjFile; template class elf::ObjFile; template class elf::ObjFile; template class elf::ObjFile; template class elf::SharedFile; template class elf::SharedFile; template class elf::SharedFile; template class elf::SharedFile; Index: head/contrib/llvm/tools/lld/ELF/InputFiles.h =================================================================== --- head/contrib/llvm/tools/lld/ELF/InputFiles.h (revision 331730) +++ head/contrib/llvm/tools/lld/ELF/InputFiles.h (revision 331731) @@ -1,348 +1,349 @@ //===- InputFiles.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_INPUT_FILES_H #define LLD_ELF_INPUT_FILES_H #include "Config.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/LLVM.h" #include "lld/Common/Reproduce.h" #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/IR/Comdat.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ELF.h" #include "llvm/Object/IRObjectFile.h" #include "llvm/Support/Threading.h" #include namespace llvm { class DWARFDebugLine; class TarWriter; struct DILineInfo; namespace lto { class InputFile; } } // namespace llvm namespace lld { namespace elf { class InputFile; class InputSectionBase; } // Returns "", "foo.a(bar.o)" or "baz.o". std::string toString(const elf::InputFile *F); namespace elf { using llvm::object::Archive; class Lazy; class Symbol; // If -reproduce option is given, all input files are written // to this tar archive. extern llvm::TarWriter *Tar; // Opens a given file. llvm::Optional readFile(StringRef Path); // The root class of input files. class InputFile { public: enum Kind { ObjKind, SharedKind, LazyObjKind, ArchiveKind, BitcodeKind, BinaryKind, }; Kind kind() const { return FileKind; } bool isElf() const { Kind K = kind(); return K == ObjKind || K == SharedKind; } StringRef getName() const { return MB.getBufferIdentifier(); } MemoryBufferRef MB; // Returns sections. It is a runtime error to call this function // on files that don't have the notion of sections. ArrayRef getSections() const { assert(FileKind == ObjKind || FileKind == BinaryKind); return Sections; } // Returns object file symbols. It is a runtime error to call this // function on files of other types. ArrayRef getSymbols() { assert(FileKind == ObjKind || FileKind == BitcodeKind || FileKind == ArchiveKind); return Symbols; } // Filename of .a which contained this file. If this file was // not in an archive file, it is the empty string. We use this // string for creating error messages. StringRef ArchiveName; // If this is an architecture-specific file, the following members // have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type. ELFKind EKind = ELFNoneKind; uint16_t EMachine = llvm::ELF::EM_NONE; uint8_t OSABI = 0; // Cache for toString(). Only toString() should use this member. mutable std::string ToStringCache; std::string getSrcMsg(const Symbol &Sym, InputSectionBase &Sec, uint64_t Offset); protected: InputFile(Kind K, MemoryBufferRef M); std::vector Sections; std::vector Symbols; private: const Kind FileKind; }; template class ELFFileBase : public InputFile { public: typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::Word Elf_Word; typedef typename ELFT::SymRange Elf_Sym_Range; ELFFileBase(Kind K, MemoryBufferRef M); static bool classof(const InputFile *F) { return F->isElf(); } llvm::object::ELFFile getObj() const { return check(llvm::object::ELFFile::create(MB.getBuffer())); } StringRef getStringTable() const { return StringTable; } uint32_t getSectionIndex(const Elf_Sym &Sym) const; Elf_Sym_Range getGlobalELFSyms(); Elf_Sym_Range getELFSyms() const { return ELFSyms; } protected: ArrayRef ELFSyms; uint32_t FirstNonLocal = 0; ArrayRef SymtabSHNDX; StringRef StringTable; void initSymtab(ArrayRef Sections, const Elf_Shdr *Symtab); }; // .o file. template class ObjFile : public ELFFileBase { typedef ELFFileBase Base; typedef typename ELFT::Rel Elf_Rel; typedef typename ELFT::Rela Elf_Rela; typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Word Elf_Word; StringRef getShtGroupSignature(ArrayRef Sections, const Elf_Shdr &Sec); ArrayRef getShtGroupEntries(const Elf_Shdr &Sec); public: static bool classof(const InputFile *F) { return F->kind() == Base::ObjKind; } ArrayRef getLocalSymbols(); + ArrayRef getGlobalSymbols(); ObjFile(MemoryBufferRef M, StringRef ArchiveName); void parse(llvm::DenseSet &ComdatGroups); Symbol &getSymbol(uint32_t SymbolIndex) const { if (SymbolIndex >= this->Symbols.size()) fatal(toString(this) + ": invalid symbol index"); return *this->Symbols[SymbolIndex]; } template Symbol &getRelocTargetSym(const RelT &Rel) const { uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL); return getSymbol(SymIndex); } // Returns source line information for a given offset. // If no information is available, returns "". std::string getLineInfo(InputSectionBase *S, uint64_t Offset); llvm::Optional getDILineInfo(InputSectionBase *, uint64_t); llvm::Optional> getVariableLoc(StringRef Name); // MIPS GP0 value defined by this file. This value represents the gp value // used to create the relocatable object and required to support // R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations. uint32_t MipsGp0 = 0; // Name of source file obtained from STT_FILE symbol value, // or empty string if there is no such symbol in object file // symbol table. StringRef SourceFile; private: void initializeSections(llvm::DenseSet &ComdatGroups); void initializeSymbols(); void initializeDwarf(); InputSectionBase *getRelocTarget(const Elf_Shdr &Sec); InputSectionBase *createInputSection(const Elf_Shdr &Sec); StringRef getSectionName(const Elf_Shdr &Sec); bool shouldMerge(const Elf_Shdr &Sec); Symbol *createSymbol(const Elf_Sym *Sym); // .shstrtab contents. StringRef SectionStringTable; // Debugging information to retrieve source file and line for error // reporting. Linker may find reasonable number of errors in a // single object file, so we cache debugging information in order to // parse it only once for each object file we link. std::unique_ptr DwarfLine; llvm::DenseMap> VariableLoc; llvm::once_flag InitDwarfLine; }; // LazyObjFile is analogous to ArchiveFile in the sense that // the file contains lazy symbols. The difference is that // LazyObjFile wraps a single file instead of multiple files. // // This class is used for --start-lib and --end-lib options which // instruct the linker to link object files between them with the // archive file semantics. class LazyObjFile : public InputFile { public: LazyObjFile(MemoryBufferRef M, StringRef ArchiveName, uint64_t OffsetInArchive) : InputFile(LazyObjKind, M), OffsetInArchive(OffsetInArchive) { this->ArchiveName = ArchiveName; } static bool classof(const InputFile *F) { return F->kind() == LazyObjKind; } template void parse(); MemoryBufferRef getBuffer(); InputFile *fetch(); private: std::vector getSymbolNames(); template std::vector getElfSymbols(); std::vector getBitcodeSymbols(); bool Seen = false; uint64_t OffsetInArchive; }; // An ArchiveFile object represents a .a file. class ArchiveFile : public InputFile { public: explicit ArchiveFile(std::unique_ptr &&File); static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } template void parse(); // Returns a memory buffer for a given symbol and the offset in the archive // for the member. An empty memory buffer and an offset of zero // is returned if we have already returned the same memory buffer. // (So that we don't instantiate same members more than once.) std::pair getMember(const Archive::Symbol *Sym); private: std::unique_ptr File; llvm::DenseSet Seen; }; class BitcodeFile : public InputFile { public: BitcodeFile(MemoryBufferRef M, StringRef ArchiveName, uint64_t OffsetInArchive); static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } template void parse(llvm::DenseSet &ComdatGroups); std::unique_ptr Obj; }; // .so file. template class SharedFile : public ELFFileBase { typedef ELFFileBase Base; typedef typename ELFT::Dyn Elf_Dyn; typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::SymRange Elf_Sym_Range; typedef typename ELFT::Verdef Elf_Verdef; typedef typename ELFT::Versym Elf_Versym; std::vector Undefs; const Elf_Shdr *VersymSec = nullptr; const Elf_Shdr *VerdefSec = nullptr; public: std::vector Verdefs; std::string SoName; llvm::ArrayRef getUndefinedSymbols() { return Undefs; } static bool classof(const InputFile *F) { return F->kind() == Base::SharedKind; } SharedFile(MemoryBufferRef M, StringRef DefaultSoName); void parseSoName(); void parseRest(); std::vector parseVerdefs(const Elf_Versym *&Versym); struct NeededVer { // The string table offset of the version name in the output file. size_t StrTab; // The version identifier for this version name. uint16_t Index; }; // Mapping from Elf_Verdef data structures to information about Elf_Vernaux // data structures in the output file. std::map VerdefMap; // Used for --as-needed bool IsNeeded; }; class BinaryFile : public InputFile { public: explicit BinaryFile(MemoryBufferRef M) : InputFile(BinaryKind, M) {} static bool classof(const InputFile *F) { return F->kind() == BinaryKind; } void parse(); }; InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "", uint64_t OffsetInArchive = 0); InputFile *createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName); extern std::vector BinaryFiles; extern std::vector BitcodeFiles; extern std::vector ObjectFiles; extern std::vector SharedFiles; } // namespace elf } // namespace lld #endif Index: head/contrib/llvm/tools/lld/ELF/SymbolTable.cpp =================================================================== --- head/contrib/llvm/tools/lld/ELF/SymbolTable.cpp (revision 331730) +++ head/contrib/llvm/tools/lld/ELF/SymbolTable.cpp (revision 331731) @@ -1,836 +1,839 @@ //===- 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 "LinkerScript.h" #include "Symbols.h" #include "SyntheticSections.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" #include "lld/Common/Strings.h" #include "llvm/ADT/STLExtras.h" using namespace llvm; using namespace llvm::object; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; SymbolTable *elf::Symtab; static InputFile *getFirstElf() { if (!ObjectFiles.empty()) return ObjectFiles[0]; if (!SharedFiles.empty()) return SharedFiles[0]; return nullptr; } // 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. static bool isCompatible(InputFile *F) { if (!F->isElf() && !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(getFirstElf())); 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) message(toString(File)); // .so file if (auto *F = dyn_cast>(File)) { // DSOs are uniquified not by filename but by soname. F->parseSoName(); if (errorCount() || !SoNames.insert(F->SoName).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 ObjectFiles.push_back(File); cast>(File)->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()) { DenseSet DummyGroups; - cast>(File)->parse(DummyGroups); + auto *Obj = cast>(File); + Obj->parse(DummyGroups); + for (Symbol *Sym : Obj->getGlobalSymbols()) + Sym->parseSymbolVersion(); ObjectFiles.push_back(File); } } Defined *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); } // 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. void SymbolTable::trace(StringRef Name) { SymMap.insert({CachedHashStringRef(Name), -1}); } // Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM. // Used to implement --wrap. template void SymbolTable::addSymbolWrap(StringRef Name) { Symbol *Sym = find(Name); if (!Sym) return; Symbol *Real = addUndefined(Saver.save("__real_" + Name)); Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name)); WrappedSymbols.push_back({Sym, Real, Wrap}); // We want to tell LTO not to inline symbols to be overwritten // because LTO doesn't know the final symbol contents after renaming. Real->CanInline = false; Sym->CanInline = false; // Tell LTO not to eliminate these symbols. Sym->IsUsedInRegularObj = true; Wrap->IsUsedInRegularObj = true; } // Apply symbol renames created by -wrap. The renames are created // before LTO in addSymbolWrap() to have a chance to inform LTO (if // LTO is running) not to include these symbols in IPO. Now that the // symbols are finalized, we can perform the replacement. void SymbolTable::applySymbolWrap() { // This function rotates 3 symbols: // // __real_sym becomes sym // sym becomes __wrap_sym // __wrap_sym becomes __real_sym // // The last part is special in that we don't want to change what references to // __wrap_sym point to, we just want have __real_sym in the symbol table. for (WrappedSymbol &W : WrappedSymbols) { // First, make a copy of __real_sym. Symbol *Real = nullptr; if (W.Real->isDefined()) { Real = (Symbol *)make(); memcpy(Real, W.Real, sizeof(SymbolUnion)); } // Replace __real_sym with sym and sym with __wrap_sym. memcpy(W.Real, W.Sym, sizeof(SymbolUnion)); memcpy(W.Sym, W.Wrap, sizeof(SymbolUnion)); // We now have two copies of __wrap_sym. Drop one. W.Wrap->IsUsedInRegularObj = false; if (Real) SymVector.push_back(Real); } } 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. std::pair SymbolTable::insert(StringRef Name) { // @@ means the symbol is the default version. In that // case @@ will be used to resolve references to . // // Since this is a hot path, the following string search code is // optimized for speed. StringRef::find(char) is much faster than // StringRef::find(StringRef). size_t Pos = Name.find('@'); if (Pos != StringRef::npos && Pos + 1 < Name.size() && Name[Pos + 1] == '@') Name = Name.take_front(Pos); auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()}); int &SymIndex = P.first->second; bool IsNew = P.second; bool Traced = false; if (SymIndex == -1) { SymIndex = SymVector.size(); IsNew = Traced = true; } Symbol *Sym; if (IsNew) { Sym = (Symbol *)make(); Sym->InVersionScript = false; Sym->Visibility = STV_DEFAULT; Sym->IsUsedInRegularObj = false; Sym->ExportDynamic = false; Sym->CanInline = true; Sym->Traced = Traced; Sym->VersionId = Config->DefaultSymbolVersion; SymVector.push_back(Sym); } else { Sym = SymVector[SymIndex]; } return {Sym, IsNew}; } // Find an existing symbol or create and insert a new one, then apply the given // attributes. std::pair SymbolTable::insert(StringRef Name, uint8_t Type, uint8_t Visibility, bool CanOmitFromDynSym, InputFile *File) { 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 (!File || File->kind() == InputFile::ObjKind) S->IsUsedInRegularObj = true; if (!WasInserted && S->Type != Symbol::UnknownType && ((Type == STT_TLS) != S->isTls())) { error("TLS attribute mismatch: " + toString(*S) + "\n>>> defined in " + toString(S->File) + "\n>>> defined in " + toString(File)); } return {S, WasInserted}; } template Symbol *SymbolTable::addUndefined(StringRef Name) { return addUndefined(Name, 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, uint8_t Binding, uint8_t StOther, uint8_t Type, bool CanOmitFromDynSym, InputFile *File) { Symbol *S; bool WasInserted; uint8_t Visibility = getVisibility(StOther); std::tie(S, WasInserted) = insert(Name, Type, Visibility, CanOmitFromDynSym, File); // An undefined symbol with non default visibility must be satisfied // in the same DSO. if (WasInserted || (isa(S) && Visibility != STV_DEFAULT)) { replaceSymbol(S, File, Name, Binding, StOther, Type); return S; } if (S->isShared() || S->isLazy() || (S->isUndefined() && Binding != STB_WEAK)) S->Binding = Binding; if (Binding != STB_WEAK) { if (auto *SS = dyn_cast(S)) if (!Config->GcSections) SS->getFile().IsNeeded = true; } if (auto *L = dyn_cast(S)) { // An undefined weak will not fetch archive members. See comment on Lazy in // Symbols.h for the details. if (Binding == STB_WEAK) L->Type = Type; else if (InputFile *F = L->fetch()) addFile(F); } return S; } // Using .symver foo,foo@@VER unfortunately creates two symbols: foo and // foo@@VER. We want to effectively ignore foo, so give precedence to // foo@@VER. // FIXME: If users can transition to using // .symver foo,foo@@@VER // we can delete this hack. static int compareVersion(Symbol *S, StringRef Name) { bool A = Name.contains("@@"); bool B = S->getName().contains("@@"); if (A && !B) return 1; if (!A && B) return -1; return 0; } // 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, StringRef Name) { if (WasInserted) return 1; if (!S->isDefined()) return 1; if (int R = compareVersion(S, Name)) return R; 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. static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding, bool IsAbsolute, uint64_t Value, StringRef Name) { if (int Cmp = compareDefined(S, WasInserted, Binding, Name)) return Cmp; if (auto *R = dyn_cast(S)) { if (R->Section && isa(R->Section)) { // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) warn("common " + S->getName() + " is overridden"); return 1; } if (R->Section == nullptr && Binding == STB_GLOBAL && IsAbsolute && R->Value == Value) return -1; } return 0; } Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_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, N); if (Cmp > 0) { auto *Bss = make("COMMON", Size, Alignment); Bss->File = &File; Bss->Live = !Config->GcSections; InputSections.push_back(Bss); replaceSymbol(S, &File, N, Binding, StOther, Type, 0, Size, Bss); } else if (Cmp == 0) { auto *D = cast(S); auto *Bss = dyn_cast_or_null(D->Section); if (!Bss) { // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) warn("common " + S->getName() + " is overridden"); return S; } if (Config->WarnCommon) warn("multiple common of " + D->getName()); Bss->Alignment = std::max(Bss->Alignment, Alignment); if (Size > Bss->Size) { D->File = Bss->File = &File; D->Size = Bss->Size = Size; } } return S; } static void warnOrError(const Twine &Msg) { if (Config->AllowMultipleDefinition) warn(Msg); else error(Msg); } static void reportDuplicate(Symbol *Sym, InputFile *NewFile) { warnOrError("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " + toString(Sym->File) + "\n>>> defined in " + toString(NewFile)); } static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec, uint64_t ErrOffset) { Defined *D = cast(Sym); if (!D->Section || !ErrSec) { reportDuplicate(Sym, ErrSec ? ErrSec->File : nullptr); return; } // Construct and print an error message in the form of: // // ld.lld: error: duplicate symbol: foo // >>> defined at bar.c:30 // >>> bar.o (/home/alice/src/bar.o) // >>> defined at baz.c:563 // >>> baz.o in archive libbaz.a auto *Sec1 = cast(D->Section); std::string Src1 = Sec1->getSrcMsg(*Sym, D->Value); std::string Obj1 = Sec1->getObjMsg(D->Value); std::string Src2 = ErrSec->getSrcMsg(*Sym, ErrOffset); std::string Obj2 = ErrSec->getObjMsg(ErrOffset); std::string Msg = "duplicate symbol: " + toString(*Sym) + "\n>>> defined at "; if (!Src1.empty()) Msg += Src1 + "\n>>> "; Msg += Obj1 + "\n>>> defined at "; if (!Src2.empty()) Msg += Src2 + "\n>>> "; Msg += Obj2; warnOrError(Msg); } Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size, uint8_t Binding, SectionBase *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, Name); if (Cmp > 0) replaceSymbol(S, File, Name, Binding, StOther, Type, Value, Size, Section); else if (Cmp == 0) reportDuplicate(S, dyn_cast_or_null(Section), Value); return S; } template void SymbolTable::addShared(StringRef Name, SharedFile &File, const typename ELFT::Sym &Sym, uint32_t Alignment, uint32_t VerdefIndex) { // 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, &File); // Make sure we preempt DSO symbols with default visibility. if (Sym.getVisibility() == STV_DEFAULT) S->ExportDynamic = true; // An undefined symbol with non default visibility must be satisfied // in the same DSO. if (WasInserted || ((S->isUndefined() || S->isLazy()) && S->getVisibility() == STV_DEFAULT)) { uint8_t Binding = S->Binding; bool WasUndefined = S->isUndefined(); replaceSymbol(S, File, Name, Sym.getBinding(), Sym.st_other, Sym.getType(), Sym.st_value, Sym.st_size, Alignment, VerdefIndex); if (!WasInserted) { S->Binding = Binding; if (!S->isWeak() && !Config->GcSections && WasUndefined) File.IsNeeded = true; } } } 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, Name); if (Cmp > 0) replaceSymbol(S, &F, Name, Binding, StOther, Type, 0, 0, nullptr); else if (Cmp == 0) reportDuplicate(S, &F); return S; } Symbol *SymbolTable::find(StringRef Name) { auto It = SymMap.find(CachedHashStringRef(Name)); if (It == SymMap.end()) return nullptr; if (It->second == -1) return nullptr; return SymVector[It->second]; } template Symbol *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F, const object::Archive::Symbol Sym) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); if (WasInserted) { replaceSymbol(S, F, Sym, Symbol::UnknownType); return S; } if (!S->isUndefined()) return S; // An undefined weak will not fetch archive members. See comment on Lazy in // Symbols.h for the details. if (S->isWeak()) { replaceSymbol(S, F, Sym, S->Type); S->Binding = STB_WEAK; return S; } std::pair MBInfo = F.getMember(&Sym); if (!MBInfo.first.getBuffer().empty()) addFile(createObjectFile(MBInfo.first, F.getName(), MBInfo.second)); return S; } template void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); if (WasInserted) { replaceSymbol(S, Obj, Name, Symbol::UnknownType); return; } if (!S->isUndefined()) return; // See comment for addLazyArchive above. if (S->isWeak()) replaceSymbol(S, Obj, Name, S->Type); else if (InputFile *F = Obj.fetch()) addFile(F); } // If we already saw this symbol, force loading its file. template void SymbolTable::fetchIfLazy(StringRef Name) { if (Symbol *B = find(Name)) { // Mark the symbol not to be eliminated by LTO // even if it is a bitcode symbol. B->IsUsedInRegularObj = true; if (auto *L = dyn_cast(B)) 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 (InputFile *F : SharedFiles) { for (StringRef U : cast>(F)->getUndefinedSymbols()) { Symbol *Sym = find(U); if (!Sym || !Sym->isDefined()) continue; Sym->ExportDynamic = true; // If -dynamic-list is given, the default version is set to // VER_NDX_LOCAL, which prevents a symbol to be exported via .dynsym. // Set to VER_NDX_GLOBAL so the symbol will be handled as if it were // specified by -dynamic-list. Sym->VersionId = VER_NDX_GLOBAL; } } } // 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. StringMap> &SymbolTable::getDemangledSyms() { if (!DemangledSyms) { DemangledSyms.emplace(); for (Symbol *Sym : SymVector) { if (!Sym->isDefined()) continue; if (Optional S = demangleItanium(Sym->getName())) (*DemangledSyms)[*S].push_back(Sym); else (*DemangledSyms)[Sym->getName()].push_back(Sym); } } return *DemangledSyms; } std::vector SymbolTable::findByVersion(SymbolVersion Ver) { if (Ver.IsExternCpp) return getDemangledSyms().lookup(Ver.Name); if (Symbol *B = find(Ver.Name)) if (B->isDefined()) return {B}; return {}; } 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) if (Sym->isDefined() && M.match(Sym->getName())) Res.push_back(Sym); 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. 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); } // Handles -dynamic-list. void SymbolTable::handleDynamicList() { for (SymbolVersion &Ver : Config->DynamicList) { std::vector Syms; if (Ver.HasWildcard) Syms = findAllByVersion(Ver); else Syms = findByVersion(Ver); for (Symbol *B : Syms) { if (!Config->Shared) B->ExportDynamic = true; else if (B->includeInDynsym()) B->IsPreemptible = true; } } } // Set symbol versions to symbols. This function handles patterns // containing no wildcard characters. 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 (Symbol *Sym : Syms) { // Skip symbols containing version info because symbol versions // specified by symbol names take precedence over version scripts. // See parseSymbolVersion(). if (Sym->getName().contains('@')) continue; if (Sym->InVersionScript) warn("duplicate symbol '" + Ver.Name + "' in version script"); Sym->VersionId = VersionId; Sym->InVersionScript = true; } } void SymbolTable::assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId) { if (!Ver.HasWildcard) return; // 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 (Symbol *B : findAllByVersion(Ver)) if (B->VersionId == Config->DefaultSymbolVersion) B->VersionId = VersionId; } // This function processes version scripts by updating VersionId // member of symbols. void SymbolTable::scanVersionScript() { // Handle edge cases first. handleAnonymousVersion(); handleDynamicList(); // 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); // Symbol themselves might know their versions because symbols // can contain versions in the form of @. // Let them parse and update their names to exclude version suffix. for (Symbol *Sym : SymVector) Sym->parseSymbolVersion(); } template void SymbolTable::addSymbolWrap(StringRef); template void SymbolTable::addSymbolWrap(StringRef); template void SymbolTable::addSymbolWrap(StringRef); template void SymbolTable::addSymbolWrap(StringRef); template Symbol *SymbolTable::addUndefined(StringRef); template Symbol *SymbolTable::addUndefined(StringRef); template Symbol *SymbolTable::addUndefined(StringRef); template Symbol *SymbolTable::addUndefined(StringRef); template Symbol *SymbolTable::addUndefined(StringRef, uint8_t, uint8_t, uint8_t, bool, InputFile *); template Symbol *SymbolTable::addUndefined(StringRef, uint8_t, uint8_t, uint8_t, bool, InputFile *); template Symbol *SymbolTable::addUndefined(StringRef, uint8_t, uint8_t, uint8_t, bool, InputFile *); template Symbol *SymbolTable::addUndefined(StringRef, uint8_t, uint8_t, uint8_t, bool, InputFile *); template void SymbolTable::addCombinedLTOObject(); template void SymbolTable::addCombinedLTOObject(); template void SymbolTable::addCombinedLTOObject(); template void SymbolTable::addCombinedLTOObject(); template Symbol * SymbolTable::addLazyArchive(StringRef, ArchiveFile &, const object::Archive::Symbol); template Symbol * SymbolTable::addLazyArchive(StringRef, ArchiveFile &, const object::Archive::Symbol); template Symbol * SymbolTable::addLazyArchive(StringRef, ArchiveFile &, const object::Archive::Symbol); template Symbol * SymbolTable::addLazyArchive(StringRef, ArchiveFile &, const object::Archive::Symbol); template void SymbolTable::addLazyObject(StringRef, LazyObjFile &); template void SymbolTable::addLazyObject(StringRef, LazyObjFile &); template void SymbolTable::addLazyObject(StringRef, LazyObjFile &); template void SymbolTable::addLazyObject(StringRef, LazyObjFile &); template void SymbolTable::addShared(StringRef, SharedFile &, const typename ELF32LE::Sym &, uint32_t Alignment, uint32_t); template void SymbolTable::addShared(StringRef, SharedFile &, const typename ELF32BE::Sym &, uint32_t Alignment, uint32_t); template void SymbolTable::addShared(StringRef, SharedFile &, const typename ELF64LE::Sym &, uint32_t Alignment, uint32_t); template void SymbolTable::addShared(StringRef, SharedFile &, const typename ELF64BE::Sym &, uint32_t Alignment, uint32_t); template void SymbolTable::fetchIfLazy(StringRef); template void SymbolTable::fetchIfLazy(StringRef); template void SymbolTable::fetchIfLazy(StringRef); template void SymbolTable::fetchIfLazy(StringRef); template void SymbolTable::scanShlibUndefined(); template void SymbolTable::scanShlibUndefined(); template void SymbolTable::scanShlibUndefined(); template void SymbolTable::scanShlibUndefined();