diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-05-22 19:44:12 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-05-22 19:44:12 +0000 |
commit | c53addf38e24e4dafe992aafb3ae928bfa8fdb0a (patch) | |
tree | 5a8f08e745d2dbfdd66c9e4838a8b7eeb7f0453f | |
parent | 2dcc0c5ee66570f02392d1fbf29f573fa47258f8 (diff) |
Vendor import of lld trunk r303571:vendor/lld/lld-trunk-r303571
Notes
Notes:
svn path=/vendor/lld/dist/; revision=318671
svn path=/vendor/lld/lld-trunk-r303571/; revision=318672; tag=vendor/lld/lld-trunk-r303571
35 files changed, 385 insertions, 1085 deletions
diff --git a/COFF/CMakeLists.txt b/COFF/CMakeLists.txt index 8f24e36c0eca..14f553e540d9 100644 --- a/COFF/CMakeLists.txt +++ b/COFF/CMakeLists.txt @@ -14,11 +14,9 @@ add_lld_library(lldCOFF Error.cpp ICF.cpp InputFiles.cpp - Librarian.cpp LTO.cpp MapFile.cpp MarkLive.cpp - ModuleDef.cpp PDB.cpp Strings.cpp SymbolTable.cpp diff --git a/COFF/Config.h b/COFF/Config.h index fafd3bcde2e3..d859b1fbb7d9 100644 --- a/COFF/Config.h +++ b/COFF/Config.h @@ -155,7 +155,6 @@ struct Configuration { uint32_t MajorOSVersion = 6; uint32_t MinorOSVersion = 0; bool DynamicBase = true; - bool AllowBind = true; bool NxCompat = true; bool AllowIsolation = true; bool TerminalServerAware = true; @@ -164,7 +163,6 @@ struct Configuration { bool AppContainer = false; // This is for debugging. - bool DebugPdb = false; bool DumpPdb = false; }; diff --git a/COFF/DLL.cpp b/COFF/DLL.cpp index f93dc5cde44c..3ac14e4ea2b0 100644 --- a/COFF/DLL.cpp +++ b/COFF/DLL.cpp @@ -100,13 +100,17 @@ public: void writeTo(uint8_t *Buf) const override { auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff); - E->ImportLookupTableRVA = LookupTab->getRVA(); E->NameRVA = DLLName->getRVA(); + + // The import descriptor table contains two pointers to + // the tables describing dllimported symbols. But the + // Windows loader actually uses only one. So we create + // only one table and set both fields to its address. + E->ImportLookupTableRVA = AddressTab->getRVA(); E->ImportAddressTableRVA = AddressTab->getRVA(); } Chunk *DLLName; - Chunk *LookupTab; Chunk *AddressTab; }; @@ -136,9 +140,9 @@ binImports(const std::vector<DefinedImportData *> &Imports) { M[Sym->getDLLName().lower()].push_back(Sym); std::vector<std::vector<DefinedImportData *>> V; - for (auto &P : M) { + for (auto &KV : M) { // Sort symbols by name for each group. - std::vector<DefinedImportData *> &Syms = P.second; + std::vector<DefinedImportData *> &Syms = KV.second; std::sort(Syms.begin(), Syms.end(), [](DefinedImportData *A, DefinedImportData *B) { return A->getName() < B->getName(); @@ -383,21 +387,14 @@ uint64_t IdataContents::getIATSize() { // See Microsoft PE/COFF spec 5.4 for details. std::vector<Chunk *> IdataContents::getChunks() { create(); - std::vector<Chunk *> V; + // The loader assumes a specific order of data. // Add each type in the correct order. - for (std::unique_ptr<Chunk> &C : Dirs) - V.push_back(C.get()); - for (std::unique_ptr<Chunk> &C : Lookups) - V.push_back(C.get()); - for (std::unique_ptr<Chunk> &C : Addresses) - V.push_back(C.get()); - for (std::unique_ptr<Chunk> &C : Hints) - V.push_back(C.get()); - for (auto &P : DLLNames) { - std::unique_ptr<Chunk> &C = P.second; - V.push_back(C.get()); - } + std::vector<Chunk *> V; + V.insert(V.end(), Dirs.begin(), Dirs.end()); + V.insert(V.end(), Addresses.begin(), Addresses.end()); + V.insert(V.end(), Hints.begin(), Hints.end()); + V.insert(V.end(), DLLNames.begin(), DLLNames.end()); return V; } @@ -406,65 +403,50 @@ void IdataContents::create() { // Create .idata contents for each DLL. for (std::vector<DefinedImportData *> &Syms : V) { - StringRef Name = Syms[0]->getDLLName(); - // Create lookup and address tables. If they have external names, // we need to create HintName chunks to store the names. // If they don't (if they are import-by-ordinals), we store only // ordinal values to the table. - size_t Base = Lookups.size(); + size_t Base = Addresses.size(); for (DefinedImportData *S : Syms) { uint16_t Ord = S->getOrdinal(); if (S->getExternalName().empty()) { - Lookups.push_back(make_unique<OrdinalOnlyChunk>(Ord)); - Addresses.push_back(make_unique<OrdinalOnlyChunk>(Ord)); + Addresses.push_back(make<OrdinalOnlyChunk>(Ord)); continue; } - auto C = make_unique<HintNameChunk>(S->getExternalName(), Ord); - Lookups.push_back(make_unique<LookupChunk>(C.get())); - Addresses.push_back(make_unique<LookupChunk>(C.get())); - Hints.push_back(std::move(C)); + auto *C = make<HintNameChunk>(S->getExternalName(), Ord); + Addresses.push_back(make<LookupChunk>(C)); + Hints.push_back(C); } // Terminate with null values. - Lookups.push_back(make_unique<NullChunk>(ptrSize())); - Addresses.push_back(make_unique<NullChunk>(ptrSize())); + Addresses.push_back(make<NullChunk>(ptrSize())); for (int I = 0, E = Syms.size(); I < E; ++I) - Syms[I]->setLocation(Addresses[Base + I].get()); + Syms[I]->setLocation(Addresses[Base + I]); // Create the import table header. - if (!DLLNames.count(Name)) - DLLNames[Name] = make_unique<StringChunk>(Name); - auto Dir = make_unique<ImportDirectoryChunk>(DLLNames[Name].get()); - Dir->LookupTab = Lookups[Base].get(); - Dir->AddressTab = Addresses[Base].get(); - Dirs.push_back(std::move(Dir)); + DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName())); + auto *Dir = make<ImportDirectoryChunk>(DLLNames.back()); + Dir->AddressTab = Addresses[Base]; + Dirs.push_back(Dir); } // Add null terminator. - Dirs.push_back(make_unique<NullChunk>(sizeof(ImportDirectoryTableEntry))); + Dirs.push_back(make<NullChunk>(sizeof(ImportDirectoryTableEntry))); } std::vector<Chunk *> DelayLoadContents::getChunks() { std::vector<Chunk *> V; - for (std::unique_ptr<Chunk> &C : Dirs) - V.push_back(C.get()); - for (std::unique_ptr<Chunk> &C : Names) - V.push_back(C.get()); - for (std::unique_ptr<Chunk> &C : HintNames) - V.push_back(C.get()); - for (auto &P : DLLNames) { - std::unique_ptr<Chunk> &C = P.second; - V.push_back(C.get()); - } + V.insert(V.end(), Dirs.begin(), Dirs.end()); + V.insert(V.end(), Names.begin(), Names.end()); + V.insert(V.end(), HintNames.begin(), HintNames.end()); + V.insert(V.end(), DLLNames.begin(), DLLNames.end()); return V; } std::vector<Chunk *> DelayLoadContents::getDataChunks() { std::vector<Chunk *> V; - for (std::unique_ptr<Chunk> &C : ModuleHandles) - V.push_back(C.get()); - for (std::unique_ptr<Chunk> &C : Addresses) - V.push_back(C.get()); + V.insert(V.end(), ModuleHandles.begin(), ModuleHandles.end()); + V.insert(V.end(), Addresses.begin(), Addresses.end()); return V; } @@ -478,55 +460,51 @@ void DelayLoadContents::create(Defined *H) { // Create .didat contents for each DLL. for (std::vector<DefinedImportData *> &Syms : V) { - StringRef Name = Syms[0]->getDLLName(); - // Create the delay import table header. - if (!DLLNames.count(Name)) - DLLNames[Name] = make_unique<StringChunk>(Name); - auto Dir = make_unique<DelayDirectoryChunk>(DLLNames[Name].get()); + DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName())); + auto *Dir = make<DelayDirectoryChunk>(DLLNames.back()); size_t Base = Addresses.size(); for (DefinedImportData *S : Syms) { - Chunk *T = newThunkChunk(S, Dir.get()); - auto A = make_unique<DelayAddressChunk>(T); - Addresses.push_back(std::move(A)); - Thunks.push_back(std::unique_ptr<Chunk>(T)); + Chunk *T = newThunkChunk(S, Dir); + auto *A = make<DelayAddressChunk>(T); + Addresses.push_back(A); + Thunks.push_back(T); StringRef ExtName = S->getExternalName(); if (ExtName.empty()) { - Names.push_back(make_unique<OrdinalOnlyChunk>(S->getOrdinal())); + Names.push_back(make<OrdinalOnlyChunk>(S->getOrdinal())); } else { - auto C = make_unique<HintNameChunk>(ExtName, 0); - Names.push_back(make_unique<LookupChunk>(C.get())); - HintNames.push_back(std::move(C)); + auto *C = make<HintNameChunk>(ExtName, 0); + Names.push_back(make<LookupChunk>(C)); + HintNames.push_back(C); } } // Terminate with null values. - Addresses.push_back(make_unique<NullChunk>(8)); - Names.push_back(make_unique<NullChunk>(8)); + Addresses.push_back(make<NullChunk>(8)); + Names.push_back(make<NullChunk>(8)); for (int I = 0, E = Syms.size(); I < E; ++I) - Syms[I]->setLocation(Addresses[Base + I].get()); - auto *MH = new NullChunk(8); + Syms[I]->setLocation(Addresses[Base + I]); + auto *MH = make<NullChunk>(8); MH->setAlign(8); - ModuleHandles.push_back(std::unique_ptr<Chunk>(MH)); + ModuleHandles.push_back(MH); // Fill the delay import table header fields. Dir->ModuleHandle = MH; - Dir->AddressTab = Addresses[Base].get(); - Dir->NameTab = Names[Base].get(); - Dirs.push_back(std::move(Dir)); + Dir->AddressTab = Addresses[Base]; + Dir->NameTab = Names[Base]; + Dirs.push_back(Dir); } // Add null terminator. - Dirs.push_back( - make_unique<NullChunk>(sizeof(delay_import_directory_table_entry))); + Dirs.push_back(make<NullChunk>(sizeof(delay_import_directory_table_entry))); } Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) { switch (Config->Machine) { case AMD64: - return new ThunkChunkX64(S, Dir, Helper); + return make<ThunkChunkX64>(S, Dir, Helper); case I386: - return new ThunkChunkX86(S, Dir, Helper); + return make<ThunkChunkX86>(S, Dir, Helper); default: llvm_unreachable("unsupported machine type"); } @@ -537,34 +515,32 @@ EdataContents::EdataContents() { for (Export &E : Config->Exports) MaxOrdinal = std::max(MaxOrdinal, E.Ordinal); - auto *DLLName = new StringChunk(sys::path::filename(Config->OutputFile)); - auto *AddressTab = new AddressTableChunk(MaxOrdinal); + auto *DLLName = make<StringChunk>(sys::path::filename(Config->OutputFile)); + auto *AddressTab = make<AddressTableChunk>(MaxOrdinal); std::vector<Chunk *> Names; for (Export &E : Config->Exports) if (!E.Noname) - Names.push_back(new StringChunk(E.ExportName)); + Names.push_back(make<StringChunk>(E.ExportName)); std::vector<Chunk *> Forwards; for (Export &E : Config->Exports) { if (E.ForwardTo.empty()) continue; - E.ForwardChunk = new StringChunk(E.ForwardTo); + E.ForwardChunk = make<StringChunk>(E.ForwardTo); Forwards.push_back(E.ForwardChunk); } - auto *NameTab = new NamePointersChunk(Names); - auto *OrdinalTab = new ExportOrdinalChunk(Names.size()); - auto *Dir = new ExportDirectoryChunk(MaxOrdinal, Names.size(), DLLName, - AddressTab, NameTab, OrdinalTab); - Chunks.push_back(std::unique_ptr<Chunk>(Dir)); - Chunks.push_back(std::unique_ptr<Chunk>(DLLName)); - Chunks.push_back(std::unique_ptr<Chunk>(AddressTab)); - Chunks.push_back(std::unique_ptr<Chunk>(NameTab)); - Chunks.push_back(std::unique_ptr<Chunk>(OrdinalTab)); - for (Chunk *C : Names) - Chunks.push_back(std::unique_ptr<Chunk>(C)); - for (Chunk *C : Forwards) - Chunks.push_back(std::unique_ptr<Chunk>(C)); + auto *NameTab = make<NamePointersChunk>(Names); + auto *OrdinalTab = make<ExportOrdinalChunk>(Names.size()); + auto *Dir = make<ExportDirectoryChunk>(MaxOrdinal, Names.size(), DLLName, + AddressTab, NameTab, OrdinalTab); + Chunks.push_back(Dir); + Chunks.push_back(DLLName); + Chunks.push_back(AddressTab); + Chunks.push_back(NameTab); + Chunks.push_back(OrdinalTab); + Chunks.insert(Chunks.end(), Names.begin(), Names.end()); + Chunks.insert(Chunks.end(), Forwards.begin(), Forwards.end()); } } // namespace coff diff --git a/COFF/DLL.h b/COFF/DLL.h index 83a12df185c2..939771b3290c 100644 --- a/COFF/DLL.h +++ b/COFF/DLL.h @@ -35,11 +35,10 @@ private: void create(); std::vector<DefinedImportData *> Imports; - std::vector<std::unique_ptr<Chunk>> Dirs; - std::vector<std::unique_ptr<Chunk>> Lookups; - std::vector<std::unique_ptr<Chunk>> Addresses; - std::vector<std::unique_ptr<Chunk>> Hints; - std::map<StringRef, std::unique_ptr<Chunk>> DLLNames; + std::vector<Chunk *> Dirs; + std::vector<Chunk *> Addresses; + std::vector<Chunk *> Hints; + std::vector<Chunk *> DLLNames; }; // Windows-specific. @@ -51,7 +50,7 @@ public: void create(Defined *Helper); std::vector<Chunk *> getChunks(); std::vector<Chunk *> getDataChunks(); - std::vector<std::unique_ptr<Chunk>> &getCodeChunks() { return Thunks; } + ArrayRef<Chunk *> getCodeChunks() { return Thunks; } uint64_t getDirRVA() { return Dirs[0]->getRVA(); } uint64_t getDirSize(); @@ -61,13 +60,13 @@ private: Defined *Helper; std::vector<DefinedImportData *> Imports; - std::vector<std::unique_ptr<Chunk>> Dirs; - std::vector<std::unique_ptr<Chunk>> ModuleHandles; - std::vector<std::unique_ptr<Chunk>> Addresses; - std::vector<std::unique_ptr<Chunk>> Names; - std::vector<std::unique_ptr<Chunk>> HintNames; - std::vector<std::unique_ptr<Chunk>> Thunks; - std::map<StringRef, std::unique_ptr<Chunk>> DLLNames; + std::vector<Chunk *> Dirs; + std::vector<Chunk *> ModuleHandles; + std::vector<Chunk *> Addresses; + std::vector<Chunk *> Names; + std::vector<Chunk *> HintNames; + std::vector<Chunk *> Thunks; + std::vector<Chunk *> DLLNames; }; // Windows-specific. @@ -75,7 +74,7 @@ private: class EdataContents { public: EdataContents(); - std::vector<std::unique_ptr<Chunk>> Chunks; + std::vector<Chunk *> Chunks; }; } // namespace coff diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp index 4c0ea44b875e..d871f942737d 100644 --- a/COFF/Driver.cpp +++ b/COFF/Driver.cpp @@ -19,6 +19,8 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Object/ArchiveWriter.h" +#include "llvm/Object/COFFImportFile.h" +#include "llvm/Object/COFFModuleDefinition.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" @@ -35,6 +37,7 @@ #include <future> using namespace llvm; +using namespace llvm::object; using namespace llvm::COFF; using llvm::sys::Process; using llvm::sys::fs::file_magic; @@ -97,12 +100,11 @@ static std::future<MBErrPair> createFutureForFile(std::string Path) { MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> MB) { MemoryBufferRef MBRef = *MB; - OwningMBs.push_back(std::move(MB)); + make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take ownership if (Driver->Tar) Driver->Tar->append(relativeToRoot(MBRef.getBufferIdentifier()), MBRef.getBuffer()); - return MBRef; } @@ -420,6 +422,84 @@ static std::string getMapFile(const opt::InputArgList &Args) { return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str(); } +static std::string getImplibPath() { + if (!Config->Implib.empty()) + return Config->Implib; + SmallString<128> Out = StringRef(Config->OutputFile); + sys::path::replace_extension(Out, ".lib"); + return Out.str(); +} + +std::vector<COFFShortExport> createCOFFShortExportFromConfig() { + std::vector<COFFShortExport> Exports; + for (Export &E1 : Config->Exports) { + COFFShortExport E2; + E2.Name = E1.Name; + E2.ExtName = E1.ExtName; + E2.Ordinal = E1.Ordinal; + E2.Noname = E1.Noname; + E2.Data = E1.Data; + E2.Private = E1.Private; + E2.Constant = E1.Constant; + Exports.push_back(E2); + } + return Exports; +} + +static void createImportLibrary() { + std::vector<COFFShortExport> Exports = createCOFFShortExportFromConfig(); + std::string DLLName = sys::path::filename(Config->OutputFile); + std::string Path = getImplibPath(); + writeImportLibrary(DLLName, Path, Exports, Config->Machine); +} + +static void parseModuleDefs(StringRef Path) { + std::unique_ptr<MemoryBuffer> MB = check( + MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); + MemoryBufferRef MBRef = MB->getMemBufferRef(); + + Expected<COFFModuleDefinition> Def = + parseCOFFModuleDefinition(MBRef, Config->Machine); + if (!Def) + fatal(errorToErrorCode(Def.takeError()).message()); + + COFFModuleDefinition &M = *Def; + if (Config->OutputFile.empty()) + Config->OutputFile = Saver.save(M.OutputFile); + + if (M.ImageBase) + Config->ImageBase = M.ImageBase; + if (M.StackReserve) + Config->StackReserve = M.StackReserve; + if (M.StackCommit) + Config->StackCommit = M.StackCommit; + if (M.HeapReserve) + Config->HeapReserve = M.HeapReserve; + if (M.HeapCommit) + Config->HeapCommit = M.HeapCommit; + if (M.MajorImageVersion) + Config->MajorImageVersion = M.MajorImageVersion; + if (M.MinorImageVersion) + Config->MinorImageVersion = M.MinorImageVersion; + if (M.MajorOSVersion) + Config->MajorOSVersion = M.MajorOSVersion; + if (M.MinorOSVersion) + Config->MinorOSVersion = M.MinorOSVersion; + + for (COFFShortExport E1 : M.Exports) { + Export E2; + E2.Name = Saver.save(E1.Name); + if (E1.isWeak()) + E2.ExtName = Saver.save(E1.ExtName); + E2.Ordinal = E1.Ordinal; + E2.Noname = E1.Noname; + E2.Data = E1.Data; + E2.Private = E1.Private; + E2.Constant = E1.Constant; + Config->Exports.push_back(E2); + } +} + std::vector<MemoryBufferRef> getArchiveMembers(Archive *File) { std::vector<MemoryBufferRef> V; Error Err = Error::success(); @@ -821,8 +901,6 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { Config->ManifestInput.push_back(Arg->getValue()); // Handle miscellaneous boolean flags. - if (Args.hasArg(OPT_allowbind_no)) - Config->AllowBind = false; if (Args.hasArg(OPT_allowisolation_no)) Config->AllowIsolation = false; if (Args.hasArg(OPT_dynamicbase_no)) @@ -834,7 +912,6 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { if (Args.hasArg(OPT_nosymtab)) Config->WriteSymtab = false; Config->DumpPdb = Args.hasArg(OPT_dumppdb); - Config->DebugPdb = Args.hasArg(OPT_debugpdb); Config->MapFile = getMapFile(Args); @@ -916,9 +993,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { // Handle /def if (auto *Arg = Args.getLastArg(OPT_deffile)) { // parseModuleDefs mutates Config object. - parseModuleDefs( - takeBuffer(check(MemoryBuffer::getFile(Arg->getValue()), - Twine("could not open ") + Arg->getValue()))); + parseModuleDefs(Arg->getValue()); } // Handle /delayload @@ -1038,7 +1113,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { // need to create a .lib file. if (!Config->Exports.empty() || Config->DLL) { fixupExports(); - writeImportLibrary(); + createImportLibrary(); assignExportOrdinals(); } diff --git a/COFF/Driver.h b/COFF/Driver.h index ad725625e030..3eb950cca25c 100644 --- a/COFF/Driver.h +++ b/COFF/Driver.h @@ -119,18 +119,11 @@ private: void enqueueTask(std::function<void()> Task); bool run(); - // Driver is the owner of all opened files. - // InputFiles have MemoryBufferRefs to them. - std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs; - std::list<std::function<void()>> TaskQueue; std::vector<StringRef> FilePaths; std::vector<MemoryBufferRef> Resources; }; -void parseModuleDefs(MemoryBufferRef MB); -void writeImportLibrary(); - // Functions below this line are defined in DriverUtils.cpp. void printHelp(const char *Argv0); diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp index 252590c7d870..ee4bd0f6b22c 100644 --- a/COFF/DriverUtils.cpp +++ b/COFF/DriverUtils.cpp @@ -43,7 +43,7 @@ namespace { class Executor { public: - explicit Executor(StringRef S) : Saver(Alloc), Prog(Saver.save(S)) {} + explicit Executor(StringRef S) : Prog(Saver.save(S)) {} void add(StringRef S) { Args.push_back(Saver.save(S)); } void add(std::string &S) { Args.push_back(Saver.save(S)); } void add(Twine S) { Args.push_back(Saver.save(S)); } @@ -67,8 +67,6 @@ public: } private: - BumpPtrAllocator Alloc; - StringSaver Saver; StringRef Prog; std::vector<StringRef> Args; }; diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp index df3b6a032cf8..6e6465cd5d62 100644 --- a/COFF/InputFiles.cpp +++ b/COFF/InputFiles.cpp @@ -137,13 +137,13 @@ void ObjectFile::initializeChunks() { // 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)); + DebugChunks.push_back(make<SectionChunk>(this, Sec)); continue; } if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) continue; - auto *C = new (Alloc) SectionChunk(this, Sec); + auto *C = make<SectionChunk>(this, Sec); Chunks.push_back(C); SparseChunks[I] = C; } @@ -200,7 +200,7 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, bool IsFirst) { StringRef Name; if (Sym.isCommon()) { - auto *C = new (Alloc) CommonChunk(Sym); + auto *C = make<CommonChunk>(Sym); Chunks.push_back(C); COFFObj->getSymbolName(Sym, Name); Symbol *S = @@ -221,7 +221,7 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, if (Sym.isExternal()) return Symtab->addAbsolute(Name, Sym)->body(); else - return new (Alloc) DefinedAbsolute(Name, Sym); + return make<DefinedAbsolute>(Name, Sym); } int32_t SectionNumber = Sym.getSectionNumber(); if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG) @@ -258,8 +258,8 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, Symtab->addRegular(this, Name, SC->isCOMDAT(), Sym.getGeneric(), SC); B = cast<DefinedRegular>(S->body()); } else - B = new (Alloc) DefinedRegular(this, /*Name*/ "", SC->isCOMDAT(), - /*IsExternal*/ false, Sym.getGeneric(), SC); + B = make<DefinedRegular>(this, /*Name*/ "", SC->isCOMDAT(), + /*IsExternal*/ false, Sym.getGeneric(), SC); if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP) SC->setSymbol(B); @@ -301,8 +301,8 @@ void ImportFile::parse() { fatal("broken import library"); // Read names and create an __imp_ symbol. - StringRef Name = StringAlloc.save(StringRef(Buf + sizeof(*Hdr))); - StringRef ImpName = StringAlloc.save("__imp_" + Name); + StringRef Name = Saver.save(StringRef(Buf + sizeof(*Hdr))); + StringRef ImpName = Saver.save("__imp_" + Name); const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1; DLLName = StringRef(NameStart); StringRef ExtName; diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h index a2fd3f59ad70..9e32b3b9f9d6 100644 --- a/COFF/InputFiles.h +++ b/COFF/InputFiles.h @@ -130,7 +130,6 @@ private: SymbolBody *createUndefined(COFFSymbolRef Sym); std::unique_ptr<COFFObjectFile> COFFObj; - llvm::BumpPtrAllocator Alloc; const coff_section *SXData = nullptr; // List of all chunks defined by this file. This includes both section @@ -162,8 +161,7 @@ private: // for details about the format. class ImportFile : public InputFile { public: - explicit ImportFile(MemoryBufferRef M) - : InputFile(ImportKind, M), StringAlloc(StringAllocAux) {} + explicit ImportFile(MemoryBufferRef M) : InputFile(ImportKind, M) {} static bool classof(const InputFile *F) { return F->kind() == ImportKind; } DefinedImportData *ImpSym = nullptr; @@ -174,9 +172,6 @@ public: private: void parse() override; - llvm::BumpPtrAllocator StringAllocAux; - llvm::StringSaver StringAlloc; - public: StringRef ExternalName; const coff_import_header *Hdr; diff --git a/COFF/Librarian.cpp b/COFF/Librarian.cpp deleted file mode 100644 index 91316ee6b0c9..000000000000 --- a/COFF/Librarian.cpp +++ /dev/null @@ -1,511 +0,0 @@ -//===- Librarian.cpp ------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains functions for the Librarian. The librarian creates and -// manages libraries of the Common Object File Format (COFF) object files. It -// primarily is used for creating static libraries and import libraries. -// -//===----------------------------------------------------------------------===// - -#include "Config.h" -#include "Driver.h" -#include "Error.h" -#include "Symbols.h" -#include "llvm/Object/Archive.h" -#include "llvm/Object/ArchiveWriter.h" -#include "llvm/Object/COFF.h" -#include "llvm/Support/Path.h" - -#include <vector> - -using namespace lld::coff; -using namespace llvm::COFF; -using namespace llvm::object; -using namespace llvm; - -static bool is32bit() { - switch (Config->Machine) { - default: - llvm_unreachable("unsupported machine"); - case IMAGE_FILE_MACHINE_AMD64: - return false; - case IMAGE_FILE_MACHINE_ARMNT: - case IMAGE_FILE_MACHINE_I386: - return true; - } -} - -static uint16_t getImgRelRelocation() { - switch (Config->Machine) { - default: - llvm_unreachable("unsupported machine"); - case IMAGE_FILE_MACHINE_AMD64: - return IMAGE_REL_AMD64_ADDR32NB; - case IMAGE_FILE_MACHINE_ARMNT: - return IMAGE_REL_ARM_ADDR32NB; - case IMAGE_FILE_MACHINE_I386: - return IMAGE_REL_I386_DIR32NB; - } -} - -template <class T> static void append(std::vector<uint8_t> &B, const T &Data) { - size_t S = B.size(); - B.resize(S + sizeof(T)); - memcpy(&B[S], &Data, sizeof(T)); -} - -static void writeStringTable(std::vector<uint8_t> &B, - ArrayRef<const std::string> Strings) { - // The COFF string table consists of a 4-byte value which is the size of the - // table, including the length field itself. This value is followed by the - // string content itself, which is an array of null-terminated C-style - // strings. The termination is important as they are referenced to by offset - // by the symbol entity in the file format. - - std::vector<uint8_t>::size_type Pos = B.size(); - std::vector<uint8_t>::size_type Offset = B.size(); - - // Skip over the length field, we will fill it in later as we will have - // computed the length while emitting the string content itself. - Pos += sizeof(uint32_t); - - for (const auto &S : Strings) { - B.resize(Pos + S.length() + 1); - strcpy(reinterpret_cast<char *>(&B[Pos]), S.c_str()); - Pos += S.length() + 1; - } - - // Backfill the length of the table now that it has been computed. - support::ulittle32_t Length(B.size() - Offset); - memcpy(&B[Offset], &Length, sizeof(Length)); -} - -static std::string getImplibPath() { - if (!Config->Implib.empty()) - return Config->Implib; - SmallString<128> Out = StringRef(Config->OutputFile); - sys::path::replace_extension(Out, ".lib"); - return Out.str(); -} - -static ImportNameType getNameType(StringRef Sym, StringRef ExtName) { - if (Sym != ExtName) - return IMPORT_NAME_UNDECORATE; - if (Config->Machine == I386 && Sym.startswith("_")) - return IMPORT_NAME_NOPREFIX; - return IMPORT_NAME; -} - -static std::string replace(StringRef S, StringRef From, StringRef To) { - size_t Pos = S.find(From); - - // From and To may be mangled, but substrings in S may not. - if (Pos == StringRef::npos && From.startswith("_") && To.startswith("_")) { - From = From.substr(1); - To = To.substr(1); - Pos = S.find(From); - } - - if (Pos == StringRef::npos) { - error(S + ": replacing '" + From + "' with '" + To + "' failed"); - return ""; - } - return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str(); -} - -static const std::string NullImportDescriptorSymbolName = - "__NULL_IMPORT_DESCRIPTOR"; - -namespace { -// This class constructs various small object files necessary to support linking -// symbols imported from a DLL. The contents are pretty strictly defined and -// nearly entirely static. The details of the structures files are defined in -// WINNT.h and the PE/COFF specification. -class ObjectFactory { - using u16 = support::ulittle16_t; - using u32 = support::ulittle32_t; - - BumpPtrAllocator Alloc; - StringRef DLLName; - StringRef Library; - std::string ImportDescriptorSymbolName; - std::string NullThunkSymbolName; - -public: - ObjectFactory(StringRef S) - : DLLName(S), Library(S.drop_back(4)), - ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()), - NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {} - - // Creates an Import Descriptor. This is a small object file which contains a - // reference to the terminators and contains the library name (entry) for the - // import name table. It will force the linker to construct the necessary - // structure to import symbols from the DLL. - NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer); - - // Creates a NULL import descriptor. This is a small object file whcih - // contains a NULL import descriptor. It is used to terminate the imports - // from a specific DLL. - NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer); - - // Create a NULL Thunk Entry. This is a small object file which contains a - // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It - // is used to terminate the IAT and ILT. - NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer); - - // Create a short import file which is described in PE/COFF spec 7. Import - // Library Format. - NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal, - ImportType Type, ImportNameType NameType); -}; -} - -NewArchiveMember -ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) { - static const uint32_t NumberOfSections = 2; - static const uint32_t NumberOfSymbols = 7; - static const uint32_t NumberOfRelocations = 3; - - // COFF Header - coff_file_header Header{ - u16(Config->Machine), u16(NumberOfSections), u32(0), - u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + - // .idata$2 - sizeof(coff_import_directory_table_entry) + - NumberOfRelocations * sizeof(coff_relocation) + - // .idata$4 - (DLLName.size() + 1)), - u32(NumberOfSymbols), u16(0), - u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0), - }; - append(Buffer, Header); - - // Section Header Table - static const coff_section SectionTable[NumberOfSections] = { - {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}, - u32(0), - u32(0), - u32(sizeof(coff_import_directory_table_entry)), - u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), - u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + - sizeof(coff_import_directory_table_entry)), - u32(0), - u16(NumberOfRelocations), - u16(0), - u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | - IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, - {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}, - u32(0), - u32(0), - u32(DLLName.size() + 1), - u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + - sizeof(coff_import_directory_table_entry) + - NumberOfRelocations * sizeof(coff_relocation)), - u32(0), - u32(0), - u16(0), - u16(0), - u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | - IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, - }; - append(Buffer, SectionTable); - - // .idata$2 - static const coff_import_directory_table_entry ImportDescriptor{ - u32(0), u32(0), u32(0), u32(0), u32(0), - }; - append(Buffer, ImportDescriptor); - - static const coff_relocation RelocationTable[NumberOfRelocations] = { - {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2), - u16(getImgRelRelocation())}, - {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)), - u32(3), u16(getImgRelRelocation())}, - {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)), - u32(4), u16(getImgRelRelocation())}, - }; - append(Buffer, RelocationTable); - - // .idata$6 - auto S = Buffer.size(); - Buffer.resize(S + DLLName.size() + 1); - memcpy(&Buffer[S], DLLName.data(), DLLName.size()); - Buffer[S + DLLName.size()] = '\0'; - - // Symbol Table - coff_symbol16 SymbolTable[NumberOfSymbols] = { - {{{0, 0, 0, 0, 0, 0, 0, 0}}, - u32(0), - u16(1), - u16(0), - IMAGE_SYM_CLASS_EXTERNAL, - 0}, - {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}}, - u32(0), - u16(1), - u16(0), - IMAGE_SYM_CLASS_SECTION, - 0}, - {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}}, - u32(0), - u16(2), - u16(0), - IMAGE_SYM_CLASS_STATIC, - 0}, - {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}}, - u32(0), - u16(0), - u16(0), - IMAGE_SYM_CLASS_SECTION, - 0}, - {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}}, - u32(0), - u16(0), - u16(0), - IMAGE_SYM_CLASS_SECTION, - 0}, - {{{0, 0, 0, 0, 0, 0, 0, 0}}, - u32(0), - u16(0), - u16(0), - IMAGE_SYM_CLASS_EXTERNAL, - 0}, - {{{0, 0, 0, 0, 0, 0, 0, 0}}, - u32(0), - u16(0), - u16(0), - IMAGE_SYM_CLASS_EXTERNAL, - 0}, - }; - reinterpret_cast<StringTableOffset &>(SymbolTable[0].Name).Offset = - sizeof(uint32_t); - reinterpret_cast<StringTableOffset &>(SymbolTable[5].Name).Offset = - sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1; - reinterpret_cast<StringTableOffset &>(SymbolTable[6].Name).Offset = - sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 + - NullImportDescriptorSymbolName.length() + 1; - append(Buffer, SymbolTable); - - // String Table - writeStringTable(Buffer, - {ImportDescriptorSymbolName, NullImportDescriptorSymbolName, - NullThunkSymbolName}); - - StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; - return {MemoryBufferRef(F, DLLName)}; -} - -NewArchiveMember -ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) { - static const uint32_t NumberOfSections = 1; - static const uint32_t NumberOfSymbols = 1; - - // COFF Header - coff_file_header Header{ - u16(Config->Machine), u16(NumberOfSections), u32(0), - u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + - // .idata$3 - sizeof(coff_import_directory_table_entry)), - u32(NumberOfSymbols), u16(0), - u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0), - }; - append(Buffer, Header); - - // Section Header Table - static const coff_section SectionTable[NumberOfSections] = { - {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'}, - u32(0), - u32(0), - u32(sizeof(coff_import_directory_table_entry)), - u32(sizeof(coff_file_header) + - (NumberOfSections * sizeof(coff_section))), - u32(0), - u32(0), - u16(0), - u16(0), - u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | - IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, - }; - append(Buffer, SectionTable); - - // .idata$3 - static const coff_import_directory_table_entry ImportDescriptor{ - u32(0), u32(0), u32(0), u32(0), u32(0), - }; - append(Buffer, ImportDescriptor); - - // Symbol Table - coff_symbol16 SymbolTable[NumberOfSymbols] = { - {{{0, 0, 0, 0, 0, 0, 0, 0}}, - u32(0), - u16(1), - u16(0), - IMAGE_SYM_CLASS_EXTERNAL, - 0}, - }; - reinterpret_cast<StringTableOffset &>(SymbolTable[0].Name).Offset = - sizeof(uint32_t); - append(Buffer, SymbolTable); - - // String Table - writeStringTable(Buffer, {NullImportDescriptorSymbolName}); - - StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; - return {MemoryBufferRef(F, DLLName)}; -} - -NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) { - static const uint32_t NumberOfSections = 2; - static const uint32_t NumberOfSymbols = 1; - uint32_t VASize = is32bit() ? 4 : 8; - - // COFF Header - coff_file_header Header{ - u16(Config->Machine), u16(NumberOfSections), u32(0), - u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + - // .idata$5 - VASize + - // .idata$4 - VASize), - u32(NumberOfSymbols), u16(0), - u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0), - }; - append(Buffer, Header); - - // Section Header Table - static const coff_section SectionTable[NumberOfSections] = { - {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}, - u32(0), - u32(0), - u32(VASize), - u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), - u32(0), - u32(0), - u16(0), - u16(0), - u32((is32bit() ? IMAGE_SCN_ALIGN_4BYTES : IMAGE_SCN_ALIGN_8BYTES) | - IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | - IMAGE_SCN_MEM_WRITE)}, - {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}, - u32(0), - u32(0), - u32(VASize), - u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + - VASize), - u32(0), - u32(0), - u16(0), - u16(0), - u32((is32bit() ? IMAGE_SCN_ALIGN_4BYTES : IMAGE_SCN_ALIGN_8BYTES) | - IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | - IMAGE_SCN_MEM_WRITE)}, - }; - append(Buffer, SectionTable); - - // .idata$5, ILT - append(Buffer, u32(0)); - if (!is32bit()) - append(Buffer, u32(0)); - - // .idata$4, IAT - append(Buffer, u32(0)); - if (!is32bit()) - append(Buffer, u32(0)); - - // Symbol Table - coff_symbol16 SymbolTable[NumberOfSymbols] = { - {{{0, 0, 0, 0, 0, 0, 0, 0}}, - u32(0), - u16(1), - u16(0), - IMAGE_SYM_CLASS_EXTERNAL, - 0}, - }; - reinterpret_cast<StringTableOffset &>(SymbolTable[0].Name).Offset = - sizeof(uint32_t); - append(Buffer, SymbolTable); - - // String Table - writeStringTable(Buffer, {NullThunkSymbolName}); - - StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; - return {MemoryBufferRef{F, DLLName}}; -} - -NewArchiveMember ObjectFactory::createShortImport(StringRef Sym, - uint16_t Ordinal, - ImportType ImportType, - ImportNameType NameType) { - size_t ImpSize = DLLName.size() + Sym.size() + 2; // +2 for NULs - size_t Size = sizeof(coff_import_header) + ImpSize; - char *Buf = Alloc.Allocate<char>(Size); - memset(Buf, 0, Size); - char *P = Buf; - - // Write short import library. - auto *Imp = reinterpret_cast<coff_import_header *>(P); - P += sizeof(*Imp); - Imp->Sig2 = 0xFFFF; - Imp->Machine = Config->Machine; - Imp->SizeOfData = ImpSize; - if (Ordinal > 0) - Imp->OrdinalHint = Ordinal; - Imp->TypeInfo = (NameType << 2) | ImportType; - - // Write symbol name and DLL name. - memcpy(P, Sym.data(), Sym.size()); - P += Sym.size() + 1; - memcpy(P, DLLName.data(), DLLName.size()); - - return {MemoryBufferRef(StringRef(Buf, Size), DLLName)}; -} - -// Creates an import library for a DLL. In this function, we first -// create an empty import library using lib.exe and then adds short -// import files to that file. -void lld::coff::writeImportLibrary() { - std::vector<NewArchiveMember> Members; - - std::string Path = getImplibPath(); - std::string DLLName = sys::path::filename(Config->OutputFile); - ObjectFactory OF(DLLName); - - std::vector<uint8_t> ImportDescriptor; - Members.push_back(OF.createImportDescriptor(ImportDescriptor)); - - std::vector<uint8_t> NullImportDescriptor; - Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor)); - - std::vector<uint8_t> NullThunk; - Members.push_back(OF.createNullThunk(NullThunk)); - - for (Export &E : Config->Exports) { - if (E.Private) - continue; - - ImportType ImportType = IMPORT_CODE; - if (E.Data) - ImportType = IMPORT_DATA; - if (E.Constant) - ImportType = IMPORT_CONST; - - ImportNameType NameType = getNameType(E.SymbolName, E.Name); - std::string Name = E.ExtName.empty() - ? std::string(E.SymbolName) - : replace(E.SymbolName, E.Name, E.ExtName); - Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType, - NameType)); - } - - std::pair<StringRef, std::error_code> Result = - writeArchive(Path, Members, /*WriteSymtab*/ true, object::Archive::K_GNU, - /*Deterministic*/ true, /*Thin*/ false); - if (auto EC = Result.second) - fatal(EC, "failed to write " + Path); -} diff --git a/COFF/ModuleDef.cpp b/COFF/ModuleDef.cpp deleted file mode 100644 index 740ce867a7c4..000000000000 --- a/COFF/ModuleDef.cpp +++ /dev/null @@ -1,304 +0,0 @@ -//===- COFF/ModuleDef.cpp -------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Windows-specific. -// A parser for the module-definition file (.def file). -// Parsed results are directly written to Config global variable. -// -// The format of module-definition files are described in this document: -// https://msdn.microsoft.com/en-us/library/28d6s79h.aspx -// -//===----------------------------------------------------------------------===// - -#include "Config.h" -#include "Error.h" -#include "Memory.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/StringSaver.h" -#include "llvm/Support/raw_ostream.h" -#include <system_error> - -using namespace llvm; - -namespace lld { -namespace coff { -namespace { - -enum Kind { - Unknown, - Eof, - Identifier, - Comma, - Equal, - KwBase, - KwConstant, - KwData, - KwExports, - KwHeapsize, - KwLibrary, - KwName, - KwNoname, - KwPrivate, - KwStacksize, - KwVersion, -}; - -struct Token { - explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {} - Kind K; - StringRef Value; -}; - -static bool isDecorated(StringRef Sym) { - return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?"); -} - -class Lexer { -public: - explicit Lexer(StringRef S) : Buf(S) {} - - Token lex() { - Buf = Buf.trim(); - if (Buf.empty()) - return Token(Eof); - - switch (Buf[0]) { - case '\0': - return Token(Eof); - case ';': { - size_t End = Buf.find('\n'); - Buf = (End == Buf.npos) ? "" : Buf.drop_front(End); - return lex(); - } - case '=': - Buf = Buf.drop_front(); - return Token(Equal, "="); - case ',': - Buf = Buf.drop_front(); - return Token(Comma, ","); - case '"': { - StringRef S; - std::tie(S, Buf) = Buf.substr(1).split('"'); - return Token(Identifier, S); - } - default: { - size_t End = Buf.find_first_of("=,\r\n \t\v"); - StringRef Word = Buf.substr(0, End); - Kind K = llvm::StringSwitch<Kind>(Word) - .Case("BASE", KwBase) - .Case("CONSTANT", KwConstant) - .Case("DATA", KwData) - .Case("EXPORTS", KwExports) - .Case("HEAPSIZE", KwHeapsize) - .Case("LIBRARY", KwLibrary) - .Case("NAME", KwName) - .Case("NONAME", KwNoname) - .Case("PRIVATE", KwPrivate) - .Case("STACKSIZE", KwStacksize) - .Case("VERSION", KwVersion) - .Default(Identifier); - Buf = (End == Buf.npos) ? "" : Buf.drop_front(End); - return Token(K, Word); - } - } - } - -private: - StringRef Buf; -}; - -class Parser { -public: - explicit Parser(StringRef S) : Lex(S) {} - - void parse() { - do { - parseOne(); - } while (Tok.K != Eof); - } - -private: - void read() { - if (Stack.empty()) { - Tok = Lex.lex(); - return; - } - Tok = Stack.back(); - Stack.pop_back(); - } - - void readAsInt(uint64_t *I) { - read(); - if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I)) - fatal("integer expected"); - } - - void expect(Kind Expected, StringRef Msg) { - read(); - if (Tok.K != Expected) - fatal(Msg); - } - - void unget() { Stack.push_back(Tok); } - - void parseOne() { - read(); - switch (Tok.K) { - case Eof: - return; - case KwExports: - for (;;) { - read(); - if (Tok.K != Identifier) { - unget(); - return; - } - parseExport(); - } - case KwHeapsize: - parseNumbers(&Config->HeapReserve, &Config->HeapCommit); - return; - case KwStacksize: - parseNumbers(&Config->StackReserve, &Config->StackCommit); - return; - case KwLibrary: - case KwName: { - bool IsDll = Tok.K == KwLibrary; // Check before parseName. - std::string Name; - parseName(&Name, &Config->ImageBase); - - // Append the appropriate file extension if not already present. - StringRef Ext = IsDll ? ".dll" : ".exe"; - if (!StringRef(Name).endswith_lower(Ext)) - Name += Ext; - - // Set the output file, but don't override /out if it was already passed. - if (Config->OutputFile.empty()) - Config->OutputFile = Name; - return; - } - case KwVersion: - parseVersion(&Config->MajorImageVersion, &Config->MinorImageVersion); - return; - default: - fatal("unknown directive: " + Tok.Value); - } - } - - void parseExport() { - Export E; - E.Name = Tok.Value; - read(); - if (Tok.K == Equal) { - read(); - if (Tok.K != Identifier) - fatal("identifier expected, but got " + Tok.Value); - E.ExtName = E.Name; - E.Name = Tok.Value; - } else { - unget(); - } - - if (Config->Machine == I386) { - if (!isDecorated(E.Name)) - E.Name = Saver.save("_" + E.Name); - if (!E.ExtName.empty() && !isDecorated(E.ExtName)) - E.ExtName = Saver.save("_" + E.ExtName); - } - - for (;;) { - read(); - if (Tok.K == Identifier && Tok.Value[0] == '@') { - Tok.Value.drop_front().getAsInteger(10, E.Ordinal); - read(); - if (Tok.K == KwNoname) { - E.Noname = true; - } else { - unget(); - } - continue; - } - if (Tok.K == KwData) { - E.Data = true; - continue; - } - if (Tok.K == KwConstant) { - warn("CONSTANT keyword is obsolete; use DATA"); - E.Constant = true; - continue; - } - if (Tok.K == KwPrivate) { - E.Private = true; - continue; - } - unget(); - Config->Exports.push_back(E); - return; - } - } - - // HEAPSIZE/STACKSIZE reserve[,commit] - void parseNumbers(uint64_t *Reserve, uint64_t *Commit) { - readAsInt(Reserve); - read(); - if (Tok.K != Comma) { - unget(); - Commit = nullptr; - return; - } - readAsInt(Commit); - } - - // NAME outputPath [BASE=address] - void parseName(std::string *Out, uint64_t *Baseaddr) { - read(); - if (Tok.K == Identifier) { - *Out = Tok.Value; - } else { - *Out = ""; - unget(); - return; - } - read(); - if (Tok.K == KwBase) { - expect(Equal, "'=' expected"); - readAsInt(Baseaddr); - } else { - unget(); - *Baseaddr = 0; - } - } - - // VERSION major[.minor] - void parseVersion(uint32_t *Major, uint32_t *Minor) { - read(); - if (Tok.K != Identifier) - fatal("identifier expected, but got " + Tok.Value); - StringRef V1, V2; - std::tie(V1, V2) = Tok.Value.split('.'); - if (V1.getAsInteger(10, *Major)) - fatal("integer expected, but got " + Tok.Value); - if (V2.empty()) - *Minor = 0; - else if (V2.getAsInteger(10, *Minor)) - fatal("integer expected, but got " + Tok.Value); - } - - Lexer Lex; - Token Tok; - std::vector<Token> Stack; -}; - -} // anonymous namespace - -void parseModuleDefs(MemoryBufferRef MB) { Parser(MB.getBuffer()).parse(); } - -} // namespace coff -} // namespace lld diff --git a/COFF/Options.td b/COFF/Options.td index 7b5573b31cd3..14a1aa04afd6 100644 --- a/COFF/Options.td +++ b/COFF/Options.td @@ -102,7 +102,6 @@ def nosymtab : F<"nosymtab">; def msvclto : F<"msvclto">; // Flags for debugging -def debugpdb : F<"debugpdb">; def dumppdb : Joined<["/", "-"], "dumppdb">; def lldmap : F<"lldmap">; def lldmap_file : Joined<["/", "-"], "lldmap:">; diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp index 61b0c64de3a8..0266148cc6c9 100644 --- a/COFF/PDB.cpp +++ b/COFF/PDB.cpp @@ -14,7 +14,8 @@ #include "SymbolTable.h" #include "Symbols.h" #include "llvm/DebugInfo/CodeView/CVDebugRecord.h" -#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" #include "llvm/DebugInfo/CodeView/SymbolDumper.h" #include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" @@ -107,6 +108,7 @@ static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder, BinaryByteStream Stream(Data, support::little); codeview::CVTypeArray Types; BinaryStreamReader Reader(Stream); + SmallVector<TypeIndex, 128> SourceToDest; // Follow type servers. If the same type server is encountered more than // once for this instance of `PDBTypeServerHandler` (for example if many // object files reference the same TypeServer), the types from the @@ -115,8 +117,8 @@ static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder, Handler.addSearchPath(llvm::sys::path::parent_path(File->getName())); if (auto EC = Reader.readArray(Types, Reader.getLength())) fatal(EC, "Reader::readArray failed"); - if (auto Err = - codeview::mergeTypeStreams(IDTable, TypeTable, &Handler, Types)) + if (auto Err = codeview::mergeTypeStreams(IDTable, TypeTable, SourceToDest, + &Handler, Types)) fatal(Err, "codeview::mergeTypeStreams failed"); } @@ -133,12 +135,11 @@ static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) { if (Data.empty()) return; - TypeDatabase TDB(0); - TypeDumpVisitor TDV(TDB, &W, false); + LazyRandomTypeCollection Types(Data, 100); + TypeDumpVisitor TDV(Types, &W, false); // Use a default implementation that does not follow type servers and instead // just dumps the contents of the TypeServer2 record. - CVTypeDumper TypeDumper(TDB); - if (auto EC = TypeDumper.dump(Data, TDV)) + if (auto EC = codeview::visitTypeStream(Types, TDV)) fatal(EC, "CVTypeDumper::dump failed"); } diff --git a/COFF/SymbolTable.h b/COFF/SymbolTable.h index bf8d6618d964..0aa8a4593b5c 100644 --- a/COFF/SymbolTable.h +++ b/COFF/SymbolTable.h @@ -15,7 +15,6 @@ #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMapInfo.h" -#include "llvm/Support/Allocator.h" #include "llvm/Support/raw_ostream.h" namespace llvm { diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp index 5c9c8375dadc..cf3ad7ef045c 100644 --- a/COFF/Writer.cpp +++ b/COFF/Writer.cpp @@ -48,8 +48,7 @@ namespace { class DebugDirectoryChunk : public Chunk { public: - DebugDirectoryChunk(const std::vector<std::unique_ptr<Chunk>> &R) - : Records(R) {} + DebugDirectoryChunk(const std::vector<Chunk *> &R) : Records(R) {} size_t getSize() const override { return Records.size() * sizeof(debug_directory); @@ -58,7 +57,7 @@ public: void writeTo(uint8_t *B) const override { auto *D = reinterpret_cast<debug_directory *>(B + OutputSectionOff); - for (const std::unique_ptr<Chunk> &Record : Records) { + for (const Chunk *Record : Records) { D->Characteristics = 0; D->TimeDateStamp = 0; D->MajorVersion = 0; @@ -74,7 +73,7 @@ public: } private: - const std::vector<std::unique_ptr<Chunk>> &Records; + const std::vector<Chunk *> &Records; }; class CVDebugRecordChunk : public Chunk { @@ -142,10 +141,10 @@ private: IdataContents Idata; DelayLoadContents DelayIdata; EdataContents Edata; - std::unique_ptr<SEHTableChunk> SEHTable; + SEHTableChunk *SEHTable = nullptr; - std::unique_ptr<Chunk> DebugDirectory; - std::vector<std::unique_ptr<Chunk>> DebugRecords; + Chunk *DebugDirectory = nullptr; + std::vector<Chunk *> DebugRecords; CVDebugRecordChunk *BuildId = nullptr; ArrayRef<uint8_t> SectionTable; @@ -153,8 +152,6 @@ private: uint32_t PointerToSymbolTable = 0; uint64_t SizeOfImage; uint64_t SizeOfHeaders; - - std::vector<std::unique_ptr<Chunk>> Chunks; }; } // anonymous namespace @@ -258,7 +255,7 @@ void Writer::run() { sortExceptionTable(); writeBuildId(); - if (!Config->PDBPath.empty()) { + if (!Config->PDBPath.empty() && Config->Debug) { const llvm::codeview::DebugInfo *DI = nullptr; if (Config->DebugTypes & static_cast<unsigned>(coff::DebugType::CV)) DI = BuildId->DI; @@ -324,19 +321,19 @@ void Writer::createMiscChunks() { // Create Debug Information Chunks if (Config->Debug) { - DebugDirectory = llvm::make_unique<DebugDirectoryChunk>(DebugRecords); + DebugDirectory = make<DebugDirectoryChunk>(DebugRecords); // TODO(compnerd) create a coffgrp entry if DebugType::CV is not enabled if (Config->DebugTypes & static_cast<unsigned>(coff::DebugType::CV)) { - auto Chunk = llvm::make_unique<CVDebugRecordChunk>(); + auto *Chunk = make<CVDebugRecordChunk>(); - BuildId = Chunk.get(); - DebugRecords.push_back(std::move(Chunk)); + BuildId = Chunk; + DebugRecords.push_back(Chunk); } - RData->addChunk(DebugDirectory.get()); - for (const std::unique_ptr<Chunk> &C : DebugRecords) - RData->addChunk(C.get()); + RData->addChunk(DebugDirectory); + for (Chunk *C : DebugRecords) + RData->addChunk(C); } // Create SEH table. x86-only. @@ -352,8 +349,8 @@ void Writer::createMiscChunks() { Handlers.insert(cast<Defined>(B)); } - SEHTable.reset(new SEHTableChunk(Handlers)); - RData->addChunk(SEHTable.get()); + SEHTable = make<SEHTableChunk>(Handlers); + RData->addChunk(SEHTable); } // Create .idata section for the DLL-imported symbol table. @@ -398,8 +395,8 @@ void Writer::createImportTables() { for (Chunk *C : DelayIdata.getDataChunks()) Sec->addChunk(C); Sec = createSection(".text"); - for (std::unique_ptr<Chunk> &C : DelayIdata.getCodeChunks()) - Sec->addChunk(C.get()); + for (Chunk *C : DelayIdata.getCodeChunks()) + Sec->addChunk(C); } } @@ -407,8 +404,8 @@ void Writer::createExportTable() { if (Config->Exports.empty()) return; OutputSection *Sec = createSection(".edata"); - for (std::unique_ptr<Chunk> &C : Edata.Chunks) - Sec->addChunk(C.get()); + for (Chunk *C : Edata.Chunks) + Sec->addChunk(C); } // The Windows loader doesn't seem to like empty sections, @@ -602,14 +599,19 @@ template <typename PEHeaderTy> void Writer::writeHeader() { PE->SizeOfStackCommit = Config->StackCommit; PE->SizeOfHeapReserve = Config->HeapReserve; PE->SizeOfHeapCommit = Config->HeapCommit; + + // Import Descriptor Tables and Import Address Tables are merged + // in our output. That's not compatible with the Binding feature + // that is sort of prelinking. Setting this flag to make it clear + // that our outputs are not for the Binding. + PE->DLLCharacteristics = IMAGE_DLL_CHARACTERISTICS_NO_BIND; + if (Config->AppContainer) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER; if (Config->DynamicBase) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; if (Config->HighEntropyVA) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA; - if (!Config->AllowBind) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND; if (Config->NxCompat) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; if (!Config->AllowIsolation) diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index 87896ec96b29..e8cfd21c4c49 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -390,14 +390,28 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A, } } -template <class ELFT> -static typename ELFT::uint -getRelocTargetVA(uint32_t Type, int64_t A, typename ELFT::uint P, - const SymbolBody &Body, RelExpr Expr) { +// ARM SBREL relocations are of the form S + A - B where B is the static base +// The ARM ABI defines base to be "addressing origin of the output segment +// defining the symbol S". We defined the "addressing origin"/static base to be +// the base of the PT_LOAD segment containing the Body. +// The procedure call standard only defines a Read Write Position Independent +// RWPI variant so in practice we should expect the static base to be the base +// of the RW segment. +static uint64_t getARMStaticBase(const SymbolBody &Body) { + OutputSection *OS = Body.getOutputSection(); + if (!OS || !OS->FirstInPtLoad) + fatal("SBREL relocation to " + Body.getName() + " without static base\n"); + return OS->FirstInPtLoad->Addr; +} + +static uint64_t getRelocTargetVA(uint32_t Type, int64_t A, uint64_t P, + const SymbolBody &Body, RelExpr Expr) { switch (Expr) { case R_ABS: case R_RELAX_GOT_PC_NOPIC: return Body.getVA(A); + case R_ARM_SBREL: + return Body.getVA(A) - getARMStaticBase(Body); case R_GOT: case R_RELAX_TLS_GD_TO_IE_ABS: return Body.getGotVA() + A; @@ -518,7 +532,7 @@ getRelocTargetVA(uint32_t Type, int64_t A, typename ELFT::uint P, case R_NEG_TLS: return Out::TlsPhdr->p_memsz - Body.getVA(A); case R_SIZE: - return Body.getSize<ELFT>() + A; + return A; // Body.getSize was already folded into the addend. case R_TLSDESC: return InX::Got->getGlobalDynAddr(Body) + A; case R_TLSDESC_PAGE: @@ -566,7 +580,7 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) { uint64_t SymVA = 0; if (!Sym.isTls() || Out::TlsPhdr) SymVA = SignExtend64<sizeof(typename ELFT::uint) * 8>( - getRelocTargetVA<ELFT>(Type, Addend, AddrLoc, Sym, R_ABS)); + getRelocTargetVA(Type, Addend, AddrLoc, Sym, R_ABS)); Target->relocateOne(BufLoc, Type, SymVA); } } @@ -577,19 +591,28 @@ template <class ELFT> elf::ObjectFile<ELFT> *InputSectionBase::getFile() const { template <class ELFT> void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) { + if (Flags & SHF_ALLOC) + relocateAlloc(Buf, BufEnd); + else + relocateNonAlloc<ELFT>(Buf, BufEnd); +} + +template <class ELFT> +void InputSectionBase::relocateNonAlloc(uint8_t *Buf, uint8_t *BufEnd) { // scanReloc function in Writer.cpp constructs Relocations // vector only for SHF_ALLOC'ed sections. For other sections, // we handle relocations directly here. - auto *IS = dyn_cast<InputSection>(this); - if (IS && !(IS->Flags & SHF_ALLOC)) { - if (IS->AreRelocsRela) - IS->relocateNonAlloc<ELFT>(Buf, IS->template relas<ELFT>()); - else - IS->relocateNonAlloc<ELFT>(Buf, IS->template rels<ELFT>()); - return; - } + auto *IS = cast<InputSection>(this); + assert(!(IS->Flags & SHF_ALLOC)); + if (IS->AreRelocsRela) + IS->relocateNonAlloc<ELFT>(Buf, IS->template relas<ELFT>()); + else + IS->relocateNonAlloc<ELFT>(Buf, IS->template rels<ELFT>()); +} - const unsigned Bits = sizeof(typename ELFT::uint) * 8; +void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) { + assert(Flags & SHF_ALLOC); + const unsigned Bits = Config->Wordsize * 8; for (const Relocation &Rel : Relocations) { uint64_t Offset = getOffset(Rel.Offset); uint8_t *BufLoc = Buf + Offset; @@ -597,8 +620,8 @@ void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) { uint64_t AddrLoc = getOutputSection()->Addr + Offset; RelExpr Expr = Rel.Expr; - uint64_t TargetVA = SignExtend64<Bits>( - getRelocTargetVA<ELFT>(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr)); + uint64_t TargetVA = SignExtend64( + getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), Bits); switch (Expr) { case R_RELAX_GOT_PC: diff --git a/ELF/InputSection.h b/ELF/InputSection.h index 57458588b690..303c398b58cd 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -167,6 +167,8 @@ public: template <class ELFT> std::string getObjMsg(uint64_t Offset); template <class ELFT> void relocate(uint8_t *Buf, uint8_t *BufEnd); + void relocateAlloc(uint8_t *Buf, uint8_t *BufEnd); + template <class ELFT> void relocateNonAlloc(uint8_t *Buf, uint8_t *BufEnd); std::vector<Relocation> Relocations; diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index 161909abf00d..c303f0524ad4 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -440,9 +440,6 @@ void LinkerScript::fabricateDefaultCommands() { // For each OutputSection that needs a VA fabricate an OutputSectionCommand // with an InputSectionDescription describing the InputSections for (OutputSection *Sec : *OutputSections) { - if (!(Sec->Flags & SHF_ALLOC)) - continue; - auto *OSCmd = make<OutputSectionCommand>(Sec->Name); OSCmd->Sec = Sec; SecToCommand[Sec] = OSCmd; diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp index 23c63e845c9a..7b82eceba02a 100644 --- a/ELF/MapFile.cpp +++ b/ELF/MapFile.cpp @@ -21,6 +21,8 @@ #include "MapFile.h" #include "InputFiles.h" +#include "LinkerScript.h" +#include "OutputSections.h" #include "Strings.h" #include "SymbolTable.h" #include "Threads.h" @@ -98,7 +100,7 @@ getSymbolStrings(ArrayRef<DefinedRegular *> Syms) { } template <class ELFT> -void elf::writeMapFile(ArrayRef<OutputSection *> OutputSections) { +void elf::writeMapFile(llvm::ArrayRef<BaseCommand *> Script) { if (Config->MapFile.empty()) return; @@ -121,7 +123,11 @@ void elf::writeMapFile(ArrayRef<OutputSection *> OutputSections) { << " Align Out In Symbol\n"; // Print out file contents. - for (OutputSection *OSec : OutputSections) { + for (BaseCommand *Base : Script) { + auto *Cmd = dyn_cast<OutputSectionCommand>(Base); + if (!Cmd) + continue; + OutputSection *OSec = Cmd->Sec; writeHeader<ELFT>(OS, OSec->Addr, OSec->Size, OSec->Alignment); OS << OSec->Name << '\n'; @@ -136,7 +142,7 @@ void elf::writeMapFile(ArrayRef<OutputSection *> OutputSections) { } } -template void elf::writeMapFile<ELF32LE>(ArrayRef<OutputSection *>); -template void elf::writeMapFile<ELF32BE>(ArrayRef<OutputSection *>); -template void elf::writeMapFile<ELF64LE>(ArrayRef<OutputSection *>); -template void elf::writeMapFile<ELF64BE>(ArrayRef<OutputSection *>); +template void elf::writeMapFile<ELF32LE>(ArrayRef<BaseCommand *>); +template void elf::writeMapFile<ELF32BE>(ArrayRef<BaseCommand *>); +template void elf::writeMapFile<ELF64LE>(ArrayRef<BaseCommand *>); +template void elf::writeMapFile<ELF64BE>(ArrayRef<BaseCommand *>); diff --git a/ELF/MapFile.h b/ELF/MapFile.h index 24d636890e53..f50ef00061ff 100644 --- a/ELF/MapFile.h +++ b/ELF/MapFile.h @@ -10,12 +10,12 @@ #ifndef LLD_ELF_MAPFILE_H #define LLD_ELF_MAPFILE_H -#include "OutputSections.h" +#include <llvm/ADT/ArrayRef.h> namespace lld { namespace elf { -template <class ELFT> -void writeMapFile(llvm::ArrayRef<OutputSection *> OutputSections); +struct BaseCommand; +template <class ELFT> void writeMapFile(llvm::ArrayRef<BaseCommand *> Script); } } diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index c505a14f3c64..5564ea246eeb 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -935,6 +935,10 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { bool IsConstant = isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, Sec, Rel.r_offset); + // The size is not going to change, so we fold it in here. + if (Expr == R_SIZE) + Addend += Body.getSize<ELFT>(); + // If the output being produced is position independent, the final value // is still not known. In that case we still need some help from the // dynamic linker. We can however do better than just copying the incoming diff --git a/ELF/Relocations.h b/ELF/Relocations.h index f3512e0a89fc..206f0d9423c9 100644 --- a/ELF/Relocations.h +++ b/ELF/Relocations.h @@ -27,6 +27,7 @@ class OutputSection; // doesn't have to know about architecture-specific details. enum RelExpr { R_ABS, + R_ARM_SBREL, R_GOT, R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index 5a2c2c37efd8..599f1441a47f 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -600,7 +600,7 @@ template <class ELFT> void EhFrameSection<ELFT>::writeTo(uint8_t *Buf) { } for (EhInputSection *S : Sections) - S->template relocate<ELFT>(Buf, nullptr); + S->relocateAlloc(Buf, nullptr); // Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table // to get a FDE from an address to which FDE is applied. So here @@ -617,16 +617,16 @@ template <class ELFT> void EhFrameSection<ELFT>::writeTo(uint8_t *Buf) { } } -GotBaseSection::GotBaseSection() +GotSection::GotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Target->GotEntrySize, ".got") {} -void GotBaseSection::addEntry(SymbolBody &Sym) { +void GotSection::addEntry(SymbolBody &Sym) { Sym.GotIndex = NumEntries; ++NumEntries; } -bool GotBaseSection::addDynTlsEntry(SymbolBody &Sym) { +bool GotSection::addDynTlsEntry(SymbolBody &Sym) { if (Sym.GlobalDynIndex != -1U) return false; Sym.GlobalDynIndex = NumEntries; @@ -637,7 +637,7 @@ bool GotBaseSection::addDynTlsEntry(SymbolBody &Sym) { // Reserves TLS entries for a TLS module ID and a TLS block offset. // In total it takes two GOT slots. -bool GotBaseSection::addTlsIndex() { +bool GotSection::addTlsIndex() { if (TlsIndexOff != uint32_t(-1)) return false; TlsIndexOff = NumEntries * Config->Wordsize; @@ -645,27 +645,23 @@ bool GotBaseSection::addTlsIndex() { return true; } -uint64_t GotBaseSection::getGlobalDynAddr(const SymbolBody &B) const { +uint64_t GotSection::getGlobalDynAddr(const SymbolBody &B) const { return this->getVA() + B.GlobalDynIndex * Config->Wordsize; } -uint64_t GotBaseSection::getGlobalDynOffset(const SymbolBody &B) const { +uint64_t GotSection::getGlobalDynOffset(const SymbolBody &B) const { return B.GlobalDynIndex * Config->Wordsize; } -void GotBaseSection::finalizeContents() { - Size = NumEntries * Config->Wordsize; -} +void GotSection::finalizeContents() { Size = NumEntries * Config->Wordsize; } -bool GotBaseSection::empty() const { +bool GotSection::empty() const { // If we have a relocation that is relative to GOT (such as GOTOFFREL), // we need to emit a GOT even if it's empty. return NumEntries == 0 && !HasGotOffRel; } -template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) { - this->template relocate<ELFT>(Buf, Buf + Size); -} +void GotSection::writeTo(uint8_t *Buf) { relocateAlloc(Buf, Buf + Size); } MipsGotSection::MipsGotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16, @@ -2242,7 +2238,7 @@ StringTableSection *InX::DynStrTab; SymbolTableBaseSection *InX::DynSymTab; InputSection *InX::Interp; GdbIndexSection *InX::GdbIndex; -GotBaseSection *InX::Got; +GotSection *InX::Got; GotPltSection *InX::GotPlt; GnuHashTableSection *InX::GnuHashTab; IgotPltSection *InX::IgotPlt; @@ -2284,11 +2280,6 @@ template class elf::MipsReginfoSection<ELF32BE>; template class elf::MipsReginfoSection<ELF64LE>; template class elf::MipsReginfoSection<ELF64BE>; -template class elf::GotSection<ELF32LE>; -template class elf::GotSection<ELF32BE>; -template class elf::GotSection<ELF64LE>; -template class elf::GotSection<ELF64BE>; - template class elf::DynamicSection<ELF32LE>; template class elf::DynamicSection<ELF32BE>; template class elf::DynamicSection<ELF64LE>; diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h index 0477c601a7df..c5ffb88c1366 100644 --- a/ELF/SyntheticSections.h +++ b/ELF/SyntheticSections.h @@ -104,12 +104,13 @@ private: llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap; }; -class GotBaseSection : public SyntheticSection { +class GotSection : public SyntheticSection { public: - GotBaseSection(); + GotSection(); size_t getSize() const override { return Size; } void finalizeContents() override; bool empty() const override; + void writeTo(uint8_t *Buf) override; void addEntry(SymbolBody &Sym); bool addDynTlsEntry(SymbolBody &Sym); @@ -130,11 +131,6 @@ protected: uint64_t Size = 0; }; -template <class ELFT> class GotSection final : public GotBaseSection { -public: - void writeTo(uint8_t *Buf) override; -}; - // .note.gnu.build-id section. class BuildIdSection : public SyntheticSection { // First 16 bytes are a header. @@ -764,7 +760,7 @@ struct InX { static GnuHashTableSection *GnuHashTab; static InputSection *Interp; static GdbIndexSection *GdbIndex; - static GotBaseSection *Got; + static GotSection *Got; static GotPltSection *GotPlt; static IgotPltSection *IgotPlt; static MipsGotSection *MipsGot; diff --git a/ELF/Target.cpp b/ELF/Target.cpp index 781d7fe3bc3f..cf7d912ad829 100644 --- a/ELF/Target.cpp +++ b/ELF/Target.cpp @@ -1693,6 +1693,8 @@ RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, case R_ARM_TLS_IE32: // GOT(S) + A - P return R_GOT_PC; + case R_ARM_SBREL32: + return R_ARM_SBREL; case R_ARM_TARGET1: return Config->Target1Rel ? R_PC : R_ABS; case R_ARM_TARGET2: @@ -1832,6 +1834,7 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, case R_ARM_GOT_PREL: case R_ARM_REL32: case R_ARM_RELATIVE: + case R_ARM_SBREL32: case R_ARM_TARGET1: case R_ARM_TARGET2: case R_ARM_TLS_GD32: diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 4be6fe53c18b..7a21d2b9f13d 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -288,8 +288,13 @@ template <class ELFT> void Writer<ELFT>::run() { if (ErrorCount) return; + // Clear the OutputSections to make sure it is not used anymore. Any + // code from this point on should be using the linker script + // commands. + OutputSections.clear(); + // Handle -Map option. - writeMapFile<ELFT>(OutputSections); + writeMapFile<ELFT>(Script->Opt.Commands); if (ErrorCount) return; @@ -403,7 +408,7 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() { InX::MipsGot = make<MipsGotSection>(); Add(InX::MipsGot); } else { - InX::Got = make<GotSection<ELFT>>(); + InX::Got = make<GotSection>(); Add(InX::Got); } @@ -626,22 +631,22 @@ bool elf::isRelroSection(const OutputSection *Sec) { // * It is easy to check if a give branch was taken. // * It is easy two see how similar two ranks are (see getRankProximity). enum RankFlags { - RF_NOT_ADDR_SET = 1 << 16, - RF_NOT_INTERP = 1 << 15, - RF_NOT_ALLOC = 1 << 14, - RF_WRITE = 1 << 13, - RF_EXEC = 1 << 12, - RF_NON_TLS_BSS = 1 << 11, - RF_NON_TLS_BSS_RO = 1 << 10, - RF_NOT_TLS = 1 << 9, - RF_BSS = 1 << 8, - RF_PPC_NOT_TOCBSS = 1 << 7, - RF_PPC_OPD = 1 << 6, - RF_PPC_TOCL = 1 << 5, - RF_PPC_TOC = 1 << 4, - RF_PPC_BRANCH_LT = 1 << 3, - RF_MIPS_GPREL = 1 << 2, - RF_MIPS_NOT_GOT = 1 << 1 + RF_NOT_ADDR_SET = 1 << 15, + RF_NOT_INTERP = 1 << 14, + RF_NOT_ALLOC = 1 << 13, + RF_WRITE = 1 << 12, + RF_EXEC = 1 << 11, + RF_NON_TLS_BSS = 1 << 10, + RF_NON_TLS_BSS_RO = 1 << 9, + RF_NOT_TLS = 1 << 8, + RF_BSS = 1 << 7, + RF_PPC_NOT_TOCBSS = 1 << 6, + RF_PPC_OPD = 1 << 5, + RF_PPC_TOCL = 1 << 4, + RF_PPC_TOC = 1 << 3, + RF_PPC_BRANCH_LT = 1 << 2, + RF_MIPS_GPREL = 1 << 1, + RF_MIPS_NOT_GOT = 1 << 0 }; static unsigned getSectionRank(const OutputSection *Sec) { diff --git a/test/COFF/armnt-imports.test b/test/COFF/armnt-imports.test index 519886eb0c06..f0aaebd3f293 100644 --- a/test/COFF/armnt-imports.test +++ b/test/COFF/armnt-imports.test @@ -6,7 +6,7 @@ # CHECK: Import { # CHECK: Name: library.dll # CHECK: ImportLookupTableRVA: 0x2028 -# CHECK: ImportAddressTableRVA: 0x2030 +# CHECK: ImportAddressTableRVA: 0x2028 # CHECK: Symbol: function (0) # CHECK: } diff --git a/test/COFF/hello32.test b/test/COFF/hello32.test index b7bc887d46eb..b7c5f28c3534 100644 --- a/test/COFF/hello32.test +++ b/test/COFF/hello32.test @@ -41,9 +41,10 @@ HEADER-NEXT: MinorSubsystemVersion: 0 HEADER-NEXT: SizeOfImage: 16896 HEADER-NEXT: SizeOfHeaders: 512 HEADER-NEXT: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3) -HEADER-NEXT: Characteristics [ (0x9140) +HEADER-NEXT: Characteristics [ (0x9940) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_APPCONTAINER (0x1000) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE (0x40) +HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_NO_BIND (0x800) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT (0x100) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000) HEADER-NEXT: ] @@ -77,7 +78,7 @@ HEADER-NEXT: LoadConfigTableRVA: 0x0 HEADER-NEXT: LoadConfigTableSize: 0x0 HEADER-NEXT: BoundImportRVA: 0x0 HEADER-NEXT: BoundImportSize: 0x0 -HEADER-NEXT: IATRVA: 0x3034 +HEADER-NEXT: IATRVA: 0x3028 HEADER-NEXT: IATSize: 0xC HEADER-NEXT: DelayImportDescriptorRVA: 0x0 HEADER-NEXT: DelayImportDescriptorSize: 0x0 @@ -113,7 +114,7 @@ IMPORTS: AddressSize: 32bit IMPORTS: Import { IMPORTS: Name: std32.dll IMPORTS: ImportLookupTableRVA: 0x3028 -IMPORTS: ImportAddressTableRVA: 0x3034 +IMPORTS: ImportAddressTableRVA: 0x3028 IMPORTS: Symbol: ExitProcess (0) IMPORTS: Symbol: MessageBoxA (1) IMPORTS: } diff --git a/test/COFF/imports.test b/test/COFF/imports.test index 584c24eb1b76..4df6d492ff28 100644 --- a/test/COFF/imports.test +++ b/test/COFF/imports.test @@ -21,14 +21,14 @@ TEXT-NEXT: callq 60 TEXT-NEXT: movl $0, %ecx TEXT-NEXT: callq 18 TEXT-NEXT: callq 29 -TEXT: jmpq *4098(%rip) -TEXT: jmpq *4090(%rip) -TEXT: jmpq *4082(%rip) +TEXT: jmpq *4066(%rip) +TEXT: jmpq *4058(%rip) +TEXT: jmpq *4050(%rip) IMPORT: Import { IMPORT-NEXT: Name: std64.dll IMPORT-NEXT: ImportLookupTableRVA: 0x3028 -IMPORT-NEXT: ImportAddressTableRVA: 0x3048 +IMPORT-NEXT: ImportAddressTableRVA: 0x3028 IMPORT-NEXT: Symbol: ExitProcess (0) IMPORT-NEXT: Symbol: (50) IMPORT-NEXT: Symbol: MessageBoxA (1) diff --git a/test/COFF/invalid-debug-type.test b/test/COFF/invalid-debug-type.test index e48b3fdd2e06..10264180314d 100644 --- a/test/COFF/invalid-debug-type.test +++ b/test/COFF/invalid-debug-type.test @@ -1,5 +1,5 @@ # RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj # RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj # RUN: lld-link /debug /debugtype:invalid /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \ -# RUN: /debugpdb %t1.obj %t2.obj +# RUN: %t1.obj %t2.obj diff --git a/test/COFF/options.test b/test/COFF/options.test index 39f944beddbc..a23da1971d15 100644 --- a/test/COFF/options.test +++ b/test/COFF/options.test @@ -2,13 +2,7 @@ # RUN: lld-link /out:%t.exe /entry:main %t.obj # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BIND %s -# RUN: lld-link /allowbind /out:%t.exe /entry:main %t.obj -# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BIND %s -BIND-NOT: IMAGE_DLL_CHARACTERISTICS_NO_BIND - -# RUN: lld-link /allowbind:no /out:%t.exe /entry:main %t.obj -# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOBIND %s -NOBIND: IMAGE_DLL_CHARACTERISTICS_NO_BIND +BIND: IMAGE_DLL_CHARACTERISTICS_NO_BIND # RUN: lld-link /out:%t.exe /entry:main %t.obj # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ISO %s diff --git a/test/COFF/pdb-none.test b/test/COFF/pdb-none.test index 480ff2a4ace3..7e428693aec4 100644 --- a/test/COFF/pdb-none.test +++ b/test/COFF/pdb-none.test @@ -1,7 +1,7 @@ # RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj # RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj # RUN: lld-link /debug /debugtype:pdata /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \ -# RUN: /debugpdb %t1.obj %t2.obj +# RUN: %t1.obj %t2.obj # RUN: llvm-pdbdump pdb2yaml -pdb-stream %t.pdb | FileCheck %s diff --git a/test/COFF/pdb-options.test b/test/COFF/pdb-options.test new file mode 100644 index 000000000000..1cc4b3abda7c --- /dev/null +++ b/test/COFF/pdb-options.test @@ -0,0 +1,20 @@ +# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj +# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj + +; If /DEBUG is not specified, /pdb is ignored. +# RUN: lld-link /pdb:%t.pdb /entry:main /nodefaultlib %t1.obj %t2.obj +# RUN: not ls %t.pdb + +; If /DEBUG and /pdb are specified, it uses the specified name. +# RUN: lld-link /DEBUG /pdb:%t.pdb /entry:main /nodefaultlib %t1.obj %t2.obj +# RUN: ls %t.pdb +# RUN: rm %t.pdb + +; If /DEBUG is specified but not /pdb, it uses a default name in the current +; directory. This is a bit hacky since but we need to be IN our test specific +; temporary directory when we run this command or we can't test this +# RUN: cd %T +# RUN: lld-link /DEBUG /entry:main /nodefaultlib %t1.obj %t2.obj +# RUN: ls %t1.pdb +# RUN: rm %t* +# RUN: cd %T/..
diff --git a/test/COFF/pdb.test b/test/COFF/pdb.test index aa14d290c737..f1fa4ec7c2b6 100644 --- a/test/COFF/pdb.test +++ b/test/COFF/pdb.test @@ -1,7 +1,7 @@ # RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj # RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj # RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \ -# RUN: /debugpdb %t1.obj %t2.obj +# RUN: %t1.obj %t2.obj # RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory -pdb-stream \ # RUN: -dbi-stream -ipi-stream -tpi-stream %t.pdb | FileCheck %s diff --git a/test/ELF/arm-sbrel32.s b/test/ELF/arm-sbrel32.s new file mode 100644 index 000000000000..7f12717195a9 --- /dev/null +++ b/test/ELF/arm-sbrel32.s @@ -0,0 +1,39 @@ +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t +// RUN: ld.lld %t -o %t2 2>&1 +// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s +// REQUIRES: arm + +// Test the R_ARM_SBREL32 relocation which calculates the offset of the Symbol +// from the static base. We define the static base to be the address of the +// segment containing the symbol + .text + .syntax unified + + .globl _start + .p2align 2 + .type _start,%function +_start: + .fnstart + bx lr + + .long foo(sbrel) + .long foo2(sbrel) + .long foo3(sbrel) + .long foo4(sbrel) +// RW segment starts here + .data + .p2align 4 +foo: .word 10 +foo2: .word 20 + + .bss +foo3: .space 4 +foo4: .space 4 + +// CHECK: Disassembly of section .text: +// CHECK-NEXT: _start: +// CHECK-NEXT: 11000: 1e ff 2f e1 bx lr +// CHECK: 11004: 00 00 00 00 .word 0x00000000 +// CHECK-NEXT: 11008: 04 00 00 00 .word 0x00000004 +// CHECK-NEXT: 1100c: 08 00 00 00 .word 0x00000008 +// CHECK-NEXT: 11010: 0c 00 00 00 .word 0x0000000c |