808 lines · cpp
1//===- COFFImportFile.cpp - COFF short import file implementation ---------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines the writeImportLibrary function.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/Object/COFFImportFile.h"14#include "llvm/ADT/ArrayRef.h"15#include "llvm/ADT/SmallVector.h"16#include "llvm/ADT/StringMap.h"17#include "llvm/ADT/Twine.h"18#include "llvm/Object/Archive.h"19#include "llvm/Object/ArchiveWriter.h"20#include "llvm/Object/COFF.h"21#include "llvm/Support/Allocator.h"22#include "llvm/Support/Endian.h"23#include "llvm/Support/Error.h"24#include "llvm/Support/ErrorHandling.h"25#include "llvm/Support/Path.h"26 27#include <cstdint>28#include <string>29#include <vector>30 31using namespace llvm::COFF;32using namespace llvm::object;33using namespace llvm;34 35namespace llvm {36namespace object {37 38StringRef COFFImportFile::getFileFormatName() const {39 switch (getMachine()) {40 case COFF::IMAGE_FILE_MACHINE_I386:41 return "COFF-import-file-i386";42 case COFF::IMAGE_FILE_MACHINE_AMD64:43 return "COFF-import-file-x86-64";44 case COFF::IMAGE_FILE_MACHINE_ARMNT:45 return "COFF-import-file-ARM";46 case COFF::IMAGE_FILE_MACHINE_ARM64:47 return "COFF-import-file-ARM64";48 case COFF::IMAGE_FILE_MACHINE_ARM64EC:49 return "COFF-import-file-ARM64EC";50 case COFF::IMAGE_FILE_MACHINE_ARM64X:51 return "COFF-import-file-ARM64X";52 default:53 return "COFF-import-file-<unknown arch>";54 }55}56 57static StringRef applyNameType(ImportNameType Type, StringRef name) {58 auto ltrim1 = [](StringRef s, StringRef chars) {59 return !s.empty() && chars.contains(s[0]) ? s.substr(1) : s;60 };61 62 switch (Type) {63 case IMPORT_NAME_NOPREFIX:64 name = ltrim1(name, "?@_");65 break;66 case IMPORT_NAME_UNDECORATE:67 name = ltrim1(name, "?@_");68 name = name.substr(0, name.find('@'));69 break;70 default:71 break;72 }73 return name;74}75 76StringRef COFFImportFile::getExportName() const {77 const coff_import_header *hdr = getCOFFImportHeader();78 StringRef name = Data.getBuffer().substr(sizeof(*hdr)).split('\0').first;79 80 switch (hdr->getNameType()) {81 case IMPORT_ORDINAL:82 name = "";83 break;84 case IMPORT_NAME_NOPREFIX:85 case IMPORT_NAME_UNDECORATE:86 name = applyNameType(static_cast<ImportNameType>(hdr->getNameType()), name);87 break;88 case IMPORT_NAME_EXPORTAS: {89 // Skip DLL name90 name = Data.getBuffer().substr(sizeof(*hdr) + name.size() + 1);91 name = name.split('\0').second.split('\0').first;92 break;93 }94 default:95 break;96 }97 98 return name;99}100 101Error COFFImportFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const {102 switch (Symb.p) {103 case ImpSymbol:104 OS << "__imp_";105 break;106 case ECAuxSymbol:107 OS << "__imp_aux_";108 break;109 }110 const char *Name = Data.getBufferStart() + sizeof(coff_import_header);111 if (Symb.p != ECThunkSymbol && COFF::isArm64EC(getMachine())) {112 if (std::optional<std::string> DemangledName =113 getArm64ECDemangledFunctionName(Name)) {114 OS << StringRef(*DemangledName);115 return Error::success();116 }117 }118 OS << StringRef(Name);119 return Error::success();120}121 122static uint16_t getImgRelRelocation(MachineTypes Machine) {123 switch (Machine) {124 default:125 llvm_unreachable("unsupported machine");126 case IMAGE_FILE_MACHINE_AMD64:127 return IMAGE_REL_AMD64_ADDR32NB;128 case IMAGE_FILE_MACHINE_ARMNT:129 return IMAGE_REL_ARM_ADDR32NB;130 case IMAGE_FILE_MACHINE_ARM64:131 case IMAGE_FILE_MACHINE_ARM64EC:132 case IMAGE_FILE_MACHINE_ARM64X:133 return IMAGE_REL_ARM64_ADDR32NB;134 case IMAGE_FILE_MACHINE_I386:135 return IMAGE_REL_I386_DIR32NB;136 case IMAGE_FILE_MACHINE_R4000:137 return IMAGE_REL_MIPS_REFWORDNB;138 }139}140 141template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {142 size_t S = B.size();143 B.resize(S + sizeof(T));144 memcpy(&B[S], &Data, sizeof(T));145}146 147static void writeStringTable(std::vector<uint8_t> &B,148 ArrayRef<const std::string_view> Strings) {149 // The COFF string table consists of a 4-byte value which is the size of the150 // table, including the length field itself. This value is followed by the151 // string content itself, which is an array of null-terminated C-style152 // strings. The termination is important as they are referenced to by offset153 // by the symbol entity in the file format.154 155 size_t Pos = B.size();156 size_t Offset = B.size();157 158 // Skip over the length field, we will fill it in later as we will have159 // computed the length while emitting the string content itself.160 Pos += sizeof(uint32_t);161 162 for (const auto &S : Strings) {163 B.resize(Pos + S.length() + 1);164 llvm::copy(S, std::next(B.begin(), Pos));165 B[Pos + S.length()] = 0;166 Pos += S.length() + 1;167 }168 169 // Backfill the length of the table now that it has been computed.170 support::ulittle32_t Length(B.size() - Offset);171 support::endian::write32le(&B[Offset], Length);172}173 174static ImportNameType getNameType(StringRef Sym, StringRef ExtName,175 MachineTypes Machine, bool MinGW) {176 // A decorated stdcall function in MSVC is exported with the177 // type IMPORT_NAME, and the exported function name includes the178 // the leading underscore. In MinGW on the other hand, a decorated179 // stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX).180 // See the comment in isDecorated in COFFModuleDefinition.cpp for more181 // details.182 if (ExtName.starts_with("_") && ExtName.contains('@') && !MinGW)183 return IMPORT_NAME;184 if (Sym != ExtName)185 return IMPORT_NAME_UNDECORATE;186 if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.starts_with("_"))187 return IMPORT_NAME_NOPREFIX;188 return IMPORT_NAME;189}190 191static Expected<std::string> replace(StringRef S, StringRef From,192 StringRef To) {193 size_t Pos = S.find(From);194 195 // From and To may be mangled, but substrings in S may not.196 if (Pos == StringRef::npos && From.starts_with("_") && To.starts_with("_")) {197 From = From.substr(1);198 To = To.substr(1);199 Pos = S.find(From);200 }201 202 if (Pos == StringRef::npos) {203 return make_error<StringError>(204 StringRef(Twine(S + ": replacing '" + From +205 "' with '" + To + "' failed").str()), object_error::parse_failed);206 }207 208 return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();209}210 211namespace {212// This class constructs various small object files necessary to support linking213// symbols imported from a DLL. The contents are pretty strictly defined and214// nearly entirely static. The details of the structures files are defined in215// WINNT.h and the PE/COFF specification.216class ObjectFactory {217 using u16 = support::ulittle16_t;218 using u32 = support::ulittle32_t;219 MachineTypes NativeMachine;220 BumpPtrAllocator Alloc;221 StringRef ImportName;222 StringRef Library;223 std::string ImportDescriptorSymbolName;224 std::string NullThunkSymbolName;225 226public:227 ObjectFactory(StringRef S, MachineTypes M)228 : NativeMachine(M), ImportName(S), Library(llvm::sys::path::stem(S)),229 ImportDescriptorSymbolName((ImportDescriptorPrefix + Library).str()),230 NullThunkSymbolName(231 (NullThunkDataPrefix + Library + NullThunkDataSuffix).str()) {}232 233 // Creates an Import Descriptor. This is a small object file which contains a234 // reference to the terminators and contains the library name (entry) for the235 // import name table. It will force the linker to construct the necessary236 // structure to import symbols from the DLL.237 NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);238 239 // Creates a NULL import descriptor. This is a small object file whcih240 // contains a NULL import descriptor. It is used to terminate the imports241 // from a specific DLL.242 NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);243 244 // Create a NULL Thunk Entry. This is a small object file which contains a245 // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It246 // is used to terminate the IAT and ILT.247 NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);248 249 // Create a short import file which is described in PE/COFF spec 7. Import250 // Library Format.251 NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,252 ImportType Type, ImportNameType NameType,253 StringRef ExportName,254 MachineTypes Machine);255 256 // Create a weak external file which is described in PE/COFF Aux Format 3.257 NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp,258 MachineTypes Machine);259 260 bool is64Bit() const { return COFF::is64Bit(NativeMachine); }261};262} // namespace263 264NewArchiveMember265ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {266 const uint32_t NumberOfSections = 2;267 const uint32_t NumberOfSymbols = 7;268 const uint32_t NumberOfRelocations = 3;269 270 // COFF Header271 coff_file_header Header{272 u16(NativeMachine),273 u16(NumberOfSections),274 u32(0),275 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +276 // .idata$2277 sizeof(coff_import_directory_table_entry) +278 NumberOfRelocations * sizeof(coff_relocation) +279 // .idata$4280 (ImportName.size() + 1)),281 u32(NumberOfSymbols),282 u16(0),283 u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE),284 };285 append(Buffer, Header);286 287 // Section Header Table288 const coff_section SectionTable[NumberOfSections] = {289 {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},290 u32(0),291 u32(0),292 u32(sizeof(coff_import_directory_table_entry)),293 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),294 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +295 sizeof(coff_import_directory_table_entry)),296 u32(0),297 u16(NumberOfRelocations),298 u16(0),299 u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |300 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},301 {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},302 u32(0),303 u32(0),304 u32(ImportName.size() + 1),305 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +306 sizeof(coff_import_directory_table_entry) +307 NumberOfRelocations * sizeof(coff_relocation)),308 u32(0),309 u32(0),310 u16(0),311 u16(0),312 u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |313 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},314 };315 append(Buffer, SectionTable);316 317 // .idata$2318 const coff_import_directory_table_entry ImportDescriptor{319 u32(0), u32(0), u32(0), u32(0), u32(0),320 };321 append(Buffer, ImportDescriptor);322 323 const coff_relocation RelocationTable[NumberOfRelocations] = {324 {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),325 u16(getImgRelRelocation(NativeMachine))},326 {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),327 u32(3), u16(getImgRelRelocation(NativeMachine))},328 {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),329 u32(4), u16(getImgRelRelocation(NativeMachine))},330 };331 append(Buffer, RelocationTable);332 333 // .idata$6334 auto S = Buffer.size();335 Buffer.resize(S + ImportName.size() + 1);336 memcpy(&Buffer[S], ImportName.data(), ImportName.size());337 Buffer[S + ImportName.size()] = '\0';338 339 // Symbol Table340 coff_symbol16 SymbolTable[NumberOfSymbols] = {341 {{{0, 0, 0, 0, 0, 0, 0, 0}},342 u32(0),343 u16(1),344 u16(0),345 IMAGE_SYM_CLASS_EXTERNAL,346 0},347 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},348 u32(0),349 u16(1),350 u16(0),351 IMAGE_SYM_CLASS_SECTION,352 0},353 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},354 u32(0),355 u16(2),356 u16(0),357 IMAGE_SYM_CLASS_STATIC,358 0},359 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},360 u32(0),361 u16(0),362 u16(0),363 IMAGE_SYM_CLASS_SECTION,364 0},365 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},366 u32(0),367 u16(0),368 u16(0),369 IMAGE_SYM_CLASS_SECTION,370 0},371 {{{0, 0, 0, 0, 0, 0, 0, 0}},372 u32(0),373 u16(0),374 u16(0),375 IMAGE_SYM_CLASS_EXTERNAL,376 0},377 {{{0, 0, 0, 0, 0, 0, 0, 0}},378 u32(0),379 u16(0),380 u16(0),381 IMAGE_SYM_CLASS_EXTERNAL,382 0},383 };384 // TODO: Name.Offset.Offset here and in the all similar places below385 // suggests a names refactoring. Maybe StringTableOffset.Value?386 SymbolTable[0].Name.Offset.Offset =387 sizeof(uint32_t);388 SymbolTable[5].Name.Offset.Offset =389 sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;390 SymbolTable[6].Name.Offset.Offset =391 sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +392 NullImportDescriptorSymbolName.length() + 1;393 append(Buffer, SymbolTable);394 395 // String Table396 writeStringTable(Buffer,397 {ImportDescriptorSymbolName, NullImportDescriptorSymbolName,398 NullThunkSymbolName});399 400 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};401 return {MemoryBufferRef(F, ImportName)};402}403 404NewArchiveMember405ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {406 const uint32_t NumberOfSections = 1;407 const uint32_t NumberOfSymbols = 1;408 409 // COFF Header410 coff_file_header Header{411 u16(NativeMachine),412 u16(NumberOfSections),413 u32(0),414 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +415 // .idata$3416 sizeof(coff_import_directory_table_entry)),417 u32(NumberOfSymbols),418 u16(0),419 u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE),420 };421 append(Buffer, Header);422 423 // Section Header Table424 const coff_section SectionTable[NumberOfSections] = {425 {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},426 u32(0),427 u32(0),428 u32(sizeof(coff_import_directory_table_entry)),429 u32(sizeof(coff_file_header) +430 (NumberOfSections * sizeof(coff_section))),431 u32(0),432 u32(0),433 u16(0),434 u16(0),435 u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |436 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},437 };438 append(Buffer, SectionTable);439 440 // .idata$3441 const coff_import_directory_table_entry ImportDescriptor{442 u32(0), u32(0), u32(0), u32(0), u32(0),443 };444 append(Buffer, ImportDescriptor);445 446 // Symbol Table447 coff_symbol16 SymbolTable[NumberOfSymbols] = {448 {{{0, 0, 0, 0, 0, 0, 0, 0}},449 u32(0),450 u16(1),451 u16(0),452 IMAGE_SYM_CLASS_EXTERNAL,453 0},454 };455 SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);456 append(Buffer, SymbolTable);457 458 // String Table459 writeStringTable(Buffer, {NullImportDescriptorSymbolName});460 461 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};462 return {MemoryBufferRef(F, ImportName)};463}464 465NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {466 const uint32_t NumberOfSections = 2;467 const uint32_t NumberOfSymbols = 1;468 uint32_t VASize = is64Bit() ? 8 : 4;469 470 // COFF Header471 coff_file_header Header{472 u16(NativeMachine),473 u16(NumberOfSections),474 u32(0),475 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +476 // .idata$5477 VASize +478 // .idata$4479 VASize),480 u32(NumberOfSymbols),481 u16(0),482 u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE),483 };484 append(Buffer, Header);485 486 // Section Header Table487 const coff_section SectionTable[NumberOfSections] = {488 {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},489 u32(0),490 u32(0),491 u32(VASize),492 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),493 u32(0),494 u32(0),495 u16(0),496 u16(0),497 u32((is64Bit() ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES) |498 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |499 IMAGE_SCN_MEM_WRITE)},500 {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},501 u32(0),502 u32(0),503 u32(VASize),504 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +505 VASize),506 u32(0),507 u32(0),508 u16(0),509 u16(0),510 u32((is64Bit() ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES) |511 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |512 IMAGE_SCN_MEM_WRITE)},513 };514 append(Buffer, SectionTable);515 516 // .idata$5, ILT517 append(Buffer, u32(0));518 if (is64Bit())519 append(Buffer, u32(0));520 521 // .idata$4, IAT522 append(Buffer, u32(0));523 if (is64Bit())524 append(Buffer, u32(0));525 526 // Symbol Table527 coff_symbol16 SymbolTable[NumberOfSymbols] = {528 {{{0, 0, 0, 0, 0, 0, 0, 0}},529 u32(0),530 u16(1),531 u16(0),532 IMAGE_SYM_CLASS_EXTERNAL,533 0},534 };535 SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);536 append(Buffer, SymbolTable);537 538 // String Table539 writeStringTable(Buffer, {NullThunkSymbolName});540 541 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};542 return {MemoryBufferRef{F, ImportName}};543}544 545NewArchiveMember546ObjectFactory::createShortImport(StringRef Sym, uint16_t Ordinal,547 ImportType ImportType, ImportNameType NameType,548 StringRef ExportName, MachineTypes Machine) {549 size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs550 if (!ExportName.empty())551 ImpSize += ExportName.size() + 1;552 size_t Size = sizeof(coff_import_header) + ImpSize;553 char *Buf = Alloc.Allocate<char>(Size);554 memset(Buf, 0, Size);555 char *P = Buf;556 557 // Write short import library.558 auto *Imp = reinterpret_cast<coff_import_header *>(P);559 P += sizeof(*Imp);560 Imp->Sig2 = 0xFFFF;561 Imp->Machine = Machine;562 Imp->SizeOfData = ImpSize;563 if (Ordinal > 0)564 Imp->OrdinalHint = Ordinal;565 Imp->TypeInfo = (NameType << 2) | ImportType;566 567 // Write symbol name and DLL name.568 memcpy(P, Sym.data(), Sym.size());569 P += Sym.size() + 1;570 memcpy(P, ImportName.data(), ImportName.size());571 if (!ExportName.empty()) {572 P += ImportName.size() + 1;573 memcpy(P, ExportName.data(), ExportName.size());574 }575 576 return {MemoryBufferRef(StringRef(Buf, Size), ImportName)};577}578 579NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym,580 StringRef Weak, bool Imp,581 MachineTypes Machine) {582 std::vector<uint8_t> Buffer;583 const uint32_t NumberOfSections = 1;584 const uint32_t NumberOfSymbols = 5;585 586 // COFF Header587 coff_file_header Header{588 u16(Machine),589 u16(NumberOfSections),590 u32(0),591 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))),592 u32(NumberOfSymbols),593 u16(0),594 u16(0),595 };596 append(Buffer, Header);597 598 // Section Header Table599 const coff_section SectionTable[NumberOfSections] = {600 {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'},601 u32(0),602 u32(0),603 u32(0),604 u32(0),605 u32(0),606 u32(0),607 u16(0),608 u16(0),609 u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}};610 append(Buffer, SectionTable);611 612 // Symbol Table613 coff_symbol16 SymbolTable[NumberOfSymbols] = {614 {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},615 u32(0),616 u16(0xFFFF),617 u16(0),618 IMAGE_SYM_CLASS_STATIC,619 0},620 {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}},621 u32(0),622 u16(0xFFFF),623 u16(0),624 IMAGE_SYM_CLASS_STATIC,625 0},626 {{{0, 0, 0, 0, 0, 0, 0, 0}},627 u32(0),628 u16(0),629 u16(0),630 IMAGE_SYM_CLASS_EXTERNAL,631 0},632 {{{0, 0, 0, 0, 0, 0, 0, 0}},633 u32(0),634 u16(0),635 u16(0),636 IMAGE_SYM_CLASS_WEAK_EXTERNAL,637 1},638 {{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}},639 u32(0),640 u16(0),641 u16(0),642 IMAGE_SYM_CLASS_NULL,643 0},644 };645 SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t);646 647 //__imp_ String Table648 StringRef Prefix = Imp ? "__imp_" : "";649 SymbolTable[3].Name.Offset.Offset =650 sizeof(uint32_t) + Sym.size() + Prefix.size() + 1;651 append(Buffer, SymbolTable);652 writeStringTable(Buffer, {(Prefix + Sym).str(),653 (Prefix + Weak).str()});654 655 // Copied here so we can still use writeStringTable656 char *Buf = Alloc.Allocate<char>(Buffer.size());657 memcpy(Buf, Buffer.data(), Buffer.size());658 return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)};659}660 661Error writeImportLibrary(StringRef ImportName, StringRef Path,662 ArrayRef<COFFShortExport> Exports,663 MachineTypes Machine, bool MinGW,664 ArrayRef<COFFShortExport> NativeExports) {665 666 MachineTypes NativeMachine = Machine;667 if (isArm64EC(Machine)) {668 NativeMachine = IMAGE_FILE_MACHINE_ARM64;669 Machine = IMAGE_FILE_MACHINE_ARM64EC;670 }671 672 std::vector<NewArchiveMember> Members;673 ObjectFactory OF(llvm::sys::path::filename(ImportName), NativeMachine);674 675 std::vector<uint8_t> ImportDescriptor;676 Members.push_back(OF.createImportDescriptor(ImportDescriptor));677 678 std::vector<uint8_t> NullImportDescriptor;679 Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));680 681 std::vector<uint8_t> NullThunk;682 Members.push_back(OF.createNullThunk(NullThunk));683 684 auto addExports = [&](ArrayRef<COFFShortExport> Exp,685 MachineTypes M) -> Error {686 StringMap<std::string> RegularImports;687 struct Deferred {688 std::string Name;689 ImportType ImpType;690 const COFFShortExport *Export;691 };692 SmallVector<Deferred, 0> Renames;693 for (const COFFShortExport &E : Exp) {694 if (E.Private)695 continue;696 697 ImportType ImportType = IMPORT_CODE;698 if (E.Data)699 ImportType = IMPORT_DATA;700 if (E.Constant)701 ImportType = IMPORT_CONST;702 703 StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName;704 std::string Name;705 706 if (E.ExtName.empty()) {707 Name = std::string(SymbolName);708 } else {709 Expected<std::string> ReplacedName =710 object::replace(SymbolName, E.Name, E.ExtName);711 if (!ReplacedName)712 return ReplacedName.takeError();713 Name.swap(*ReplacedName);714 }715 716 ImportNameType NameType;717 std::string ExportName;718 if (E.Noname) {719 NameType = IMPORT_ORDINAL;720 } else if (!E.ExportAs.empty()) {721 NameType = IMPORT_NAME_EXPORTAS;722 ExportName = E.ExportAs;723 } else if (!E.ImportName.empty()) {724 // If we need to import from a specific ImportName, we may need to use725 // a weak alias (which needs another import to point at). But if we can726 // express ImportName based on the symbol name and a specific NameType,727 // prefer that over an alias.728 if (Machine == IMAGE_FILE_MACHINE_I386 &&729 applyNameType(IMPORT_NAME_UNDECORATE, Name) == E.ImportName)730 NameType = IMPORT_NAME_UNDECORATE;731 else if (Machine == IMAGE_FILE_MACHINE_I386 &&732 applyNameType(IMPORT_NAME_NOPREFIX, Name) == E.ImportName)733 NameType = IMPORT_NAME_NOPREFIX;734 else if (isArm64EC(M)) {735 NameType = IMPORT_NAME_EXPORTAS;736 ExportName = E.ImportName;737 } else if (Name == E.ImportName)738 NameType = IMPORT_NAME;739 else {740 Deferred D;741 D.Name = Name;742 D.ImpType = ImportType;743 D.Export = &E;744 Renames.push_back(D);745 continue;746 }747 } else {748 NameType = getNameType(SymbolName, E.Name, M, MinGW);749 }750 751 // On ARM64EC, use EXPORTAS to import demangled name for mangled symbols.752 if (ImportType == IMPORT_CODE && isArm64EC(M)) {753 if (std::optional<std::string> MangledName =754 getArm64ECMangledFunctionName(Name)) {755 if (!E.Noname && ExportName.empty()) {756 NameType = IMPORT_NAME_EXPORTAS;757 ExportName.swap(Name);758 }759 Name = std::move(*MangledName);760 } else if (!E.Noname && ExportName.empty()) {761 std::optional<std::string> DemangledName =762 getArm64ECDemangledFunctionName(Name);763 if (!DemangledName)764 return make_error<StringError>(765 StringRef(Twine("Invalid ARM64EC function name '" + Name + "'")766 .str()),767 object_error::parse_failed);768 NameType = IMPORT_NAME_EXPORTAS;769 ExportName = std::move(*DemangledName);770 }771 }772 773 RegularImports[applyNameType(NameType, Name)] = Name;774 Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType,775 NameType, ExportName, M));776 }777 for (const auto &D : Renames) {778 auto It = RegularImports.find(D.Export->ImportName);779 if (It != RegularImports.end()) {780 // We have a regular import entry for a symbol with the name we781 // want to reference; produce an alias pointing at that.782 StringRef Symbol = It->second;783 if (D.ImpType == IMPORT_CODE)784 Members.push_back(OF.createWeakExternal(Symbol, D.Name, false, M));785 Members.push_back(OF.createWeakExternal(Symbol, D.Name, true, M));786 } else {787 Members.push_back(OF.createShortImport(D.Name, D.Export->Ordinal,788 D.ImpType, IMPORT_NAME_EXPORTAS,789 D.Export->ImportName, M));790 }791 }792 return Error::success();793 };794 795 if (Error e = addExports(Exports, Machine))796 return e;797 if (Error e = addExports(NativeExports, NativeMachine))798 return e;799 800 return writeArchive(Path, Members, SymtabWritingMode::NormalSymtab,801 object::Archive::K_COFF,802 /*Deterministic*/ true, /*Thin*/ false,803 /*OldArchiveBuf*/ nullptr, isArm64EC(Machine));804}805 806} // namespace object807} // namespace llvm808