Index: include/llvm/Object/COFFImportFile.h =================================================================== --- include/llvm/Object/COFFImportFile.h +++ include/llvm/Object/COFFImportFile.h @@ -9,7 +9,8 @@ // // COFF short import file is a special kind of file which contains // only symbol names for DLL-exported symbols. This class implements -// SymbolicFile interface for the file. +// exporting of Symbols to create libraries and a SymbolicFile +// interface for the file type. // //===----------------------------------------------------------------------===// @@ -68,6 +69,30 @@ } }; +struct COFFShortExport { + StringRef Name; + StringRef ExtName; + + uint16_t Ordinal = 0; + bool Noname = false; + bool Data = false; + bool Private = false; + bool Constant = false; + + StringRef SymbolName; + + bool operator==(const COFFShortExport &E) { + return (Name == E.Name && ExtName == E.ExtName && + Ordinal == E.Ordinal && Noname == E.Noname && + Data == E.Data && Private == E.Private); + } +}; + +std::error_code writeImportLibrary(StringRef DLLName, + std::string &Path, + std::vector *Exports, + COFF::MachineTypes Machine); + } // namespace object } // namespace llvm Index: include/llvm/Support/DEFParser.h =================================================================== --- /dev/null +++ include/llvm/Support/DEFParser.h @@ -0,0 +1,53 @@ +//===--- DEFParser.h - Simple YAML parser --------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a DEF parser. +// +// 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 +// +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_SUPPORT_DEFPARSER_H +#define LLVM_SUPPORT_DEFPARSER_H + +#include "llvm/Object/COFFImportFile.h" +#include "llvm/Object/COFF.h" + +namespace llvm { +namespace def { + +struct DEFInfo { + COFF::MachineTypes Machine = COFF::IMAGE_FILE_MACHINE_UNKNOWN; + COFF::WindowsSubsystem Subsystem = COFF::IMAGE_SUBSYSTEM_UNKNOWN; + std::string OutputFile; + uint64_t ImageBase = -1; + uint64_t StackReserve = 1024 * 1024; + uint64_t StackCommit = 4096; + uint64_t HeapReserve = 1024 * 1024; + uint64_t HeapCommit = 4096; + uint32_t MajorImageVersion = 0; + uint32_t MinorImageVersion = 0; + uint32_t MajorOSVersion = 6; + uint32_t MinorOSVersion = 0; +}; + +void parseModuleDefs(MemoryBufferRef MB, + std::vector *Exports, + DEFInfo *Info); + +} // End namespace yaml. +} // End namespace llvm. + +#endif \ No newline at end of file Index: lib/Object/CMakeLists.txt =================================================================== --- lib/Object/CMakeLists.txt +++ lib/Object/CMakeLists.txt @@ -2,6 +2,7 @@ Archive.cpp ArchiveWriter.cpp Binary.cpp + COFFImportFile.cpp COFFObjectFile.cpp Decompressor.cpp ELF.cpp Index: lib/Object/COFFImportFile.cpp =================================================================== --- /dev/null +++ lib/Object/COFFImportFile.cpp @@ -0,0 +1,508 @@ +//===- COFFImportFile.cpp - COFF short import file implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the writeImportLibrary function. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/COFFImportFile.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/ArchiveWriter.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Path.h" + +#include +#include +#include +#include +#include + +using namespace llvm::COFF; +using namespace llvm::object; +using namespace llvm; + +namespace llvm { +namespace object{ + +static bool is32bit(MachineTypes Machine) { + switch (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(MachineTypes Machine) { + switch (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 static void append(std::vector &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 &B, + ArrayRef 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::size_type Pos = B.size(); + std::vector::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(&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 ImportNameType getNameType(StringRef Sym, StringRef ExtName, MachineTypes Machine) { + if (Sym != ExtName) + return IMPORT_NAME_UNDECORATE; + if (Machine == IMAGE_FILE_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) { + // TODO: What do I do here with the lld style error? + //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; + MachineTypes Machine; + BumpPtrAllocator Alloc; + StringRef DLLName; + StringRef Library; + std::string ImportDescriptorSymbolName; + std::string NullThunkSymbolName; + +public: + ObjectFactory(StringRef S, MachineTypes M) + : Machine(M), 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 &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 &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 &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 &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(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(Machine) ? 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(Machine))}, + {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)), + u32(3), u16(getImgRelRelocation(Machine))}, + {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)), + u32(4), u16(getImgRelRelocation(Machine))}, + }; + 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(SymbolTable[0].Name).Offset = + sizeof(uint32_t); + reinterpret_cast(SymbolTable[5].Name).Offset = + sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1; + reinterpret_cast(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(Buffer.data()), Buffer.size()}; + return {MemoryBufferRef(F, DLLName)}; +} + +NewArchiveMember +ObjectFactory::createNullImportDescriptor(std::vector &Buffer) { + static const uint32_t NumberOfSections = 1; + static const uint32_t NumberOfSymbols = 1; + + // COFF Header + coff_file_header Header{ + u16(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(Machine) ? 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(SymbolTable[0].Name).Offset = + sizeof(uint32_t); + append(Buffer, SymbolTable); + + // String Table + writeStringTable(Buffer, {NullImportDescriptorSymbolName}); + + StringRef F{reinterpret_cast(Buffer.data()), Buffer.size()}; + return {MemoryBufferRef(F, DLLName)}; +} + +NewArchiveMember ObjectFactory::createNullThunk(std::vector &Buffer) { + static const uint32_t NumberOfSections = 2; + static const uint32_t NumberOfSymbols = 1; + uint32_t VASize = is32bit(Machine) ? 4 : 8; + + // COFF Header + coff_file_header Header{ + u16(Machine), u16(NumberOfSections), u32(0), + u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + + // .idata$5 + VASize + + // .idata$4 + VASize), + u32(NumberOfSymbols), u16(0), + u16(is32bit(Machine) ? 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(Machine) ? 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(Machine) ? 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(Machine)) + append(Buffer, u32(0)); + + // .idata$4, IAT + append(Buffer, u32(0)); + if (!is32bit(Machine)) + 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(SymbolTable[0].Name).Offset = + sizeof(uint32_t); + append(Buffer, SymbolTable); + + // String Table + writeStringTable(Buffer, {NullThunkSymbolName}); + + StringRef F{reinterpret_cast(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(Size); + memset(Buf, 0, Size); + char *P = Buf; + + // Write short import library. + auto *Imp = reinterpret_cast(P); + P += sizeof(*Imp); + Imp->Sig2 = 0xFFFF; + Imp->Machine = 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)}; +} + +std::error_code +writeImportLibrary(StringRef DLLName, + std::string &Path, + std::vector *Exports, + MachineTypes Machine) { + + std::vector Members; + ObjectFactory OF(llvm::sys::path::filename(DLLName), Machine); + + std::vector ImportDescriptor; + Members.push_back(OF.createImportDescriptor(ImportDescriptor)); + + std::vector NullImportDescriptor; + Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor)); + + std::vector NullThunk; + Members.push_back(OF.createNullThunk(NullThunk)); + + for (COFFShortExport &E : *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, Machine); + 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 Result = + writeArchive(Path, Members, /*WriteSymtab*/ true, object::Archive::K_GNU, + /*Deterministic*/ true, /*Thin*/ false); + + return Result.second; +} + +} // namespace object +} // namespace llvm Index: lib/Support/CMakeLists.txt =================================================================== --- lib/Support/CMakeLists.txt +++ lib/Support/CMakeLists.txt @@ -56,6 +56,7 @@ DebugCounter.cpp DeltaAlgorithm.cpp DAGDeltaAlgorithm.cpp + DEFParser.cpp Dwarf.cpp Error.cpp ErrorHandling.cpp Index: lib/Support/DEFParser.cpp =================================================================== --- /dev/null +++ lib/Support/DEFParser.cpp @@ -0,0 +1,345 @@ +//===--- DEFParser.cpp - Simple DEF parser ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a DEF parser. +// +// Windows-specific. +// A parser for the module-definition file (.def file). +// +// The format of module-definition files are described in this document: +// https://msdn.microsoft.com/en-us/library/28d6s79h.aspx +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/DEFParser.h" +#include "Memory.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Object/COFFImportFile.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/StringSaver.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace llvm::COFF; +using namespace llvm::object; +using namespace llvm; + +#include +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +StringRef Argv0; +static std::mutex Mu; +raw_ostream *ErrorOS; +BumpPtrAllocator BAlloc; +StringSaver Saver{BAlloc}; + +static void print(StringRef S, raw_ostream::Colors C) { + *ErrorOS << Argv0 + ": "; + *ErrorOS << S; +} + +void fatal(const Twine &Msg) { + llvm::errs() << Msg << "\n"; + exit(1); +} + +void fatal(std::error_code EC, const Twine &Msg) { + fatal(Msg + ": " + EC.message()); +} + +void fatal(llvm::Error &Err, const Twine &Msg) { + fatal(errorToErrorCode(std::move(Err)), Msg); +} +void warn(const Twine &Msg) { + std::lock_guard Lock(Mu); + print("warning: ", raw_ostream::MAGENTA); + *ErrorOS << Msg << "\n"; +} + +namespace llvm { +namespace def { + +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(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, std::vector *E, + DEFInfo *I) : Lex(S), Exports(E), Info(I) {} + + 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(&Info->HeapReserve, &Info->HeapCommit); + return; + case KwStacksize: + parseNumbers(&Info->StackReserve, &Info->StackCommit); + return; + case KwLibrary: + case KwName: { + bool IsDll = Tok.K == KwLibrary; // Check before parseName. + std::string Name; + parseName(&Name, &Info->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 (Info->OutputFile.empty()) + Info->OutputFile = Name; + return; + } + case KwVersion: + parseVersion(&Info->MajorImageVersion, &Info->MinorImageVersion); + return; + default: + fatal("unknown directive: " + Tok.Value); + } + } + + void parseExport() { + COFFShortExport 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 (Info->Machine == IMAGE_FILE_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(); + 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 Stack; + std::vector *Exports; + DEFInfo *Info; +}; + +void parseModuleDefs(MemoryBufferRef MB, + std::vector *Exports, + DEFInfo *Info) { + Parser(MB.getBuffer(), Exports, Info).parse(); +} + +} // namespace def +} // namespace llvm Index: tools/lld/COFF/CMakeLists.txt =================================================================== --- tools/lld/COFF/CMakeLists.txt +++ tools/lld/COFF/CMakeLists.txt @@ -14,11 +14,9 @@ Error.cpp ICF.cpp InputFiles.cpp - Librarian.cpp LTO.cpp MapFile.cpp MarkLive.cpp - ModuleDef.cpp PDB.cpp Strings.cpp SymbolTable.cpp Index: tools/lld/COFF/Chunks.cpp =================================================================== --- tools/lld/COFF/Chunks.cpp +++ tools/lld/COFF/Chunks.cpp @@ -50,8 +50,8 @@ uint64_t P) const { uint64_t S = Sym->getRVA(); switch (Type) { - case IMAGE_REL_AMD64_ADDR32: add32(Off, S + Config->ImageBase); break; - case IMAGE_REL_AMD64_ADDR64: add64(Off, S + Config->ImageBase); break; + case IMAGE_REL_AMD64_ADDR32: add32(Off, S + Config->Info.ImageBase); break; + case IMAGE_REL_AMD64_ADDR64: add64(Off, S + Config->Info.ImageBase); break; case IMAGE_REL_AMD64_ADDR32NB: add32(Off, S); break; case IMAGE_REL_AMD64_REL32: add32(Off, S - P - 4); break; case IMAGE_REL_AMD64_REL32_1: add32(Off, S - P - 5); break; @@ -71,7 +71,7 @@ uint64_t S = Sym->getRVA(); switch (Type) { case IMAGE_REL_I386_ABSOLUTE: break; - case IMAGE_REL_I386_DIR32: add32(Off, S + Config->ImageBase); break; + case IMAGE_REL_I386_DIR32: add32(Off, S + Config->Info.ImageBase); break; case IMAGE_REL_I386_DIR32NB: add32(Off, S); break; case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break; case IMAGE_REL_I386_SECTION: add16(Off, Sym->getSectionIndex()); break; @@ -129,9 +129,9 @@ if (Sym->isExecutable()) S |= 1; switch (Type) { - case IMAGE_REL_ARM_ADDR32: add32(Off, S + Config->ImageBase); break; + case IMAGE_REL_ARM_ADDR32: add32(Off, S + Config->Info.ImageBase); break; case IMAGE_REL_ARM_ADDR32NB: add32(Off, S); break; - case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, S + Config->ImageBase); break; + case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, S + Config->Info.ImageBase); break; case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, S - P - 4); break; case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, S - P - 4); break; case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, S - P - 4); break; @@ -154,7 +154,7 @@ SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex); Defined *Sym = cast(Body); uint64_t P = RVA + Rel.VirtualAddress; - switch (Config->Machine) { + switch (Config->Info.Machine) { case AMD64: applyRelX64(Off, Rel.Type, Sym, P); break; @@ -175,7 +175,7 @@ } static uint8_t getBaserelType(const coff_relocation &Rel) { - switch (Config->Machine) { + switch (Config->Info.Machine) { case AMD64: if (Rel.Type == IMAGE_REL_AMD64_ADDR64) return IMAGE_REL_BASED_DIR64; @@ -282,7 +282,7 @@ memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86)); // The first two bytes is a JMP instruction. Fill its operand. write32le(Buf + OutputSectionOff + 2, - ImpSymbol->getRVA() + Config->ImageBase); + ImpSymbol->getRVA() + Config->Info.ImageBase); } void ImportThunkChunkARM::getBaserels(std::vector *Res) { @@ -292,7 +292,7 @@ void ImportThunkChunkARM::writeTo(uint8_t *Buf) const { memcpy(Buf + OutputSectionOff, ImportThunkARM, sizeof(ImportThunkARM)); // Fix mov.w and mov.t operands. - applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase); + applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->Info.ImageBase); } void LocalImportChunk::getBaserels(std::vector *Res) { @@ -305,9 +305,9 @@ void LocalImportChunk::writeTo(uint8_t *Buf) const { if (Config->is64()) { - write64le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase); + write64le(Buf + OutputSectionOff, Sym->getRVA() + Config->Info.ImageBase); } else { - write32le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase); + write32le(Buf + OutputSectionOff, Sym->getRVA() + Config->Info.ImageBase); } } @@ -377,7 +377,7 @@ } uint8_t Baserel::getDefaultType() { - switch (Config->Machine) { + switch (Config->Info.Machine) { case AMD64: return IMAGE_REL_BASED_DIR64; case I386: Index: tools/lld/COFF/Config.h =================================================================== --- tools/lld/COFF/Config.h +++ tools/lld/COFF/Config.h @@ -11,7 +11,9 @@ #define LLD_COFF_CONFIG_H #include "llvm/ADT/StringRef.h" +#include "llvm/Object/COFFImportFile.h" #include "llvm/Object/COFF.h" +#include "llvm/Support/DEFParser.h" #include #include #include @@ -22,6 +24,7 @@ using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN; using llvm::COFF::WindowsSubsystem; +using llvm::object::COFFShortExport; using llvm::StringRef; class DefinedAbsolute; class DefinedRelative; @@ -36,15 +39,9 @@ // Represents an /export option. struct Export { - StringRef Name; // N in /export:N or /export:E=N - StringRef ExtName; // E in /export:E=N - SymbolBody *Sym = nullptr; - uint16_t Ordinal = 0; - bool Noname = false; - bool Data = false; - bool Private = false; - bool Constant = false; + COFFShortExport Info; + SymbolBody *Sym = nullptr; // If an export is a form of /export:foo=dllname.bar, that means // that foo should be exported as an alias to bar in the DLL. // ForwardTo is set to "dllname.bar" part. Usually empty. @@ -53,14 +50,7 @@ // True if this /export option was in .drectves section. bool Directives = false; - StringRef SymbolName; StringRef ExportName; // Name in DLL - - bool operator==(const Export &E) { - return (Name == E.Name && ExtName == E.ExtName && - Ordinal == E.Ordinal && Noname == E.Noname && - Data == E.Data && Private == E.Private); - } }; enum class DebugType { @@ -73,14 +63,12 @@ // Global configuration. struct Configuration { enum ManifestKind { SideBySide, Embed, No }; - bool is64() { return Machine == AMD64; } + bool is64() { return Info.Machine == AMD64; } - llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN; + llvm::def::DEFInfo Info; bool Verbose = false; - WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN; SymbolBody *Entry = nullptr; bool NoEntry = false; - std::string OutputFile; bool ColorDiagnostics; bool DoGC = true; bool DoICF = true; @@ -145,15 +133,6 @@ // Used for /lldmap. std::string MapFile; - uint64_t ImageBase = -1; - uint64_t StackReserve = 1024 * 1024; - uint64_t StackCommit = 4096; - uint64_t HeapReserve = 1024 * 1024; - uint64_t HeapCommit = 4096; - uint32_t MajorImageVersion = 0; - uint32_t MinorImageVersion = 0; - uint32_t MajorOSVersion = 6; - uint32_t MinorOSVersion = 0; bool DynamicBase = true; bool AllowBind = true; bool NxCompat = true; Index: tools/lld/COFF/DLL.cpp =================================================================== --- tools/lld/COFF/DLL.cpp +++ tools/lld/COFF/DLL.cpp @@ -244,8 +244,8 @@ void writeTo(uint8_t *Buf) const override { memcpy(Buf + OutputSectionOff, ThunkX86, sizeof(ThunkX86)); - write32le(Buf + OutputSectionOff + 3, Imp->getRVA() + Config->ImageBase); - write32le(Buf + OutputSectionOff + 8, Desc->getRVA() + Config->ImageBase); + write32le(Buf + OutputSectionOff + 3, Imp->getRVA() + Config->Info.ImageBase); + write32le(Buf + OutputSectionOff + 8, Desc->getRVA() + Config->Info.ImageBase); write32le(Buf + OutputSectionOff + 13, Helper->getRVA() - RVA - 17); } @@ -267,9 +267,9 @@ void writeTo(uint8_t *Buf) const override { if (Config->is64()) { - write64le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase); + write64le(Buf + OutputSectionOff, Thunk->getRVA() + Config->Info.ImageBase); } else { - write32le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase); + write32le(Buf + OutputSectionOff, Thunk->getRVA() + Config->Info.ImageBase); } } @@ -320,7 +320,7 @@ void writeTo(uint8_t *Buf) const override { for (Export &E : Config->Exports) { - uint8_t *P = Buf + OutputSectionOff + E.Ordinal * 4; + uint8_t *P = Buf + OutputSectionOff + E.Info.Ordinal * 4; if (E.ForwardChunk) { write32le(P, E.ForwardChunk->getRVA()); } else { @@ -358,9 +358,9 @@ void writeTo(uint8_t *Buf) const override { uint8_t *P = Buf + OutputSectionOff; for (Export &E : Config->Exports) { - if (E.Noname) + if (E.Info.Noname) continue; - write16le(P, E.Ordinal); + write16le(P, E.Info.Ordinal); P += 2; } } @@ -522,7 +522,7 @@ } Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) { - switch (Config->Machine) { + switch (Config->Info.Machine) { case AMD64: return new ThunkChunkX64(S, Dir, Helper); case I386: @@ -535,13 +535,13 @@ EdataContents::EdataContents() { uint16_t MaxOrdinal = 0; for (Export &E : Config->Exports) - MaxOrdinal = std::max(MaxOrdinal, E.Ordinal); + MaxOrdinal = std::max(MaxOrdinal, E.Info.Ordinal); - auto *DLLName = new StringChunk(sys::path::filename(Config->OutputFile)); + auto *DLLName = new StringChunk(sys::path::filename(Config->Info.OutputFile)); auto *AddressTab = new AddressTableChunk(MaxOrdinal); std::vector Names; for (Export &E : Config->Exports) - if (!E.Noname) + if (!E.Info.Noname) Names.push_back(new StringChunk(E.ExportName)); std::vector Forwards; Index: tools/lld/COFF/Driver.h =================================================================== --- tools/lld/COFF/Driver.h +++ tools/lld/COFF/Driver.h @@ -128,9 +128,6 @@ std::vector Resources; }; -void parseModuleDefs(MemoryBufferRef MB); -void writeImportLibrary(); - // Functions below this line are defined in DriverUtils.cpp. void printHelp(const char *Argv0); Index: tools/lld/COFF/Driver.cpp =================================================================== --- tools/lld/COFF/Driver.cpp +++ tools/lld/COFF/Driver.cpp @@ -20,10 +20,12 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/LibDriver/LibDriver.h" #include "llvm/Object/ArchiveWriter.h" +#include "llvm/Object/COFFImportFile.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/DEFParser.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/TarWriter.h" @@ -35,6 +37,8 @@ #include using namespace llvm; +using namespace llvm::def; +using namespace llvm::object; using namespace llvm::COFF; using llvm::sys::Process; using llvm::sys::fs::file_magic; @@ -317,8 +321,8 @@ // Symbol names are mangled by appending "_" prefix on x86. StringRef LinkerDriver::mangle(StringRef Sym) { - assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN); - if (Config->Machine == I386) + assert(Config->Info.Machine != IMAGE_FILE_MACHINE_UNKNOWN); + if (Config->Info.Machine == I386) return Saver.save("_" + Sym); return Sym; } @@ -416,10 +420,50 @@ return Arg->getValue(); assert(Arg->getOption().getID() == OPT_lldmap); - StringRef OutFile = Config->OutputFile; + StringRef OutFile = Config->Info.OutputFile; return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str(); } +static std::string getImplibPath() { + if (!Config->Implib.empty()) + return Config->Implib; + SmallString<128> Out = StringRef(Config->Info.OutputFile); + sys::path::replace_extension(Out, ".lib"); + return Out.str(); +} + +static void +addShortExportsFromConfig(std::vector *Exports) { + std::vector COFFShortExports; + for (Export &E : Config->Exports) { + Exports->push_back(E.Info); + } +} + +static void +importShortExportsToConfig(std::vector *importShortLib) { + for (COFFShortExport &shortExport : *importShortLib) { + Export addedExport; + addedExport.Info = shortExport; + Config->Exports.push_back(addedExport); + } +} + +static void createImportLibrary() { + std::vector Exports; + addShortExportsFromConfig(&Exports); + std::string DLLName = sys::path::filename(Config->Info.OutputFile); + std::string Path = getImplibPath(); + writeImportLibrary(DLLName, Path, &Exports, Config->Info.Machine); +} + +static void mutateModuleDefs(MemoryBufferRef MB) { + std::vector COFFShortExports; + parseModuleDefs(MB, &COFFShortExports, &Config->Info); + importShortExportsToConfig(&COFFShortExports); +} + + std::vector getArchiveMembers(Archive *File) { std::vector V; Error Err = Error::success(); @@ -644,7 +688,7 @@ // Handle /out if (auto *Arg = Args.getLastArg(OPT_out)) - Config->OutputFile = Arg->getValue(); + Config->Info.OutputFile = Arg->getValue(); // Handle /verbose if (Args.hasArg(OPT_verbose)) @@ -696,7 +740,7 @@ // Handle /machine if (auto *Arg = Args.getLastArg(OPT_machine)) - Config->Machine = getMachineType(Arg->getValue()); + Config->Info.Machine = getMachineType(Arg->getValue()); // Handle /nodefaultlib: for (auto *Arg : Args.filtered(OPT_nodefaultlib)) @@ -708,25 +752,25 @@ // Handle /base if (auto *Arg = Args.getLastArg(OPT_base)) - parseNumbers(Arg->getValue(), &Config->ImageBase); + parseNumbers(Arg->getValue(), &Config->Info.ImageBase); // Handle /stack if (auto *Arg = Args.getLastArg(OPT_stack)) - parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit); + parseNumbers(Arg->getValue(), &Config->Info.StackReserve, &Config->Info.StackCommit); // Handle /heap if (auto *Arg = Args.getLastArg(OPT_heap)) - parseNumbers(Arg->getValue(), &Config->HeapReserve, &Config->HeapCommit); + parseNumbers(Arg->getValue(), &Config->Info.HeapReserve, &Config->Info.HeapCommit); // Handle /version if (auto *Arg = Args.getLastArg(OPT_version)) - parseVersion(Arg->getValue(), &Config->MajorImageVersion, - &Config->MinorImageVersion); + parseVersion(Arg->getValue(), &Config->Info.MajorImageVersion, + &Config->Info.MinorImageVersion); // Handle /subsystem if (auto *Arg = Args.getLastArg(OPT_subsystem)) - parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion, - &Config->MinorOSVersion); + parseSubsystem(Arg->getValue(), &Config->Info.Subsystem, &Config->Info.MajorOSVersion, + &Config->Info.MinorOSVersion); // Handle /alternatename for (auto *Arg : Args.filtered(OPT_alternatename)) @@ -860,9 +904,9 @@ // We should have inferred a machine type by now from the input files, but if // not we assume x64. - if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { + if (Config->Info.Machine == IMAGE_FILE_MACHINE_UNKNOWN) { warn("/machine is not specified. x64 is assumed"); - Config->Machine = AMD64; + Config->Info.Machine = AMD64; } // Windows specific -- Input files can be Windows resource files (.res files). @@ -888,7 +932,7 @@ if (auto *Arg = Args.getLastArg(OPT_entry)) { Config->Entry = addUndefined(mangle(Arg->getValue())); } else if (Args.hasArg(OPT_dll) && !Config->NoEntry) { - StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup@12" + StringRef S = (Config->Info.Machine == I386) ? "__DllMainCRTStartup@12" : "_DllMainCRTStartup"; Config->Entry = addUndefined(S); } else if (!Config->NoEntry) { @@ -904,11 +948,11 @@ // Handle /export for (auto *Arg : Args.filtered(OPT_export)) { Export E = parseExport(Arg->getValue()); - 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); + if (Config->Info.Machine == I386) { + if (!isDecorated(E.Info.Name)) + E.Info.Name = Saver.save("_" + E.Info.Name); + if (!E.Info.ExtName.empty() && !isDecorated(E.Info.ExtName)) + E.Info.ExtName = Saver.save("_" + E.Info.ExtName); } Config->Exports.push_back(E); } @@ -916,7 +960,7 @@ // Handle /def if (auto *Arg = Args.getLastArg(OPT_deffile)) { // parseModuleDefs mutates Config object. - parseModuleDefs( + mutateModuleDefs( takeBuffer(check(MemoryBuffer::getFile(Arg->getValue()), Twine("could not open ") + Arg->getValue()))); } @@ -924,7 +968,7 @@ // Handle /delayload for (auto *Arg : Args.filtered(OPT_delayload)) { Config->DelayLoads.insert(StringRef(Arg->getValue()).lower()); - if (Config->Machine == I386) { + if (Config->Info.Machine == I386) { Config->DelayLoadHelper = addUndefined("___delayLoadHelper2@8"); } else { Config->DelayLoadHelper = addUndefined("__delayLoadHelper2"); @@ -932,14 +976,14 @@ } // Set default image name if neither /out or /def set it. - if (Config->OutputFile.empty()) { - Config->OutputFile = + if (Config->Info.OutputFile.empty()) { + Config->Info.OutputFile = getOutputPath((*Args.filtered(OPT_INPUT).begin())->getValue()); } // Put the PDB next to the image if no /pdb flag was passed. if (Config->Debug && Config->PDBPath.empty()) { - Config->PDBPath = Config->OutputFile; + Config->PDBPath = Config->Info.OutputFile; sys::path::replace_extension(Config->PDBPath, ".pdb"); } @@ -948,11 +992,11 @@ Config->PDBPath = ""; // Set default image base if /base is not given. - if (Config->ImageBase == uint64_t(-1)) - Config->ImageBase = getDefaultImageBase(); + if (Config->Info.ImageBase == uint64_t(-1)) + Config->Info.ImageBase = getDefaultImageBase(); Symtab.addRelative(mangle("__ImageBase"), 0); - if (Config->Machine == I386) { + if (Config->Info.Machine == I386) { Config->SEHTable = Symtab.addRelative("___safe_se_handler_table", 0); Config->SEHCount = Symtab.addAbsolute("___safe_se_handler_count", 0); } @@ -976,7 +1020,7 @@ for (Export &E : Config->Exports) { if (!E.ForwardTo.empty()) continue; - E.Sym = addUndefined(E.Name); + E.Sym = addUndefined(E.Info.Name); if (!E.Directives) Symtab.mangleMaybe(E.Sym); } @@ -1019,9 +1063,9 @@ // Windows specific -- if no /subsystem is given, we need to infer // that from entry point name. - if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) { - Config->Subsystem = inferSubsystem(); - if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) + if (Config->Info.Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) { + Config->Info.Subsystem = inferSubsystem(); + if (Config->Info.Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) fatal("subsystem must be defined"); } @@ -1038,7 +1082,7 @@ // need to create a .lib file. if (!Config->Exports.empty() || Config->DLL) { fixupExports(); - writeImportLibrary(); + createImportLibrary(); assignExportOrdinals(); } Index: tools/lld/COFF/DriverUtils.cpp =================================================================== --- tools/lld/COFF/DriverUtils.cpp +++ tools/lld/COFF/DriverUtils.cpp @@ -429,7 +429,7 @@ void createSideBySideManifest() { std::string Path = Config->ManifestFile; if (Path == "") - Path = Config->OutputFile + ".manifest"; + Path = Config->Info.OutputFile + ".manifest"; std::error_code EC; raw_fd_ostream Out(Path, EC, sys::fs::F_Text); if (EC) @@ -444,24 +444,24 @@ Export parseExport(StringRef Arg) { Export E; StringRef Rest; - std::tie(E.Name, Rest) = Arg.split(","); - if (E.Name.empty()) + std::tie(E.Info.Name, Rest) = Arg.split(","); + if (E.Info.Name.empty()) goto err; - if (E.Name.find('=') != StringRef::npos) { + if (E.Info.Name.find('=') != StringRef::npos) { StringRef X, Y; - std::tie(X, Y) = E.Name.split("="); + std::tie(X, Y) = E.Info.Name.split("="); // If "=.". if (Y.find(".") != StringRef::npos) { - E.Name = X; + E.Info.Name = X; E.ForwardTo = Y; return E; } - E.ExtName = X; - E.Name = Y; - if (E.Name.empty()) + E.Info.ExtName = X; + E.Info.Name = Y; + if (E.Info.Name.empty()) goto err; } @@ -470,21 +470,21 @@ StringRef Tok; std::tie(Tok, Rest) = Rest.split(","); if (Tok.equals_lower("noname")) { - if (E.Ordinal == 0) + if (E.Info.Ordinal == 0) goto err; - E.Noname = true; + E.Info.Noname = true; continue; } if (Tok.equals_lower("data")) { - E.Data = true; + E.Info.Data = true; continue; } if (Tok.equals_lower("constant")) { - E.Constant = true; + E.Info.Constant = true; continue; } if (Tok.equals_lower("private")) { - E.Private = true; + E.Info.Private = true; continue; } if (Tok.startswith("@")) { @@ -493,7 +493,7 @@ goto err; if (Ord <= 0 || 65535 < Ord) goto err; - E.Ordinal = Ord; + E.Info.Ordinal = Ord; continue; } goto err; @@ -505,7 +505,7 @@ } static StringRef undecorate(StringRef Sym) { - if (Config->Machine != I386) + if (Config->Info.Machine != I386) return Sym; return Sym.startswith("_") ? Sym.substr(1) : Sym; } @@ -516,29 +516,29 @@ // Symbol ordinals must be unique. std::set Ords; for (Export &E : Config->Exports) { - if (E.Ordinal == 0) + if (E.Info.Ordinal == 0) continue; - if (!Ords.insert(E.Ordinal).second) - fatal("duplicate export ordinal: " + E.Name); + if (!Ords.insert(E.Info.Ordinal).second) + fatal("duplicate export ordinal: " + E.Info.Name); } for (Export &E : Config->Exports) { SymbolBody *Sym = E.Sym; if (!E.ForwardTo.empty()) { - E.SymbolName = E.Name; + E.Info.SymbolName = E.Info.Name; } else { if (auto *U = dyn_cast(Sym)) if (U->WeakAlias) Sym = U->WeakAlias; - E.SymbolName = Sym->getName(); + E.Info.SymbolName = Sym->getName(); } } for (Export &E : Config->Exports) { if (!E.ForwardTo.empty()) { - E.ExportName = undecorate(E.Name); + E.ExportName = undecorate(E.Info.Name); } else { - E.ExportName = undecorate(E.ExtName.empty() ? E.Name : E.ExtName); + E.ExportName = undecorate(E.Info.ExtName.empty() ? E.Info.Name : E.Info.ExtName); } } @@ -553,9 +553,9 @@ continue; } Export *Existing = Pair.first->second; - if (E == *Existing || E.Name != Existing->Name) + if (E.Info == Existing->Info || E.Info.Name != Existing->Info.Name) continue; - warn("duplicate /export option: " + E.Name); + warn("duplicate /export option: " + E.Info.Name); } Config->Exports = std::move(V); @@ -570,10 +570,10 @@ // Assign unique ordinals if default (= 0). uint16_t Max = 0; for (Export &E : Config->Exports) - Max = std::max(Max, E.Ordinal); + Max = std::max(Max, E.Info.Ordinal); for (Export &E : Config->Exports) - if (E.Ordinal == 0) - E.Ordinal = ++Max; + if (E.Info.Ordinal == 0) + E.Info.Ordinal = ++Max; } // Parses a string in the form of "key=value" and check @@ -599,7 +599,7 @@ // Execute cvtres.exe. Executor E("cvtres.exe"); - E.add("/machine:" + machineToStr(Config->Machine)); + E.add("/machine:" + machineToStr(Config->Info.Machine)); E.add("/readonly"); E.add("/nologo"); E.add("/out:" + Twine(File.Path)); Index: tools/lld/COFF/LTO.cpp =================================================================== --- tools/lld/COFF/LTO.cpp +++ tools/lld/COFF/LTO.cpp @@ -70,7 +70,7 @@ Conf.DiagHandler = diagnosticHandler; Conf.OptLevel = Config->LTOOptLevel; if (Config->SaveTemps) - checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".", + checkError(Conf.addSaveTemps(std::string(Config->Info.OutputFile) + ".", /*UseInputModulePath*/ true)); lto::ThinBackend Backend; if (Config->LTOJobs != 0) @@ -130,9 +130,9 @@ continue; if (Config->SaveTemps) { if (I == 0) - saveBuffer(Buff[I], Config->OutputFile + ".lto.obj"); + saveBuffer(Buff[I], Config->Info.OutputFile + ".lto.obj"); else - saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.obj"); + saveBuffer(Buff[I], Config->Info.OutputFile + Twine(I) + ".lto.obj"); } Ret.emplace_back(Buff[I].data(), Buff[I].size()); } Index: tools/lld/COFF/Librarian.cpp =================================================================== --- tools/lld/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 - -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 static void append(std::vector &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 &B, - ArrayRef 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::size_type Pos = B.size(); - std::vector::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(&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 &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 &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 &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 &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(SymbolTable[0].Name).Offset = - sizeof(uint32_t); - reinterpret_cast(SymbolTable[5].Name).Offset = - sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1; - reinterpret_cast(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(Buffer.data()), Buffer.size()}; - return {MemoryBufferRef(F, DLLName)}; -} - -NewArchiveMember -ObjectFactory::createNullImportDescriptor(std::vector &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(SymbolTable[0].Name).Offset = - sizeof(uint32_t); - append(Buffer, SymbolTable); - - // String Table - writeStringTable(Buffer, {NullImportDescriptorSymbolName}); - - StringRef F{reinterpret_cast(Buffer.data()), Buffer.size()}; - return {MemoryBufferRef(F, DLLName)}; -} - -NewArchiveMember ObjectFactory::createNullThunk(std::vector &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(SymbolTable[0].Name).Offset = - sizeof(uint32_t); - append(Buffer, SymbolTable); - - // String Table - writeStringTable(Buffer, {NullThunkSymbolName}); - - StringRef F{reinterpret_cast(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(Size); - memset(Buf, 0, Size); - char *P = Buf; - - // Write short import library. - auto *Imp = reinterpret_cast(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 Members; - - std::string Path = getImplibPath(); - std::string DLLName = sys::path::filename(Config->OutputFile); - ObjectFactory OF(DLLName); - - std::vector ImportDescriptor; - Members.push_back(OF.createImportDescriptor(ImportDescriptor)); - - std::vector NullImportDescriptor; - Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor)); - - std::vector 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 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); -} Index: tools/lld/COFF/ModuleDef.cpp =================================================================== --- tools/lld/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 - -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(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 Stack; -}; - -} // anonymous namespace - -void parseModuleDefs(MemoryBufferRef MB) { Parser(MB.getBuffer()).parse(); } - -} // namespace coff -} // namespace lld Index: tools/lld/COFF/SymbolTable.cpp =================================================================== --- tools/lld/COFF/SymbolTable.cpp +++ tools/lld/COFF/SymbolTable.cpp @@ -61,11 +61,11 @@ File->parse(); MachineTypes MT = File->getMachineType(); - if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { - Config->Machine = MT; - } else if (MT != IMAGE_FILE_MACHINE_UNKNOWN && Config->Machine != MT) { + if (Config->Info.Machine == IMAGE_FILE_MACHINE_UNKNOWN) { + Config->Info.Machine = MT; + } else if (MT != IMAGE_FILE_MACHINE_UNKNOWN && Config->Info.Machine != MT) { fatal(toString(File) + ": machine type " + machineToStr(MT) + - " conflicts with " + machineToStr(Config->Machine)); + " conflicts with " + machineToStr(Config->Info.Machine)); } if (auto *F = dyn_cast(File)) { @@ -305,7 +305,7 @@ } Symbol *SymbolTable::findUnderscore(StringRef Name) { - if (Config->Machine == I386) + if (Config->Info.Machine == I386) return find(("_" + Name).str()); return find(Name); } @@ -323,7 +323,7 @@ if (Symbol *Sym = find(Name)) if (!isa(Sym->body())) return Name; - if (Config->Machine != I386) + if (Config->Info.Machine != I386) return findByPrefix(("?" + Name + "@@Y").str()); if (!Name.startswith("_")) return ""; Index: tools/lld/COFF/Symbols.h =================================================================== --- tools/lld/COFF/Symbols.h +++ tools/lld/COFF/Symbols.h @@ -209,7 +209,7 @@ return S->kind() == DefinedAbsoluteKind; } - uint64_t getRVA() { return VA - Config->ImageBase; } + uint64_t getRVA() { return VA - Config->Info.ImageBase; } void setVA(uint64_t V) { VA = V; } private: Index: tools/lld/COFF/Writer.cpp =================================================================== --- tools/lld/COFF/Writer.cpp +++ tools/lld/COFF/Writer.cpp @@ -247,7 +247,7 @@ removeEmptySections(); setSectionPermissions(); createSymbolAndStringTable(); - openFile(Config->OutputFile); + openFile(Config->Info.OutputFile); if (Config->is64()) { writeHeader(); } else { @@ -340,7 +340,7 @@ } // Create SEH table. x86-only. - if (Config->Machine != I386) + if (Config->Info.Machine != I386) return; std::set Handlers; @@ -561,7 +561,7 @@ // Write COFF header auto *COFF = reinterpret_cast(Buf); Buf += sizeof(*COFF); - COFF->Machine = Config->Machine; + COFF->Machine = Config->Info.Machine; COFF->NumberOfSections = OutputSections.size(); COFF->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; if (Config->LargeAddressAware) @@ -579,29 +579,29 @@ auto *PE = reinterpret_cast(Buf); Buf += sizeof(*PE); PE->Magic = Config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32; - PE->ImageBase = Config->ImageBase; + PE->ImageBase = Config->Info.ImageBase; PE->SectionAlignment = PageSize; PE->FileAlignment = SectorSize; - PE->MajorImageVersion = Config->MajorImageVersion; - PE->MinorImageVersion = Config->MinorImageVersion; - PE->MajorOperatingSystemVersion = Config->MajorOSVersion; - PE->MinorOperatingSystemVersion = Config->MinorOSVersion; - PE->MajorSubsystemVersion = Config->MajorOSVersion; - PE->MinorSubsystemVersion = Config->MinorOSVersion; - PE->Subsystem = Config->Subsystem; + PE->MajorImageVersion = Config->Info.MajorImageVersion; + PE->MinorImageVersion = Config->Info.MinorImageVersion; + PE->MajorOperatingSystemVersion = Config->Info.MajorOSVersion; + PE->MinorOperatingSystemVersion = Config->Info.MinorOSVersion; + PE->MajorSubsystemVersion = Config->Info.MajorOSVersion; + PE->MinorSubsystemVersion = Config->Info.MinorOSVersion; + PE->Subsystem = Config->Info.Subsystem; PE->SizeOfImage = SizeOfImage; PE->SizeOfHeaders = SizeOfHeaders; if (!Config->NoEntry) { Defined *Entry = cast(Config->Entry); PE->AddressOfEntryPoint = Entry->getRVA(); // Pointer to thumb code must have the LSB set, so adjust it. - if (Config->Machine == ARMNT) + if (Config->Info.Machine == ARMNT) PE->AddressOfEntryPoint |= 1; } - PE->SizeOfStackReserve = Config->StackReserve; - PE->SizeOfStackCommit = Config->StackCommit; - PE->SizeOfHeapReserve = Config->HeapReserve; - PE->SizeOfHeapCommit = Config->HeapCommit; + PE->SizeOfStackReserve = Config->Info.StackReserve; + PE->SizeOfStackCommit = Config->Info.StackCommit; + PE->SizeOfHeapReserve = Config->Info.HeapReserve; + PE->SizeOfHeapCommit = Config->Info.HeapCommit; if (Config->AppContainer) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER; if (Config->DynamicBase) @@ -758,14 +758,14 @@ // We assume .pdata contains function table entries only. uint8_t *Begin = Buffer->getBufferStart() + Sec->getFileOff(); uint8_t *End = Begin + Sec->getVirtualSize(); - if (Config->Machine == AMD64) { + if (Config->Info.Machine == AMD64) { struct Entry { ulittle32_t Begin, End, Unwind; }; parallel_sort( (Entry *)Begin, (Entry *)End, [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); return; } - if (Config->Machine == ARMNT) { + if (Config->Info.Machine == ARMNT) { struct Entry { ulittle32_t Begin, Unwind; }; parallel_sort( (Entry *)Begin, (Entry *)End,