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-exception 6 // 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/Twine.h" 16 #include "llvm/Object/Archive.h" 17 #include "llvm/Object/ArchiveWriter.h" 18 #include "llvm/Object/COFF.h" 19 #include "llvm/Support/Allocator.h" 20 #include "llvm/Support/Endian.h" 21 #include "llvm/Support/Error.h" 22 #include "llvm/Support/ErrorHandling.h" 23 #include "llvm/Support/Path.h" 24 25 #include <cstdint> 26 #include <string> 27 #include <vector> 28 29 using namespace llvm::COFF; 30 using namespace llvm::object; 31 using namespace llvm; 32 33 namespace llvm { 34 namespace object { 35 36 StringRef COFFImportFile::getFileFormatName() const { 37 switch (getMachine()) { 38 case COFF::IMAGE_FILE_MACHINE_I386: 39 return "COFF-import-file-i386"; 40 case COFF::IMAGE_FILE_MACHINE_AMD64: 41 return "COFF-import-file-x86-64"; 42 case COFF::IMAGE_FILE_MACHINE_ARMNT: 43 return "COFF-import-file-ARM"; 44 case COFF::IMAGE_FILE_MACHINE_ARM64: 45 return "COFF-import-file-ARM64"; 46 case COFF::IMAGE_FILE_MACHINE_ARM64EC: 47 return "COFF-import-file-ARM64EC"; 48 case COFF::IMAGE_FILE_MACHINE_ARM64X: 49 return "COFF-import-file-ARM64X"; 50 default: 51 return "COFF-import-file-<unknown arch>"; 52 } 53 } 54 55 StringRef COFFImportFile::getExportName() const { 56 const coff_import_header *hdr = getCOFFImportHeader(); 57 StringRef name = Data.getBuffer().substr(sizeof(*hdr)).split('\0').first; 58 59 auto ltrim1 = [](StringRef s, StringRef chars) { 60 return !s.empty() && chars.contains(s[0]) ? s.substr(1) : s; 61 }; 62 63 switch (hdr->getNameType()) { 64 case IMPORT_ORDINAL: 65 name = ""; 66 break; 67 case IMPORT_NAME_NOPREFIX: 68 name = ltrim1(name, "?@_"); 69 break; 70 case IMPORT_NAME_UNDECORATE: 71 name = ltrim1(name, "?@_"); 72 name = name.substr(0, name.find('@')); 73 break; 74 case IMPORT_NAME_EXPORTAS: { 75 // Skip DLL name 76 name = Data.getBuffer().substr(sizeof(*hdr) + name.size() + 1); 77 name = name.split('\0').second.split('\0').first; 78 break; 79 } 80 default: 81 break; 82 } 83 84 return name; 85 } 86 87 static uint16_t getImgRelRelocation(MachineTypes Machine) { 88 switch (Machine) { 89 default: 90 llvm_unreachable("unsupported machine"); 91 case IMAGE_FILE_MACHINE_AMD64: 92 return IMAGE_REL_AMD64_ADDR32NB; 93 case IMAGE_FILE_MACHINE_ARMNT: 94 return IMAGE_REL_ARM_ADDR32NB; 95 case IMAGE_FILE_MACHINE_ARM64: 96 case IMAGE_FILE_MACHINE_ARM64EC: 97 case IMAGE_FILE_MACHINE_ARM64X: 98 return IMAGE_REL_ARM64_ADDR32NB; 99 case IMAGE_FILE_MACHINE_I386: 100 return IMAGE_REL_I386_DIR32NB; 101 } 102 } 103 104 template <class T> static void append(std::vector<uint8_t> &B, const T &Data) { 105 size_t S = B.size(); 106 B.resize(S + sizeof(T)); 107 memcpy(&B[S], &Data, sizeof(T)); 108 } 109 110 static void writeStringTable(std::vector<uint8_t> &B, 111 ArrayRef<const std::string_view> Strings) { 112 // The COFF string table consists of a 4-byte value which is the size of the 113 // table, including the length field itself. This value is followed by the 114 // string content itself, which is an array of null-terminated C-style 115 // strings. The termination is important as they are referenced to by offset 116 // by the symbol entity in the file format. 117 118 size_t Pos = B.size(); 119 size_t Offset = B.size(); 120 121 // Skip over the length field, we will fill it in later as we will have 122 // computed the length while emitting the string content itself. 123 Pos += sizeof(uint32_t); 124 125 for (const auto &S : Strings) { 126 B.resize(Pos + S.length() + 1); 127 std::copy(S.begin(), S.end(), std::next(B.begin(), Pos)); 128 B[Pos + S.length()] = 0; 129 Pos += S.length() + 1; 130 } 131 132 // Backfill the length of the table now that it has been computed. 133 support::ulittle32_t Length(B.size() - Offset); 134 support::endian::write32le(&B[Offset], Length); 135 } 136 137 static ImportNameType getNameType(StringRef Sym, StringRef ExtName, 138 MachineTypes Machine, bool MinGW) { 139 // A decorated stdcall function in MSVC is exported with the 140 // type IMPORT_NAME, and the exported function name includes the 141 // the leading underscore. In MinGW on the other hand, a decorated 142 // stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX). 143 // See the comment in isDecorated in COFFModuleDefinition.cpp for more 144 // details. 145 if (ExtName.starts_with("_") && ExtName.contains('@') && !MinGW) 146 return IMPORT_NAME; 147 if (Sym != ExtName) 148 return IMPORT_NAME_UNDECORATE; 149 if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.starts_with("_")) 150 return IMPORT_NAME_NOPREFIX; 151 return IMPORT_NAME; 152 } 153 154 static Expected<std::string> replace(StringRef S, StringRef From, 155 StringRef To) { 156 size_t Pos = S.find(From); 157 158 // From and To may be mangled, but substrings in S may not. 159 if (Pos == StringRef::npos && From.starts_with("_") && To.starts_with("_")) { 160 From = From.substr(1); 161 To = To.substr(1); 162 Pos = S.find(From); 163 } 164 165 if (Pos == StringRef::npos) { 166 return make_error<StringError>( 167 StringRef(Twine(S + ": replacing '" + From + 168 "' with '" + To + "' failed").str()), object_error::parse_failed); 169 } 170 171 return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str(); 172 } 173 174 namespace { 175 // This class constructs various small object files necessary to support linking 176 // symbols imported from a DLL. The contents are pretty strictly defined and 177 // nearly entirely static. The details of the structures files are defined in 178 // WINNT.h and the PE/COFF specification. 179 class ObjectFactory { 180 using u16 = support::ulittle16_t; 181 using u32 = support::ulittle32_t; 182 MachineTypes NativeMachine; 183 BumpPtrAllocator Alloc; 184 StringRef ImportName; 185 StringRef Library; 186 std::string ImportDescriptorSymbolName; 187 std::string NullThunkSymbolName; 188 189 public: 190 ObjectFactory(StringRef S, MachineTypes M) 191 : NativeMachine(M), ImportName(S), Library(llvm::sys::path::stem(S)), 192 ImportDescriptorSymbolName((ImportDescriptorPrefix + Library).str()), 193 NullThunkSymbolName( 194 (NullThunkDataPrefix + Library + NullThunkDataSuffix).str()) {} 195 196 // Creates an Import Descriptor. This is a small object file which contains a 197 // reference to the terminators and contains the library name (entry) for the 198 // import name table. It will force the linker to construct the necessary 199 // structure to import symbols from the DLL. 200 NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer); 201 202 // Creates a NULL import descriptor. This is a small object file whcih 203 // contains a NULL import descriptor. It is used to terminate the imports 204 // from a specific DLL. 205 NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer); 206 207 // Create a NULL Thunk Entry. This is a small object file which contains a 208 // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It 209 // is used to terminate the IAT and ILT. 210 NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer); 211 212 // Create a short import file which is described in PE/COFF spec 7. Import 213 // Library Format. 214 NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal, 215 ImportType Type, ImportNameType NameType, 216 StringRef ExportName, 217 MachineTypes Machine); 218 219 // Create a weak external file which is described in PE/COFF Aux Format 3. 220 NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp, 221 MachineTypes Machine); 222 223 bool is64Bit() const { return COFF::is64Bit(NativeMachine); } 224 }; 225 } // namespace 226 227 NewArchiveMember 228 ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) { 229 const uint32_t NumberOfSections = 2; 230 const uint32_t NumberOfSymbols = 7; 231 const uint32_t NumberOfRelocations = 3; 232 233 // COFF Header 234 coff_file_header Header{ 235 u16(NativeMachine), 236 u16(NumberOfSections), 237 u32(0), 238 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + 239 // .idata$2 240 sizeof(coff_import_directory_table_entry) + 241 NumberOfRelocations * sizeof(coff_relocation) + 242 // .idata$4 243 (ImportName.size() + 1)), 244 u32(NumberOfSymbols), 245 u16(0), 246 u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE), 247 }; 248 append(Buffer, Header); 249 250 // Section Header Table 251 const coff_section SectionTable[NumberOfSections] = { 252 {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}, 253 u32(0), 254 u32(0), 255 u32(sizeof(coff_import_directory_table_entry)), 256 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), 257 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + 258 sizeof(coff_import_directory_table_entry)), 259 u32(0), 260 u16(NumberOfRelocations), 261 u16(0), 262 u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | 263 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, 264 {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}, 265 u32(0), 266 u32(0), 267 u32(ImportName.size() + 1), 268 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + 269 sizeof(coff_import_directory_table_entry) + 270 NumberOfRelocations * sizeof(coff_relocation)), 271 u32(0), 272 u32(0), 273 u16(0), 274 u16(0), 275 u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | 276 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, 277 }; 278 append(Buffer, SectionTable); 279 280 // .idata$2 281 const coff_import_directory_table_entry ImportDescriptor{ 282 u32(0), u32(0), u32(0), u32(0), u32(0), 283 }; 284 append(Buffer, ImportDescriptor); 285 286 const coff_relocation RelocationTable[NumberOfRelocations] = { 287 {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2), 288 u16(getImgRelRelocation(NativeMachine))}, 289 {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)), 290 u32(3), u16(getImgRelRelocation(NativeMachine))}, 291 {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)), 292 u32(4), u16(getImgRelRelocation(NativeMachine))}, 293 }; 294 append(Buffer, RelocationTable); 295 296 // .idata$6 297 auto S = Buffer.size(); 298 Buffer.resize(S + ImportName.size() + 1); 299 memcpy(&Buffer[S], ImportName.data(), ImportName.size()); 300 Buffer[S + ImportName.size()] = '\0'; 301 302 // Symbol Table 303 coff_symbol16 SymbolTable[NumberOfSymbols] = { 304 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 305 u32(0), 306 u16(1), 307 u16(0), 308 IMAGE_SYM_CLASS_EXTERNAL, 309 0}, 310 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}}, 311 u32(0), 312 u16(1), 313 u16(0), 314 IMAGE_SYM_CLASS_SECTION, 315 0}, 316 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}}, 317 u32(0), 318 u16(2), 319 u16(0), 320 IMAGE_SYM_CLASS_STATIC, 321 0}, 322 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}}, 323 u32(0), 324 u16(0), 325 u16(0), 326 IMAGE_SYM_CLASS_SECTION, 327 0}, 328 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}}, 329 u32(0), 330 u16(0), 331 u16(0), 332 IMAGE_SYM_CLASS_SECTION, 333 0}, 334 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 335 u32(0), 336 u16(0), 337 u16(0), 338 IMAGE_SYM_CLASS_EXTERNAL, 339 0}, 340 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 341 u32(0), 342 u16(0), 343 u16(0), 344 IMAGE_SYM_CLASS_EXTERNAL, 345 0}, 346 }; 347 // TODO: Name.Offset.Offset here and in the all similar places below 348 // suggests a names refactoring. Maybe StringTableOffset.Value? 349 SymbolTable[0].Name.Offset.Offset = 350 sizeof(uint32_t); 351 SymbolTable[5].Name.Offset.Offset = 352 sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1; 353 SymbolTable[6].Name.Offset.Offset = 354 sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 + 355 NullImportDescriptorSymbolName.length() + 1; 356 append(Buffer, SymbolTable); 357 358 // String Table 359 writeStringTable(Buffer, 360 {ImportDescriptorSymbolName, NullImportDescriptorSymbolName, 361 NullThunkSymbolName}); 362 363 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; 364 return {MemoryBufferRef(F, ImportName)}; 365 } 366 367 NewArchiveMember 368 ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) { 369 const uint32_t NumberOfSections = 1; 370 const uint32_t NumberOfSymbols = 1; 371 372 // COFF Header 373 coff_file_header Header{ 374 u16(NativeMachine), 375 u16(NumberOfSections), 376 u32(0), 377 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + 378 // .idata$3 379 sizeof(coff_import_directory_table_entry)), 380 u32(NumberOfSymbols), 381 u16(0), 382 u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE), 383 }; 384 append(Buffer, Header); 385 386 // Section Header Table 387 const coff_section SectionTable[NumberOfSections] = { 388 {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'}, 389 u32(0), 390 u32(0), 391 u32(sizeof(coff_import_directory_table_entry)), 392 u32(sizeof(coff_file_header) + 393 (NumberOfSections * sizeof(coff_section))), 394 u32(0), 395 u32(0), 396 u16(0), 397 u16(0), 398 u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | 399 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, 400 }; 401 append(Buffer, SectionTable); 402 403 // .idata$3 404 const coff_import_directory_table_entry ImportDescriptor{ 405 u32(0), u32(0), u32(0), u32(0), u32(0), 406 }; 407 append(Buffer, ImportDescriptor); 408 409 // Symbol Table 410 coff_symbol16 SymbolTable[NumberOfSymbols] = { 411 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 412 u32(0), 413 u16(1), 414 u16(0), 415 IMAGE_SYM_CLASS_EXTERNAL, 416 0}, 417 }; 418 SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t); 419 append(Buffer, SymbolTable); 420 421 // String Table 422 writeStringTable(Buffer, {NullImportDescriptorSymbolName}); 423 424 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; 425 return {MemoryBufferRef(F, ImportName)}; 426 } 427 428 NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) { 429 const uint32_t NumberOfSections = 2; 430 const uint32_t NumberOfSymbols = 1; 431 uint32_t VASize = is64Bit() ? 8 : 4; 432 433 // COFF Header 434 coff_file_header Header{ 435 u16(NativeMachine), 436 u16(NumberOfSections), 437 u32(0), 438 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + 439 // .idata$5 440 VASize + 441 // .idata$4 442 VASize), 443 u32(NumberOfSymbols), 444 u16(0), 445 u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE), 446 }; 447 append(Buffer, Header); 448 449 // Section Header Table 450 const coff_section SectionTable[NumberOfSections] = { 451 {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}, 452 u32(0), 453 u32(0), 454 u32(VASize), 455 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), 456 u32(0), 457 u32(0), 458 u16(0), 459 u16(0), 460 u32((is64Bit() ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES) | 461 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | 462 IMAGE_SCN_MEM_WRITE)}, 463 {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}, 464 u32(0), 465 u32(0), 466 u32(VASize), 467 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + 468 VASize), 469 u32(0), 470 u32(0), 471 u16(0), 472 u16(0), 473 u32((is64Bit() ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES) | 474 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | 475 IMAGE_SCN_MEM_WRITE)}, 476 }; 477 append(Buffer, SectionTable); 478 479 // .idata$5, ILT 480 append(Buffer, u32(0)); 481 if (is64Bit()) 482 append(Buffer, u32(0)); 483 484 // .idata$4, IAT 485 append(Buffer, u32(0)); 486 if (is64Bit()) 487 append(Buffer, u32(0)); 488 489 // Symbol Table 490 coff_symbol16 SymbolTable[NumberOfSymbols] = { 491 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 492 u32(0), 493 u16(1), 494 u16(0), 495 IMAGE_SYM_CLASS_EXTERNAL, 496 0}, 497 }; 498 SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t); 499 append(Buffer, SymbolTable); 500 501 // String Table 502 writeStringTable(Buffer, {NullThunkSymbolName}); 503 504 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; 505 return {MemoryBufferRef{F, ImportName}}; 506 } 507 508 NewArchiveMember 509 ObjectFactory::createShortImport(StringRef Sym, uint16_t Ordinal, 510 ImportType ImportType, ImportNameType NameType, 511 StringRef ExportName, MachineTypes Machine) { 512 size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs 513 if (!ExportName.empty()) 514 ImpSize += ExportName.size() + 1; 515 size_t Size = sizeof(coff_import_header) + ImpSize; 516 char *Buf = Alloc.Allocate<char>(Size); 517 memset(Buf, 0, Size); 518 char *P = Buf; 519 520 // Write short import library. 521 auto *Imp = reinterpret_cast<coff_import_header *>(P); 522 P += sizeof(*Imp); 523 Imp->Sig2 = 0xFFFF; 524 Imp->Machine = Machine; 525 Imp->SizeOfData = ImpSize; 526 if (Ordinal > 0) 527 Imp->OrdinalHint = Ordinal; 528 Imp->TypeInfo = (NameType << 2) | ImportType; 529 530 // Write symbol name and DLL name. 531 memcpy(P, Sym.data(), Sym.size()); 532 P += Sym.size() + 1; 533 memcpy(P, ImportName.data(), ImportName.size()); 534 if (!ExportName.empty()) { 535 P += ImportName.size() + 1; 536 memcpy(P, ExportName.data(), ExportName.size()); 537 } 538 539 return {MemoryBufferRef(StringRef(Buf, Size), ImportName)}; 540 } 541 542 NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym, 543 StringRef Weak, bool Imp, 544 MachineTypes Machine) { 545 std::vector<uint8_t> Buffer; 546 const uint32_t NumberOfSections = 1; 547 const uint32_t NumberOfSymbols = 5; 548 549 // COFF Header 550 coff_file_header Header{ 551 u16(Machine), 552 u16(NumberOfSections), 553 u32(0), 554 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))), 555 u32(NumberOfSymbols), 556 u16(0), 557 u16(0), 558 }; 559 append(Buffer, Header); 560 561 // Section Header Table 562 const coff_section SectionTable[NumberOfSections] = { 563 {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'}, 564 u32(0), 565 u32(0), 566 u32(0), 567 u32(0), 568 u32(0), 569 u32(0), 570 u16(0), 571 u16(0), 572 u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}}; 573 append(Buffer, SectionTable); 574 575 // Symbol Table 576 coff_symbol16 SymbolTable[NumberOfSymbols] = { 577 {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}}, 578 u32(0), 579 u16(0xFFFF), 580 u16(0), 581 IMAGE_SYM_CLASS_STATIC, 582 0}, 583 {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}}, 584 u32(0), 585 u16(0xFFFF), 586 u16(0), 587 IMAGE_SYM_CLASS_STATIC, 588 0}, 589 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 590 u32(0), 591 u16(0), 592 u16(0), 593 IMAGE_SYM_CLASS_EXTERNAL, 594 0}, 595 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 596 u32(0), 597 u16(0), 598 u16(0), 599 IMAGE_SYM_CLASS_WEAK_EXTERNAL, 600 1}, 601 {{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}}, 602 u32(0), 603 u16(0), 604 u16(0), 605 IMAGE_SYM_CLASS_NULL, 606 0}, 607 }; 608 SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t); 609 610 //__imp_ String Table 611 StringRef Prefix = Imp ? "__imp_" : ""; 612 SymbolTable[3].Name.Offset.Offset = 613 sizeof(uint32_t) + Sym.size() + Prefix.size() + 1; 614 append(Buffer, SymbolTable); 615 writeStringTable(Buffer, {(Prefix + Sym).str(), 616 (Prefix + Weak).str()}); 617 618 // Copied here so we can still use writeStringTable 619 char *Buf = Alloc.Allocate<char>(Buffer.size()); 620 memcpy(Buf, Buffer.data(), Buffer.size()); 621 return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)}; 622 } 623 624 Error writeImportLibrary(StringRef ImportName, StringRef Path, 625 ArrayRef<COFFShortExport> Exports, 626 MachineTypes Machine, bool MinGW) { 627 628 MachineTypes NativeMachine = 629 isArm64EC(Machine) ? IMAGE_FILE_MACHINE_ARM64 : Machine; 630 631 std::vector<NewArchiveMember> Members; 632 ObjectFactory OF(llvm::sys::path::filename(ImportName), NativeMachine); 633 634 std::vector<uint8_t> ImportDescriptor; 635 Members.push_back(OF.createImportDescriptor(ImportDescriptor)); 636 637 std::vector<uint8_t> NullImportDescriptor; 638 Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor)); 639 640 std::vector<uint8_t> NullThunk; 641 Members.push_back(OF.createNullThunk(NullThunk)); 642 643 for (const COFFShortExport &E : Exports) { 644 if (E.Private) 645 continue; 646 647 ImportType ImportType = IMPORT_CODE; 648 if (E.Data) 649 ImportType = IMPORT_DATA; 650 if (E.Constant) 651 ImportType = IMPORT_CONST; 652 653 StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName; 654 std::string Name; 655 656 if (E.ExtName.empty()) { 657 Name = std::string(SymbolName); 658 } else { 659 Expected<std::string> ReplacedName = 660 replace(SymbolName, E.Name, E.ExtName); 661 if (!ReplacedName) 662 return ReplacedName.takeError(); 663 Name.swap(*ReplacedName); 664 } 665 666 if (!E.AliasTarget.empty() && Name != E.AliasTarget) { 667 Members.push_back( 668 OF.createWeakExternal(E.AliasTarget, Name, false, Machine)); 669 Members.push_back( 670 OF.createWeakExternal(E.AliasTarget, Name, true, Machine)); 671 continue; 672 } 673 674 ImportNameType NameType; 675 std::string ExportName; 676 if (E.Noname) { 677 NameType = IMPORT_ORDINAL; 678 } else { 679 NameType = getNameType(SymbolName, E.Name, Machine, MinGW); 680 } 681 682 // On ARM64EC, use EXPORTAS to import demangled name for mangled symbols. 683 if (ImportType == IMPORT_CODE && isArm64EC(Machine)) { 684 if (std::optional<std::string> MangledName = 685 getArm64ECMangledFunctionName(Name)) { 686 if (ExportName.empty()) { 687 NameType = IMPORT_NAME_EXPORTAS; 688 ExportName.swap(Name); 689 } 690 Name = std::move(*MangledName); 691 } else if (ExportName.empty()) { 692 NameType = IMPORT_NAME_EXPORTAS; 693 ExportName = std::move(*getArm64ECDemangledFunctionName(Name)); 694 } 695 } 696 697 Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType, 698 NameType, ExportName, Machine)); 699 } 700 701 return writeArchive(Path, Members, SymtabWritingMode::NormalSymtab, 702 MinGW ? object::Archive::K_GNU : object::Archive::K_COFF, 703 /*Deterministic*/ true, /*Thin*/ false, 704 /*OldArchiveBuf*/ nullptr, isArm64EC(Machine)); 705 } 706 707 } // namespace object 708 } // namespace llvm 709