diff options
Diffstat (limited to 'COFF/InputFiles.cpp')
-rw-r--r-- | COFF/InputFiles.cpp | 179 |
1 files changed, 102 insertions, 77 deletions
diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp index ff26826371fa..0a97c2185f89 100644 --- a/COFF/InputFiles.cpp +++ b/COFF/InputFiles.cpp @@ -7,11 +7,15 @@ // //===----------------------------------------------------------------------===// +#include "InputFiles.h" #include "Chunks.h" #include "Config.h" +#include "Driver.h" #include "Error.h" -#include "InputFiles.h" +#include "Memory.h" +#include "SymbolTable.h" #include "Symbols.h" +#include "llvm-c/lto.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" @@ -26,88 +30,58 @@ #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Target/TargetOptions.h" -#include "llvm-c/lto.h" #include <cstring> #include <system_error> #include <utility> +using namespace llvm; using namespace llvm::COFF; using namespace llvm::object; using namespace llvm::support::endian; using llvm::Triple; using llvm::support::ulittle32_t; +using llvm::sys::fs::file_magic; +using llvm::sys::fs::identify_magic; namespace lld { namespace coff { -int InputFile::NextIndex = 0; -llvm::LLVMContext BitcodeFile::Context; - -// Returns the last element of a path, which is supposed to be a filename. -static StringRef getBasename(StringRef Path) { - size_t Pos = Path.find_last_of("\\/"); - if (Pos == StringRef::npos) - return Path; - return Path.substr(Pos + 1); -} +LLVMContext BitcodeFile::Context; -// Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)". -std::string InputFile::getShortName() { - if (ParentName == "") - return getName().lower(); - std::string Res = (getBasename(ParentName) + "(" + - getBasename(getName()) + ")").str(); - return StringRef(Res).lower(); -} +ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} void ArchiveFile::parse() { // Parse a MemoryBufferRef as an archive file. - File = check(Archive::create(MB), "failed to parse static library"); - - // Allocate a buffer for Lazy objects. - size_t NumSyms = File->getNumberOfSymbols(); - LazySymbols.reserve(NumSyms); + File = check(Archive::create(MB), toString(this)); // Read the symbol table to construct Lazy objects. for (const Archive::Symbol &Sym : File->symbols()) - LazySymbols.emplace_back(this, Sym); - - // Seen is a map from member files to boolean values. Initially - // all members are mapped to false, which indicates all these files - // are not read yet. - Error Err; - for (auto &Child : File->children(Err)) - Seen[Child.getChildOffset()].clear(); - if (Err) - fatal(Err, "failed to parse static library"); + Symtab->addLazy(this, Sym); } // Returns a buffer pointing to a member file containing a given symbol. -// This function is thread-safe. -MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) { +void ArchiveFile::addMember(const Archive::Symbol *Sym) { const Archive::Child &C = check(Sym->getMember(), "could not get the member for symbol " + Sym->getName()); // Return an empty buffer if we have already returned the same buffer. - if (Seen[C.getChildOffset()].test_and_set()) - return MemoryBufferRef(); - return check(C.getMemoryBufferRef(), - "could not get the buffer for the member defining symbol " + - Sym->getName()); + if (!Seen.insert(C.getChildOffset()).second) + return; + + Driver->enqueueArchiveMember(C, Sym->getName(), getName()); } void ObjectFile::parse() { // Parse a memory buffer as a COFF file. - std::unique_ptr<Binary> Bin = - check(createBinary(MB), "failed to parse object file"); + std::unique_ptr<Binary> Bin = check(createBinary(MB), toString(this)); if (auto *Obj = dyn_cast<COFFObjectFile>(Bin.get())) { Bin.release(); COFFObj.reset(Obj); } else { - fatal(getName() + " is not a COFF file"); + fatal(toString(this) + " is not a COFF file"); } // Read section and symbol tables. @@ -137,13 +111,28 @@ void ObjectFile::initializeChunks() { Directives = std::string((const char *)Data.data(), Data.size()); continue; } - // Skip non-DWARF debug info. MSVC linker converts the sections into - // a PDB file, but we don't support that. - if (Name == ".debug" || Name.startswith(".debug$")) - continue; - // We want to preserve DWARF debug sections only when /debug is on. + + // Object files may have DWARF debug info or MS CodeView debug info + // (or both). + // + // DWARF sections don't need any special handling from the perspective + // of the linker; they are just a data section containing relocations. + // We can just link them to complete debug info. + // + // CodeView needs a linker support. We need to interpret and debug + // info, and then write it to a separate .pdb file. + + // Ignore debug info unless /debug is given. if (!Config->Debug && Name.startswith(".debug")) continue; + + // CodeView sections are stored to a different vector because they are + // not linked in the regular manner. + if (Name == ".debug" || Name.startswith(".debug$")) { + DebugChunks.push_back(new (Alloc) SectionChunk(this, Sec)); + continue; + } + if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) continue; auto *C = new (Alloc) SectionChunk(this, Sec); @@ -156,12 +145,14 @@ void ObjectFile::initializeSymbols() { uint32_t NumSymbols = COFFObj->getNumberOfSymbols(); SymbolBodies.reserve(NumSymbols); SparseSymbolBodies.resize(NumSymbols); - llvm::SmallVector<std::pair<Undefined *, uint32_t>, 8> WeakAliases; + SmallVector<std::pair<SymbolBody *, uint32_t>, 8> WeakAliases; int32_t LastSectionNumber = 0; for (uint32_t I = 0; I < NumSymbols; ++I) { // Get a COFFSymbolRef object. - COFFSymbolRef Sym = - check(COFFObj->getSymbol(I), "broken object file: " + getName()); + ErrorOr<COFFSymbolRef> SymOrErr = COFFObj->getSymbol(I); + if (!SymOrErr) + fatal(SymOrErr.getError(), "broken object file: " + toString(this)); + COFFSymbolRef Sym = *SymOrErr; const void *AuxP = nullptr; if (Sym.getNumberOfAuxSymbols()) @@ -175,7 +166,7 @@ void ObjectFile::initializeSymbols() { Body = createUndefined(Sym); uint32_t TagIndex = static_cast<const coff_aux_weak_external *>(AuxP)->TagIndex; - WeakAliases.emplace_back((Undefined *)Body, TagIndex); + WeakAliases.emplace_back(Body, TagIndex); } else { Body = createDefined(Sym, AuxP, IsFirst); } @@ -186,23 +177,30 @@ void ObjectFile::initializeSymbols() { I += Sym.getNumberOfAuxSymbols(); LastSectionNumber = Sym.getSectionNumber(); } - for (auto WeakAlias : WeakAliases) - WeakAlias.first->WeakAlias = SparseSymbolBodies[WeakAlias.second]; + for (auto WeakAlias : WeakAliases) { + auto *U = dyn_cast<Undefined>(WeakAlias.first); + if (!U) + continue; + // Report an error if two undefined symbols have different weak aliases. + if (U->WeakAlias && U->WeakAlias != SparseSymbolBodies[WeakAlias.second]) + Symtab->reportDuplicate(U->symbol(), this); + U->WeakAlias = SparseSymbolBodies[WeakAlias.second]; + } } -Undefined *ObjectFile::createUndefined(COFFSymbolRef Sym) { +SymbolBody *ObjectFile::createUndefined(COFFSymbolRef Sym) { StringRef Name; COFFObj->getSymbolName(Sym, Name); - return new (Alloc) Undefined(Name); + return Symtab->addUndefined(Name, this, Sym.isWeakExternal())->body(); } -Defined *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, - bool IsFirst) { +SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, + bool IsFirst) { StringRef Name; if (Sym.isCommon()) { auto *C = new (Alloc) CommonChunk(Sym); Chunks.push_back(C); - return new (Alloc) DefinedCommon(this, Sym, C); + return Symtab->addCommon(this, Sym, C)->body(); } if (Sym.isAbsolute()) { COFFObj->getSymbolName(Sym, Name); @@ -215,7 +213,10 @@ Defined *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, SEHCompat = true; return nullptr; } - return new (Alloc) DefinedAbsolute(Name, Sym); + if (Sym.isExternal()) + return Symtab->addAbsolute(Name, Sym)->body(); + else + return new (Alloc) DefinedAbsolute(Name, Sym); } int32_t SectionNumber = Sym.getSectionNumber(); if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG) @@ -223,12 +224,12 @@ Defined *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, // Reserved sections numbers don't have contents. if (llvm::COFF::isReservedSectionNumber(SectionNumber)) - fatal("broken object file: " + getName()); + fatal("broken object file: " + toString(this)); // This symbol references a section which is not present in the section // header. if ((uint32_t)SectionNumber >= SparseChunks.size()) - fatal("broken object file: " + getName()); + fatal("broken object file: " + toString(this)); // Nothing else to do without a section chunk. auto *SC = cast_or_null<SectionChunk>(SparseChunks[SectionNumber]); @@ -245,7 +246,11 @@ Defined *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, SC->Checksum = Aux->CheckSum; } - auto *B = new (Alloc) DefinedRegular(this, Sym, SC); + DefinedRegular *B; + if (Sym.isExternal()) + B = cast<DefinedRegular>(Symtab->addRegular(this, Sym, SC)->body()); + else + B = new (Alloc) DefinedRegular(this, Sym, SC); if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP) SC->setSymbol(B); @@ -307,28 +312,29 @@ void ImportFile::parse() { ExtName = ExtName.substr(0, ExtName.find('@')); break; } - ImpSym = new (Alloc) DefinedImportData(DLLName, ImpName, ExtName, Hdr); - SymbolBodies.push_back(ImpSym); + + this->Hdr = Hdr; + ExternalName = ExtName; + + ImpSym = cast<DefinedImportData>( + Symtab->addImportData(ImpName, this)->body()); // If type is function, we need to create a thunk which jump to an // address pointed by the __imp_ symbol. (This allows you to call // DLL functions just like regular non-DLL functions.) if (Hdr->getType() != llvm::COFF::IMPORT_CODE) return; - ThunkSym = new (Alloc) DefinedImportThunk(Name, ImpSym, Hdr->Machine); - SymbolBodies.push_back(ThunkSym); + ThunkSym = cast<DefinedImportThunk>( + Symtab->addImportThunk(Name, ImpSym, Hdr->Machine)->body()); } void BitcodeFile::parse() { - // Usually parse() is thread-safe, but bitcode file is an exception. - std::lock_guard<std::mutex> Lock(Mu); - Context.enableDebugTypeODRUniquing(); ErrorOr<std::unique_ptr<LTOModule>> ModOrErr = LTOModule::createFromBuffer( Context, MB.getBufferStart(), MB.getBufferSize(), llvm::TargetOptions()); M = check(std::move(ModOrErr), "could not create LTO module"); - llvm::StringSaver Saver(Alloc); + StringSaver Saver(Alloc); for (unsigned I = 0, E = M->getSymbolCount(); I != E; ++I) { lto_symbol_attributes Attrs = M->getSymbolAttributes(I); if ((Attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL) @@ -337,15 +343,15 @@ void BitcodeFile::parse() { StringRef SymName = Saver.save(M->getSymbolName(I)); int SymbolDef = Attrs & LTO_SYMBOL_DEFINITION_MASK; if (SymbolDef == LTO_SYMBOL_DEFINITION_UNDEFINED) { - SymbolBodies.push_back(new (Alloc) Undefined(SymName)); + SymbolBodies.push_back(Symtab->addUndefined(SymName, this, false)->body()); } else { bool Replaceable = (SymbolDef == LTO_SYMBOL_DEFINITION_TENTATIVE || // common (Attrs & LTO_SYMBOL_COMDAT) || // comdat (SymbolDef == LTO_SYMBOL_DEFINITION_WEAK && // weak external (Attrs & LTO_SYMBOL_ALIAS))); - SymbolBodies.push_back(new (Alloc) DefinedBitcode(this, SymName, - Replaceable)); + SymbolBodies.push_back( + Symtab->addBitcode(this, SymName, Replaceable)->body()); } } @@ -367,7 +373,26 @@ MachineTypes BitcodeFile::getMachineType() { } } -std::mutex BitcodeFile::Mu; +// Returns the last element of a path, which is supposed to be a filename. +static StringRef getBasename(StringRef Path) { + size_t Pos = Path.find_last_of("\\/"); + if (Pos == StringRef::npos) + return Path; + return Path.substr(Pos + 1); +} + +// Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)". +std::string toString(InputFile *File) { + if (!File) + return "(internal)"; + if (File->ParentName.empty()) + return File->getName().lower(); + + std::string Res = + (getBasename(File->ParentName) + "(" + getBasename(File->getName()) + ")") + .str(); + return StringRef(Res).lower(); +} } // namespace coff } // namespace lld |