630 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			630 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- COFFImportFile.cpp - COFF short import file implementation ---------===//
 | |
| //
 | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | |
| // See https://llvm.org/LICENSE.txt for license information.
 | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| // This file defines the writeImportLibrary function.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "llvm/Object/COFFImportFile.h"
 | |
| #include "llvm/ADT/ArrayRef.h"
 | |
| #include "llvm/ADT/Twine.h"
 | |
| #include "llvm/Object/Archive.h"
 | |
| #include "llvm/Object/ArchiveWriter.h"
 | |
| #include "llvm/Object/COFF.h"
 | |
| #include "llvm/Support/Allocator.h"
 | |
| #include "llvm/Support/Endian.h"
 | |
| #include "llvm/Support/Error.h"
 | |
| #include "llvm/Support/ErrorHandling.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(Machine),
 | |
|       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 = E.Noname
 | |
|                                   ? IMPORT_ORDINAL
 | |
|                                   : getNameType(SymbolName, E.Name,
 | |
|                                                 Machine, MinGW);
 | |
|     Expected<std::string> Name = E.ExtName.empty()
 | |
|                                      ? std::string(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
 |