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" 15*0fca6ea1SDimitry Andric #include "llvm/ADT/SmallVector.h" 16*0fca6ea1SDimitry Andric #include "llvm/ADT/StringMap.h" 1781ad6265SDimitry Andric #include "llvm/ADT/Twine.h" 180b57cec5SDimitry Andric #include "llvm/Object/Archive.h" 190b57cec5SDimitry Andric #include "llvm/Object/ArchiveWriter.h" 200b57cec5SDimitry Andric #include "llvm/Object/COFF.h" 2181ad6265SDimitry Andric #include "llvm/Support/Allocator.h" 2281ad6265SDimitry Andric #include "llvm/Support/Endian.h" 230b57cec5SDimitry Andric #include "llvm/Support/Error.h" 2481ad6265SDimitry Andric #include "llvm/Support/ErrorHandling.h" 250b57cec5SDimitry Andric #include "llvm/Support/Path.h" 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric #include <cstdint> 280b57cec5SDimitry Andric #include <string> 290b57cec5SDimitry Andric #include <vector> 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric using namespace llvm::COFF; 320b57cec5SDimitry Andric using namespace llvm::object; 330b57cec5SDimitry Andric using namespace llvm; 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric namespace llvm { 360b57cec5SDimitry Andric namespace object { 370b57cec5SDimitry Andric 387a6dacacSDimitry Andric StringRef COFFImportFile::getFileFormatName() const { 397a6dacacSDimitry Andric switch (getMachine()) { 407a6dacacSDimitry Andric case COFF::IMAGE_FILE_MACHINE_I386: 417a6dacacSDimitry Andric return "COFF-import-file-i386"; 427a6dacacSDimitry Andric case COFF::IMAGE_FILE_MACHINE_AMD64: 437a6dacacSDimitry Andric return "COFF-import-file-x86-64"; 447a6dacacSDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARMNT: 457a6dacacSDimitry Andric return "COFF-import-file-ARM"; 467a6dacacSDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64: 477a6dacacSDimitry Andric return "COFF-import-file-ARM64"; 487a6dacacSDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64EC: 497a6dacacSDimitry Andric return "COFF-import-file-ARM64EC"; 507a6dacacSDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64X: 517a6dacacSDimitry Andric return "COFF-import-file-ARM64X"; 527a6dacacSDimitry Andric default: 537a6dacacSDimitry Andric return "COFF-import-file-<unknown arch>"; 547a6dacacSDimitry Andric } 557a6dacacSDimitry Andric } 567a6dacacSDimitry Andric 57*0fca6ea1SDimitry Andric static StringRef applyNameType(ImportNameType Type, StringRef name) { 58439352acSDimitry Andric auto ltrim1 = [](StringRef s, StringRef chars) { 59439352acSDimitry Andric return !s.empty() && chars.contains(s[0]) ? s.substr(1) : s; 60439352acSDimitry Andric }; 61439352acSDimitry Andric 62*0fca6ea1SDimitry Andric switch (Type) { 63439352acSDimitry Andric case IMPORT_NAME_NOPREFIX: 64439352acSDimitry Andric name = ltrim1(name, "?@_"); 65439352acSDimitry Andric break; 66439352acSDimitry Andric case IMPORT_NAME_UNDECORATE: 67439352acSDimitry Andric name = ltrim1(name, "?@_"); 68439352acSDimitry Andric name = name.substr(0, name.find('@')); 69439352acSDimitry Andric break; 70*0fca6ea1SDimitry Andric default: 71*0fca6ea1SDimitry Andric break; 72*0fca6ea1SDimitry Andric } 73*0fca6ea1SDimitry Andric return name; 74*0fca6ea1SDimitry Andric } 75*0fca6ea1SDimitry Andric 76*0fca6ea1SDimitry Andric StringRef COFFImportFile::getExportName() const { 77*0fca6ea1SDimitry Andric const coff_import_header *hdr = getCOFFImportHeader(); 78*0fca6ea1SDimitry Andric StringRef name = Data.getBuffer().substr(sizeof(*hdr)).split('\0').first; 79*0fca6ea1SDimitry Andric 80*0fca6ea1SDimitry Andric switch (hdr->getNameType()) { 81*0fca6ea1SDimitry Andric case IMPORT_ORDINAL: 82*0fca6ea1SDimitry Andric name = ""; 83*0fca6ea1SDimitry Andric break; 84*0fca6ea1SDimitry Andric case IMPORT_NAME_NOPREFIX: 85*0fca6ea1SDimitry Andric case IMPORT_NAME_UNDECORATE: 86*0fca6ea1SDimitry Andric name = applyNameType(static_cast<ImportNameType>(hdr->getNameType()), name); 87*0fca6ea1SDimitry Andric break; 88439352acSDimitry Andric case IMPORT_NAME_EXPORTAS: { 89439352acSDimitry Andric // Skip DLL name 90439352acSDimitry Andric name = Data.getBuffer().substr(sizeof(*hdr) + name.size() + 1); 91439352acSDimitry Andric name = name.split('\0').second.split('\0').first; 92439352acSDimitry Andric break; 93439352acSDimitry Andric } 94439352acSDimitry Andric default: 95439352acSDimitry Andric break; 96439352acSDimitry Andric } 97439352acSDimitry Andric 98439352acSDimitry Andric return name; 99439352acSDimitry Andric } 100439352acSDimitry Andric 101*0fca6ea1SDimitry Andric Error COFFImportFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const { 102*0fca6ea1SDimitry Andric switch (Symb.p) { 103*0fca6ea1SDimitry Andric case ImpSymbol: 104*0fca6ea1SDimitry Andric OS << "__imp_"; 105*0fca6ea1SDimitry Andric break; 106*0fca6ea1SDimitry Andric case ECAuxSymbol: 107*0fca6ea1SDimitry Andric OS << "__imp_aux_"; 108*0fca6ea1SDimitry Andric break; 109*0fca6ea1SDimitry Andric } 110*0fca6ea1SDimitry Andric const char *Name = Data.getBufferStart() + sizeof(coff_import_header); 111*0fca6ea1SDimitry Andric if (Symb.p != ECThunkSymbol && COFF::isArm64EC(getMachine())) { 112*0fca6ea1SDimitry Andric if (std::optional<std::string> DemangledName = 113*0fca6ea1SDimitry Andric getArm64ECDemangledFunctionName(Name)) { 114*0fca6ea1SDimitry Andric OS << StringRef(*DemangledName); 115*0fca6ea1SDimitry Andric return Error::success(); 116*0fca6ea1SDimitry Andric } 117*0fca6ea1SDimitry Andric } 118*0fca6ea1SDimitry Andric OS << StringRef(Name); 119*0fca6ea1SDimitry Andric return Error::success(); 120*0fca6ea1SDimitry Andric } 121*0fca6ea1SDimitry Andric 1220b57cec5SDimitry Andric static uint16_t getImgRelRelocation(MachineTypes Machine) { 1230b57cec5SDimitry Andric switch (Machine) { 1240b57cec5SDimitry Andric default: 1250b57cec5SDimitry Andric llvm_unreachable("unsupported machine"); 1260b57cec5SDimitry Andric case IMAGE_FILE_MACHINE_AMD64: 1270b57cec5SDimitry Andric return IMAGE_REL_AMD64_ADDR32NB; 1280b57cec5SDimitry Andric case IMAGE_FILE_MACHINE_ARMNT: 1290b57cec5SDimitry Andric return IMAGE_REL_ARM_ADDR32NB; 1300b57cec5SDimitry Andric case IMAGE_FILE_MACHINE_ARM64: 131bdd1243dSDimitry Andric case IMAGE_FILE_MACHINE_ARM64EC: 13206c3fb27SDimitry Andric case IMAGE_FILE_MACHINE_ARM64X: 1330b57cec5SDimitry Andric return IMAGE_REL_ARM64_ADDR32NB; 1340b57cec5SDimitry Andric case IMAGE_FILE_MACHINE_I386: 1350b57cec5SDimitry Andric return IMAGE_REL_I386_DIR32NB; 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric template <class T> static void append(std::vector<uint8_t> &B, const T &Data) { 1400b57cec5SDimitry Andric size_t S = B.size(); 1410b57cec5SDimitry Andric B.resize(S + sizeof(T)); 1420b57cec5SDimitry Andric memcpy(&B[S], &Data, sizeof(T)); 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric static void writeStringTable(std::vector<uint8_t> &B, 146439352acSDimitry Andric ArrayRef<const std::string_view> Strings) { 1470b57cec5SDimitry Andric // The COFF string table consists of a 4-byte value which is the size of the 1480b57cec5SDimitry Andric // table, including the length field itself. This value is followed by the 1490b57cec5SDimitry Andric // string content itself, which is an array of null-terminated C-style 1500b57cec5SDimitry Andric // strings. The termination is important as they are referenced to by offset 1510b57cec5SDimitry Andric // by the symbol entity in the file format. 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric size_t Pos = B.size(); 1540b57cec5SDimitry Andric size_t Offset = B.size(); 1550b57cec5SDimitry Andric 1560b57cec5SDimitry Andric // Skip over the length field, we will fill it in later as we will have 1570b57cec5SDimitry Andric // computed the length while emitting the string content itself. 1580b57cec5SDimitry Andric Pos += sizeof(uint32_t); 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric for (const auto &S : Strings) { 1610b57cec5SDimitry Andric B.resize(Pos + S.length() + 1); 16206c3fb27SDimitry Andric std::copy(S.begin(), S.end(), std::next(B.begin(), Pos)); 16306c3fb27SDimitry Andric B[Pos + S.length()] = 0; 1640b57cec5SDimitry Andric Pos += S.length() + 1; 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric // Backfill the length of the table now that it has been computed. 1680b57cec5SDimitry Andric support::ulittle32_t Length(B.size() - Offset); 1690b57cec5SDimitry Andric support::endian::write32le(&B[Offset], Length); 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric static ImportNameType getNameType(StringRef Sym, StringRef ExtName, 1730b57cec5SDimitry Andric MachineTypes Machine, bool MinGW) { 1740b57cec5SDimitry Andric // A decorated stdcall function in MSVC is exported with the 1750b57cec5SDimitry Andric // type IMPORT_NAME, and the exported function name includes the 1760b57cec5SDimitry Andric // the leading underscore. In MinGW on the other hand, a decorated 1770b57cec5SDimitry Andric // stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX). 1780b57cec5SDimitry Andric // See the comment in isDecorated in COFFModuleDefinition.cpp for more 1790b57cec5SDimitry Andric // details. 1805f757f3fSDimitry Andric if (ExtName.starts_with("_") && ExtName.contains('@') && !MinGW) 1810b57cec5SDimitry Andric return IMPORT_NAME; 1820b57cec5SDimitry Andric if (Sym != ExtName) 1830b57cec5SDimitry Andric return IMPORT_NAME_UNDECORATE; 1845f757f3fSDimitry Andric if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.starts_with("_")) 1850b57cec5SDimitry Andric return IMPORT_NAME_NOPREFIX; 1860b57cec5SDimitry Andric return IMPORT_NAME; 1870b57cec5SDimitry Andric } 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric static Expected<std::string> replace(StringRef S, StringRef From, 1900b57cec5SDimitry Andric StringRef To) { 1910b57cec5SDimitry Andric size_t Pos = S.find(From); 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric // From and To may be mangled, but substrings in S may not. 1945f757f3fSDimitry Andric if (Pos == StringRef::npos && From.starts_with("_") && To.starts_with("_")) { 1950b57cec5SDimitry Andric From = From.substr(1); 1960b57cec5SDimitry Andric To = To.substr(1); 1970b57cec5SDimitry Andric Pos = S.find(From); 1980b57cec5SDimitry Andric } 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric if (Pos == StringRef::npos) { 2010b57cec5SDimitry Andric return make_error<StringError>( 2020b57cec5SDimitry Andric StringRef(Twine(S + ": replacing '" + From + 2030b57cec5SDimitry Andric "' with '" + To + "' failed").str()), object_error::parse_failed); 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str(); 2070b57cec5SDimitry Andric } 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric namespace { 2100b57cec5SDimitry Andric // This class constructs various small object files necessary to support linking 2110b57cec5SDimitry Andric // symbols imported from a DLL. The contents are pretty strictly defined and 2120b57cec5SDimitry Andric // nearly entirely static. The details of the structures files are defined in 2130b57cec5SDimitry Andric // WINNT.h and the PE/COFF specification. 2140b57cec5SDimitry Andric class ObjectFactory { 2150b57cec5SDimitry Andric using u16 = support::ulittle16_t; 2160b57cec5SDimitry Andric using u32 = support::ulittle32_t; 2177a6dacacSDimitry Andric MachineTypes NativeMachine; 2180b57cec5SDimitry Andric BumpPtrAllocator Alloc; 2190b57cec5SDimitry Andric StringRef ImportName; 2200b57cec5SDimitry Andric StringRef Library; 2210b57cec5SDimitry Andric std::string ImportDescriptorSymbolName; 2220b57cec5SDimitry Andric std::string NullThunkSymbolName; 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric public: 2250b57cec5SDimitry Andric ObjectFactory(StringRef S, MachineTypes M) 2267a6dacacSDimitry Andric : NativeMachine(M), ImportName(S), Library(llvm::sys::path::stem(S)), 227439352acSDimitry Andric ImportDescriptorSymbolName((ImportDescriptorPrefix + Library).str()), 228439352acSDimitry Andric NullThunkSymbolName( 229439352acSDimitry Andric (NullThunkDataPrefix + Library + NullThunkDataSuffix).str()) {} 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric // Creates an Import Descriptor. This is a small object file which contains a 2320b57cec5SDimitry Andric // reference to the terminators and contains the library name (entry) for the 2330b57cec5SDimitry Andric // import name table. It will force the linker to construct the necessary 2340b57cec5SDimitry Andric // structure to import symbols from the DLL. 2350b57cec5SDimitry Andric NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer); 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric // Creates a NULL import descriptor. This is a small object file whcih 2380b57cec5SDimitry Andric // contains a NULL import descriptor. It is used to terminate the imports 2390b57cec5SDimitry Andric // from a specific DLL. 2400b57cec5SDimitry Andric NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer); 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric // Create a NULL Thunk Entry. This is a small object file which contains a 2430b57cec5SDimitry Andric // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It 2440b57cec5SDimitry Andric // is used to terminate the IAT and ILT. 2450b57cec5SDimitry Andric NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer); 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric // Create a short import file which is described in PE/COFF spec 7. Import 2480b57cec5SDimitry Andric // Library Format. 2490b57cec5SDimitry Andric NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal, 2507a6dacacSDimitry Andric ImportType Type, ImportNameType NameType, 251439352acSDimitry Andric StringRef ExportName, 2527a6dacacSDimitry Andric MachineTypes Machine); 2530b57cec5SDimitry Andric 2540b57cec5SDimitry Andric // Create a weak external file which is described in PE/COFF Aux Format 3. 2557a6dacacSDimitry Andric NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp, 2567a6dacacSDimitry Andric MachineTypes Machine); 2577a6dacacSDimitry Andric 2587a6dacacSDimitry Andric bool is64Bit() const { return COFF::is64Bit(NativeMachine); } 2590b57cec5SDimitry Andric }; 2600b57cec5SDimitry Andric } // namespace 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric NewArchiveMember 2630b57cec5SDimitry Andric ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) { 2640b57cec5SDimitry Andric const uint32_t NumberOfSections = 2; 2650b57cec5SDimitry Andric const uint32_t NumberOfSymbols = 7; 2660b57cec5SDimitry Andric const uint32_t NumberOfRelocations = 3; 2670b57cec5SDimitry Andric 2680b57cec5SDimitry Andric // COFF Header 2690b57cec5SDimitry Andric coff_file_header Header{ 2707a6dacacSDimitry Andric u16(NativeMachine), 2710b57cec5SDimitry Andric u16(NumberOfSections), 2720b57cec5SDimitry Andric u32(0), 2730b57cec5SDimitry Andric u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + 2740b57cec5SDimitry Andric // .idata$2 2750b57cec5SDimitry Andric sizeof(coff_import_directory_table_entry) + 2760b57cec5SDimitry Andric NumberOfRelocations * sizeof(coff_relocation) + 2770b57cec5SDimitry Andric // .idata$4 2780b57cec5SDimitry Andric (ImportName.size() + 1)), 2790b57cec5SDimitry Andric u32(NumberOfSymbols), 2800b57cec5SDimitry Andric u16(0), 2817a6dacacSDimitry Andric u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE), 2820b57cec5SDimitry Andric }; 2830b57cec5SDimitry Andric append(Buffer, Header); 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric // Section Header Table 2860b57cec5SDimitry Andric const coff_section SectionTable[NumberOfSections] = { 2870b57cec5SDimitry Andric {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}, 2880b57cec5SDimitry Andric u32(0), 2890b57cec5SDimitry Andric u32(0), 2900b57cec5SDimitry Andric u32(sizeof(coff_import_directory_table_entry)), 2910b57cec5SDimitry Andric u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), 2920b57cec5SDimitry Andric u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + 2930b57cec5SDimitry Andric sizeof(coff_import_directory_table_entry)), 2940b57cec5SDimitry Andric u32(0), 2950b57cec5SDimitry Andric u16(NumberOfRelocations), 2960b57cec5SDimitry Andric u16(0), 2970b57cec5SDimitry Andric u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | 2980b57cec5SDimitry Andric IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, 2990b57cec5SDimitry Andric {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}, 3000b57cec5SDimitry Andric u32(0), 3010b57cec5SDimitry Andric u32(0), 3020b57cec5SDimitry Andric u32(ImportName.size() + 1), 3030b57cec5SDimitry Andric u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + 3040b57cec5SDimitry Andric sizeof(coff_import_directory_table_entry) + 3050b57cec5SDimitry Andric NumberOfRelocations * sizeof(coff_relocation)), 3060b57cec5SDimitry Andric u32(0), 3070b57cec5SDimitry Andric u32(0), 3080b57cec5SDimitry Andric u16(0), 3090b57cec5SDimitry Andric u16(0), 3100b57cec5SDimitry Andric u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | 3110b57cec5SDimitry Andric IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, 3120b57cec5SDimitry Andric }; 3130b57cec5SDimitry Andric append(Buffer, SectionTable); 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric // .idata$2 3160b57cec5SDimitry Andric const coff_import_directory_table_entry ImportDescriptor{ 3170b57cec5SDimitry Andric u32(0), u32(0), u32(0), u32(0), u32(0), 3180b57cec5SDimitry Andric }; 3190b57cec5SDimitry Andric append(Buffer, ImportDescriptor); 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric const coff_relocation RelocationTable[NumberOfRelocations] = { 3220b57cec5SDimitry Andric {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2), 3237a6dacacSDimitry Andric u16(getImgRelRelocation(NativeMachine))}, 3240b57cec5SDimitry Andric {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)), 3257a6dacacSDimitry Andric u32(3), u16(getImgRelRelocation(NativeMachine))}, 3260b57cec5SDimitry Andric {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)), 3277a6dacacSDimitry Andric u32(4), u16(getImgRelRelocation(NativeMachine))}, 3280b57cec5SDimitry Andric }; 3290b57cec5SDimitry Andric append(Buffer, RelocationTable); 3300b57cec5SDimitry Andric 3310b57cec5SDimitry Andric // .idata$6 3320b57cec5SDimitry Andric auto S = Buffer.size(); 3330b57cec5SDimitry Andric Buffer.resize(S + ImportName.size() + 1); 3340b57cec5SDimitry Andric memcpy(&Buffer[S], ImportName.data(), ImportName.size()); 3350b57cec5SDimitry Andric Buffer[S + ImportName.size()] = '\0'; 3360b57cec5SDimitry Andric 3370b57cec5SDimitry Andric // Symbol Table 3380b57cec5SDimitry Andric coff_symbol16 SymbolTable[NumberOfSymbols] = { 3390b57cec5SDimitry Andric {{{0, 0, 0, 0, 0, 0, 0, 0}}, 3400b57cec5SDimitry Andric u32(0), 3410b57cec5SDimitry Andric u16(1), 3420b57cec5SDimitry Andric u16(0), 3430b57cec5SDimitry Andric IMAGE_SYM_CLASS_EXTERNAL, 3440b57cec5SDimitry Andric 0}, 3450b57cec5SDimitry Andric {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}}, 3460b57cec5SDimitry Andric u32(0), 3470b57cec5SDimitry Andric u16(1), 3480b57cec5SDimitry Andric u16(0), 3490b57cec5SDimitry Andric IMAGE_SYM_CLASS_SECTION, 3500b57cec5SDimitry Andric 0}, 3510b57cec5SDimitry Andric {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}}, 3520b57cec5SDimitry Andric u32(0), 3530b57cec5SDimitry Andric u16(2), 3540b57cec5SDimitry Andric u16(0), 3550b57cec5SDimitry Andric IMAGE_SYM_CLASS_STATIC, 3560b57cec5SDimitry Andric 0}, 3570b57cec5SDimitry Andric {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}}, 3580b57cec5SDimitry Andric u32(0), 3590b57cec5SDimitry Andric u16(0), 3600b57cec5SDimitry Andric u16(0), 3610b57cec5SDimitry Andric IMAGE_SYM_CLASS_SECTION, 3620b57cec5SDimitry Andric 0}, 3630b57cec5SDimitry Andric {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}}, 3640b57cec5SDimitry Andric u32(0), 3650b57cec5SDimitry Andric u16(0), 3660b57cec5SDimitry Andric u16(0), 3670b57cec5SDimitry Andric IMAGE_SYM_CLASS_SECTION, 3680b57cec5SDimitry Andric 0}, 3690b57cec5SDimitry Andric {{{0, 0, 0, 0, 0, 0, 0, 0}}, 3700b57cec5SDimitry Andric u32(0), 3710b57cec5SDimitry Andric u16(0), 3720b57cec5SDimitry Andric u16(0), 3730b57cec5SDimitry Andric IMAGE_SYM_CLASS_EXTERNAL, 3740b57cec5SDimitry Andric 0}, 3750b57cec5SDimitry Andric {{{0, 0, 0, 0, 0, 0, 0, 0}}, 3760b57cec5SDimitry Andric u32(0), 3770b57cec5SDimitry Andric u16(0), 3780b57cec5SDimitry Andric u16(0), 3790b57cec5SDimitry Andric IMAGE_SYM_CLASS_EXTERNAL, 3800b57cec5SDimitry Andric 0}, 3810b57cec5SDimitry Andric }; 3820b57cec5SDimitry Andric // TODO: Name.Offset.Offset here and in the all similar places below 3830b57cec5SDimitry Andric // suggests a names refactoring. Maybe StringTableOffset.Value? 3840b57cec5SDimitry Andric SymbolTable[0].Name.Offset.Offset = 3850b57cec5SDimitry Andric sizeof(uint32_t); 3860b57cec5SDimitry Andric SymbolTable[5].Name.Offset.Offset = 3870b57cec5SDimitry Andric sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1; 3880b57cec5SDimitry Andric SymbolTable[6].Name.Offset.Offset = 3890b57cec5SDimitry Andric sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 + 3900b57cec5SDimitry Andric NullImportDescriptorSymbolName.length() + 1; 3910b57cec5SDimitry Andric append(Buffer, SymbolTable); 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric // String Table 3940b57cec5SDimitry Andric writeStringTable(Buffer, 3950b57cec5SDimitry Andric {ImportDescriptorSymbolName, NullImportDescriptorSymbolName, 3960b57cec5SDimitry Andric NullThunkSymbolName}); 3970b57cec5SDimitry Andric 3980b57cec5SDimitry Andric StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; 3990b57cec5SDimitry Andric return {MemoryBufferRef(F, ImportName)}; 4000b57cec5SDimitry Andric } 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric NewArchiveMember 4030b57cec5SDimitry Andric ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) { 4040b57cec5SDimitry Andric const uint32_t NumberOfSections = 1; 4050b57cec5SDimitry Andric const uint32_t NumberOfSymbols = 1; 4060b57cec5SDimitry Andric 4070b57cec5SDimitry Andric // COFF Header 4080b57cec5SDimitry Andric coff_file_header Header{ 4097a6dacacSDimitry Andric u16(NativeMachine), 4100b57cec5SDimitry Andric u16(NumberOfSections), 4110b57cec5SDimitry Andric u32(0), 4120b57cec5SDimitry Andric u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + 4130b57cec5SDimitry Andric // .idata$3 4140b57cec5SDimitry Andric sizeof(coff_import_directory_table_entry)), 4150b57cec5SDimitry Andric u32(NumberOfSymbols), 4160b57cec5SDimitry Andric u16(0), 4177a6dacacSDimitry Andric u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE), 4180b57cec5SDimitry Andric }; 4190b57cec5SDimitry Andric append(Buffer, Header); 4200b57cec5SDimitry Andric 4210b57cec5SDimitry Andric // Section Header Table 4220b57cec5SDimitry Andric const coff_section SectionTable[NumberOfSections] = { 4230b57cec5SDimitry Andric {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'}, 4240b57cec5SDimitry Andric u32(0), 4250b57cec5SDimitry Andric u32(0), 4260b57cec5SDimitry Andric u32(sizeof(coff_import_directory_table_entry)), 4270b57cec5SDimitry Andric u32(sizeof(coff_file_header) + 4280b57cec5SDimitry Andric (NumberOfSections * sizeof(coff_section))), 4290b57cec5SDimitry Andric u32(0), 4300b57cec5SDimitry Andric u32(0), 4310b57cec5SDimitry Andric u16(0), 4320b57cec5SDimitry Andric u16(0), 4330b57cec5SDimitry Andric u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | 4340b57cec5SDimitry Andric IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, 4350b57cec5SDimitry Andric }; 4360b57cec5SDimitry Andric append(Buffer, SectionTable); 4370b57cec5SDimitry Andric 4380b57cec5SDimitry Andric // .idata$3 4390b57cec5SDimitry Andric const coff_import_directory_table_entry ImportDescriptor{ 4400b57cec5SDimitry Andric u32(0), u32(0), u32(0), u32(0), u32(0), 4410b57cec5SDimitry Andric }; 4420b57cec5SDimitry Andric append(Buffer, ImportDescriptor); 4430b57cec5SDimitry Andric 4440b57cec5SDimitry Andric // Symbol Table 4450b57cec5SDimitry Andric coff_symbol16 SymbolTable[NumberOfSymbols] = { 4460b57cec5SDimitry Andric {{{0, 0, 0, 0, 0, 0, 0, 0}}, 4470b57cec5SDimitry Andric u32(0), 4480b57cec5SDimitry Andric u16(1), 4490b57cec5SDimitry Andric u16(0), 4500b57cec5SDimitry Andric IMAGE_SYM_CLASS_EXTERNAL, 4510b57cec5SDimitry Andric 0}, 4520b57cec5SDimitry Andric }; 4530b57cec5SDimitry Andric SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t); 4540b57cec5SDimitry Andric append(Buffer, SymbolTable); 4550b57cec5SDimitry Andric 4560b57cec5SDimitry Andric // String Table 4570b57cec5SDimitry Andric writeStringTable(Buffer, {NullImportDescriptorSymbolName}); 4580b57cec5SDimitry Andric 4590b57cec5SDimitry Andric StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; 4600b57cec5SDimitry Andric return {MemoryBufferRef(F, ImportName)}; 4610b57cec5SDimitry Andric } 4620b57cec5SDimitry Andric 4630b57cec5SDimitry Andric NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) { 4640b57cec5SDimitry Andric const uint32_t NumberOfSections = 2; 4650b57cec5SDimitry Andric const uint32_t NumberOfSymbols = 1; 4667a6dacacSDimitry Andric uint32_t VASize = is64Bit() ? 8 : 4; 4670b57cec5SDimitry Andric 4680b57cec5SDimitry Andric // COFF Header 4690b57cec5SDimitry Andric coff_file_header Header{ 4707a6dacacSDimitry Andric u16(NativeMachine), 4710b57cec5SDimitry Andric u16(NumberOfSections), 4720b57cec5SDimitry Andric u32(0), 4730b57cec5SDimitry Andric u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + 4740b57cec5SDimitry Andric // .idata$5 4750b57cec5SDimitry Andric VASize + 4760b57cec5SDimitry Andric // .idata$4 4770b57cec5SDimitry Andric VASize), 4780b57cec5SDimitry Andric u32(NumberOfSymbols), 4790b57cec5SDimitry Andric u16(0), 4807a6dacacSDimitry Andric u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE), 4810b57cec5SDimitry Andric }; 4820b57cec5SDimitry Andric append(Buffer, Header); 4830b57cec5SDimitry Andric 4840b57cec5SDimitry Andric // Section Header Table 4850b57cec5SDimitry Andric const coff_section SectionTable[NumberOfSections] = { 4860b57cec5SDimitry Andric {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}, 4870b57cec5SDimitry Andric u32(0), 4880b57cec5SDimitry Andric u32(0), 4890b57cec5SDimitry Andric u32(VASize), 4900b57cec5SDimitry Andric u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), 4910b57cec5SDimitry Andric u32(0), 4920b57cec5SDimitry Andric u32(0), 4930b57cec5SDimitry Andric u16(0), 4940b57cec5SDimitry Andric u16(0), 4957a6dacacSDimitry Andric u32((is64Bit() ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES) | 4960b57cec5SDimitry Andric IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | 4970b57cec5SDimitry Andric IMAGE_SCN_MEM_WRITE)}, 4980b57cec5SDimitry Andric {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}, 4990b57cec5SDimitry Andric u32(0), 5000b57cec5SDimitry Andric u32(0), 5010b57cec5SDimitry Andric u32(VASize), 5020b57cec5SDimitry Andric u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + 5030b57cec5SDimitry Andric VASize), 5040b57cec5SDimitry Andric u32(0), 5050b57cec5SDimitry Andric u32(0), 5060b57cec5SDimitry Andric u16(0), 5070b57cec5SDimitry Andric u16(0), 5087a6dacacSDimitry Andric u32((is64Bit() ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES) | 5090b57cec5SDimitry Andric IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | 5100b57cec5SDimitry Andric IMAGE_SCN_MEM_WRITE)}, 5110b57cec5SDimitry Andric }; 5120b57cec5SDimitry Andric append(Buffer, SectionTable); 5130b57cec5SDimitry Andric 5140b57cec5SDimitry Andric // .idata$5, ILT 5150b57cec5SDimitry Andric append(Buffer, u32(0)); 5167a6dacacSDimitry Andric if (is64Bit()) 5170b57cec5SDimitry Andric append(Buffer, u32(0)); 5180b57cec5SDimitry Andric 5190b57cec5SDimitry Andric // .idata$4, IAT 5200b57cec5SDimitry Andric append(Buffer, u32(0)); 5217a6dacacSDimitry Andric if (is64Bit()) 5220b57cec5SDimitry Andric append(Buffer, u32(0)); 5230b57cec5SDimitry Andric 5240b57cec5SDimitry Andric // Symbol Table 5250b57cec5SDimitry Andric coff_symbol16 SymbolTable[NumberOfSymbols] = { 5260b57cec5SDimitry Andric {{{0, 0, 0, 0, 0, 0, 0, 0}}, 5270b57cec5SDimitry Andric u32(0), 5280b57cec5SDimitry Andric u16(1), 5290b57cec5SDimitry Andric u16(0), 5300b57cec5SDimitry Andric IMAGE_SYM_CLASS_EXTERNAL, 5310b57cec5SDimitry Andric 0}, 5320b57cec5SDimitry Andric }; 5330b57cec5SDimitry Andric SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t); 5340b57cec5SDimitry Andric append(Buffer, SymbolTable); 5350b57cec5SDimitry Andric 5360b57cec5SDimitry Andric // String Table 5370b57cec5SDimitry Andric writeStringTable(Buffer, {NullThunkSymbolName}); 5380b57cec5SDimitry Andric 5390b57cec5SDimitry Andric StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; 5400b57cec5SDimitry Andric return {MemoryBufferRef{F, ImportName}}; 5410b57cec5SDimitry Andric } 5420b57cec5SDimitry Andric 543439352acSDimitry Andric NewArchiveMember 544439352acSDimitry Andric ObjectFactory::createShortImport(StringRef Sym, uint16_t Ordinal, 545439352acSDimitry Andric ImportType ImportType, ImportNameType NameType, 546439352acSDimitry Andric StringRef ExportName, MachineTypes Machine) { 5470b57cec5SDimitry Andric size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs 548439352acSDimitry Andric if (!ExportName.empty()) 549439352acSDimitry Andric ImpSize += ExportName.size() + 1; 5500b57cec5SDimitry Andric size_t Size = sizeof(coff_import_header) + ImpSize; 5510b57cec5SDimitry Andric char *Buf = Alloc.Allocate<char>(Size); 5520b57cec5SDimitry Andric memset(Buf, 0, Size); 5530b57cec5SDimitry Andric char *P = Buf; 5540b57cec5SDimitry Andric 5550b57cec5SDimitry Andric // Write short import library. 5560b57cec5SDimitry Andric auto *Imp = reinterpret_cast<coff_import_header *>(P); 5570b57cec5SDimitry Andric P += sizeof(*Imp); 5580b57cec5SDimitry Andric Imp->Sig2 = 0xFFFF; 5590b57cec5SDimitry Andric Imp->Machine = Machine; 5600b57cec5SDimitry Andric Imp->SizeOfData = ImpSize; 5610b57cec5SDimitry Andric if (Ordinal > 0) 5620b57cec5SDimitry Andric Imp->OrdinalHint = Ordinal; 5630b57cec5SDimitry Andric Imp->TypeInfo = (NameType << 2) | ImportType; 5640b57cec5SDimitry Andric 5650b57cec5SDimitry Andric // Write symbol name and DLL name. 5660b57cec5SDimitry Andric memcpy(P, Sym.data(), Sym.size()); 5670b57cec5SDimitry Andric P += Sym.size() + 1; 5680b57cec5SDimitry Andric memcpy(P, ImportName.data(), ImportName.size()); 569439352acSDimitry Andric if (!ExportName.empty()) { 570439352acSDimitry Andric P += ImportName.size() + 1; 571439352acSDimitry Andric memcpy(P, ExportName.data(), ExportName.size()); 572439352acSDimitry Andric } 5730b57cec5SDimitry Andric 5740b57cec5SDimitry Andric return {MemoryBufferRef(StringRef(Buf, Size), ImportName)}; 5750b57cec5SDimitry Andric } 5760b57cec5SDimitry Andric 5770b57cec5SDimitry Andric NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym, 5787a6dacacSDimitry Andric StringRef Weak, bool Imp, 5797a6dacacSDimitry Andric MachineTypes Machine) { 5800b57cec5SDimitry Andric std::vector<uint8_t> Buffer; 5810b57cec5SDimitry Andric const uint32_t NumberOfSections = 1; 5820b57cec5SDimitry Andric const uint32_t NumberOfSymbols = 5; 5830b57cec5SDimitry Andric 5840b57cec5SDimitry Andric // COFF Header 5850b57cec5SDimitry Andric coff_file_header Header{ 5860b57cec5SDimitry Andric u16(Machine), 5870b57cec5SDimitry Andric u16(NumberOfSections), 5880b57cec5SDimitry Andric u32(0), 5890b57cec5SDimitry Andric u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))), 5900b57cec5SDimitry Andric u32(NumberOfSymbols), 5910b57cec5SDimitry Andric u16(0), 5920b57cec5SDimitry Andric u16(0), 5930b57cec5SDimitry Andric }; 5940b57cec5SDimitry Andric append(Buffer, Header); 5950b57cec5SDimitry Andric 5960b57cec5SDimitry Andric // Section Header Table 5970b57cec5SDimitry Andric const coff_section SectionTable[NumberOfSections] = { 5980b57cec5SDimitry Andric {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'}, 5990b57cec5SDimitry Andric u32(0), 6000b57cec5SDimitry Andric u32(0), 6010b57cec5SDimitry Andric u32(0), 6020b57cec5SDimitry Andric u32(0), 6030b57cec5SDimitry Andric u32(0), 6040b57cec5SDimitry Andric u32(0), 6050b57cec5SDimitry Andric u16(0), 6060b57cec5SDimitry Andric u16(0), 6070b57cec5SDimitry Andric u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}}; 6080b57cec5SDimitry Andric append(Buffer, SectionTable); 6090b57cec5SDimitry Andric 6100b57cec5SDimitry Andric // Symbol Table 6110b57cec5SDimitry Andric coff_symbol16 SymbolTable[NumberOfSymbols] = { 6120b57cec5SDimitry Andric {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}}, 6130b57cec5SDimitry Andric u32(0), 6140b57cec5SDimitry Andric u16(0xFFFF), 6150b57cec5SDimitry Andric u16(0), 6160b57cec5SDimitry Andric IMAGE_SYM_CLASS_STATIC, 6170b57cec5SDimitry Andric 0}, 6180b57cec5SDimitry Andric {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}}, 6190b57cec5SDimitry Andric u32(0), 6200b57cec5SDimitry Andric u16(0xFFFF), 6210b57cec5SDimitry Andric u16(0), 6220b57cec5SDimitry Andric IMAGE_SYM_CLASS_STATIC, 6230b57cec5SDimitry Andric 0}, 6240b57cec5SDimitry Andric {{{0, 0, 0, 0, 0, 0, 0, 0}}, 6250b57cec5SDimitry Andric u32(0), 6260b57cec5SDimitry Andric u16(0), 6270b57cec5SDimitry Andric u16(0), 6280b57cec5SDimitry Andric IMAGE_SYM_CLASS_EXTERNAL, 6290b57cec5SDimitry Andric 0}, 6300b57cec5SDimitry Andric {{{0, 0, 0, 0, 0, 0, 0, 0}}, 6310b57cec5SDimitry Andric u32(0), 6320b57cec5SDimitry Andric u16(0), 6330b57cec5SDimitry Andric u16(0), 6340b57cec5SDimitry Andric IMAGE_SYM_CLASS_WEAK_EXTERNAL, 6350b57cec5SDimitry Andric 1}, 6360b57cec5SDimitry Andric {{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}}, 6370b57cec5SDimitry Andric u32(0), 6380b57cec5SDimitry Andric u16(0), 6390b57cec5SDimitry Andric u16(0), 6400b57cec5SDimitry Andric IMAGE_SYM_CLASS_NULL, 6410b57cec5SDimitry Andric 0}, 6420b57cec5SDimitry Andric }; 6430b57cec5SDimitry Andric SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t); 6440b57cec5SDimitry Andric 6450b57cec5SDimitry Andric //__imp_ String Table 6460b57cec5SDimitry Andric StringRef Prefix = Imp ? "__imp_" : ""; 6470b57cec5SDimitry Andric SymbolTable[3].Name.Offset.Offset = 6480b57cec5SDimitry Andric sizeof(uint32_t) + Sym.size() + Prefix.size() + 1; 6490b57cec5SDimitry Andric append(Buffer, SymbolTable); 6500b57cec5SDimitry Andric writeStringTable(Buffer, {(Prefix + Sym).str(), 6510b57cec5SDimitry Andric (Prefix + Weak).str()}); 6520b57cec5SDimitry Andric 6530b57cec5SDimitry Andric // Copied here so we can still use writeStringTable 6540b57cec5SDimitry Andric char *Buf = Alloc.Allocate<char>(Buffer.size()); 6550b57cec5SDimitry Andric memcpy(Buf, Buffer.data(), Buffer.size()); 6560b57cec5SDimitry Andric return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)}; 6570b57cec5SDimitry Andric } 6580b57cec5SDimitry Andric 6590b57cec5SDimitry Andric Error writeImportLibrary(StringRef ImportName, StringRef Path, 6600b57cec5SDimitry Andric ArrayRef<COFFShortExport> Exports, 661*0fca6ea1SDimitry Andric MachineTypes Machine, bool MinGW, 662*0fca6ea1SDimitry Andric ArrayRef<COFFShortExport> NativeExports) { 6630b57cec5SDimitry Andric 664*0fca6ea1SDimitry Andric MachineTypes NativeMachine = Machine; 665*0fca6ea1SDimitry Andric if (isArm64EC(Machine)) { 666*0fca6ea1SDimitry Andric NativeMachine = IMAGE_FILE_MACHINE_ARM64; 667*0fca6ea1SDimitry Andric Machine = IMAGE_FILE_MACHINE_ARM64EC; 668*0fca6ea1SDimitry Andric } 6697a6dacacSDimitry Andric 6700b57cec5SDimitry Andric std::vector<NewArchiveMember> Members; 6717a6dacacSDimitry Andric ObjectFactory OF(llvm::sys::path::filename(ImportName), NativeMachine); 6720b57cec5SDimitry Andric 6730b57cec5SDimitry Andric std::vector<uint8_t> ImportDescriptor; 6740b57cec5SDimitry Andric Members.push_back(OF.createImportDescriptor(ImportDescriptor)); 6750b57cec5SDimitry Andric 6760b57cec5SDimitry Andric std::vector<uint8_t> NullImportDescriptor; 6770b57cec5SDimitry Andric Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor)); 6780b57cec5SDimitry Andric 6790b57cec5SDimitry Andric std::vector<uint8_t> NullThunk; 6800b57cec5SDimitry Andric Members.push_back(OF.createNullThunk(NullThunk)); 6810b57cec5SDimitry Andric 682*0fca6ea1SDimitry Andric auto addExports = [&](ArrayRef<COFFShortExport> Exp, 683*0fca6ea1SDimitry Andric MachineTypes M) -> Error { 684*0fca6ea1SDimitry Andric StringMap<std::string> RegularImports; 685*0fca6ea1SDimitry Andric struct Deferred { 686*0fca6ea1SDimitry Andric std::string Name; 687*0fca6ea1SDimitry Andric ImportType ImpType; 688*0fca6ea1SDimitry Andric const COFFShortExport *Export; 689*0fca6ea1SDimitry Andric }; 690*0fca6ea1SDimitry Andric SmallVector<Deferred, 0> Renames; 691*0fca6ea1SDimitry Andric for (const COFFShortExport &E : Exp) { 6920b57cec5SDimitry Andric if (E.Private) 6930b57cec5SDimitry Andric continue; 6940b57cec5SDimitry Andric 6950b57cec5SDimitry Andric ImportType ImportType = IMPORT_CODE; 6960b57cec5SDimitry Andric if (E.Data) 6970b57cec5SDimitry Andric ImportType = IMPORT_DATA; 6980b57cec5SDimitry Andric if (E.Constant) 6990b57cec5SDimitry Andric ImportType = IMPORT_CONST; 7000b57cec5SDimitry Andric 7010b57cec5SDimitry Andric StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName; 702439352acSDimitry Andric std::string Name; 7030b57cec5SDimitry Andric 704439352acSDimitry Andric if (E.ExtName.empty()) { 705439352acSDimitry Andric Name = std::string(SymbolName); 706439352acSDimitry Andric } else { 707439352acSDimitry Andric Expected<std::string> ReplacedName = 708439352acSDimitry Andric replace(SymbolName, E.Name, E.ExtName); 709439352acSDimitry Andric if (!ReplacedName) 710439352acSDimitry Andric return ReplacedName.takeError(); 711439352acSDimitry Andric Name.swap(*ReplacedName); 712439352acSDimitry Andric } 7130b57cec5SDimitry Andric 714439352acSDimitry Andric ImportNameType NameType; 715439352acSDimitry Andric std::string ExportName; 716439352acSDimitry Andric if (E.Noname) { 717439352acSDimitry Andric NameType = IMPORT_ORDINAL; 718*0fca6ea1SDimitry Andric } else if (!E.ExportAs.empty()) { 719*0fca6ea1SDimitry Andric NameType = IMPORT_NAME_EXPORTAS; 720*0fca6ea1SDimitry Andric ExportName = E.ExportAs; 721*0fca6ea1SDimitry Andric } else if (!E.ImportName.empty()) { 722*0fca6ea1SDimitry Andric // If we need to import from a specific ImportName, we may need to use 723*0fca6ea1SDimitry Andric // a weak alias (which needs another import to point at). But if we can 724*0fca6ea1SDimitry Andric // express ImportName based on the symbol name and a specific NameType, 725*0fca6ea1SDimitry Andric // prefer that over an alias. 726*0fca6ea1SDimitry Andric if (Machine == IMAGE_FILE_MACHINE_I386 && 727*0fca6ea1SDimitry Andric applyNameType(IMPORT_NAME_UNDECORATE, Name) == E.ImportName) 728*0fca6ea1SDimitry Andric NameType = IMPORT_NAME_UNDECORATE; 729*0fca6ea1SDimitry Andric else if (Machine == IMAGE_FILE_MACHINE_I386 && 730*0fca6ea1SDimitry Andric applyNameType(IMPORT_NAME_NOPREFIX, Name) == E.ImportName) 731*0fca6ea1SDimitry Andric NameType = IMPORT_NAME_NOPREFIX; 732*0fca6ea1SDimitry Andric else if (isArm64EC(M)) { 733*0fca6ea1SDimitry Andric NameType = IMPORT_NAME_EXPORTAS; 734*0fca6ea1SDimitry Andric ExportName = E.ImportName; 735*0fca6ea1SDimitry Andric } else if (Name == E.ImportName) 736*0fca6ea1SDimitry Andric NameType = IMPORT_NAME; 737*0fca6ea1SDimitry Andric else { 738*0fca6ea1SDimitry Andric Deferred D; 739*0fca6ea1SDimitry Andric D.Name = Name; 740*0fca6ea1SDimitry Andric D.ImpType = ImportType; 741*0fca6ea1SDimitry Andric D.Export = &E; 742*0fca6ea1SDimitry Andric Renames.push_back(D); 743*0fca6ea1SDimitry Andric continue; 744*0fca6ea1SDimitry Andric } 745439352acSDimitry Andric } else { 746*0fca6ea1SDimitry Andric NameType = getNameType(SymbolName, E.Name, M, MinGW); 747439352acSDimitry Andric } 748439352acSDimitry Andric 749439352acSDimitry Andric // On ARM64EC, use EXPORTAS to import demangled name for mangled symbols. 750*0fca6ea1SDimitry Andric if (ImportType == IMPORT_CODE && isArm64EC(M)) { 751439352acSDimitry Andric if (std::optional<std::string> MangledName = 752439352acSDimitry Andric getArm64ECMangledFunctionName(Name)) { 753*0fca6ea1SDimitry Andric if (!E.Noname && ExportName.empty()) { 754439352acSDimitry Andric NameType = IMPORT_NAME_EXPORTAS; 755439352acSDimitry Andric ExportName.swap(Name); 756439352acSDimitry Andric } 757439352acSDimitry Andric Name = std::move(*MangledName); 758*0fca6ea1SDimitry Andric } else if (!E.Noname && ExportName.empty()) { 759439352acSDimitry Andric NameType = IMPORT_NAME_EXPORTAS; 760439352acSDimitry Andric ExportName = std::move(*getArm64ECDemangledFunctionName(Name)); 761439352acSDimitry Andric } 762439352acSDimitry Andric } 763439352acSDimitry Andric 764*0fca6ea1SDimitry Andric RegularImports[applyNameType(NameType, Name)] = Name; 765439352acSDimitry Andric Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType, 766*0fca6ea1SDimitry Andric NameType, ExportName, M)); 7670b57cec5SDimitry Andric } 768*0fca6ea1SDimitry Andric for (const auto &D : Renames) { 769*0fca6ea1SDimitry Andric auto It = RegularImports.find(D.Export->ImportName); 770*0fca6ea1SDimitry Andric if (It != RegularImports.end()) { 771*0fca6ea1SDimitry Andric // We have a regular import entry for a symbol with the name we 772*0fca6ea1SDimitry Andric // want to reference; produce an alias pointing at that. 773*0fca6ea1SDimitry Andric StringRef Symbol = It->second; 774*0fca6ea1SDimitry Andric if (D.ImpType == IMPORT_CODE) 775*0fca6ea1SDimitry Andric Members.push_back(OF.createWeakExternal(Symbol, D.Name, false, M)); 776*0fca6ea1SDimitry Andric Members.push_back(OF.createWeakExternal(Symbol, D.Name, true, M)); 777*0fca6ea1SDimitry Andric } else { 778*0fca6ea1SDimitry Andric Members.push_back(OF.createShortImport(D.Name, D.Export->Ordinal, 779*0fca6ea1SDimitry Andric D.ImpType, IMPORT_NAME_EXPORTAS, 780*0fca6ea1SDimitry Andric D.Export->ImportName, M)); 781*0fca6ea1SDimitry Andric } 782*0fca6ea1SDimitry Andric } 783*0fca6ea1SDimitry Andric return Error::success(); 784*0fca6ea1SDimitry Andric }; 785*0fca6ea1SDimitry Andric 786*0fca6ea1SDimitry Andric if (Error e = addExports(Exports, Machine)) 787*0fca6ea1SDimitry Andric return e; 788*0fca6ea1SDimitry Andric if (Error e = addExports(NativeExports, NativeMachine)) 789*0fca6ea1SDimitry Andric return e; 7900b57cec5SDimitry Andric 7915f757f3fSDimitry Andric return writeArchive(Path, Members, SymtabWritingMode::NormalSymtab, 792*0fca6ea1SDimitry Andric object::Archive::K_COFF, 7935f757f3fSDimitry Andric /*Deterministic*/ true, /*Thin*/ false, 7945f757f3fSDimitry Andric /*OldArchiveBuf*/ nullptr, isArm64EC(Machine)); 7950b57cec5SDimitry Andric } 7960b57cec5SDimitry Andric 7970b57cec5SDimitry Andric } // namespace object 7980b57cec5SDimitry Andric } // namespace llvm 799