diff options
| -rw-r--r-- | lld/COFF/Chunks.cpp | 4 | ||||
| -rw-r--r-- | lld/COFF/Chunks.h | 1 | ||||
| -rw-r--r-- | lld/COFF/Config.h | 15 | ||||
| -rw-r--r-- | lld/COFF/DLL.cpp | 2 | ||||
| -rw-r--r-- | lld/COFF/Driver.cpp | 14 | ||||
| -rw-r--r-- | lld/COFF/Driver.h | 3 | ||||
| -rw-r--r-- | lld/COFF/DriverUtils.cpp | 10 | ||||
| -rw-r--r-- | lld/COFF/ICF.cpp | 8 | ||||
| -rw-r--r-- | lld/COFF/InputFiles.cpp | 96 | ||||
| -rw-r--r-- | lld/COFF/InputFiles.h | 44 | ||||
| -rw-r--r-- | lld/COFF/MarkLive.cpp | 6 | ||||
| -rw-r--r-- | lld/COFF/SymbolTable.cpp | 412 | ||||
| -rw-r--r-- | lld/COFF/SymbolTable.h | 48 | ||||
| -rw-r--r-- | lld/COFF/Symbols.cpp | 142 | ||||
| -rw-r--r-- | lld/COFF/Symbols.h | 114 | ||||
| -rw-r--r-- | lld/COFF/Writer.cpp | 32 | ||||
| -rw-r--r-- | lld/test/COFF/include2.test | 2 | ||||
| -rw-r--r-- | lld/test/COFF/order.test | 2 | ||||
| -rw-r--r-- | lld/test/COFF/symtab.test | 52 |
19 files changed, 465 insertions, 542 deletions
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp index dc50df7da4f..7f0dfa92ec1 100644 --- a/lld/COFF/Chunks.cpp +++ b/lld/COFF/Chunks.cpp @@ -150,7 +150,7 @@ void SectionChunk::writeTo(uint8_t *Buf) const { // Apply relocations. for (const coff_relocation &Rel : Relocs) { uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress; - SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex)->repl(); + SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex); Defined *Sym = cast<Defined>(Body); uint64_t P = RVA + Rel.VirtualAddress; switch (Config->Machine) { @@ -203,7 +203,7 @@ void SectionChunk::getBaserels(std::vector<Baserel> *Res) { uint8_t Ty = getBaserelType(Rel); if (Ty == IMAGE_REL_BASED_ABSOLUTE) continue; - SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex)->repl(); + SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex); if (isa<DefinedAbsolute>(Body)) continue; Res->emplace_back(RVA + Rel.VirtualAddress, Ty); diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h index 53ccde3b138..59e36b84c9b 100644 --- a/lld/COFF/Chunks.h +++ b/lld/COFF/Chunks.h @@ -28,7 +28,6 @@ using llvm::object::COFFSymbolRef; using llvm::object::SectionRef; using llvm::object::coff_relocation; using llvm::object::coff_section; -using llvm::sys::fs::file_magic; class Baserel; class Defined; diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index 7fd8fec8eca..56b2b51788f 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -26,7 +26,8 @@ using llvm::StringRef; class DefinedAbsolute; class DefinedRelative; class StringChunk; -class Undefined; +struct Symbol; +class SymbolBody; // Short aliases. static const auto AMD64 = llvm::COFF::IMAGE_FILE_MACHINE_AMD64; @@ -37,7 +38,7 @@ static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386; struct Export { StringRef Name; // N in /export:N or /export:E=N StringRef ExtName; // E in /export:E=N - Undefined *Sym = nullptr; + SymbolBody *Sym = nullptr; uint16_t Ordinal = 0; bool Noname = false; bool Data = false; @@ -76,7 +77,7 @@ struct Configuration { llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN; bool Verbose = false; WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN; - Undefined *Entry = nullptr; + SymbolBody *Entry = nullptr; bool NoEntry = false; std::string OutputFile; bool DoGC = true; @@ -89,7 +90,7 @@ struct Configuration { StringRef PDBPath; // Symbols in this set are considered as live by the garbage collector. - std::set<Undefined *> GCRoot; + std::set<SymbolBody *> GCRoot; std::set<StringRef> NoDefaultLibs; bool NoDefaultLibAll = false; @@ -100,11 +101,11 @@ struct Configuration { std::vector<Export> Exports; std::set<std::string> DelayLoads; std::map<std::string, int> DLLOrder; - Undefined *DelayLoadHelper = nullptr; + SymbolBody *DelayLoadHelper = nullptr; // Used for SafeSEH. - DefinedRelative *SEHTable = nullptr; - DefinedAbsolute *SEHCount = nullptr; + Symbol *SEHTable = nullptr; + Symbol *SEHCount = nullptr; // Used for /opt:lldlto=N unsigned LTOOptLevel = 2; diff --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp index 9ac370c11d5..f93dc5cde44 100644 --- a/lld/COFF/DLL.cpp +++ b/lld/COFF/DLL.cpp @@ -324,7 +324,7 @@ public: if (E.ForwardChunk) { write32le(P, E.ForwardChunk->getRVA()); } else { - write32le(P, cast<Defined>(E.Sym->repl())->getRVA()); + write32le(P, cast<Defined>(E.Sym)->getRVA()); } } } diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 36b64c82f8b..63841a4e721 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -207,10 +207,10 @@ void LinkerDriver::addLibSearchPaths() { } } -Undefined *LinkerDriver::addUndefined(StringRef Name) { - Undefined *U = Symtab.addUndefined(Name); - Config->GCRoot.insert(U); - return U; +SymbolBody *LinkerDriver::addUndefined(StringRef Name) { + SymbolBody *B = Symtab.addUndefined(Name); + Config->GCRoot.insert(B); + return B; } // Symbol names are mangled by appending "_" prefix on x86. @@ -232,7 +232,7 @@ StringRef LinkerDriver::findDefaultEntry() { }; for (auto E : Entries) { StringRef Entry = Symtab.findMangle(mangle(E[0])); - if (!Entry.empty() && !isa<Undefined>(Symtab.find(Entry)->Body)) + if (!Entry.empty() && !isa<Undefined>(Symtab.find(Entry)->body())) return mangle(E[1]); } return ""; @@ -715,7 +715,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { Symbol *Sym = Symtab.find(From); if (!Sym) continue; - if (auto *U = dyn_cast<Undefined>(Sym->Body)) + if (auto *U = dyn_cast<Undefined>(Sym->body())) if (!U->WeakAlias) U->WeakAlias = Symtab.addUndefined(To); } @@ -734,7 +734,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { Symtab.addCombinedLTOObjects(); // Make sure we have resolved all symbols. - Symtab.reportRemainingUndefines(/*Resolve=*/true); + Symtab.reportRemainingUndefines(); // Windows specific -- if no /subsystem is given, we need to infer // that from entry point name. diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h index cd60790c732..e1edc7dac0b 100644 --- a/lld/COFF/Driver.h +++ b/lld/COFF/Driver.h @@ -59,6 +59,7 @@ private: class LinkerDriver { public: + LinkerDriver() { coff::Symtab = &Symtab; } void link(llvm::ArrayRef<const char *> Args); // Used by the resolver to parse .drectve section contents. @@ -86,7 +87,7 @@ private: std::vector<StringRef> SearchPaths; std::set<std::string> VisitedFiles; - Undefined *addUndefined(StringRef Sym); + SymbolBody *addUndefined(StringRef Sym); StringRef mangle(StringRef Sym); // Windows specific -- "main" is not the only main function in Windows. diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp index f8572fab1e1..9dc6a80dd16 100644 --- a/lld/COFF/DriverUtils.cpp +++ b/lld/COFF/DriverUtils.cpp @@ -510,13 +510,13 @@ void fixupExports() { } for (Export &E : Config->Exports) { + SymbolBody *Sym = E.Sym; if (!E.ForwardTo.empty()) { E.SymbolName = E.Name; - } else if (Undefined *U = cast_or_null<Undefined>(E.Sym->WeakAlias)) { - E.SymbolName = U->getName(); - } else { - E.SymbolName = E.Sym->getName(); - } + } else if (auto *U = dyn_cast<Undefined>(Sym)) + if (U->WeakAlias) + Sym = U->WeakAlias; + E.SymbolName = Sym->getName(); } for (Export &E : Config->Exports) { diff --git a/lld/COFF/ICF.cpp b/lld/COFF/ICF.cpp index da608cff700..196fbe2610e 100644 --- a/lld/COFF/ICF.cpp +++ b/lld/COFF/ICF.cpp @@ -115,8 +115,8 @@ bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) { R1.VirtualAddress != R2.VirtualAddress) { return false; } - SymbolBody *B1 = A->File->getSymbolBody(R1.SymbolTableIndex)->repl(); - SymbolBody *B2 = B->File->getSymbolBody(R2.SymbolTableIndex)->repl(); + SymbolBody *B1 = A->File->getSymbolBody(R1.SymbolTableIndex); + SymbolBody *B2 = B->File->getSymbolBody(R2.SymbolTableIndex); if (B1 == B2) return true; if (auto *D1 = dyn_cast<DefinedRegular>(B1)) @@ -141,8 +141,8 @@ bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) { bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) { // Compare relocations. auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) { - SymbolBody *B1 = A->File->getSymbolBody(R1.SymbolTableIndex)->repl(); - SymbolBody *B2 = B->File->getSymbolBody(R2.SymbolTableIndex)->repl(); + SymbolBody *B1 = A->File->getSymbolBody(R1.SymbolTableIndex); + SymbolBody *B2 = B->File->getSymbolBody(R2.SymbolTableIndex); if (B1 == B2) return true; if (auto *D1 = dyn_cast<DefinedRegular>(B1)) diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp index d2146c2f97c..37789c94771 100644 --- a/lld/COFF/InputFiles.cpp +++ b/lld/COFF/InputFiles.cpp @@ -12,7 +12,9 @@ #include "Driver.h" #include "Error.h" #include "InputFiles.h" +#include "SymbolTable.h" #include "Symbols.h" +#include "lld/Support/Memory.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" @@ -39,13 +41,13 @@ 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; LLVMContext BitcodeFile::Context; -std::mutex BitcodeFile::Mu; ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} @@ -53,14 +55,6 @@ void ArchiveFile::parse() { // Parse a MemoryBufferRef as an archive file. File = check(Archive::create(MB), toString(this)); - // Allocate a buffer for Lazy objects. - size_t NumSyms = File->getNumberOfSymbols(); - LazySymbols.reserve(NumSyms); - - // 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. @@ -69,18 +63,22 @@ void ArchiveFile::parse() { Seen[Child.getChildOffset()].clear(); if (Err) fatal(Err, toString(this)); + + // Read the symbol table to construct Lazy objects. + for (const Archive::Symbol &Sym : File->symbols()) + 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) { +InputFile *ArchiveFile::getMember(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 nullptr; MemoryBufferRef MB = check(C.getMemoryBufferRef(), @@ -90,10 +88,21 @@ MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) { Driver->Cpio->append(relativeToRoot(check(C.getFullName())), MB.getBuffer()); - return MB; -} + file_magic Magic = identify_magic(MB.getBuffer()); + if (Magic == file_magic::coff_import_library) + return make<ImportFile>(MB); + + InputFile *Obj; + if (Magic == file_magic::coff_object) + Obj = make<ObjectFile>(MB); + else if (Magic == file_magic::bitcode) + Obj = make<BitcodeFile>(MB); + else + fatal("unknown file type: " + MB.getBufferIdentifier()); -MutableArrayRef<Lazy> ArchiveFile::getLazySymbols() { return LazySymbols; } + Obj->ParentName = getName(); + return Obj; +} void ObjectFile::parse() { // Parse a memory buffer as a COFF file. @@ -167,7 +176,7 @@ void ObjectFile::initializeSymbols() { uint32_t NumSymbols = COFFObj->getNumberOfSymbols(); SymbolBodies.reserve(NumSymbols); SparseSymbolBodies.resize(NumSymbols); - 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. @@ -188,7 +197,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); } @@ -199,23 +208,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); @@ -228,7 +244,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) @@ -258,7 +277,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); @@ -320,22 +343,23 @@ 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()); @@ -350,15 +374,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()); } } diff --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h index 14aecd45be8..3f199bd014c 100644 --- a/lld/COFF/InputFiles.h +++ b/lld/COFF/InputFiles.h @@ -31,6 +31,7 @@ using llvm::COFF::MachineTypes; using llvm::object::Archive; using llvm::object::COFFObjectFile; using llvm::object::COFFSymbolRef; +using llvm::object::coff_import_header; using llvm::object::coff_section; class Chunk; @@ -39,6 +40,7 @@ class DefinedImportData; class DefinedImportThunk; class Lazy; class SectionChunk; +struct Symbol; class SymbolBody; class Undefined; @@ -52,9 +54,6 @@ public: // Returns the filename. StringRef getName() { return MB.getBufferIdentifier(); } - // Returns symbols defined by this file. - virtual std::vector<SymbolBody *> &getSymbols() = 0; - // Reads a file (the constructor doesn't do that). virtual void parse() = 0; @@ -67,14 +66,8 @@ public: // Returns .drectve section contents if exist. StringRef getDirectives() { return StringRef(Directives).trim(); } - // Each file has a unique index. The index number is used to - // resolve ties in symbol resolution. - int Index; - static int NextIndex; - protected: - InputFile(Kind K, MemoryBufferRef M) - : Index(NextIndex++), MB(M), FileKind(K) {} + InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} MemoryBufferRef MB; std::string Directives; @@ -90,22 +83,14 @@ public: static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } void parse() override; - // Returns a memory buffer for a given symbol. An empty memory buffer - // is returned if we have already returned the same memory buffer. - // (So that we don't instantiate same members more than once.) - MemoryBufferRef getMember(const Archive::Symbol *Sym); - - llvm::MutableArrayRef<Lazy> getLazySymbols(); - - // All symbols returned by ArchiveFiles are of Lazy type. - std::vector<SymbolBody *> &getSymbols() override { - llvm_unreachable("internal fatal"); - } + // Returns an input file for a given symbol. A null pointer is returned if we + // have already returned the same input file. (So that we don't instantiate + // the same member more than once.) + InputFile *getMember(const Archive::Symbol *Sym); private: std::unique_ptr<Archive> File; std::string Filename; - std::vector<Lazy> LazySymbols; std::map<uint64_t, std::atomic_flag> Seen; }; @@ -118,7 +103,7 @@ public: MachineTypes getMachineType() override; std::vector<Chunk *> &getChunks() { return Chunks; } std::vector<SectionChunk *> &getDebugChunks() { return DebugChunks; } - std::vector<SymbolBody *> &getSymbols() override { return SymbolBodies; } + std::vector<SymbolBody *> &getSymbols() { return SymbolBodies; } // Returns a SymbolBody object for the SymbolIndex'th symbol in the // underlying object file. @@ -142,8 +127,8 @@ private: void initializeSymbols(); void initializeSEH(); - Defined *createDefined(COFFSymbolRef Sym, const void *Aux, bool IsFirst); - Undefined *createUndefined(COFFSymbolRef Sym); + SymbolBody *createDefined(COFFSymbolRef Sym, const void *Aux, bool IsFirst); + SymbolBody *createUndefined(COFFSymbolRef Sym); std::unique_ptr<COFFObjectFile> COFFObj; llvm::BumpPtrAllocator Alloc; @@ -181,7 +166,6 @@ public: explicit ImportFile(MemoryBufferRef M) : InputFile(ImportKind, M), StringAlloc(StringAllocAux) {} static bool classof(const InputFile *F) { return F->kind() == ImportKind; } - std::vector<SymbolBody *> &getSymbols() override { return SymbolBodies; } DefinedImportData *ImpSym = nullptr; DefinedImportThunk *ThunkSym = nullptr; @@ -190,10 +174,14 @@ public: private: void parse() override; - std::vector<SymbolBody *> SymbolBodies; llvm::BumpPtrAllocator Alloc; llvm::BumpPtrAllocator StringAllocAux; llvm::StringSaver StringAlloc; + +public: + StringRef ExternalName; + const coff_import_header *Hdr; + Chunk *Location = nullptr; }; // Used for LTO. @@ -201,7 +189,7 @@ class BitcodeFile : public InputFile { public: explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {} static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } - std::vector<SymbolBody *> &getSymbols() override { return SymbolBodies; } + std::vector<SymbolBody *> &getSymbols() { return SymbolBodies; } MachineTypes getMachineType() override; std::unique_ptr<LTOModule> takeModule() { return std::move(M); } diff --git a/lld/COFF/MarkLive.cpp b/lld/COFF/MarkLive.cpp index 0870986ad81..0156d238b67 100644 --- a/lld/COFF/MarkLive.cpp +++ b/lld/COFF/MarkLive.cpp @@ -38,8 +38,8 @@ void markLive(const std::vector<Chunk *> &Chunks) { }; // Add GC root chunks. - for (Undefined *U : Config->GCRoot) - if (auto *D = dyn_cast<DefinedRegular>(U->repl())) + for (SymbolBody *B : Config->GCRoot) + if (auto *D = dyn_cast<DefinedRegular>(B)) Enqueue(D->getChunk()); while (!Worklist.empty()) { @@ -48,7 +48,7 @@ void markLive(const std::vector<Chunk *> &Chunks) { // Mark all symbols listed in the relocation table for this section. for (SymbolBody *S : SC->symbols()) - if (auto *D = dyn_cast<DefinedRegular>(S->repl())) + if (auto *D = dyn_cast<DefinedRegular>(S)) Enqueue(D->getChunk()); // Mark associative sections if any. diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp index 9bc705e7a06..2f7add24780 100644 --- a/lld/COFF/SymbolTable.cpp +++ b/lld/COFF/SymbolTable.cpp @@ -12,7 +12,6 @@ #include "Driver.h" #include "Error.h" #include "Symbols.h" -#include "lld/Core/Parallel.h" #include "lld/Support/Memory.h" #include "llvm/IR/LLVMContext.h" #include "llvm/LTO/legacy/LTOCodeGenerator.h" @@ -25,21 +24,15 @@ using namespace llvm; namespace lld { namespace coff { -void SymbolTable::addFile(InputFile *File) { -#if LLVM_ENABLE_THREADS - std::launch Policy = std::launch::async; -#else - std::launch Policy = std::launch::deferred; -#endif +SymbolTable *Symtab; +void SymbolTable::addFile(InputFile *File) { Files.push_back(File); if (auto *F = dyn_cast<ArchiveFile>(File)) { - ArchiveQueue.push_back( - std::async(Policy, [=]() { F->parse(); return F; })); + ArchiveQueue.push_back(F); return; } - ObjectQueue.push_back( - std::async(Policy, [=]() { File->parse(); return File; })); + ObjectQueue.push_back(File); if (auto *F = dyn_cast<ObjectFile>(File)) { ObjectFiles.push_back(F); } else if (auto *F = dyn_cast<BitcodeFile>(File)) { @@ -53,7 +46,7 @@ void SymbolTable::step() { if (queueEmpty()) return; readObjects(); - readArchives(); + readArchive(); } void SymbolTable::run() { @@ -61,26 +54,17 @@ void SymbolTable::run() { step(); } -void SymbolTable::readArchives() { +void SymbolTable::readArchive() { if (ArchiveQueue.empty()) return; // Add lazy symbols to the symbol table. Lazy symbols that conflict // with existing undefined symbols are accumulated in LazySyms. - std::vector<Symbol *> LazySyms; - for (std::future<ArchiveFile *> &Future : ArchiveQueue) { - ArchiveFile *File = Future.get(); - if (Config->Verbose) - outs() << "Reading " << toString(File) << "\n"; - for (Lazy &Sym : File->getLazySymbols()) - addLazy(&Sym, &LazySyms); - } - ArchiveQueue.clear(); - - // Add archive member files to ObjectQueue that should resolve - // existing undefined symbols. - for (Symbol *Sym : LazySyms) - addMemberFile(cast<Lazy>(Sym->Body)); + ArchiveFile *File = ArchiveQueue.front(); + ArchiveQueue.pop_front(); + if (Config->Verbose) + outs() << "Reading " << toString(File) << "\n"; + File->parse(); } void SymbolTable::readObjects() { @@ -90,14 +74,12 @@ void SymbolTable::readObjects() { // Add defined and undefined symbols to the symbol table. std::vector<StringRef> Directives; for (size_t I = 0; I < ObjectQueue.size(); ++I) { - InputFile *File = ObjectQueue[I].get(); + InputFile *File = ObjectQueue[I]; if (Config->Verbose) outs() << "Reading " << toString(File) << "\n"; + File->parse(); // Adding symbols may add more files to ObjectQueue // (but not to ArchiveQueue). - for (SymbolBody *Sym : File->getSymbols()) - if (Sym->isExternal()) - addSymbol(Sym); StringRef S = File->getDirectives(); if (!S.empty()) { Directives.push_back(S); @@ -117,127 +99,239 @@ bool SymbolTable::queueEmpty() { return ArchiveQueue.empty() && ObjectQueue.empty(); } -void SymbolTable::reportRemainingUndefines(bool Resolve) { +void SymbolTable::reportRemainingUndefines() { SmallPtrSet<SymbolBody *, 8> Undefs; for (auto &I : Symtab) { Symbol *Sym = I.second; - auto *Undef = dyn_cast<Undefined>(Sym->Body); + auto *Undef = dyn_cast<Undefined>(Sym->body()); if (!Undef) continue; + if (!Sym->IsUsedInRegularObj) + continue; StringRef Name = Undef->getName(); // A weak alias may have been resolved, so check for that. if (Defined *D = Undef->getWeakAlias()) { - if (Resolve) - Sym->Body = D; + // We resolve weak aliases by replacing the alias's SymbolBody with the + // target's SymbolBody. This causes all SymbolBody pointers referring to + // the old symbol to instead refer to the new symbol. However, we can't + // just blindly copy sizeof(Symbol::Body) bytes from D to Sym->Body + // because D may be an internal symbol, and internal symbols are stored as + // "unparented" SymbolBodies. For that reason we need to check which type + // of symbol we are dealing with and copy the correct number of bytes. + if (isa<DefinedRegular>(D)) + memcpy(Sym->Body.buffer, D, sizeof(DefinedRegular)); + else if (isa<DefinedAbsolute>(D)) + memcpy(Sym->Body.buffer, D, sizeof(DefinedAbsolute)); + else + // No other internal symbols are possible. + Sym->Body = D->symbol()->Body; continue; } // If we can resolve a symbol by removing __imp_ prefix, do that. // This odd rule is for compatibility with MSVC linker. if (Name.startswith("__imp_")) { Symbol *Imp = find(Name.substr(strlen("__imp_"))); - if (Imp && isa<Defined>(Imp->Body)) { - if (!Resolve) - continue; - auto *D = cast<Defined>(Imp->Body); - auto *S = make<DefinedLocalImport>(Name, D); - LocalImportChunks.push_back(S->getChunk()); - Sym->Body = S; + if (Imp && isa<Defined>(Imp->body())) { + auto *D = cast<Defined>(Imp->body()); + replaceBody<DefinedLocalImport>(Sym, Name, D); + LocalImportChunks.push_back( + cast<DefinedLocalImport>(Sym->body())->getChunk()); continue; } } // Remaining undefined symbols are not fatal if /force is specified. // They are replaced with dummy defined symbols. - if (Config->Force && Resolve) - Sym->Body = make<DefinedAbsolute>(Name, 0); - Undefs.insert(Sym->Body); + if (Config->Force) + replaceBody<DefinedAbsolute>(Sym, Name, 0); + Undefs.insert(Sym->body()); } if (Undefs.empty()) return; - for (Undefined *U : Config->GCRoot) - if (Undefs.count(U->repl())) - errs() << "<root>: undefined symbol: " << U->getName() << "\n"; - for (InputFile *File : Files) - if (!isa<ArchiveFile>(File)) - for (SymbolBody *Sym : File->getSymbols()) - if (Undefs.count(Sym->repl())) - errs() << toString(File) << ": undefined symbol: " << Sym->getName() - << "\n"; + for (SymbolBody *B : Config->GCRoot) + if (Undefs.count(B)) + errs() << "<root>: undefined symbol: " << B->getName() << "\n"; + for (ObjectFile *File : ObjectFiles) + for (SymbolBody *Sym : File->getSymbols()) + if (Undefs.count(Sym)) + errs() << toString(File) << ": undefined symbol: " << Sym->getName() + << "\n"; if (!Config->Force) fatal("link failed"); } -void SymbolTable::addLazy(Lazy *New, std::vector<Symbol *> *Accum) { - Symbol *Sym = insert(New); - if (Sym->Body == New) - return; - SymbolBody *Existing = Sym->Body; - if (isa<Defined>(Existing)) - return; - if (Lazy *L = dyn_cast<Lazy>(Existing)) - if (L->getFileIndex() < New->getFileIndex()) - return; - Sym->Body = New; - New->setBackref(Sym); - if (isa<Undefined>(Existing)) - Accum->push_back(Sym); +std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) { + Symbol *&Sym = Symtab[Name]; + if (Sym) + return {Sym, false}; + Sym = make<Symbol>(); + Sym->IsUsedInRegularObj = false; + return {Sym, true}; } -void SymbolTable::addSymbol(SymbolBody *New) { - // Find an existing symbol or create and insert a new one. - assert(isa<Defined>(New) || isa<Undefined>(New)); - Symbol *Sym = insert(New); - if (Sym->Body == New) - return; - SymbolBody *Existing = Sym->Body; - - // If we have an undefined symbol and a lazy symbol, - // let the lazy symbol to read a member file. - if (auto *L = dyn_cast<Lazy>(Existing)) { - // Undefined symbols with weak aliases need not to be resolved, - // since they would be replaced with weak aliases if they remain - // undefined. - if (auto *U = dyn_cast<Undefined>(New)) { - if (!U->WeakAlias) { - addMemberFile(L); - return; - } - } - Sym->Body = New; +Symbol *SymbolTable::addUndefined(StringRef Name, InputFile *F, + bool IsWeakAlias) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + if (!F || !isa<BitcodeFile>(F)) + S->IsUsedInRegularObj = true; + if (WasInserted || (isa<Lazy>(S->body()) && IsWeakAlias)) { + replaceBody<Undefined>(S, Name); + return S; + } + if (auto *L = dyn_cast<Lazy>(S->body())) + addMemberFile(L->File, L->Sym); + return S; +} + +void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol Sym) { + StringRef Name = Sym.getName(); + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + if (WasInserted) { + replaceBody<Lazy>(S, F, Sym); return; } + auto *U = dyn_cast<Undefined>(S->body()); + if (!U || U->WeakAlias) + return; + addMemberFile(F, Sym); +} + +void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) { + fatal("duplicate symbol: " + toString(*Existing->body()) + " in " + + toString(Existing->body()->getFile()) + " and in " + + (NewFile ? toString(NewFile) : "(internal)")); +} + +Symbol *SymbolTable::addAbsolute(StringRef N, COFFSymbolRef Sym) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(N); + S->IsUsedInRegularObj = true; + if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body())) + replaceBody<DefinedAbsolute>(S, N, Sym); + else if (!isa<DefinedCOFF>(S->body())) + reportDuplicate(S, nullptr); + return S; +} - // compare() returns -1, 0, or 1 if the lhs symbol is less preferable, - // equivalent (conflicting), or more preferable, respectively. - int Comp = Existing->compare(New); - if (Comp == 0) - fatal("duplicate symbol: " + toString(*Existing) + " in " + - toString(Existing->getFile()) + " and in " + - toString(New->getFile())); - if (Comp < 0) - Sym->Body = New; +Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(N); + S->IsUsedInRegularObj = true; + if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body())) + replaceBody<DefinedAbsolute>(S, N, VA); + else if (!isa<DefinedCOFF>(S->body())) + reportDuplicate(S, nullptr); + return S; } -Symbol *SymbolTable::insert(SymbolBody *New) { - Symbol *&Sym = Symtab[New->getName()]; - if (Sym) { - New->setBackref(Sym); - return Sym; +Symbol *SymbolTable::addRelative(StringRef N, uint64_t VA) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(N); + S->IsUsedInRegularObj = true; + if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body())) + replaceBody<DefinedRelative>(S, N, VA); + else if (!isa<DefinedCOFF>(S->body())) + reportDuplicate(S, nullptr); + return S; +} + +Symbol *SymbolTable::addRegular(ObjectFile *F, COFFSymbolRef Sym, + SectionChunk *C) { + StringRef Name; + F->getCOFFObj()->getSymbolName(Sym, Name); + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + S->IsUsedInRegularObj = true; + if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body())) + replaceBody<DefinedRegular>(S, F, Sym, C); + else if (auto *R = dyn_cast<DefinedRegular>(S->body())) { + if (!C->isCOMDAT() || !R->isCOMDAT()) + reportDuplicate(S, F); + } else if (auto *B = dyn_cast<DefinedBitcode>(S->body())) { + if (B->IsReplaceable) + replaceBody<DefinedRegular>(S, F, Sym, C); + else if (!C->isCOMDAT()) + reportDuplicate(S, F); + } else + replaceBody<DefinedRegular>(S, F, Sym, C); + return S; +} + +Symbol *SymbolTable::addBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(N); + if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body())) { + replaceBody<DefinedBitcode>(S, F, N, IsReplaceable); + return S; } - Sym = make<Symbol>(New); - New->setBackref(Sym); - return Sym; + if (isa<DefinedCommon>(S->body())) + return S; + if (IsReplaceable) + if (isa<DefinedRegular>(S->body()) || isa<DefinedBitcode>(S->body())) + return S; + reportDuplicate(S, F); + return S; +} + +Symbol *SymbolTable::addCommon(ObjectFile *F, COFFSymbolRef Sym, + CommonChunk *C) { + StringRef Name; + F->getCOFFObj()->getSymbolName(Sym, Name); + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + S->IsUsedInRegularObj = true; + if (WasInserted || !isa<DefinedCOFF>(S->body())) + replaceBody<DefinedCommon>(S, F, Sym, C); + else if (auto *DC = dyn_cast<DefinedCommon>(S->body())) + if (Sym.getValue() > DC->getSize()) + replaceBody<DefinedCommon>(S, F, Sym, C); + return S; +} + +Symbol *SymbolTable::addImportData(StringRef N, ImportFile *F) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(N); + S->IsUsedInRegularObj = true; + if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body())) + replaceBody<DefinedImportData>(S, N, F); + else if (!isa<DefinedCOFF>(S->body())) + reportDuplicate(S, nullptr); + return S; +} + +Symbol *SymbolTable::addImportThunk(StringRef Name, DefinedImportData *ID, + uint16_t Machine) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + S->IsUsedInRegularObj = true; + if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body())) + replaceBody<DefinedImportThunk>(S, Name, ID, Machine); + else if (!isa<DefinedCOFF>(S->body())) + reportDuplicate(S, nullptr); + return S; } // Reads an archive member file pointed by a given symbol. -void SymbolTable::addMemberFile(Lazy *Body) { - InputFile *File = Body->getMember(); +void SymbolTable::addMemberFile(ArchiveFile *F, const Archive::Symbol Sym) { + InputFile *File = F->getMember(&Sym); // getMember returns an empty buffer if the member was already // read from the library. if (!File) return; if (Config->Verbose) - outs() << "Loaded " << toString(File) << " for " << Body->getName() << "\n"; + outs() << "Loaded " << toString(File) << " for " << Sym.getName() << "\n"; addFile(File); } @@ -274,7 +368,7 @@ StringRef SymbolTable::findByPrefix(StringRef Prefix) { StringRef SymbolTable::findMangle(StringRef Name) { if (Symbol *Sym = find(Name)) - if (!isa<Undefined>(Sym->Body)) + if (!isa<Undefined>(Sym->body())) return Name; if (Config->Machine != I386) return findByPrefix(("?" + Name + "@@Y").str()); @@ -288,34 +382,17 @@ StringRef SymbolTable::findMangle(StringRef Name) { return findByPrefix(("?" + Name.substr(1) + "@@Y").str()); } -void SymbolTable::mangleMaybe(Undefined *U) { - if (U->WeakAlias) - return; - if (!isa<Undefined>(U->repl())) +void SymbolTable::mangleMaybe(SymbolBody *B) { + auto *U = dyn_cast<Undefined>(B); + if (!U || U->WeakAlias) return; StringRef Alias = findMangle(U->getName()); if (!Alias.empty()) U->WeakAlias = addUndefined(Alias); } -Undefined *SymbolTable::addUndefined(StringRef Name) { - auto *New = make<Undefined>(Name); - addSymbol(New); - if (auto *U = dyn_cast<Undefined>(New->repl())) - return U; - return New; -} - -DefinedRelative *SymbolTable::addRelative(StringRef Name, uint64_t VA) { - auto *New = make<DefinedRelative>(Name, VA); - addSymbol(New); - return New; -} - -DefinedAbsolute *SymbolTable::addAbsolute(StringRef Name, uint64_t VA) { - auto *New = make<DefinedAbsolute>(Name, VA); - addSymbol(New); - return New; +SymbolBody *SymbolTable::addUndefined(StringRef Name) { + return addUndefined(Name, nullptr, false)->body(); } void SymbolTable::printMap(llvm::raw_ostream &OS) { @@ -329,59 +406,19 @@ void SymbolTable::printMap(llvm::raw_ostream &OS) { } } -void SymbolTable::addCombinedLTOObject(ObjectFile *Obj) { - for (SymbolBody *Body : Obj->getSymbols()) { - if (!Body->isExternal()) - continue; - // We should not see any new undefined symbols at this point, but we'll - // diagnose them later in reportRemainingUndefines(). - StringRef Name = Body->getName(); - Symbol *Sym = insert(Body); - SymbolBody *Existing = Sym->Body; - - if (Existing == Body) - continue; - - if (isa<DefinedBitcode>(Existing)) { - Sym->Body = Body; - continue; - } - if (isa<Undefined>(Body)) { - if (auto *L = dyn_cast<Lazy>(Existing)) { - // We may see new references to runtime library symbols such as __chkstk - // here. These symbols must be wholly defined in non-bitcode files. - addMemberFile(L); - continue; - } - } - - int Comp = Existing->compare(Body); - if (Comp == 0) - fatal("LTO: unexpected duplicate symbol: " + Name); - if (Comp < 0) - Sym->Body = Body; - } -} - void SymbolTable::addCombinedLTOObjects() { if (BitcodeFiles.empty()) return; - // Diagnose any undefined symbols early, but do not resolve weak externals, - // as resolution breaks the invariant that each Symbol points to a unique - // SymbolBody, which we rely on to replace DefinedBitcode symbols correctly. - reportRemainingUndefines(/*Resolve=*/false); - // Create an object file and add it to the symbol table by replacing any // DefinedBitcode symbols with the definitions in the object file. LTOCodeGenerator CG(BitcodeFile::Context); CG.setOptLevel(Config->LTOOptLevel); std::vector<ObjectFile *> Objs = createLTOObjects(&CG); - for (ObjectFile *Obj : Objs) - addCombinedLTOObject(Obj); - size_t NumBitcodeFiles = BitcodeFiles.size(); + for (ObjectFile *Obj : Objs) + Obj->parse(); run(); if (BitcodeFiles.size() != NumBitcodeFiles) fatal("LTO: late loaded symbol created new bitcode reference"); @@ -390,25 +427,17 @@ void SymbolTable::addCombinedLTOObjects() { // Combine and compile bitcode files and then return the result // as a vector of regular COFF object files. std::vector<ObjectFile *> SymbolTable::createLTOObjects(LTOCodeGenerator *CG) { - // All symbols referenced by non-bitcode objects must be preserved. - for (ObjectFile *File : ObjectFiles) - for (SymbolBody *Body : File->getSymbols()) - if (auto *S = dyn_cast<DefinedBitcode>(Body->repl())) - CG->addMustPreserveSymbol(S->getName()); - - // Likewise for bitcode symbols which we initially resolved to non-bitcode. + // All symbols referenced by non-bitcode objects, including GC roots, must be + // preserved. We must also replace bitcode symbols with undefined symbols so + // that they may be replaced with real definitions without conflicting. for (BitcodeFile *File : BitcodeFiles) - for (SymbolBody *Body : File->getSymbols()) - if (isa<DefinedBitcode>(Body) && !isa<DefinedBitcode>(Body->repl())) + for (SymbolBody *Body : File->getSymbols()) { + if (!isa<DefinedBitcode>(Body)) + continue; + if (Body->symbol()->IsUsedInRegularObj) CG->addMustPreserveSymbol(Body->getName()); - - // Likewise for other symbols that must be preserved. - for (Undefined *U : Config->GCRoot) { - if (auto *S = dyn_cast<DefinedBitcode>(U->repl())) - CG->addMustPreserveSymbol(S->getName()); - else if (auto *S = dyn_cast_or_null<DefinedBitcode>(U->getWeakAlias())) - CG->addMustPreserveSymbol(S->getName()); - } + replaceBody<Undefined>(Body->symbol(), Body->getName()); + } CG->setModule(BitcodeFiles[0]->takeModule()); for (unsigned I = 1, E = BitcodeFiles.size(); I != E; ++I) @@ -438,7 +467,6 @@ std::vector<ObjectFile *> SymbolTable::createLTOObjects(LTOCodeGenerator *CG) { auto *ObjFile = new ObjectFile(MemoryBufferRef(Obj, "<LTO object>")); Files.emplace_back(ObjFile); ObjectFiles.push_back(ObjFile); - ObjFile->parse(); ObjFiles.push_back(ObjFile); } diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h index 1d11fa76db3..a7f27afa336 100644 --- a/lld/COFF/SymbolTable.h +++ b/lld/COFF/SymbolTable.h @@ -22,6 +22,7 @@ #endif #include <future> +#include <list> namespace llvm { struct LTOCodeGenerator; @@ -31,6 +32,7 @@ namespace lld { namespace coff { class Chunk; +class CommonChunk; class Defined; class DefinedAbsolute; class DefinedRelative; @@ -48,7 +50,9 @@ struct Symbol; // conflicts. For example, obviously, a defined symbol is better than // an undefined symbol. Or, if there's a conflict between a lazy and a // undefined, it'll read an archive member to read a real definition -// to replace the lazy symbol. The logic is implemented in resolve(). +// to replace the lazy symbol. The logic is implemented in the +// add*() functions, which are called by input files as they are parsed. +// There is one add* function per symbol type. class SymbolTable { public: void addFile(InputFile *File); @@ -57,9 +61,10 @@ public: void run(); bool queueEmpty(); - // Print an error message on undefined symbols. If Resolve is true, try to - // resolve any undefined symbols and update the symbol table accordingly. - void reportRemainingUndefines(bool Resolve); + // Try to resolve any undefined symbols and update the symbol table + // accordingly, then print an error message for any remaining undefined + // symbols. + void reportRemainingUndefines(); // Returns a list of chunks of selected symbols. std::vector<Chunk *> getChunks(); @@ -72,7 +77,7 @@ public: // mangled symbol. This function tries to find a mangled name // for U from the symbol table, and if found, set the symbol as // a weak alias for U. - void mangleMaybe(Undefined *U); + void mangleMaybe(SymbolBody *B); StringRef findMangle(StringRef Name); // Print a layout map to OS. @@ -91,36 +96,49 @@ public: std::vector<ObjectFile *> ObjectFiles; // Creates an Undefined symbol for a given name. - Undefined *addUndefined(StringRef Name); - DefinedRelative *addRelative(StringRef Name, uint64_t VA); - DefinedAbsolute *addAbsolute(StringRef Name, uint64_t VA); + SymbolBody *addUndefined(StringRef Name); + + Symbol *addRelative(StringRef N, uint64_t VA); + Symbol *addAbsolute(StringRef N, uint64_t VA); + + Symbol *addUndefined(StringRef Name, InputFile *F, bool IsWeakAlias); + void addLazy(ArchiveFile *F, const Archive::Symbol Sym); + Symbol *addAbsolute(StringRef N, COFFSymbolRef S); + Symbol *addRegular(ObjectFile *F, COFFSymbolRef S, SectionChunk *C); + Symbol *addBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable); + Symbol *addCommon(ObjectFile *F, COFFSymbolRef S, CommonChunk *C); + Symbol *addImportData(StringRef N, ImportFile *F); + Symbol *addImportThunk(StringRef Name, DefinedImportData *S, + uint16_t Machine); + + void reportDuplicate(Symbol *Existing, InputFile *NewFile); // A list of chunks which to be added to .rdata. std::vector<Chunk *> LocalImportChunks; private: - void readArchives(); + void readArchive(); void readObjects(); - void addSymbol(SymbolBody *New); - void addLazy(Lazy *New, std::vector<Symbol *> *Accum); - Symbol *insert(SymbolBody *New); + std::pair<Symbol *, bool> insert(StringRef Name); StringRef findByPrefix(StringRef Prefix); - void addMemberFile(Lazy *Body); + void addMemberFile(ArchiveFile *F, const Archive::Symbol Sym); void addCombinedLTOObject(ObjectFile *Obj); std::vector<ObjectFile *> createLTOObjects(llvm::LTOCodeGenerator *CG); llvm::DenseMap<StringRef, Symbol *> Symtab; std::vector<InputFile *> Files; - std::vector<std::future<ArchiveFile *>> ArchiveQueue; - std::vector<std::future<InputFile *>> ObjectQueue; + std::list<ArchiveFile *> ArchiveQueue; + std::vector<InputFile *> ObjectQueue; std::vector<BitcodeFile *> BitcodeFiles; std::vector<SmallString<0>> Objs; }; +extern SymbolTable *Symtab; + } // namespace coff } // namespace lld diff --git a/lld/COFF/Symbols.cpp b/lld/COFF/Symbols.cpp index 29879110124..d714ac9a5e0 100644 --- a/lld/COFF/Symbols.cpp +++ b/lld/COFF/Symbols.cpp @@ -18,8 +18,6 @@ using namespace llvm; using namespace llvm::object; -using llvm::sys::fs::identify_magic; -using llvm::sys::fs::file_magic; namespace lld { namespace coff { @@ -49,120 +47,6 @@ InputFile *SymbolBody::getFile() { return nullptr; } -// Returns 1, 0 or -1 if this symbol should take precedence -// over the Other, tie or lose, respectively. -int SymbolBody::compare(SymbolBody *Other) { - Kind LK = kind(), RK = Other->kind(); - - // Normalize so that the smaller kind is on the left. - if (LK > RK) - return -Other->compare(this); - - // First handle comparisons between two different kinds. - if (LK != RK) { - if (RK > LastDefinedKind) { - if (LK == LazyKind && cast<Undefined>(Other)->WeakAlias) - return -1; - - // The LHS is either defined or lazy and so it wins. - assert((LK <= LastDefinedKind || LK == LazyKind) && "Bad kind!"); - return 1; - } - - // Bitcode has special complexities. - if (RK == DefinedBitcodeKind) { - auto *RHS = cast<DefinedBitcode>(Other); - - switch (LK) { - case DefinedCommonKind: - return 1; - - case DefinedRegularKind: - // As an approximation, regular symbols win over bitcode symbols, - // but we definitely have a conflict if the regular symbol is not - // replaceable and neither is the bitcode symbol. We do not - // replicate the rest of the symbol resolution logic here; symbol - // resolution will be done accurately after lowering bitcode symbols - // to regular symbols in addCombinedLTOObject(). - if (cast<DefinedRegular>(this)->isCOMDAT() || RHS->IsReplaceable) - return 1; - - // Fallthrough to the default of a tie otherwise. - default: - return 0; - } - } - - // Either of the object file kind will trump a higher kind. - if (LK <= LastDefinedCOFFKind) - return 1; - - // The remaining kind pairs are ties amongst defined symbols. - return 0; - } - - // Now handle the case where the kinds are the same. - switch (LK) { - case DefinedRegularKind: { - auto *LHS = cast<DefinedRegular>(this); - auto *RHS = cast<DefinedRegular>(Other); - if (LHS->isCOMDAT() && RHS->isCOMDAT()) - return LHS->getFileIndex() < RHS->getFileIndex() ? 1 : -1; - return 0; - } - - case DefinedCommonKind: { - auto *LHS = cast<DefinedCommon>(this); - auto *RHS = cast<DefinedCommon>(Other); - if (LHS->getSize() == RHS->getSize()) - return LHS->getFileIndex() < RHS->getFileIndex() ? 1 : -1; - return LHS->getSize() > RHS->getSize() ? 1 : -1; - } - - case DefinedBitcodeKind: { - auto *LHS = cast<DefinedBitcode>(this); - auto *RHS = cast<DefinedBitcode>(Other); - // If both are non-replaceable, we have a tie. - if (!LHS->IsReplaceable && !RHS->IsReplaceable) - return 0; - - // Non-replaceable symbols win, but even two replaceable symboles don't - // tie. If both symbols are replaceable, choice is arbitrary. - if (RHS->IsReplaceable && LHS->IsReplaceable) - return uintptr_t(LHS) < uintptr_t(RHS) ? 1 : -1; - return LHS->IsReplaceable ? -1 : 1; - } - - case LazyKind: { - // Don't tie, pick the earliest. - auto *LHS = cast<Lazy>(this); - auto *RHS = cast<Lazy>(Other); - return LHS->getFileIndex() < RHS->getFileIndex() ? 1 : -1; - } - - case UndefinedKind: { - auto *LHS = cast<Undefined>(this); - auto *RHS = cast<Undefined>(Other); - // Tie if both undefined symbols have different weak aliases. - if (LHS->WeakAlias && RHS->WeakAlias) { - if (LHS->WeakAlias->getName() != RHS->WeakAlias->getName()) - return 0; - return uintptr_t(LHS) < uintptr_t(RHS) ? 1 : -1; - } - return LHS->WeakAlias ? 1 : -1; - } - - case DefinedLocalImportKind: - case DefinedImportThunkKind: - case DefinedImportDataKind: - case DefinedAbsoluteKind: - case DefinedRelativeKind: - // These all simply tie. - return 0; - } - llvm_unreachable("unknown symbol kind"); -} - COFFSymbolRef DefinedCOFF::getCOFFSymbol() { size_t SymSize = File->getCOFFObj()->getSymbolTableEntrySize(); if (SymSize == sizeof(coff_symbol16)) @@ -182,34 +66,10 @@ DefinedImportThunk::DefinedImportThunk(StringRef Name, DefinedImportData *S, } } -InputFile *Lazy::getMember() { - MemoryBufferRef MBRef = File->getMember(&Sym); - - // getMember returns an empty buffer if the member was already - // read from the library. - if (MBRef.getBuffer().empty()) - return nullptr; - - file_magic Magic = identify_magic(MBRef.getBuffer()); - if (Magic == file_magic::coff_import_library) - return make<ImportFile>(MBRef); - - InputFile *Obj; - if (Magic == file_magic::coff_object) - Obj = make<ObjectFile>(MBRef); - else if (Magic == file_magic::bitcode) - Obj = make<BitcodeFile>(MBRef); - else - fatal("unknown file type: " + File->getName()); - - Obj->ParentName = File->getName(); - return Obj; -} - Defined *Undefined::getWeakAlias() { // A weak alias may be a weak alias to another symbol, so check recursively. for (SymbolBody *A = WeakAlias; A; A = cast<Undefined>(A)->WeakAlias) - if (auto *D = dyn_cast<Defined>(A->repl())) + if (auto *D = dyn_cast<Defined>(A)) return D; return nullptr; } diff --git a/lld/COFF/Symbols.h b/lld/COFF/Symbols.h index 1089fdcb7dc..240a67aa1f1 100644 --- a/lld/COFF/Symbols.h +++ b/lld/COFF/Symbols.h @@ -32,15 +32,8 @@ class ArchiveFile; class BitcodeFile; class InputFile; class ObjectFile; -class SymbolBody; - -// A real symbol object, SymbolBody, is usually accessed indirectly -// through a Symbol. There's always one Symbol for each symbol name. -// The resolver updates SymbolBody pointers as it resolves symbols. -struct Symbol { - explicit Symbol(SymbolBody *P) : Body(P) {} - SymbolBody *Body; -}; +struct Symbol; +class SymbolTable; // The base class for real symbol classes. class SymbolBody { @@ -78,21 +71,13 @@ public: // Returns the file from which this symbol was created. InputFile *getFile(); - // A SymbolBody has a backreference to a Symbol. Originally they are - // doubly-linked. A backreference will never change. But the pointer - // in the Symbol may be mutated by the resolver. If you have a - // pointer P to a SymbolBody and are not sure whether the resolver - // has chosen the object among other objects having the same name, - // you can access P->Backref->Body to get the resolver's result. - void setBackref(Symbol *P) { Backref = P; } - SymbolBody *repl() { return Backref ? Backref->Body : this; } - - // Decides which symbol should "win" in the symbol table, this or - // the Other. Returns 1 if this wins, -1 if the Other wins, or 0 if - // they are duplicate (conflicting) symbols. - int compare(SymbolBody *Other); + Symbol *symbol(); + const Symbol *symbol() const { + return const_cast<SymbolBody *>(this)->symbol(); + } protected: + friend SymbolTable; explicit SymbolBody(Kind K, StringRef N = "") : SymbolKind(K), IsExternal(true), IsCOMDAT(false), IsReplaceable(false), Name(N) {} @@ -107,7 +92,6 @@ protected: unsigned IsReplaceable : 1; StringRef Name; - Symbol *Backref = nullptr; }; // The base class for any defined symbols, including absolute symbols, @@ -149,7 +133,6 @@ public: } ObjectFile *getFile() { return File; } - int getFileIndex() { return File->Index; } COFFSymbolRef getCOFFSymbol(); @@ -195,7 +178,7 @@ public: uint64_t getRVA() { return Data->getRVA(); } private: - friend SymbolBody; + friend SymbolTable; uint64_t getSize() { return Sym->Value; } CommonChunk *Data; }; @@ -254,15 +237,12 @@ public: static bool classof(const SymbolBody *S) { return S->kind() == LazyKind; } - // Returns an object file for this symbol, or a nullptr if the file - // was already returned. - InputFile *getMember(); - - int getFileIndex() { return File->Index; } - ArchiveFile *File; private: + friend SymbolTable; + +private: const Archive::Symbol Sym; }; @@ -295,26 +275,22 @@ public: // table in an output. The former has "__imp_" prefix. class DefinedImportData : public Defined { public: - DefinedImportData(StringRef D, StringRef N, StringRef E, - const coff_import_header *H) - : Defined(DefinedImportDataKind, N), DLLName(D), ExternalName(E), Hdr(H) { + DefinedImportData(StringRef N, ImportFile *F) + : Defined(DefinedImportDataKind, N), File(F) { } static bool classof(const SymbolBody *S) { return S->kind() == DefinedImportDataKind; } - uint64_t getRVA() { return Location->getRVA(); } - StringRef getDLLName() { return DLLName; } - StringRef getExternalName() { return ExternalName; } - void setLocation(Chunk *AddressTable) { Location = AddressTable; } - uint16_t getOrdinal() { return Hdr->OrdinalHint; } + uint64_t getRVA() { return File->Location->getRVA(); } + StringRef getDLLName() { return File->DLLName; } + StringRef getExternalName() { return File->ExternalName; } + void setLocation(Chunk *AddressTable) { File->Location = AddressTable; } + uint16_t getOrdinal() { return File->Hdr->OrdinalHint; } private: - StringRef DLLName; - StringRef ExternalName; - const coff_import_header *Hdr; - Chunk *Location = nullptr; + ImportFile *File; }; // This class represents a symbol for a jump table entry which jumps @@ -345,17 +321,17 @@ private: class DefinedLocalImport : public Defined { public: DefinedLocalImport(StringRef N, Defined *S) - : Defined(DefinedLocalImportKind, N), Data(S) {} + : Defined(DefinedLocalImportKind, N), Data(new LocalImportChunk(S)) {} static bool classof(const SymbolBody *S) { return S->kind() == DefinedLocalImportKind; } - uint64_t getRVA() { return Data.getRVA(); } - Chunk *getChunk() { return &Data; } + uint64_t getRVA() { return Data->getRVA(); } + Chunk *getChunk() { return Data.get(); } private: - LocalImportChunk Data; + std::unique_ptr<LocalImportChunk> Data; }; class DefinedBitcode : public Defined { @@ -363,6 +339,11 @@ class DefinedBitcode : public Defined { public: DefinedBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable) : Defined(DefinedBitcodeKind, N), File(F) { + // IsReplaceable tracks whether the bitcode symbol may be replaced with some + // other (defined, common or bitcode) symbol. This is the case for common, + // comdat and weak external symbols. We try to replace bitcode symbols with + // "real" symbols (see SymbolTable::add{Regular,Bitcode}), and resolve the + // result against the real symbol from the combined LTO object. this->IsReplaceable = IsReplaceable; } @@ -398,6 +379,45 @@ inline uint64_t Defined::getRVA() { llvm_unreachable("unknown symbol kind"); } +// A real symbol object, SymbolBody, is usually stored within a Symbol. There's +// always one Symbol for each symbol name. The resolver updates the SymbolBody +// stored in the Body field of this object as it resolves symbols. Symbol also +// holds computed properties of symbol names. +struct Symbol { + // True if this symbol was referenced by a regular (non-bitcode) object. + unsigned IsUsedInRegularObj : 1; + + // This field is used to store the Symbol's SymbolBody. This instantiation of + // AlignedCharArrayUnion gives us a struct with a char array field that is + // large and aligned enough to store any derived class of SymbolBody. + llvm::AlignedCharArrayUnion<DefinedRegular, DefinedCommon, DefinedAbsolute, + DefinedRelative, Lazy, Undefined, + DefinedImportData, DefinedImportThunk, + DefinedLocalImport, DefinedBitcode> + Body; + + SymbolBody *body() { + return reinterpret_cast<SymbolBody *>(Body.buffer); + } + const SymbolBody *body() const { return const_cast<Symbol *>(this)->body(); } +}; + +template <typename T, typename... ArgT> +void replaceBody(Symbol *S, ArgT &&... Arg) { + static_assert(sizeof(T) <= sizeof(S->Body), "Body too small"); + static_assert(alignof(T) <= alignof(decltype(S->Body)), + "Body not aligned enough"); + assert(static_cast<SymbolBody *>(static_cast<T *>(nullptr)) == nullptr && + "Not a SymbolBody"); + new (S->Body.buffer) T(std::forward<ArgT>(Arg)...); +} + +inline Symbol *SymbolBody::symbol() { + assert(isExternal()); + return reinterpret_cast<Symbol *>(reinterpret_cast<char *>(this) - + offsetof(Symbol, Body)); +} + std::string toString(SymbolBody &B); } // namespace coff diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 4c5eb22cf31..13d95c6ea77 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -388,7 +388,7 @@ void Writer::createMiscChunks() { if (!File->SEHCompat) return; for (SymbolBody *B : File->SEHandlers) - Handlers.insert(cast<Defined>(B->repl())); + Handlers.insert(cast<Defined>(B)); } SEHTable.reset(new SEHTableChunk(Handlers)); @@ -428,7 +428,7 @@ void Writer::createImportTables() { Sec->addChunk(C); } if (!DelayIdata.empty()) { - Defined *Helper = cast<Defined>(Config->DelayLoadHelper->repl()); + Defined *Helper = cast<Defined>(Config->DelayLoadHelper); DelayIdata.create(Helper); OutputSection *Sec = createSection(".didat"); for (Chunk *C : DelayIdata.getChunks()) @@ -471,6 +471,10 @@ size_t Writer::addEntryToStringTable(StringRef Str) { } Optional<coff_symbol16> Writer::createSymbol(Defined *Def) { + // Relative symbols are unrepresentable in a COFF symbol table. + if (isa<DefinedRelative>(Def)) + return None; + if (auto *D = dyn_cast<DefinedRegular>(Def)) if (!D->getChunk()->isLive()) return None; @@ -497,7 +501,6 @@ Optional<coff_symbol16> Writer::createSymbol(Defined *Def) { switch (Def->kind()) { case SymbolBody::DefinedAbsoluteKind: - case SymbolBody::DefinedRelativeKind: Sym.Value = Def->getRVA(); Sym.SectionNumber = IMAGE_SYM_ABSOLUTE; break; @@ -530,16 +533,13 @@ void Writer::createSymbolAndStringTable() { Sec->setStringTableOff(addEntryToStringTable(Name)); } + std::set<SymbolBody *> SeenSymbols; for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) for (SymbolBody *B : File->getSymbols()) if (auto *D = dyn_cast<Defined>(B)) - if (Optional<coff_symbol16> Sym = createSymbol(D)) - OutputSymtab.push_back(*Sym); - - for (ImportFile *File : Symtab->ImportFiles) - for (SymbolBody *B : File->getSymbols()) - if (Optional<coff_symbol16> Sym = createSymbol(cast<Defined>(B))) - OutputSymtab.push_back(*Sym); + if (SeenSymbols.insert(D).second) + if (Optional<coff_symbol16> Sym = createSymbol(D)) + OutputSymtab.push_back(*Sym); OutputSection *LastSection = OutputSections.back(); // We position the symbol table to be adjacent to the end of the last section. @@ -630,7 +630,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() { PE->SizeOfImage = SizeOfImage; PE->SizeOfHeaders = SizeOfHeaders; if (!Config->NoEntry) { - Defined *Entry = cast<Defined>(Config->Entry->repl()); + Defined *Entry = cast<Defined>(Config->Entry); PE->AddressOfEntryPoint = Entry->getRVA(); // Pointer to thumb code must have the LSB set, so adjust it. if (Config->Machine == ARMNT) @@ -685,7 +685,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() { Dir[BASE_RELOCATION_TABLE].Size = Sec->getVirtualSize(); } if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) { - if (Defined *B = dyn_cast<Defined>(Sym->Body)) { + if (Defined *B = dyn_cast<Defined>(Sym->body())) { Dir[TLS_TABLE].RelativeVirtualAddress = B->getRVA(); Dir[TLS_TABLE].Size = Config->is64() ? sizeof(object::coff_tls_directory64) @@ -697,7 +697,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() { Dir[DEBUG_DIRECTORY].Size = DebugDirectory->getSize(); } if (Symbol *Sym = Symtab->findUnderscore("_load_config_used")) { - if (auto *B = dyn_cast<DefinedRegular>(Sym->Body)) { + if (auto *B = dyn_cast<DefinedRegular>(Sym->body())) { SectionChunk *SC = B->getChunk(); assert(B->getRVA() >= SC->getRVA()); uint64_t OffsetInChunk = B->getRVA() - SC->getRVA(); @@ -754,8 +754,10 @@ void Writer::openFile(StringRef Path) { void Writer::fixSafeSEHSymbols() { if (!SEHTable) return; - Config->SEHTable->setRVA(SEHTable->getRVA()); - Config->SEHCount->setVA(SEHTable->getSize() / 4); + if (auto *T = dyn_cast<DefinedRelative>(Config->SEHTable->body())) + T->setRVA(SEHTable->getRVA()); + if (auto *C = dyn_cast<DefinedAbsolute>(Config->SEHCount->body())) + C->setVA(SEHTable->getSize() / 4); } // Handles /section options to allow users to overwrite diff --git a/lld/test/COFF/include2.test b/lld/test/COFF/include2.test index f2379eaede4..528a27319e7 100644 --- a/lld/test/COFF/include2.test +++ b/lld/test/COFF/include2.test @@ -9,6 +9,6 @@ CHECK: include2.test.tmp1.obj CHECK: include2.test.tmp2.lib -CHECK: include2.test.tmp3.lib CHECK: include2.test.tmp2.lib(include2.test.tmp2.obj) for foo +CHECK: include2.test.tmp3.lib CHECK: include2.test.tmp3.lib(include2.test.tmp3.obj) for bar diff --git a/lld/test/COFF/order.test b/lld/test/COFF/order.test index 6a0cee8a32e..0ce638aae4f 100644 --- a/lld/test/COFF/order.test +++ b/lld/test/COFF/order.test @@ -11,5 +11,5 @@ CHECK: order.test.tmp1.obj CHECK: order.test.tmp3.obj CHECK: order.test.tmp2.lib -CHECK: order.test.tmp3.lib CHECK: order.test.tmp2.lib(order.test.tmp2.obj) for foo +CHECK: order.test.tmp3.lib diff --git a/lld/test/COFF/symtab.test b/lld/test/COFF/symtab.test index bf7f9964795..ffaca285d6f 100644 --- a/lld/test/COFF/symtab.test +++ b/lld/test/COFF/symtab.test @@ -36,17 +36,17 @@ # CHECK-NEXT: AuxSymbolCount: 0 # CHECK-NEXT: } # CHECK-NEXT: Symbol { -# CHECK-NEXT: Name: message -# CHECK-NEXT: Value: 6 -# CHECK-NEXT: Section: .text2 (3) +# CHECK-NEXT: Name: MessageBoxA +# CHECK-NEXT: Value: 80 +# CHECK-NEXT: Section: .text (2) # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) -# CHECK-NEXT: StorageClass: Static (0x3) +# CHECK-NEXT: StorageClass: External (0x2) # CHECK-NEXT: AuxSymbolCount: 0 # CHECK-NEXT: } # CHECK-NEXT: Symbol { -# CHECK-NEXT: Name: main -# CHECK-NEXT: Value: 0 +# CHECK-NEXT: Name: ExitProcess +# CHECK-NEXT: Value: 64 # CHECK-NEXT: Section: .text (2) # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) @@ -54,8 +54,8 @@ # CHECK-NEXT: AuxSymbolCount: 0 # CHECK-NEXT: } # CHECK-NEXT: Symbol { -# CHECK-NEXT: Name: caption -# CHECK-NEXT: Value: 0 +# CHECK-NEXT: Name: message +# CHECK-NEXT: Value: 6 # CHECK-NEXT: Section: .text2 (3) # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) @@ -63,26 +63,8 @@ # CHECK-NEXT: AuxSymbolCount: 0 # CHECK-NEXT: } # CHECK-NEXT: Symbol { -# CHECK-NEXT: Name: abs_symbol -# CHECK-NEXT: Value: 2662186735 -# CHECK-NEXT: Section: IMAGE_SYM_ABSOLUTE (-1) -# CHECK-NEXT: BaseType: Null (0x0) -# CHECK-NEXT: ComplexType: Null (0x0) -# CHECK-NEXT: StorageClass: External (0x2) -# CHECK-NEXT: AuxSymbolCount: 0 -# CHECK-NEXT: } -# CHECK-NEXT: Symbol { -# CHECK-NEXT: Name: __imp_ExitProcess -# CHECK-NEXT: Value: 64 -# CHECK-NEXT: Section: .idata (5) -# CHECK-NEXT: BaseType: Null (0x0) -# CHECK-NEXT: ComplexType: Null (0x0) -# CHECK-NEXT: StorageClass: External (0x2) -# CHECK-NEXT: AuxSymbolCount: 0 -# CHECK-NEXT: } -# CHECK-NEXT: Symbol { -# CHECK-NEXT: Name: ExitProcess -# CHECK-NEXT: Value: 64 +# CHECK-NEXT: Name: main +# CHECK-NEXT: Value: 0 # CHECK-NEXT: Section: .text (2) # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) @@ -90,18 +72,18 @@ # CHECK-NEXT: AuxSymbolCount: 0 # CHECK-NEXT: } # CHECK-NEXT: Symbol { -# CHECK-NEXT: Name: __imp_MessageBoxA -# CHECK-NEXT: Value: 72 -# CHECK-NEXT: Section: .idata (5) +# CHECK-NEXT: Name: caption +# CHECK-NEXT: Value: 0 +# CHECK-NEXT: Section: .text2 (3) # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) -# CHECK-NEXT: StorageClass: External (0x2) +# CHECK-NEXT: StorageClass: Static (0x3) # CHECK-NEXT: AuxSymbolCount: 0 # CHECK-NEXT: } # CHECK-NEXT: Symbol { -# CHECK-NEXT: Name: MessageBoxA -# CHECK-NEXT: Value: 80 -# CHECK-NEXT: Section: .text (2) +# CHECK-NEXT: Name: abs_symbol +# CHECK-NEXT: Value: 2662186735 +# CHECK-NEXT: Section: IMAGE_SYM_ABSOLUTE (-1) # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) # CHECK-NEXT: StorageClass: External (0x2) |

