diff options
Diffstat (limited to 'COFF/InputFiles.cpp')
-rw-r--r-- | COFF/InputFiles.cpp | 394 |
1 files changed, 244 insertions, 150 deletions
diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp index 7d41caebb4b9..a8f52e0391f7 100644 --- a/COFF/InputFiles.cpp +++ b/COFF/InputFiles.cpp @@ -11,10 +11,10 @@ #include "Chunks.h" #include "Config.h" #include "Driver.h" -#include "Error.h" -#include "Memory.h" #include "SymbolTable.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "llvm-c/lto.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Triple.h" @@ -43,14 +43,18 @@ using llvm::support::ulittle32_t; namespace lld { namespace coff { +std::vector<ObjFile *> ObjFile::Instances; +std::vector<ImportFile *> ImportFile::Instances; +std::vector<BitcodeFile *> BitcodeFile::Instances; + /// Checks that Source is compatible with being a weak alias to Target. /// If Source is Undefined and has no weak alias set, makes it a weak /// alias to Target. static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F, - SymbolBody *Source, SymbolBody *Target) { + Symbol *Source, Symbol *Target) { if (auto *U = dyn_cast<Undefined>(Source)) { if (U->WeakAlias && U->WeakAlias != Target) - Symtab->reportDuplicate(Source->symbol(), F); + Symtab->reportDuplicate(Source, F); U->WeakAlias = Target; } } @@ -59,7 +63,7 @@ ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} void ArchiveFile::parse() { // Parse a MemoryBufferRef as an archive file. - File = check(Archive::create(MB), toString(this)); + File = CHECK(Archive::create(MB), this); // Read the symbol table to construct Lazy objects. for (const Archive::Symbol &Sym : File->symbols()) @@ -69,7 +73,7 @@ void ArchiveFile::parse() { // Returns a buffer pointing to a member file containing a given symbol. void ArchiveFile::addMember(const Archive::Symbol *Sym) { const Archive::Child &C = - check(Sym->getMember(), + CHECK(Sym->getMember(), "could not get the member for symbol " + Sym->getName()); // Return an empty buffer if we have already returned the same buffer. @@ -79,9 +83,28 @@ void ArchiveFile::addMember(const Archive::Symbol *Sym) { Driver->enqueueArchiveMember(C, Sym->getName(), getName()); } -void ObjectFile::parse() { +std::vector<MemoryBufferRef> getArchiveMembers(Archive *File) { + std::vector<MemoryBufferRef> V; + Error Err = Error::success(); + for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) { + Archive::Child C = + CHECK(COrErr, + File->getFileName() + ": could not get the child of the archive"); + MemoryBufferRef MBRef = + CHECK(C.getMemoryBufferRef(), + File->getFileName() + + ": could not get the buffer for a child of the archive"); + V.push_back(MBRef); + } + if (Err) + fatal(File->getFileName() + + ": Archive::children failed: " + toString(std::move(Err))); + return V; +} + +void ObjFile::parse() { // Parse a memory buffer as a COFF file. - std::unique_ptr<Binary> Bin = check(createBinary(MB), toString(this)); + std::unique_ptr<Binary> Bin = CHECK(createBinary(MB), this); if (auto *Obj = dyn_cast<COFFObjectFile>(Bin.get())) { Bin.release(); @@ -93,114 +116,184 @@ void ObjectFile::parse() { // Read section and symbol tables. initializeChunks(); initializeSymbols(); - initializeSEH(); } -void ObjectFile::initializeChunks() { +// We set SectionChunk pointers in the SparseChunks vector to this value +// temporarily to mark comdat sections as having an unknown resolution. As we +// walk the object file's symbol table, once we visit either a leader symbol or +// an associative section definition together with the parent comdat's leader, +// we set the pointer to either nullptr (to mark the section as discarded) or a +// valid SectionChunk for that section. +static SectionChunk *const PendingComdat = reinterpret_cast<SectionChunk *>(1); + +void ObjFile::initializeChunks() { uint32_t NumSections = COFFObj->getNumberOfSections(); Chunks.reserve(NumSections); SparseChunks.resize(NumSections + 1); for (uint32_t I = 1; I < NumSections + 1; ++I) { const coff_section *Sec; - StringRef Name; if (auto EC = COFFObj->getSection(I, Sec)) - fatal(EC, "getSection failed: #" + Twine(I)); - if (auto EC = COFFObj->getSectionName(Sec, Name)) - fatal(EC, "getSectionName failed: #" + Twine(I)); - if (Name == ".sxdata") { - SXData = Sec; - continue; - } - if (Name == ".drectve") { - ArrayRef<uint8_t> Data; - COFFObj->getSectionContents(Sec, Data); - Directives = std::string((const char *)Data.data(), Data.size()); - continue; - } + fatal("getSection failed: #" + Twine(I) + ": " + EC.message()); - // 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; - - if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) - continue; - auto *C = make<SectionChunk>(this, Sec); - - // CodeView sections are stored to a different vector because they are not - // linked in the regular manner. - if (C->isCodeView()) - DebugChunks.push_back(C); + if (Sec->Characteristics & IMAGE_SCN_LNK_COMDAT) + SparseChunks[I] = PendingComdat; else - Chunks.push_back(C); + SparseChunks[I] = readSection(I, nullptr); + } +} - SparseChunks[I] = C; +SectionChunk *ObjFile::readSection(uint32_t SectionNumber, + const coff_aux_section_definition *Def) { + const coff_section *Sec; + StringRef Name; + if (auto EC = COFFObj->getSection(SectionNumber, Sec)) + fatal("getSection failed: #" + Twine(SectionNumber) + ": " + EC.message()); + if (auto EC = COFFObj->getSectionName(Sec, Name)) + fatal("getSectionName failed: #" + Twine(SectionNumber) + ": " + + EC.message()); + if (Name == ".sxdata") { + ArrayRef<uint8_t> Data; + COFFObj->getSectionContents(Sec, Data); + if (Data.size() % 4 != 0) + fatal(".sxdata must be an array of symbol table indices"); + SXData = {reinterpret_cast<const ulittle32_t *>(Data.data()), + Data.size() / 4}; + return nullptr; + } + if (Name == ".drectve") { + ArrayRef<uint8_t> Data; + COFFObj->getSectionContents(Sec, Data); + Directives = std::string((const char *)Data.data(), Data.size()); + return nullptr; } + + // 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")) + return nullptr; + + if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) + return nullptr; + auto *C = make<SectionChunk>(this, Sec); + if (Def) + C->Checksum = Def->CheckSum; + + // CodeView sections are stored to a different vector because they are not + // linked in the regular manner. + if (C->isCodeView()) + DebugChunks.push_back(C); + else + Chunks.push_back(C); + + return C; } -void ObjectFile::initializeSymbols() { +void ObjFile::readAssociativeDefinition( + COFFSymbolRef Sym, const coff_aux_section_definition *Def) { + SectionChunk *Parent = SparseChunks[Def->getNumber(Sym.isBigObj())]; + + // If the parent is pending, it probably means that its section definition + // appears after us in the symbol table. Leave the associated section as + // pending; we will handle it during the second pass in initializeSymbols(). + if (Parent == PendingComdat) + return; + + // Check whether the parent is prevailing. If it is, so are we, and we read + // the section; otherwise mark it as discarded. + int32_t SectionNumber = Sym.getSectionNumber(); + if (Parent) { + SparseChunks[SectionNumber] = readSection(SectionNumber, Def); + if (SparseChunks[SectionNumber]) + Parent->addAssociative(SparseChunks[SectionNumber]); + } else { + SparseChunks[SectionNumber] = nullptr; + } +} + +Symbol *ObjFile::createRegular(COFFSymbolRef Sym) { + SectionChunk *SC = SparseChunks[Sym.getSectionNumber()]; + if (Sym.isExternal()) { + StringRef Name; + COFFObj->getSymbolName(Sym, Name); + if (SC) + return Symtab->addRegular(this, Name, Sym.getGeneric(), SC); + return Symtab->addUndefined(Name, this, false); + } + if (SC) + return make<DefinedRegular>(this, /*Name*/ "", false, + /*IsExternal*/ false, Sym.getGeneric(), SC); + return nullptr; +} + +void ObjFile::initializeSymbols() { uint32_t NumSymbols = COFFObj->getNumberOfSymbols(); - SymbolBodies.reserve(NumSymbols); - SparseSymbolBodies.resize(NumSymbols); + Symbols.resize(NumSymbols); - SmallVector<std::pair<SymbolBody *, uint32_t>, 8> WeakAliases; - int32_t LastSectionNumber = 0; + SmallVector<std::pair<Symbol *, uint32_t>, 8> WeakAliases; + std::vector<uint32_t> PendingIndexes; + PendingIndexes.reserve(NumSymbols); + + std::vector<const coff_aux_section_definition *> ComdatDefs( + COFFObj->getNumberOfSections() + 1); for (uint32_t I = 0; I < NumSymbols; ++I) { - // Get a COFFSymbolRef object. - 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()) - AuxP = COFFObj->getSymbol(I + 1)->getRawPtr(); - bool IsFirst = (LastSectionNumber != Sym.getSectionNumber()); - - SymbolBody *Body = nullptr; - if (Sym.isUndefined()) { - Body = createUndefined(Sym); - } else if (Sym.isWeakExternal()) { - Body = createUndefined(Sym); - uint32_t TagIndex = - static_cast<const coff_aux_weak_external *>(AuxP)->TagIndex; - WeakAliases.emplace_back(Body, TagIndex); + COFFSymbolRef COFFSym = check(COFFObj->getSymbol(I)); + if (COFFSym.isUndefined()) { + Symbols[I] = createUndefined(COFFSym); + } else if (COFFSym.isWeakExternal()) { + Symbols[I] = createUndefined(COFFSym); + uint32_t TagIndex = COFFSym.getAux<coff_aux_weak_external>()->TagIndex; + WeakAliases.emplace_back(Symbols[I], TagIndex); + } else if (Optional<Symbol *> OptSym = createDefined(COFFSym, ComdatDefs)) { + Symbols[I] = *OptSym; } else { - Body = createDefined(Sym, AuxP, IsFirst); - } - if (Body) { - SymbolBodies.push_back(Body); - SparseSymbolBodies[I] = Body; + // createDefined() returns None if a symbol belongs to a section that + // was pending at the point when the symbol was read. This can happen in + // two cases: + // 1) section definition symbol for a comdat leader; + // 2) symbol belongs to a comdat section associated with a section whose + // section definition symbol appears later in the symbol table. + // In both of these cases, we can expect the section to be resolved by + // the time we finish visiting the remaining symbols in the symbol + // table. So we postpone the handling of this symbol until that time. + PendingIndexes.push_back(I); } - I += Sym.getNumberOfAuxSymbols(); - LastSectionNumber = Sym.getSectionNumber(); + I += COFFSym.getNumberOfAuxSymbols(); + } + + for (uint32_t I : PendingIndexes) { + COFFSymbolRef Sym = check(COFFObj->getSymbol(I)); + if (auto *Def = Sym.getSectionDefinition()) + if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) + readAssociativeDefinition(Sym, Def); + Symbols[I] = createRegular(Sym); } for (auto &KV : WeakAliases) { - SymbolBody *Sym = KV.first; + Symbol *Sym = KV.first; uint32_t Idx = KV.second; - checkAndSetWeakAlias(Symtab, this, Sym, SparseSymbolBodies[Idx]); + checkAndSetWeakAlias(Symtab, this, Sym, Symbols[Idx]); } } -SymbolBody *ObjectFile::createUndefined(COFFSymbolRef Sym) { +Symbol *ObjFile::createUndefined(COFFSymbolRef Sym) { StringRef Name; COFFObj->getSymbolName(Sym, Name); - return Symtab->addUndefined(Name, this, Sym.isWeakExternal())->body(); + return Symtab->addUndefined(Name, this, Sym.isWeakExternal()); } -SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, - bool IsFirst) { +Optional<Symbol *> ObjFile::createDefined( + COFFSymbolRef Sym, + std::vector<const coff_aux_section_definition *> &ComdatDefs) { StringRef Name; if (Sym.isCommon()) { auto *C = make<CommonChunk>(Sym); @@ -208,7 +301,7 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, COFFObj->getSymbolName(Sym, Name); Symbol *S = Symtab->addCommon(this, Name, Sym.getValue(), Sym.getGeneric(), C); - return S->body(); + return S; } if (Sym.isAbsolute()) { COFFObj->getSymbolName(Sym, Name); @@ -222,7 +315,7 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, return nullptr; } if (Sym.isExternal()) - return Symtab->addAbsolute(Name, Sym)->body(); + return Symtab->addAbsolute(Name, Sym); else return make<DefinedAbsolute>(Name, Sym); } @@ -239,54 +332,49 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, if ((uint32_t)SectionNumber >= SparseChunks.size()) fatal("broken object file: " + toString(this)); - // Nothing else to do without a section chunk. - auto *SC = cast_or_null<SectionChunk>(SparseChunks[SectionNumber]); - if (!SC) - return nullptr; - - // Handle section definitions - if (IsFirst && AuxP) { - auto *Aux = reinterpret_cast<const coff_aux_section_definition *>(AuxP); - if (Aux->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) - if (auto *ParentSC = cast_or_null<SectionChunk>( - SparseChunks[Aux->getNumber(Sym.isBigObj())])) { - ParentSC->addAssociative(SC); - // If we already discarded the parent, discard the child. - if (ParentSC->isDiscarded()) - SC->markDiscarded(); - } - SC->Checksum = Aux->CheckSum; + // Handle comdat leader symbols. + if (const coff_aux_section_definition *Def = ComdatDefs[SectionNumber]) { + ComdatDefs[SectionNumber] = nullptr; + Symbol *Leader; + bool Prevailing; + if (Sym.isExternal()) { + COFFObj->getSymbolName(Sym, Name); + std::tie(Leader, Prevailing) = + Symtab->addComdat(this, Name, Sym.getGeneric()); + } else { + Leader = make<DefinedRegular>(this, /*Name*/ "", false, + /*IsExternal*/ false, Sym.getGeneric()); + Prevailing = true; + } + if (Prevailing) { + SectionChunk *C = readSection(SectionNumber, Def); + SparseChunks[SectionNumber] = C; + C->Sym = cast<DefinedRegular>(Leader); + cast<DefinedRegular>(Leader)->Data = &C->Repl; + } else { + SparseChunks[SectionNumber] = nullptr; + } + return Leader; } - DefinedRegular *B; - if (Sym.isExternal()) { - COFFObj->getSymbolName(Sym, Name); - Symbol *S = - Symtab->addRegular(this, Name, SC->isCOMDAT(), Sym.getGeneric(), SC); - B = cast<DefinedRegular>(S->body()); - } else - B = make<DefinedRegular>(this, /*Name*/ "", SC->isCOMDAT(), - /*IsExternal*/ false, Sym.getGeneric(), SC); - if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP) - SC->setSymbol(B); - - return B; -} + // Read associative section definitions and prepare to handle the comdat + // leader symbol by setting the section's ComdatDefs pointer if we encounter a + // non-associative comdat. + if (SparseChunks[SectionNumber] == PendingComdat) { + if (auto *Def = Sym.getSectionDefinition()) { + if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) + readAssociativeDefinition(Sym, Def); + else + ComdatDefs[SectionNumber] = Def; + } + } -void ObjectFile::initializeSEH() { - if (!SEHCompat || !SXData) - return; - ArrayRef<uint8_t> A; - COFFObj->getSectionContents(SXData, A); - if (A.size() % 4 != 0) - fatal(".sxdata must be an array of symbol table indices"); - auto *I = reinterpret_cast<const ulittle32_t *>(A.data()); - auto *E = reinterpret_cast<const ulittle32_t *>(A.data() + A.size()); - for (; I != E; ++I) - SEHandlers.insert(SparseSymbolBodies[*I]); + if (SparseChunks[SectionNumber] == PendingComdat) + return None; + return createRegular(Sym); } -MachineTypes ObjectFile::getMachineType() { +MachineTypes ObjFile::getMachineType() { if (COFFObj) return static_cast<MachineTypes>(COFFObj->getMachine()); return IMAGE_FILE_MACHINE_UNKNOWN; @@ -332,26 +420,27 @@ void ImportFile::parse() { this->Hdr = Hdr; ExternalName = ExtName; - ImpSym = cast<DefinedImportData>( - Symtab->addImportData(ImpName, this)->body()); + ImpSym = Symtab->addImportData(ImpName, this); + if (Hdr->getType() == llvm::COFF::IMPORT_CONST) - ConstSym = - cast<DefinedImportData>(Symtab->addImportData(Name, this)->body()); + static_cast<void>(Symtab->addImportData(Name, this)); // 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 = cast<DefinedImportThunk>( - Symtab->addImportThunk(Name, ImpSym, Hdr->Machine)->body()); + if (Hdr->getType() == llvm::COFF::IMPORT_CODE) + ThunkSym = Symtab->addImportThunk(Name, ImpSym, Hdr->Machine); } void BitcodeFile::parse() { Obj = check(lto::InputFile::create(MemoryBufferRef( MB.getBuffer(), Saver.save(ParentName + MB.getBufferIdentifier())))); + std::vector<std::pair<Symbol *, bool>> Comdat(Obj->getComdatTable().size()); + for (size_t I = 0; I != Obj->getComdatTable().size(); ++I) + Comdat[I] = Symtab->addComdat(this, Saver.save(Obj->getComdatTable()[I])); for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) { StringRef SymName = Saver.save(ObjSym.getName()); + int ComdatIndex = ObjSym.getComdatIndex(); Symbol *Sym; if (ObjSym.isUndefined()) { Sym = Symtab->addUndefined(SymName, this, false); @@ -361,13 +450,19 @@ void BitcodeFile::parse() { // Weak external. Sym = Symtab->addUndefined(SymName, this, true); std::string Fallback = ObjSym.getCOFFWeakExternalFallback(); - SymbolBody *Alias = Symtab->addUndefined(Saver.save(Fallback)); - checkAndSetWeakAlias(Symtab, this, Sym->body(), Alias); + Symbol *Alias = Symtab->addUndefined(Saver.save(Fallback)); + checkAndSetWeakAlias(Symtab, this, Sym, Alias); + } else if (ComdatIndex != -1) { + if (SymName == Obj->getComdatTable()[ComdatIndex]) + Sym = Comdat[ComdatIndex].first; + else if (Comdat[ComdatIndex].second) + Sym = Symtab->addRegular(this, SymName); + else + Sym = Symtab->addUndefined(SymName, this, false); } else { - bool IsCOMDAT = ObjSym.getComdatIndex() != -1; - Sym = Symtab->addRegular(this, SymName, IsCOMDAT); + Sym = Symtab->addRegular(this, SymName); } - SymbolBodies.push_back(Sym->body()); + SymbolBodies.push_back(Sym); } Directives = Obj->getCOFFLinkerOpts(); } @@ -398,14 +493,13 @@ static StringRef getBasename(StringRef Path) { } // Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)". -std::string lld::toString(coff::InputFile *File) { +std::string lld::toString(const coff::InputFile *File) { if (!File) - return "(internal)"; + return "<internal>"; if (File->ParentName.empty()) - return File->getName().lower(); + return File->getName(); - std::string Res = - (getBasename(File->ParentName) + "(" + getBasename(File->getName()) + ")") - .str(); - return StringRef(Res).lower(); + return (getBasename(File->ParentName) + "(" + getBasename(File->getName()) + + ")") + .str(); } |