10b57cec5SDimitry Andric //===- COFFImportFile.cpp - COFF short import file implementation ---------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file defines the writeImportLibrary function. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "llvm/Object/COFFImportFile.h" 140b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 1581ad6265SDimitry Andric #include "llvm/ADT/Twine.h" 160b57cec5SDimitry Andric #include "llvm/Object/Archive.h" 170b57cec5SDimitry Andric #include "llvm/Object/ArchiveWriter.h" 180b57cec5SDimitry Andric #include "llvm/Object/COFF.h" 1981ad6265SDimitry Andric #include "llvm/Support/Allocator.h" 2081ad6265SDimitry Andric #include "llvm/Support/Endian.h" 210b57cec5SDimitry Andric #include "llvm/Support/Error.h" 2281ad6265SDimitry Andric #include "llvm/Support/ErrorHandling.h" 230b57cec5SDimitry Andric #include "llvm/Support/Path.h" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric #include <cstdint> 260b57cec5SDimitry Andric #include <string> 270b57cec5SDimitry Andric #include <vector> 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric using namespace llvm::COFF; 300b57cec5SDimitry Andric using namespace llvm::object; 310b57cec5SDimitry Andric using namespace llvm; 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric namespace llvm { 340b57cec5SDimitry Andric namespace object { 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric static uint16_t getImgRelRelocation(MachineTypes Machine) { 370b57cec5SDimitry Andric switch (Machine) { 380b57cec5SDimitry Andric default: 390b57cec5SDimitry Andric llvm_unreachable("unsupported machine"); 400b57cec5SDimitry Andric case IMAGE_FILE_MACHINE_AMD64: 410b57cec5SDimitry Andric return IMAGE_REL_AMD64_ADDR32NB; 420b57cec5SDimitry Andric case IMAGE_FILE_MACHINE_ARMNT: 430b57cec5SDimitry Andric return IMAGE_REL_ARM_ADDR32NB; 440b57cec5SDimitry Andric case IMAGE_FILE_MACHINE_ARM64: 45bdd1243dSDimitry Andric case IMAGE_FILE_MACHINE_ARM64EC: 4606c3fb27SDimitry Andric case IMAGE_FILE_MACHINE_ARM64X: 470b57cec5SDimitry Andric return IMAGE_REL_ARM64_ADDR32NB; 480b57cec5SDimitry Andric case IMAGE_FILE_MACHINE_I386: 490b57cec5SDimitry Andric return IMAGE_REL_I386_DIR32NB; 500b57cec5SDimitry Andric } 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric template <class T> static void append(std::vector<uint8_t> &B, const T &Data) { 540b57cec5SDimitry Andric size_t S = B.size(); 550b57cec5SDimitry Andric B.resize(S + sizeof(T)); 560b57cec5SDimitry Andric memcpy(&B[S], &Data, sizeof(T)); 570b57cec5SDimitry Andric } 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric static void writeStringTable(std::vector<uint8_t> &B, 600b57cec5SDimitry Andric ArrayRef<const std::string> Strings) { 610b57cec5SDimitry Andric // The COFF string table consists of a 4-byte value which is the size of the 620b57cec5SDimitry Andric // table, including the length field itself. This value is followed by the 630b57cec5SDimitry Andric // string content itself, which is an array of null-terminated C-style 640b57cec5SDimitry Andric // strings. The termination is important as they are referenced to by offset 650b57cec5SDimitry Andric // by the symbol entity in the file format. 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric size_t Pos = B.size(); 680b57cec5SDimitry Andric size_t Offset = B.size(); 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric // Skip over the length field, we will fill it in later as we will have 710b57cec5SDimitry Andric // computed the length while emitting the string content itself. 720b57cec5SDimitry Andric Pos += sizeof(uint32_t); 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric for (const auto &S : Strings) { 750b57cec5SDimitry Andric B.resize(Pos + S.length() + 1); 7606c3fb27SDimitry Andric std::copy(S.begin(), S.end(), std::next(B.begin(), Pos)); 7706c3fb27SDimitry Andric B[Pos + S.length()] = 0; 780b57cec5SDimitry Andric Pos += S.length() + 1; 790b57cec5SDimitry Andric } 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric // Backfill the length of the table now that it has been computed. 820b57cec5SDimitry Andric support::ulittle32_t Length(B.size() - Offset); 830b57cec5SDimitry Andric support::endian::write32le(&B[Offset], Length); 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric static ImportNameType getNameType(StringRef Sym, StringRef ExtName, 870b57cec5SDimitry Andric MachineTypes Machine, bool MinGW) { 880b57cec5SDimitry Andric // A decorated stdcall function in MSVC is exported with the 890b57cec5SDimitry Andric // type IMPORT_NAME, and the exported function name includes the 900b57cec5SDimitry Andric // the leading underscore. In MinGW on the other hand, a decorated 910b57cec5SDimitry Andric // stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX). 920b57cec5SDimitry Andric // See the comment in isDecorated in COFFModuleDefinition.cpp for more 930b57cec5SDimitry Andric // details. 94*5f757f3fSDimitry Andric if (ExtName.starts_with("_") && ExtName.contains('@') && !MinGW) 950b57cec5SDimitry Andric return IMPORT_NAME; 960b57cec5SDimitry Andric if (Sym != ExtName) 970b57cec5SDimitry Andric return IMPORT_NAME_UNDECORATE; 98*5f757f3fSDimitry Andric if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.starts_with("_")) 990b57cec5SDimitry Andric return IMPORT_NAME_NOPREFIX; 1000b57cec5SDimitry Andric return IMPORT_NAME; 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric static Expected<std::string> replace(StringRef S, StringRef From, 1040b57cec5SDimitry Andric StringRef To) { 1050b57cec5SDimitry Andric size_t Pos = S.find(From); 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric // From and To may be mangled, but substrings in S may not. 108*5f757f3fSDimitry Andric if (Pos == StringRef::npos && From.starts_with("_") && To.starts_with("_")) { 1090b57cec5SDimitry Andric From = From.substr(1); 1100b57cec5SDimitry Andric To = To.substr(1); 1110b57cec5SDimitry Andric Pos = S.find(From); 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric if (Pos == StringRef::npos) { 1150b57cec5SDimitry Andric return make_error<StringError>( 1160b57cec5SDimitry Andric StringRef(Twine(S + ": replacing '" + From + 1170b57cec5SDimitry Andric "' with '" + To + "' failed").str()), object_error::parse_failed); 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str(); 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric static const std::string NullImportDescriptorSymbolName = 1240b57cec5SDimitry Andric "__NULL_IMPORT_DESCRIPTOR"; 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric namespace { 1270b57cec5SDimitry Andric // This class constructs various small object files necessary to support linking 1280b57cec5SDimitry Andric // symbols imported from a DLL. The contents are pretty strictly defined and 1290b57cec5SDimitry Andric // nearly entirely static. The details of the structures files are defined in 1300b57cec5SDimitry Andric // WINNT.h and the PE/COFF specification. 1310b57cec5SDimitry Andric class ObjectFactory { 1320b57cec5SDimitry Andric using u16 = support::ulittle16_t; 1330b57cec5SDimitry Andric using u32 = support::ulittle32_t; 1340b57cec5SDimitry Andric MachineTypes Machine; 1350b57cec5SDimitry Andric BumpPtrAllocator Alloc; 1360b57cec5SDimitry Andric StringRef ImportName; 1370b57cec5SDimitry Andric StringRef Library; 1380b57cec5SDimitry Andric std::string ImportDescriptorSymbolName; 1390b57cec5SDimitry Andric std::string NullThunkSymbolName; 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric public: 1420b57cec5SDimitry Andric ObjectFactory(StringRef S, MachineTypes M) 143*5f757f3fSDimitry Andric : Machine(M), ImportName(S), Library(llvm::sys::path::stem(S)), 1440b57cec5SDimitry Andric ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()), 1450b57cec5SDimitry Andric NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {} 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric // Creates an Import Descriptor. This is a small object file which contains a 1480b57cec5SDimitry Andric // reference to the terminators and contains the library name (entry) for the 1490b57cec5SDimitry Andric // import name table. It will force the linker to construct the necessary 1500b57cec5SDimitry Andric // structure to import symbols from the DLL. 1510b57cec5SDimitry Andric NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer); 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric // Creates a NULL import descriptor. This is a small object file whcih 1540b57cec5SDimitry Andric // contains a NULL import descriptor. It is used to terminate the imports 1550b57cec5SDimitry Andric // from a specific DLL. 1560b57cec5SDimitry Andric NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer); 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric // Create a NULL Thunk Entry. This is a small object file which contains a 1590b57cec5SDimitry Andric // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It 1600b57cec5SDimitry Andric // is used to terminate the IAT and ILT. 1610b57cec5SDimitry Andric NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer); 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric // Create a short import file which is described in PE/COFF spec 7. Import 1640b57cec5SDimitry Andric // Library Format. 1650b57cec5SDimitry Andric NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal, 1660b57cec5SDimitry Andric ImportType Type, ImportNameType NameType); 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric // Create a weak external file which is described in PE/COFF Aux Format 3. 1690b57cec5SDimitry Andric NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp); 1700b57cec5SDimitry Andric }; 1710b57cec5SDimitry Andric } // namespace 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric NewArchiveMember 1740b57cec5SDimitry Andric ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) { 1750b57cec5SDimitry Andric const uint32_t NumberOfSections = 2; 1760b57cec5SDimitry Andric const uint32_t NumberOfSymbols = 7; 1770b57cec5SDimitry Andric const uint32_t NumberOfRelocations = 3; 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric // COFF Header 1800b57cec5SDimitry Andric coff_file_header Header{ 1810b57cec5SDimitry Andric u16(Machine), 1820b57cec5SDimitry Andric u16(NumberOfSections), 1830b57cec5SDimitry Andric u32(0), 1840b57cec5SDimitry Andric u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + 1850b57cec5SDimitry Andric // .idata$2 1860b57cec5SDimitry Andric sizeof(coff_import_directory_table_entry) + 1870b57cec5SDimitry Andric NumberOfRelocations * sizeof(coff_relocation) + 1880b57cec5SDimitry Andric // .idata$4 1890b57cec5SDimitry Andric (ImportName.size() + 1)), 1900b57cec5SDimitry Andric u32(NumberOfSymbols), 1910b57cec5SDimitry Andric u16(0), 192*5f757f3fSDimitry Andric u16(is64Bit(Machine) ? C_Invalid : IMAGE_FILE_32BIT_MACHINE), 1930b57cec5SDimitry Andric }; 1940b57cec5SDimitry Andric append(Buffer, Header); 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric // Section Header Table 1970b57cec5SDimitry Andric const coff_section SectionTable[NumberOfSections] = { 1980b57cec5SDimitry Andric {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}, 1990b57cec5SDimitry Andric u32(0), 2000b57cec5SDimitry Andric u32(0), 2010b57cec5SDimitry Andric u32(sizeof(coff_import_directory_table_entry)), 2020b57cec5SDimitry Andric u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), 2030b57cec5SDimitry Andric u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + 2040b57cec5SDimitry Andric sizeof(coff_import_directory_table_entry)), 2050b57cec5SDimitry Andric u32(0), 2060b57cec5SDimitry Andric u16(NumberOfRelocations), 2070b57cec5SDimitry Andric u16(0), 2080b57cec5SDimitry Andric u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | 2090b57cec5SDimitry Andric IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, 2100b57cec5SDimitry Andric {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}, 2110b57cec5SDimitry Andric u32(0), 2120b57cec5SDimitry Andric u32(0), 2130b57cec5SDimitry Andric u32(ImportName.size() + 1), 2140b57cec5SDimitry Andric u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + 2150b57cec5SDimitry Andric sizeof(coff_import_directory_table_entry) + 2160b57cec5SDimitry Andric NumberOfRelocations * sizeof(coff_relocation)), 2170b57cec5SDimitry Andric u32(0), 2180b57cec5SDimitry Andric u32(0), 2190b57cec5SDimitry Andric u16(0), 2200b57cec5SDimitry Andric u16(0), 2210b57cec5SDimitry Andric u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | 2220b57cec5SDimitry Andric IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, 2230b57cec5SDimitry Andric }; 2240b57cec5SDimitry Andric append(Buffer, SectionTable); 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric // .idata$2 2270b57cec5SDimitry Andric const coff_import_directory_table_entry ImportDescriptor{ 2280b57cec5SDimitry Andric u32(0), u32(0), u32(0), u32(0), u32(0), 2290b57cec5SDimitry Andric }; 2300b57cec5SDimitry Andric append(Buffer, ImportDescriptor); 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric const coff_relocation RelocationTable[NumberOfRelocations] = { 2330b57cec5SDimitry Andric {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2), 2340b57cec5SDimitry Andric u16(getImgRelRelocation(Machine))}, 2350b57cec5SDimitry Andric {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)), 2360b57cec5SDimitry Andric u32(3), u16(getImgRelRelocation(Machine))}, 2370b57cec5SDimitry Andric {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)), 2380b57cec5SDimitry Andric u32(4), u16(getImgRelRelocation(Machine))}, 2390b57cec5SDimitry Andric }; 2400b57cec5SDimitry Andric append(Buffer, RelocationTable); 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric // .idata$6 2430b57cec5SDimitry Andric auto S = Buffer.size(); 2440b57cec5SDimitry Andric Buffer.resize(S + ImportName.size() + 1); 2450b57cec5SDimitry Andric memcpy(&Buffer[S], ImportName.data(), ImportName.size()); 2460b57cec5SDimitry Andric Buffer[S + ImportName.size()] = '\0'; 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric // Symbol Table 2490b57cec5SDimitry Andric coff_symbol16 SymbolTable[NumberOfSymbols] = { 2500b57cec5SDimitry Andric {{{0, 0, 0, 0, 0, 0, 0, 0}}, 2510b57cec5SDimitry Andric u32(0), 2520b57cec5SDimitry Andric u16(1), 2530b57cec5SDimitry Andric u16(0), 2540b57cec5SDimitry Andric IMAGE_SYM_CLASS_EXTERNAL, 2550b57cec5SDimitry Andric 0}, 2560b57cec5SDimitry Andric {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}}, 2570b57cec5SDimitry Andric u32(0), 2580b57cec5SDimitry Andric u16(1), 2590b57cec5SDimitry Andric u16(0), 2600b57cec5SDimitry Andric IMAGE_SYM_CLASS_SECTION, 2610b57cec5SDimitry Andric 0}, 2620b57cec5SDimitry Andric {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}}, 2630b57cec5SDimitry Andric u32(0), 2640b57cec5SDimitry Andric u16(2), 2650b57cec5SDimitry Andric u16(0), 2660b57cec5SDimitry Andric IMAGE_SYM_CLASS_STATIC, 2670b57cec5SDimitry Andric 0}, 2680b57cec5SDimitry Andric {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}}, 2690b57cec5SDimitry Andric u32(0), 2700b57cec5SDimitry Andric u16(0), 2710b57cec5SDimitry Andric u16(0), 2720b57cec5SDimitry Andric IMAGE_SYM_CLASS_SECTION, 2730b57cec5SDimitry Andric 0}, 2740b57cec5SDimitry Andric {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}}, 2750b57cec5SDimitry Andric u32(0), 2760b57cec5SDimitry Andric u16(0), 2770b57cec5SDimitry Andric u16(0), 2780b57cec5SDimitry Andric IMAGE_SYM_CLASS_SECTION, 2790b57cec5SDimitry Andric 0}, 2800b57cec5SDimitry Andric {{{0, 0, 0, 0, 0, 0, 0, 0}}, 2810b57cec5SDimitry Andric u32(0), 2820b57cec5SDimitry Andric u16(0), 2830b57cec5SDimitry Andric u16(0), 2840b57cec5SDimitry Andric IMAGE_SYM_CLASS_EXTERNAL, 2850b57cec5SDimitry Andric 0}, 2860b57cec5SDimitry Andric {{{0, 0, 0, 0, 0, 0, 0, 0}}, 2870b57cec5SDimitry Andric u32(0), 2880b57cec5SDimitry Andric u16(0), 2890b57cec5SDimitry Andric u16(0), 2900b57cec5SDimitry Andric IMAGE_SYM_CLASS_EXTERNAL, 2910b57cec5SDimitry Andric 0}, 2920b57cec5SDimitry Andric }; 2930b57cec5SDimitry Andric // TODO: Name.Offset.Offset here and in the all similar places below 2940b57cec5SDimitry Andric // suggests a names refactoring. Maybe StringTableOffset.Value? 2950b57cec5SDimitry Andric SymbolTable[0].Name.Offset.Offset = 2960b57cec5SDimitry Andric sizeof(uint32_t); 2970b57cec5SDimitry Andric SymbolTable[5].Name.Offset.Offset = 2980b57cec5SDimitry Andric sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1; 2990b57cec5SDimitry Andric SymbolTable[6].Name.Offset.Offset = 3000b57cec5SDimitry Andric sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 + 3010b57cec5SDimitry Andric NullImportDescriptorSymbolName.length() + 1; 3020b57cec5SDimitry Andric append(Buffer, SymbolTable); 3030b57cec5SDimitry Andric 3040b57cec5SDimitry Andric // String Table 3050b57cec5SDimitry Andric writeStringTable(Buffer, 3060b57cec5SDimitry Andric {ImportDescriptorSymbolName, NullImportDescriptorSymbolName, 3070b57cec5SDimitry Andric NullThunkSymbolName}); 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; 3100b57cec5SDimitry Andric return {MemoryBufferRef(F, ImportName)}; 3110b57cec5SDimitry Andric } 3120b57cec5SDimitry Andric 3130b57cec5SDimitry Andric NewArchiveMember 3140b57cec5SDimitry Andric ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) { 3150b57cec5SDimitry Andric const uint32_t NumberOfSections = 1; 3160b57cec5SDimitry Andric const uint32_t NumberOfSymbols = 1; 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric // COFF Header 3190b57cec5SDimitry Andric coff_file_header Header{ 3200b57cec5SDimitry Andric u16(Machine), 3210b57cec5SDimitry Andric u16(NumberOfSections), 3220b57cec5SDimitry Andric u32(0), 3230b57cec5SDimitry Andric u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + 3240b57cec5SDimitry Andric // .idata$3 3250b57cec5SDimitry Andric sizeof(coff_import_directory_table_entry)), 3260b57cec5SDimitry Andric u32(NumberOfSymbols), 3270b57cec5SDimitry Andric u16(0), 328*5f757f3fSDimitry Andric u16(is64Bit(Machine) ? C_Invalid : IMAGE_FILE_32BIT_MACHINE), 3290b57cec5SDimitry Andric }; 3300b57cec5SDimitry Andric append(Buffer, Header); 3310b57cec5SDimitry Andric 3320b57cec5SDimitry Andric // Section Header Table 3330b57cec5SDimitry Andric const coff_section SectionTable[NumberOfSections] = { 3340b57cec5SDimitry Andric {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'}, 3350b57cec5SDimitry Andric u32(0), 3360b57cec5SDimitry Andric u32(0), 3370b57cec5SDimitry Andric u32(sizeof(coff_import_directory_table_entry)), 3380b57cec5SDimitry Andric u32(sizeof(coff_file_header) + 3390b57cec5SDimitry Andric (NumberOfSections * sizeof(coff_section))), 3400b57cec5SDimitry Andric u32(0), 3410b57cec5SDimitry Andric u32(0), 3420b57cec5SDimitry Andric u16(0), 3430b57cec5SDimitry Andric u16(0), 3440b57cec5SDimitry Andric u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | 3450b57cec5SDimitry Andric IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, 3460b57cec5SDimitry Andric }; 3470b57cec5SDimitry Andric append(Buffer, SectionTable); 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric // .idata$3 3500b57cec5SDimitry Andric const coff_import_directory_table_entry ImportDescriptor{ 3510b57cec5SDimitry Andric u32(0), u32(0), u32(0), u32(0), u32(0), 3520b57cec5SDimitry Andric }; 3530b57cec5SDimitry Andric append(Buffer, ImportDescriptor); 3540b57cec5SDimitry Andric 3550b57cec5SDimitry Andric // Symbol Table 3560b57cec5SDimitry Andric coff_symbol16 SymbolTable[NumberOfSymbols] = { 3570b57cec5SDimitry Andric {{{0, 0, 0, 0, 0, 0, 0, 0}}, 3580b57cec5SDimitry Andric u32(0), 3590b57cec5SDimitry Andric u16(1), 3600b57cec5SDimitry Andric u16(0), 3610b57cec5SDimitry Andric IMAGE_SYM_CLASS_EXTERNAL, 3620b57cec5SDimitry Andric 0}, 3630b57cec5SDimitry Andric }; 3640b57cec5SDimitry Andric SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t); 3650b57cec5SDimitry Andric append(Buffer, SymbolTable); 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric // String Table 3680b57cec5SDimitry Andric writeStringTable(Buffer, {NullImportDescriptorSymbolName}); 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; 3710b57cec5SDimitry Andric return {MemoryBufferRef(F, ImportName)}; 3720b57cec5SDimitry Andric } 3730b57cec5SDimitry Andric 3740b57cec5SDimitry Andric NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) { 3750b57cec5SDimitry Andric const uint32_t NumberOfSections = 2; 3760b57cec5SDimitry Andric const uint32_t NumberOfSymbols = 1; 377*5f757f3fSDimitry Andric uint32_t VASize = is64Bit(Machine) ? 8 : 4; 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric // COFF Header 3800b57cec5SDimitry Andric coff_file_header Header{ 3810b57cec5SDimitry Andric u16(Machine), 3820b57cec5SDimitry Andric u16(NumberOfSections), 3830b57cec5SDimitry Andric u32(0), 3840b57cec5SDimitry Andric u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + 3850b57cec5SDimitry Andric // .idata$5 3860b57cec5SDimitry Andric VASize + 3870b57cec5SDimitry Andric // .idata$4 3880b57cec5SDimitry Andric VASize), 3890b57cec5SDimitry Andric u32(NumberOfSymbols), 3900b57cec5SDimitry Andric u16(0), 391*5f757f3fSDimitry Andric u16(is64Bit(Machine) ? C_Invalid : IMAGE_FILE_32BIT_MACHINE), 3920b57cec5SDimitry Andric }; 3930b57cec5SDimitry Andric append(Buffer, Header); 3940b57cec5SDimitry Andric 3950b57cec5SDimitry Andric // Section Header Table 3960b57cec5SDimitry Andric const coff_section SectionTable[NumberOfSections] = { 3970b57cec5SDimitry Andric {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}, 3980b57cec5SDimitry Andric u32(0), 3990b57cec5SDimitry Andric u32(0), 4000b57cec5SDimitry Andric u32(VASize), 4010b57cec5SDimitry Andric u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), 4020b57cec5SDimitry Andric u32(0), 4030b57cec5SDimitry Andric u32(0), 4040b57cec5SDimitry Andric u16(0), 4050b57cec5SDimitry Andric u16(0), 406*5f757f3fSDimitry Andric u32((is64Bit(Machine) ? IMAGE_SCN_ALIGN_8BYTES 407*5f757f3fSDimitry Andric : IMAGE_SCN_ALIGN_4BYTES) | 4080b57cec5SDimitry Andric IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | 4090b57cec5SDimitry Andric IMAGE_SCN_MEM_WRITE)}, 4100b57cec5SDimitry Andric {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}, 4110b57cec5SDimitry Andric u32(0), 4120b57cec5SDimitry Andric u32(0), 4130b57cec5SDimitry Andric u32(VASize), 4140b57cec5SDimitry Andric u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + 4150b57cec5SDimitry Andric VASize), 4160b57cec5SDimitry Andric u32(0), 4170b57cec5SDimitry Andric u32(0), 4180b57cec5SDimitry Andric u16(0), 4190b57cec5SDimitry Andric u16(0), 420*5f757f3fSDimitry Andric u32((is64Bit(Machine) ? IMAGE_SCN_ALIGN_8BYTES 421*5f757f3fSDimitry Andric : IMAGE_SCN_ALIGN_4BYTES) | 4220b57cec5SDimitry Andric IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | 4230b57cec5SDimitry Andric IMAGE_SCN_MEM_WRITE)}, 4240b57cec5SDimitry Andric }; 4250b57cec5SDimitry Andric append(Buffer, SectionTable); 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric // .idata$5, ILT 4280b57cec5SDimitry Andric append(Buffer, u32(0)); 429*5f757f3fSDimitry Andric if (is64Bit(Machine)) 4300b57cec5SDimitry Andric append(Buffer, u32(0)); 4310b57cec5SDimitry Andric 4320b57cec5SDimitry Andric // .idata$4, IAT 4330b57cec5SDimitry Andric append(Buffer, u32(0)); 434*5f757f3fSDimitry Andric if (is64Bit(Machine)) 4350b57cec5SDimitry Andric append(Buffer, u32(0)); 4360b57cec5SDimitry Andric 4370b57cec5SDimitry Andric // Symbol Table 4380b57cec5SDimitry Andric coff_symbol16 SymbolTable[NumberOfSymbols] = { 4390b57cec5SDimitry Andric {{{0, 0, 0, 0, 0, 0, 0, 0}}, 4400b57cec5SDimitry Andric u32(0), 4410b57cec5SDimitry Andric u16(1), 4420b57cec5SDimitry Andric u16(0), 4430b57cec5SDimitry Andric IMAGE_SYM_CLASS_EXTERNAL, 4440b57cec5SDimitry Andric 0}, 4450b57cec5SDimitry Andric }; 4460b57cec5SDimitry Andric SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t); 4470b57cec5SDimitry Andric append(Buffer, SymbolTable); 4480b57cec5SDimitry Andric 4490b57cec5SDimitry Andric // String Table 4500b57cec5SDimitry Andric writeStringTable(Buffer, {NullThunkSymbolName}); 4510b57cec5SDimitry Andric 4520b57cec5SDimitry Andric StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; 4530b57cec5SDimitry Andric return {MemoryBufferRef{F, ImportName}}; 4540b57cec5SDimitry Andric } 4550b57cec5SDimitry Andric 4560b57cec5SDimitry Andric NewArchiveMember ObjectFactory::createShortImport(StringRef Sym, 4570b57cec5SDimitry Andric uint16_t Ordinal, 4580b57cec5SDimitry Andric ImportType ImportType, 4590b57cec5SDimitry Andric ImportNameType NameType) { 4600b57cec5SDimitry Andric size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs 4610b57cec5SDimitry Andric size_t Size = sizeof(coff_import_header) + ImpSize; 4620b57cec5SDimitry Andric char *Buf = Alloc.Allocate<char>(Size); 4630b57cec5SDimitry Andric memset(Buf, 0, Size); 4640b57cec5SDimitry Andric char *P = Buf; 4650b57cec5SDimitry Andric 4660b57cec5SDimitry Andric // Write short import library. 4670b57cec5SDimitry Andric auto *Imp = reinterpret_cast<coff_import_header *>(P); 4680b57cec5SDimitry Andric P += sizeof(*Imp); 4690b57cec5SDimitry Andric Imp->Sig2 = 0xFFFF; 4700b57cec5SDimitry Andric Imp->Machine = Machine; 4710b57cec5SDimitry Andric Imp->SizeOfData = ImpSize; 4720b57cec5SDimitry Andric if (Ordinal > 0) 4730b57cec5SDimitry Andric Imp->OrdinalHint = Ordinal; 4740b57cec5SDimitry Andric Imp->TypeInfo = (NameType << 2) | ImportType; 4750b57cec5SDimitry Andric 4760b57cec5SDimitry Andric // Write symbol name and DLL name. 4770b57cec5SDimitry Andric memcpy(P, Sym.data(), Sym.size()); 4780b57cec5SDimitry Andric P += Sym.size() + 1; 4790b57cec5SDimitry Andric memcpy(P, ImportName.data(), ImportName.size()); 4800b57cec5SDimitry Andric 4810b57cec5SDimitry Andric return {MemoryBufferRef(StringRef(Buf, Size), ImportName)}; 4820b57cec5SDimitry Andric } 4830b57cec5SDimitry Andric 4840b57cec5SDimitry Andric NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym, 4850b57cec5SDimitry Andric StringRef Weak, bool Imp) { 4860b57cec5SDimitry Andric std::vector<uint8_t> Buffer; 4870b57cec5SDimitry Andric const uint32_t NumberOfSections = 1; 4880b57cec5SDimitry Andric const uint32_t NumberOfSymbols = 5; 4890b57cec5SDimitry Andric 4900b57cec5SDimitry Andric // COFF Header 4910b57cec5SDimitry Andric coff_file_header Header{ 4920b57cec5SDimitry Andric u16(Machine), 4930b57cec5SDimitry Andric u16(NumberOfSections), 4940b57cec5SDimitry Andric u32(0), 4950b57cec5SDimitry Andric u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))), 4960b57cec5SDimitry Andric u32(NumberOfSymbols), 4970b57cec5SDimitry Andric u16(0), 4980b57cec5SDimitry Andric u16(0), 4990b57cec5SDimitry Andric }; 5000b57cec5SDimitry Andric append(Buffer, Header); 5010b57cec5SDimitry Andric 5020b57cec5SDimitry Andric // Section Header Table 5030b57cec5SDimitry Andric const coff_section SectionTable[NumberOfSections] = { 5040b57cec5SDimitry Andric {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'}, 5050b57cec5SDimitry Andric u32(0), 5060b57cec5SDimitry Andric u32(0), 5070b57cec5SDimitry Andric u32(0), 5080b57cec5SDimitry Andric u32(0), 5090b57cec5SDimitry Andric u32(0), 5100b57cec5SDimitry Andric u32(0), 5110b57cec5SDimitry Andric u16(0), 5120b57cec5SDimitry Andric u16(0), 5130b57cec5SDimitry Andric u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}}; 5140b57cec5SDimitry Andric append(Buffer, SectionTable); 5150b57cec5SDimitry Andric 5160b57cec5SDimitry Andric // Symbol Table 5170b57cec5SDimitry Andric coff_symbol16 SymbolTable[NumberOfSymbols] = { 5180b57cec5SDimitry Andric {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}}, 5190b57cec5SDimitry Andric u32(0), 5200b57cec5SDimitry Andric u16(0xFFFF), 5210b57cec5SDimitry Andric u16(0), 5220b57cec5SDimitry Andric IMAGE_SYM_CLASS_STATIC, 5230b57cec5SDimitry Andric 0}, 5240b57cec5SDimitry Andric {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}}, 5250b57cec5SDimitry Andric u32(0), 5260b57cec5SDimitry Andric u16(0xFFFF), 5270b57cec5SDimitry Andric u16(0), 5280b57cec5SDimitry Andric IMAGE_SYM_CLASS_STATIC, 5290b57cec5SDimitry Andric 0}, 5300b57cec5SDimitry Andric {{{0, 0, 0, 0, 0, 0, 0, 0}}, 5310b57cec5SDimitry Andric u32(0), 5320b57cec5SDimitry Andric u16(0), 5330b57cec5SDimitry Andric u16(0), 5340b57cec5SDimitry Andric IMAGE_SYM_CLASS_EXTERNAL, 5350b57cec5SDimitry Andric 0}, 5360b57cec5SDimitry Andric {{{0, 0, 0, 0, 0, 0, 0, 0}}, 5370b57cec5SDimitry Andric u32(0), 5380b57cec5SDimitry Andric u16(0), 5390b57cec5SDimitry Andric u16(0), 5400b57cec5SDimitry Andric IMAGE_SYM_CLASS_WEAK_EXTERNAL, 5410b57cec5SDimitry Andric 1}, 5420b57cec5SDimitry Andric {{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}}, 5430b57cec5SDimitry Andric u32(0), 5440b57cec5SDimitry Andric u16(0), 5450b57cec5SDimitry Andric u16(0), 5460b57cec5SDimitry Andric IMAGE_SYM_CLASS_NULL, 5470b57cec5SDimitry Andric 0}, 5480b57cec5SDimitry Andric }; 5490b57cec5SDimitry Andric SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t); 5500b57cec5SDimitry Andric 5510b57cec5SDimitry Andric //__imp_ String Table 5520b57cec5SDimitry Andric StringRef Prefix = Imp ? "__imp_" : ""; 5530b57cec5SDimitry Andric SymbolTable[3].Name.Offset.Offset = 5540b57cec5SDimitry Andric sizeof(uint32_t) + Sym.size() + Prefix.size() + 1; 5550b57cec5SDimitry Andric append(Buffer, SymbolTable); 5560b57cec5SDimitry Andric writeStringTable(Buffer, {(Prefix + Sym).str(), 5570b57cec5SDimitry Andric (Prefix + Weak).str()}); 5580b57cec5SDimitry Andric 5590b57cec5SDimitry Andric // Copied here so we can still use writeStringTable 5600b57cec5SDimitry Andric char *Buf = Alloc.Allocate<char>(Buffer.size()); 5610b57cec5SDimitry Andric memcpy(Buf, Buffer.data(), Buffer.size()); 5620b57cec5SDimitry Andric return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)}; 5630b57cec5SDimitry Andric } 5640b57cec5SDimitry Andric 5650b57cec5SDimitry Andric Error writeImportLibrary(StringRef ImportName, StringRef Path, 5660b57cec5SDimitry Andric ArrayRef<COFFShortExport> Exports, 5670b57cec5SDimitry Andric MachineTypes Machine, bool MinGW) { 5680b57cec5SDimitry Andric 5690b57cec5SDimitry Andric std::vector<NewArchiveMember> Members; 5700b57cec5SDimitry Andric ObjectFactory OF(llvm::sys::path::filename(ImportName), Machine); 5710b57cec5SDimitry Andric 5720b57cec5SDimitry Andric std::vector<uint8_t> ImportDescriptor; 5730b57cec5SDimitry Andric Members.push_back(OF.createImportDescriptor(ImportDescriptor)); 5740b57cec5SDimitry Andric 5750b57cec5SDimitry Andric std::vector<uint8_t> NullImportDescriptor; 5760b57cec5SDimitry Andric Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor)); 5770b57cec5SDimitry Andric 5780b57cec5SDimitry Andric std::vector<uint8_t> NullThunk; 5790b57cec5SDimitry Andric Members.push_back(OF.createNullThunk(NullThunk)); 5800b57cec5SDimitry Andric 581*5f757f3fSDimitry Andric for (const COFFShortExport &E : Exports) { 5820b57cec5SDimitry Andric if (E.Private) 5830b57cec5SDimitry Andric continue; 5840b57cec5SDimitry Andric 5850b57cec5SDimitry Andric ImportType ImportType = IMPORT_CODE; 5860b57cec5SDimitry Andric if (E.Data) 5870b57cec5SDimitry Andric ImportType = IMPORT_DATA; 5880b57cec5SDimitry Andric if (E.Constant) 5890b57cec5SDimitry Andric ImportType = IMPORT_CONST; 5900b57cec5SDimitry Andric 5910b57cec5SDimitry Andric StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName; 5920b57cec5SDimitry Andric ImportNameType NameType = E.Noname 5930b57cec5SDimitry Andric ? IMPORT_ORDINAL 5940b57cec5SDimitry Andric : getNameType(SymbolName, E.Name, 5950b57cec5SDimitry Andric Machine, MinGW); 5960b57cec5SDimitry Andric Expected<std::string> Name = E.ExtName.empty() 5975ffd83dbSDimitry Andric ? std::string(SymbolName) 5980b57cec5SDimitry Andric : replace(SymbolName, E.Name, E.ExtName); 5990b57cec5SDimitry Andric 6000b57cec5SDimitry Andric if (!Name) 6010b57cec5SDimitry Andric return Name.takeError(); 6020b57cec5SDimitry Andric 6030b57cec5SDimitry Andric if (!E.AliasTarget.empty() && *Name != E.AliasTarget) { 6040b57cec5SDimitry Andric Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, false)); 6050b57cec5SDimitry Andric Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, true)); 6060b57cec5SDimitry Andric continue; 6070b57cec5SDimitry Andric } 6080b57cec5SDimitry Andric 6090b57cec5SDimitry Andric Members.push_back( 6100b57cec5SDimitry Andric OF.createShortImport(*Name, E.Ordinal, ImportType, NameType)); 6110b57cec5SDimitry Andric } 6120b57cec5SDimitry Andric 613*5f757f3fSDimitry Andric return writeArchive(Path, Members, SymtabWritingMode::NormalSymtab, 614*5f757f3fSDimitry Andric MinGW ? object::Archive::K_GNU : object::Archive::K_COFF, 615*5f757f3fSDimitry Andric /*Deterministic*/ true, /*Thin*/ false, 616*5f757f3fSDimitry Andric /*OldArchiveBuf*/ nullptr, isArm64EC(Machine)); 6170b57cec5SDimitry Andric } 6180b57cec5SDimitry Andric 6190b57cec5SDimitry Andric } // namespace object 6200b57cec5SDimitry Andric } // namespace llvm 621