|  | //===- COFFImportFile.cpp - COFF short import file implementation ---------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file defines the writeImportLibrary function. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/Object/COFFImportFile.h" | 
|  | #include "llvm/ADT/ArrayRef.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 <cstdint> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | 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_ARM64: | 
|  | 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_ARM64: | 
|  | return IMAGE_REL_ARM64_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. | 
|  |  | 
|  | size_t Pos = B.size(); | 
|  | size_t 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); | 
|  | support::endian::write32le(&B[Offset], Length); | 
|  | } | 
|  |  | 
|  | static ImportNameType getNameType(StringRef Sym, StringRef ExtName, | 
|  | MachineTypes Machine, bool MinGW) { | 
|  | // A decorated stdcall function in MSVC is exported with the | 
|  | // type IMPORT_NAME, and the exported function name includes the | 
|  | // the leading underscore. In MinGW on the other hand, a decorated | 
|  | // stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX). | 
|  | // See the comment in isDecorated in COFFModuleDefinition.cpp for more | 
|  | // details. | 
|  | if (ExtName.startswith("_") && ExtName.contains('@') && !MinGW) | 
|  | return IMPORT_NAME; | 
|  | if (Sym != ExtName) | 
|  | return IMPORT_NAME_UNDECORATE; | 
|  | if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.startswith("_")) | 
|  | return IMPORT_NAME_NOPREFIX; | 
|  | return IMPORT_NAME; | 
|  | } | 
|  |  | 
|  | static Expected<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) { | 
|  | return make_error<StringError>( | 
|  | StringRef(Twine(S + ": replacing '" + From + | 
|  | "' with '" + To + "' failed").str()), object_error::parse_failed); | 
|  | } | 
|  |  | 
|  | 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 ImportName; | 
|  | StringRef Library; | 
|  | std::string ImportDescriptorSymbolName; | 
|  | std::string NullThunkSymbolName; | 
|  |  | 
|  | public: | 
|  | ObjectFactory(StringRef S, MachineTypes M) | 
|  | : Machine(M), ImportName(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); | 
|  |  | 
|  | // Create a weak external file which is described in PE/COFF Aux Format 3. | 
|  | NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp); | 
|  | }; | 
|  | } // namespace | 
|  |  | 
|  | NewArchiveMember | 
|  | ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) { | 
|  | const uint32_t NumberOfSections = 2; | 
|  | const uint32_t NumberOfSymbols = 7; | 
|  | 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 | 
|  | (ImportName.size() + 1)), | 
|  | u32(NumberOfSymbols), | 
|  | u16(0), | 
|  | u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid), | 
|  | }; | 
|  | append(Buffer, Header); | 
|  |  | 
|  | // Section Header Table | 
|  | 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(ImportName.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 | 
|  | const coff_import_directory_table_entry ImportDescriptor{ | 
|  | u32(0), u32(0), u32(0), u32(0), u32(0), | 
|  | }; | 
|  | append(Buffer, ImportDescriptor); | 
|  |  | 
|  | 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 + ImportName.size() + 1); | 
|  | memcpy(&Buffer[S], ImportName.data(), ImportName.size()); | 
|  | Buffer[S + ImportName.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}, | 
|  | }; | 
|  | // TODO: Name.Offset.Offset here and in the all similar places below | 
|  | // suggests a names refactoring. Maybe StringTableOffset.Value? | 
|  | SymbolTable[0].Name.Offset.Offset = | 
|  | sizeof(uint32_t); | 
|  | SymbolTable[5].Name.Offset.Offset = | 
|  | sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1; | 
|  | SymbolTable[6].Name.Offset.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, ImportName)}; | 
|  | } | 
|  |  | 
|  | NewArchiveMember | 
|  | ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) { | 
|  | const uint32_t NumberOfSections = 1; | 
|  | 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 : C_Invalid), | 
|  | }; | 
|  | append(Buffer, Header); | 
|  |  | 
|  | // Section Header Table | 
|  | 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 | 
|  | 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}, | 
|  | }; | 
|  | SymbolTable[0].Name.Offset.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, ImportName)}; | 
|  | } | 
|  |  | 
|  | NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) { | 
|  | const uint32_t NumberOfSections = 2; | 
|  | 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 : C_Invalid), | 
|  | }; | 
|  | append(Buffer, Header); | 
|  |  | 
|  | // Section Header Table | 
|  | 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}, | 
|  | }; | 
|  | SymbolTable[0].Name.Offset.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, ImportName}}; | 
|  | } | 
|  |  | 
|  | NewArchiveMember ObjectFactory::createShortImport(StringRef Sym, | 
|  | uint16_t Ordinal, | 
|  | ImportType ImportType, | 
|  | ImportNameType NameType) { | 
|  | size_t ImpSize = ImportName.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 = 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, ImportName.data(), ImportName.size()); | 
|  |  | 
|  | return {MemoryBufferRef(StringRef(Buf, Size), ImportName)}; | 
|  | } | 
|  |  | 
|  | NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym, | 
|  | StringRef Weak, bool Imp) { | 
|  | std::vector<uint8_t> Buffer; | 
|  | const uint32_t NumberOfSections = 1; | 
|  | const uint32_t NumberOfSymbols = 5; | 
|  |  | 
|  | // COFF Header | 
|  | coff_file_header Header{ | 
|  | u16(0), | 
|  | u16(NumberOfSections), | 
|  | u32(0), | 
|  | u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))), | 
|  | u32(NumberOfSymbols), | 
|  | u16(0), | 
|  | u16(0), | 
|  | }; | 
|  | append(Buffer, Header); | 
|  |  | 
|  | // Section Header Table | 
|  | const coff_section SectionTable[NumberOfSections] = { | 
|  | {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'}, | 
|  | u32(0), | 
|  | u32(0), | 
|  | u32(0), | 
|  | u32(0), | 
|  | u32(0), | 
|  | u32(0), | 
|  | u16(0), | 
|  | u16(0), | 
|  | u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}}; | 
|  | append(Buffer, SectionTable); | 
|  |  | 
|  | // Symbol Table | 
|  | coff_symbol16 SymbolTable[NumberOfSymbols] = { | 
|  | {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}}, | 
|  | u32(0), | 
|  | u16(0xFFFF), | 
|  | u16(0), | 
|  | IMAGE_SYM_CLASS_STATIC, | 
|  | 0}, | 
|  | {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}}, | 
|  | u32(0), | 
|  | u16(0xFFFF), | 
|  | u16(0), | 
|  | IMAGE_SYM_CLASS_STATIC, | 
|  | 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_WEAK_EXTERNAL, | 
|  | 1}, | 
|  | {{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}}, | 
|  | u32(0), | 
|  | u16(0), | 
|  | u16(0), | 
|  | IMAGE_SYM_CLASS_NULL, | 
|  | 0}, | 
|  | }; | 
|  | SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t); | 
|  |  | 
|  | //__imp_ String Table | 
|  | StringRef Prefix = Imp ? "__imp_" : ""; | 
|  | SymbolTable[3].Name.Offset.Offset = | 
|  | sizeof(uint32_t) + Sym.size() + Prefix.size() + 1; | 
|  | append(Buffer, SymbolTable); | 
|  | writeStringTable(Buffer, {(Prefix + Sym).str(), | 
|  | (Prefix + Weak).str()}); | 
|  |  | 
|  | // Copied here so we can still use writeStringTable | 
|  | char *Buf = Alloc.Allocate<char>(Buffer.size()); | 
|  | memcpy(Buf, Buffer.data(), Buffer.size()); | 
|  | return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)}; | 
|  | } | 
|  |  | 
|  | Error writeImportLibrary(StringRef ImportName, StringRef Path, | 
|  | ArrayRef<COFFShortExport> Exports, | 
|  | MachineTypes Machine, bool MinGW) { | 
|  |  | 
|  | std::vector<NewArchiveMember> Members; | 
|  | ObjectFactory OF(llvm::sys::path::filename(ImportName), Machine); | 
|  |  | 
|  | 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 (COFFShortExport E : Exports) { | 
|  | if (E.Private) | 
|  | continue; | 
|  |  | 
|  | ImportType ImportType = IMPORT_CODE; | 
|  | if (E.Data) | 
|  | ImportType = IMPORT_DATA; | 
|  | if (E.Constant) | 
|  | ImportType = IMPORT_CONST; | 
|  |  | 
|  | StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName; | 
|  | ImportNameType NameType = getNameType(SymbolName, E.Name, Machine, MinGW); | 
|  | Expected<std::string> Name = E.ExtName.empty() | 
|  | ? SymbolName | 
|  | : replace(SymbolName, E.Name, E.ExtName); | 
|  |  | 
|  | if (!Name) | 
|  | return Name.takeError(); | 
|  |  | 
|  | if (!E.AliasTarget.empty() && *Name != E.AliasTarget) { | 
|  | Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, false)); | 
|  | Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, true)); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | Members.push_back( | 
|  | OF.createShortImport(*Name, E.Ordinal, ImportType, NameType)); | 
|  | } | 
|  |  | 
|  | return writeArchive(Path, Members, /*WriteSymtab*/ true, | 
|  | object::Archive::K_GNU, | 
|  | /*Deterministic*/ true, /*Thin*/ false); | 
|  | } | 
|  |  | 
|  | } // namespace object | 
|  | } // namespace llvm |