diff options
Diffstat (limited to 'ELF/InputFiles.cpp')
-rw-r--r-- | ELF/InputFiles.cpp | 231 |
1 files changed, 87 insertions, 144 deletions
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index 98b88283cf09..fdf935a30856 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -17,7 +17,6 @@ #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" @@ -37,18 +36,31 @@ using namespace llvm::sys; using namespace llvm::sys::fs; using namespace llvm::support::endian; -using namespace lld; -using namespace lld::elf; +namespace lld { +// Returns "<internal>", "foo.a(bar.o)" or "baz.o". +std::string toString(const elf::InputFile *f) { + if (!f) + return "<internal>"; + + if (f->toStringCache.empty()) { + if (f->archiveName.empty()) + f->toStringCache = f->getName(); + else + f->toStringCache = (f->archiveName + "(" + f->getName() + ")").str(); + } + return f->toStringCache; +} +namespace elf { bool InputFile::isInGroup; uint32_t InputFile::nextGroupId; -std::vector<BinaryFile *> elf::binaryFiles; -std::vector<BitcodeFile *> elf::bitcodeFiles; -std::vector<LazyObjFile *> elf::lazyObjFiles; -std::vector<InputFile *> elf::objectFiles; -std::vector<SharedFile *> elf::sharedFiles; +std::vector<BinaryFile *> binaryFiles; +std::vector<BitcodeFile *> bitcodeFiles; +std::vector<LazyObjFile *> lazyObjFiles; +std::vector<InputFile *> objectFiles; +std::vector<SharedFile *> sharedFiles; -std::unique_ptr<TarWriter> elf::tar; +std::unique_ptr<TarWriter> tar; static ELFKind getELFKind(MemoryBufferRef mb, StringRef archiveName) { unsigned char size; @@ -88,7 +100,7 @@ InputFile::InputFile(Kind k, MemoryBufferRef m) ++nextGroupId; } -Optional<MemoryBufferRef> elf::readFile(StringRef path) { +Optional<MemoryBufferRef> 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("/")) @@ -127,18 +139,18 @@ static bool isCompatible(InputFile *file) { if (!config->emulation.empty()) { error(toString(file) + " is incompatible with " + config->emulation); - } else { - InputFile *existing; - if (!objectFiles.empty()) - existing = objectFiles[0]; - else if (!sharedFiles.empty()) - existing = sharedFiles[0]; - else - existing = bitcodeFiles[0]; - - error(toString(file) + " is incompatible with " + toString(existing)); + return false; } + InputFile *existing; + if (!objectFiles.empty()) + existing = objectFiles[0]; + else if (!sharedFiles.empty()) + existing = sharedFiles[0]; + else + existing = bitcodeFiles[0]; + + error(toString(file) + " is incompatible with " + toString(existing)); return false; } @@ -188,7 +200,7 @@ template <class ELFT> static void doParseFile(InputFile *file) { } // Add symbols in File to the symbol table. -void elf::parseFile(InputFile *file) { +void parseFile(InputFile *file) { switch (config->ekind) { case ELF32LEKind: doParseFile<ELF32LE>(file); @@ -252,57 +264,8 @@ std::string InputFile::getSrcMsg(const Symbol &sym, InputSectionBase &sec, } template <class ELFT> void ObjFile<ELFT>::initializeDwarf() { - dwarf = llvm::make_unique<DWARFContext>(make_unique<LLDDwarfObj<ELFT>>(this)); - for (std::unique_ptr<DWARFUnit> &cu : dwarf->compile_units()) { - auto report = [](Error err) { - handleAllErrors(std::move(err), - [](ErrorInfoBase &info) { warn(info.message()); }); - }; - Expected<const DWARFDebugLine::LineTable *> expectedLT = - dwarf->getLineTableForUnit(cu.get(), report); - const DWARFDebugLine::LineTable *lt = nullptr; - if (expectedLT) - lt = *expectedLT; - else - report(expectedLT.takeError()); - if (!lt) - continue; - lineTables.push_back(lt); - - // Loop over variable records and insert them to variableLoc. - for (const auto &entry : cu->dies()) { - DWARFDie die(cu.get(), &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); - - // Here we want to take the variable name to add it into variableLoc. - // Variable can have regular and linkage name associated. At first, we try - // to get linkage name as it can be different, for example when we have - // two variables in different namespaces of the same object. Use common - // name otherwise, but handle the case when it also absent in case if the - // input object file lacks some debug info. - StringRef name = - dwarf::toString(die.find(dwarf::DW_AT_linkage_name), - dwarf::toString(die.find(dwarf::DW_AT_name), "")); - if (!name.empty()) - variableLoc.insert({name, {lt, file, line}}); - } - } + dwarf = make<DWARFCache>(std::make_unique<DWARFContext>( + std::make_unique<LLDDwarfObj<ELFT>>(this))); } // Returns the pair of file name and line number describing location of data @@ -312,19 +275,7 @@ Optional<std::pair<std::string, unsigned>> ObjFile<ELFT>::getVariableLoc(StringRef name) { llvm::call_once(initDwarfLine, [this]() { initializeDwarf(); }); - // 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 (!it->second.lt->getFileNameByIndex( - it->second.file, {}, - DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, fileName)) - return None; - - return std::make_pair(fileName, it->second.line); + return dwarf->getVariableLoc(name); } // Returns source line information for a given offset @@ -346,28 +297,7 @@ Optional<DILineInfo> ObjFile<ELFT>::getDILineInfo(InputSectionBase *s, // Use fake address calcuated by adding section file offset and offset in // section. See comments for ObjectInfo class. - DILineInfo info; - for (const llvm::DWARFDebugLine::LineTable *lt : lineTables) { - if (lt->getFileLineInfoForAddress( - {s->getOffsetInFile() + offset, sectionIndex}, nullptr, - DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, info)) - return info; - } - return None; -} - -// Returns "<internal>", "foo.a(bar.o)" or "baz.o". -std::string lld::toString(const InputFile *f) { - if (!f) - return "<internal>"; - - if (f->toStringCache.empty()) { - if (f->archiveName.empty()) - f->toStringCache = f->getName(); - else - f->toStringCache = (f->archiveName + "(" + f->getName() + ")").str(); - } - return f->toStringCache; + return dwarf->getDILineInfo(s->getOffsetInFile() + offset, sectionIndex); } ELFFileBase::ELFFileBase(Kind k, MemoryBufferRef mb) : InputFile(k, mb) { @@ -484,7 +414,8 @@ StringRef ObjFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> sections, return signature; } -template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &sec) { +template <class ELFT> +bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &sec, StringRef name) { // On a regular link we don't merge sections if -O0 (default is -O1). This // sometimes makes the linker significantly faster, although the output will // be bigger. @@ -516,14 +447,16 @@ template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &sec) { if (entSize == 0) return false; if (sec.sh_size % entSize) - fatal(toString(this) + - ": SHF_MERGE section size must be a multiple of sh_entsize"); + fatal(toString(this) + ":(" + name + "): SHF_MERGE section size (" + + Twine(sec.sh_size) + ") must be a multiple of sh_entsize (" + + Twine(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"); + fatal(toString(this) + ":(" + name + + "): writable SHF_MERGE section is not supported"); return true; } @@ -573,7 +506,7 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats) { this->sectionStringTable = CHECK(obj.getSectionStringTable(objSections), this); - for (size_t i = 0, e = objSections.size(); i < e; i++) { + for (size_t i = 0, e = objSections.size(); i < e; ++i) { if (this->sections[i] == &InputSection::discarded) continue; const Elf_Shdr &sec = objSections[i]; @@ -652,25 +585,29 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats) { default: this->sections[i] = createInputSection(sec); } + } + + for (size_t i = 0, e = objSections.size(); i < e; ++i) { + if (this->sections[i] == &InputSection::discarded) + continue; + const Elf_Shdr &sec = objSections[i]; + if (!(sec.sh_flags & SHF_LINK_ORDER)) + continue; // .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) { - InputSectionBase *linkSec = nullptr; - if (sec.sh_link < this->sections.size()) - linkSec = this->sections[sec.sh_link]; - if (!linkSec) - fatal(toString(this) + - ": invalid sh_link index: " + Twine(sec.sh_link)); - - InputSection *isec = cast<InputSection>(this->sections[i]); - linkSec->dependentSections.push_back(isec); - if (!isa<InputSection>(linkSec)) - error("a section " + isec->name + - " with SHF_LINK_ORDER should not refer a non-regular " - "section: " + - toString(linkSec)); - } + InputSectionBase *linkSec = nullptr; + if (sec.sh_link < this->sections.size()) + linkSec = this->sections[sec.sh_link]; + if (!linkSec) + fatal(toString(this) + ": invalid sh_link index: " + Twine(sec.sh_link)); + + InputSection *isec = cast<InputSection>(this->sections[i]); + linkSec->dependentSections.push_back(isec); + if (!isa<InputSection>(linkSec)) + error("a section " + isec->name + + " with SHF_LINK_ORDER should not refer a non-regular section: " + + toString(linkSec)); } } @@ -1030,7 +967,7 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &sec) { if (name == ".eh_frame" && !config->relocatable) return make<EhInputSection>(*this, sec, name); - if (shouldMerge(sec)) + if (shouldMerge(sec, name)) return make<MergeInputSection>(*this, sec, name); return make<InputSection>(*this, sec, name); } @@ -1094,6 +1031,7 @@ template <class ELFT> void ObjFile<ELFT>::initializeSymbols() { // Handle global undefined symbols. if (eSym.st_shndx == SHN_UNDEF) { this->symbols[i]->resolve(Undefined{this, name, binding, stOther, type}); + this->symbols[i]->referenced = true; continue; } @@ -1144,7 +1082,7 @@ void ArchiveFile::fetch(const Archive::Symbol &sym) { Archive::Child c = CHECK(sym.getMember(), toString(this) + ": could not get the member for symbol " + - sym.getName()); + toELFString(sym)); if (!seen.insert(c.getChildOffset()).second) return; @@ -1153,7 +1091,7 @@ void ArchiveFile::fetch(const Archive::Symbol &sym) { CHECK(c.getMemoryBufferRef(), toString(this) + ": could not get the buffer for the member defining symbol " + - sym.getName()); + toELFString(sym)); if (tar && c.getParent()->isThin()) tar->append(relativeToRoot(CHECK(c.getFullName(), this)), mb.getBuffer()); @@ -1470,10 +1408,12 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &keptComdats, int c = objSym.getComdatIndex(); if (objSym.isUndefined() || (c != -1 && !keptComdats[c])) { - Undefined New(&f, name, binding, visibility, type); + Undefined newSym(&f, name, binding, visibility, type); if (canOmitFromDynSym) - New.exportDynamic = false; - return symtab->addSymbol(New); + newSym.exportDynamic = false; + Symbol *ret = symtab->addSymbol(newSym); + ret->referenced = true; + return ret; } if (objSym.isCommon()) @@ -1481,10 +1421,10 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &keptComdats, CommonSymbol{&f, name, binding, visibility, STT_OBJECT, objSym.getCommonAlignment(), objSym.getCommonSize()}); - Defined New(&f, name, binding, visibility, type, 0, 0, nullptr); + Defined newSym(&f, name, binding, visibility, type, 0, 0, nullptr); if (canOmitFromDynSym) - New.exportDynamic = false; - return symtab->addSymbol(New); + newSym.exportDynamic = false; + return symtab->addSymbol(newSym); } template <class ELFT> void BitcodeFile::parse() { @@ -1523,8 +1463,8 @@ void BinaryFile::parse() { STV_DEFAULT, STT_OBJECT, data.size(), 0, nullptr}); } -InputFile *elf::createObjectFile(MemoryBufferRef mb, StringRef archiveName, - uint64_t offsetInArchive) { +InputFile *createObjectFile(MemoryBufferRef mb, StringRef archiveName, + uint64_t offsetInArchive) { if (isBitcode(mb)) return make<BitcodeFile>(mb, archiveName, offsetInArchive); @@ -1615,7 +1555,7 @@ template <class ELFT> void LazyObjFile::parse() { } } -std::string elf::replaceThinLTOSuffix(StringRef path) { +std::string replaceThinLTOSuffix(StringRef path) { StringRef suffix = config->thinLTOObjectSuffixReplace.first; StringRef repl = config->thinLTOObjectSuffixReplace.second; @@ -1634,12 +1574,15 @@ template void LazyObjFile::parse<ELF32BE>(); template void LazyObjFile::parse<ELF64LE>(); template void LazyObjFile::parse<ELF64BE>(); -template class elf::ObjFile<ELF32LE>; -template class elf::ObjFile<ELF32BE>; -template class elf::ObjFile<ELF64LE>; -template class elf::ObjFile<ELF64BE>; +template class ObjFile<ELF32LE>; +template class ObjFile<ELF32BE>; +template class ObjFile<ELF64LE>; +template class ObjFile<ELF64BE>; template void SharedFile::parse<ELF32LE>(); template void SharedFile::parse<ELF32BE>(); template void SharedFile::parse<ELF64LE>(); template void SharedFile::parse<ELF64BE>(); + +} // namespace elf +} // namespace lld |