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/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 31 using namespace llvm::COFF; 32 using namespace llvm::object; 33 using namespace llvm; 34 35 namespace llvm { 36 namespace object { 37 38 StringRef 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 57 static 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 76 StringRef 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 name 90 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 101 Error 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 122 static 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 } 137 } 138 139 template <class T> static void append(std::vector<uint8_t> &B, const T &Data) { 140 size_t S = B.size(); 141 B.resize(S + sizeof(T)); 142 memcpy(&B[S], &Data, sizeof(T)); 143 } 144 145 static void writeStringTable(std::vector<uint8_t> &B, 146 ArrayRef<const std::string_view> Strings) { 147 // The COFF string table consists of a 4-byte value which is the size of the 148 // table, including the length field itself. This value is followed by the 149 // string content itself, which is an array of null-terminated C-style 150 // strings. The termination is important as they are referenced to by offset 151 // by the symbol entity in the file format. 152 153 size_t Pos = B.size(); 154 size_t Offset = B.size(); 155 156 // Skip over the length field, we will fill it in later as we will have 157 // computed the length while emitting the string content itself. 158 Pos += sizeof(uint32_t); 159 160 for (const auto &S : Strings) { 161 B.resize(Pos + S.length() + 1); 162 std::copy(S.begin(), S.end(), std::next(B.begin(), Pos)); 163 B[Pos + S.length()] = 0; 164 Pos += S.length() + 1; 165 } 166 167 // Backfill the length of the table now that it has been computed. 168 support::ulittle32_t Length(B.size() - Offset); 169 support::endian::write32le(&B[Offset], Length); 170 } 171 172 static ImportNameType getNameType(StringRef Sym, StringRef ExtName, 173 MachineTypes Machine, bool MinGW) { 174 // A decorated stdcall function in MSVC is exported with the 175 // type IMPORT_NAME, and the exported function name includes the 176 // the leading underscore. In MinGW on the other hand, a decorated 177 // stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX). 178 // See the comment in isDecorated in COFFModuleDefinition.cpp for more 179 // details. 180 if (ExtName.starts_with("_") && ExtName.contains('@') && !MinGW) 181 return IMPORT_NAME; 182 if (Sym != ExtName) 183 return IMPORT_NAME_UNDECORATE; 184 if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.starts_with("_")) 185 return IMPORT_NAME_NOPREFIX; 186 return IMPORT_NAME; 187 } 188 189 static Expected<std::string> replace(StringRef S, StringRef From, 190 StringRef To) { 191 size_t Pos = S.find(From); 192 193 // From and To may be mangled, but substrings in S may not. 194 if (Pos == StringRef::npos && From.starts_with("_") && To.starts_with("_")) { 195 From = From.substr(1); 196 To = To.substr(1); 197 Pos = S.find(From); 198 } 199 200 if (Pos == StringRef::npos) { 201 return make_error<StringError>( 202 StringRef(Twine(S + ": replacing '" + From + 203 "' with '" + To + "' failed").str()), object_error::parse_failed); 204 } 205 206 return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str(); 207 } 208 209 namespace { 210 // This class constructs various small object files necessary to support linking 211 // symbols imported from a DLL. The contents are pretty strictly defined and 212 // nearly entirely static. The details of the structures files are defined in 213 // WINNT.h and the PE/COFF specification. 214 class ObjectFactory { 215 using u16 = support::ulittle16_t; 216 using u32 = support::ulittle32_t; 217 MachineTypes NativeMachine; 218 BumpPtrAllocator Alloc; 219 StringRef ImportName; 220 StringRef Library; 221 std::string ImportDescriptorSymbolName; 222 std::string NullThunkSymbolName; 223 224 public: 225 ObjectFactory(StringRef S, MachineTypes M) 226 : NativeMachine(M), ImportName(S), Library(llvm::sys::path::stem(S)), 227 ImportDescriptorSymbolName((ImportDescriptorPrefix + Library).str()), 228 NullThunkSymbolName( 229 (NullThunkDataPrefix + Library + NullThunkDataSuffix).str()) {} 230 231 // Creates an Import Descriptor. This is a small object file which contains a 232 // reference to the terminators and contains the library name (entry) for the 233 // import name table. It will force the linker to construct the necessary 234 // structure to import symbols from the DLL. 235 NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer); 236 237 // Creates a NULL import descriptor. This is a small object file whcih 238 // contains a NULL import descriptor. It is used to terminate the imports 239 // from a specific DLL. 240 NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer); 241 242 // Create a NULL Thunk Entry. This is a small object file which contains a 243 // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It 244 // is used to terminate the IAT and ILT. 245 NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer); 246 247 // Create a short import file which is described in PE/COFF spec 7. Import 248 // Library Format. 249 NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal, 250 ImportType Type, ImportNameType NameType, 251 StringRef ExportName, 252 MachineTypes Machine); 253 254 // Create a weak external file which is described in PE/COFF Aux Format 3. 255 NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp, 256 MachineTypes Machine); 257 258 bool is64Bit() const { return COFF::is64Bit(NativeMachine); } 259 }; 260 } // namespace 261 262 NewArchiveMember 263 ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) { 264 const uint32_t NumberOfSections = 2; 265 const uint32_t NumberOfSymbols = 7; 266 const uint32_t NumberOfRelocations = 3; 267 268 // COFF Header 269 coff_file_header Header{ 270 u16(NativeMachine), 271 u16(NumberOfSections), 272 u32(0), 273 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + 274 // .idata$2 275 sizeof(coff_import_directory_table_entry) + 276 NumberOfRelocations * sizeof(coff_relocation) + 277 // .idata$4 278 (ImportName.size() + 1)), 279 u32(NumberOfSymbols), 280 u16(0), 281 u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE), 282 }; 283 append(Buffer, Header); 284 285 // Section Header Table 286 const coff_section SectionTable[NumberOfSections] = { 287 {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}, 288 u32(0), 289 u32(0), 290 u32(sizeof(coff_import_directory_table_entry)), 291 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), 292 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + 293 sizeof(coff_import_directory_table_entry)), 294 u32(0), 295 u16(NumberOfRelocations), 296 u16(0), 297 u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | 298 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, 299 {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}, 300 u32(0), 301 u32(0), 302 u32(ImportName.size() + 1), 303 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + 304 sizeof(coff_import_directory_table_entry) + 305 NumberOfRelocations * sizeof(coff_relocation)), 306 u32(0), 307 u32(0), 308 u16(0), 309 u16(0), 310 u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | 311 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, 312 }; 313 append(Buffer, SectionTable); 314 315 // .idata$2 316 const coff_import_directory_table_entry ImportDescriptor{ 317 u32(0), u32(0), u32(0), u32(0), u32(0), 318 }; 319 append(Buffer, ImportDescriptor); 320 321 const coff_relocation RelocationTable[NumberOfRelocations] = { 322 {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2), 323 u16(getImgRelRelocation(NativeMachine))}, 324 {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)), 325 u32(3), u16(getImgRelRelocation(NativeMachine))}, 326 {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)), 327 u32(4), u16(getImgRelRelocation(NativeMachine))}, 328 }; 329 append(Buffer, RelocationTable); 330 331 // .idata$6 332 auto S = Buffer.size(); 333 Buffer.resize(S + ImportName.size() + 1); 334 memcpy(&Buffer[S], ImportName.data(), ImportName.size()); 335 Buffer[S + ImportName.size()] = '\0'; 336 337 // Symbol Table 338 coff_symbol16 SymbolTable[NumberOfSymbols] = { 339 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 340 u32(0), 341 u16(1), 342 u16(0), 343 IMAGE_SYM_CLASS_EXTERNAL, 344 0}, 345 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}}, 346 u32(0), 347 u16(1), 348 u16(0), 349 IMAGE_SYM_CLASS_SECTION, 350 0}, 351 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}}, 352 u32(0), 353 u16(2), 354 u16(0), 355 IMAGE_SYM_CLASS_STATIC, 356 0}, 357 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}}, 358 u32(0), 359 u16(0), 360 u16(0), 361 IMAGE_SYM_CLASS_SECTION, 362 0}, 363 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}}, 364 u32(0), 365 u16(0), 366 u16(0), 367 IMAGE_SYM_CLASS_SECTION, 368 0}, 369 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 370 u32(0), 371 u16(0), 372 u16(0), 373 IMAGE_SYM_CLASS_EXTERNAL, 374 0}, 375 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 376 u32(0), 377 u16(0), 378 u16(0), 379 IMAGE_SYM_CLASS_EXTERNAL, 380 0}, 381 }; 382 // TODO: Name.Offset.Offset here and in the all similar places below 383 // suggests a names refactoring. Maybe StringTableOffset.Value? 384 SymbolTable[0].Name.Offset.Offset = 385 sizeof(uint32_t); 386 SymbolTable[5].Name.Offset.Offset = 387 sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1; 388 SymbolTable[6].Name.Offset.Offset = 389 sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 + 390 NullImportDescriptorSymbolName.length() + 1; 391 append(Buffer, SymbolTable); 392 393 // String Table 394 writeStringTable(Buffer, 395 {ImportDescriptorSymbolName, NullImportDescriptorSymbolName, 396 NullThunkSymbolName}); 397 398 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; 399 return {MemoryBufferRef(F, ImportName)}; 400 } 401 402 NewArchiveMember 403 ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) { 404 const uint32_t NumberOfSections = 1; 405 const uint32_t NumberOfSymbols = 1; 406 407 // COFF Header 408 coff_file_header Header{ 409 u16(NativeMachine), 410 u16(NumberOfSections), 411 u32(0), 412 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + 413 // .idata$3 414 sizeof(coff_import_directory_table_entry)), 415 u32(NumberOfSymbols), 416 u16(0), 417 u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE), 418 }; 419 append(Buffer, Header); 420 421 // Section Header Table 422 const coff_section SectionTable[NumberOfSections] = { 423 {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'}, 424 u32(0), 425 u32(0), 426 u32(sizeof(coff_import_directory_table_entry)), 427 u32(sizeof(coff_file_header) + 428 (NumberOfSections * sizeof(coff_section))), 429 u32(0), 430 u32(0), 431 u16(0), 432 u16(0), 433 u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | 434 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, 435 }; 436 append(Buffer, SectionTable); 437 438 // .idata$3 439 const coff_import_directory_table_entry ImportDescriptor{ 440 u32(0), u32(0), u32(0), u32(0), u32(0), 441 }; 442 append(Buffer, ImportDescriptor); 443 444 // Symbol Table 445 coff_symbol16 SymbolTable[NumberOfSymbols] = { 446 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 447 u32(0), 448 u16(1), 449 u16(0), 450 IMAGE_SYM_CLASS_EXTERNAL, 451 0}, 452 }; 453 SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t); 454 append(Buffer, SymbolTable); 455 456 // String Table 457 writeStringTable(Buffer, {NullImportDescriptorSymbolName}); 458 459 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; 460 return {MemoryBufferRef(F, ImportName)}; 461 } 462 463 NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) { 464 const uint32_t NumberOfSections = 2; 465 const uint32_t NumberOfSymbols = 1; 466 uint32_t VASize = is64Bit() ? 8 : 4; 467 468 // COFF Header 469 coff_file_header Header{ 470 u16(NativeMachine), 471 u16(NumberOfSections), 472 u32(0), 473 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + 474 // .idata$5 475 VASize + 476 // .idata$4 477 VASize), 478 u32(NumberOfSymbols), 479 u16(0), 480 u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE), 481 }; 482 append(Buffer, Header); 483 484 // Section Header Table 485 const coff_section SectionTable[NumberOfSections] = { 486 {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}, 487 u32(0), 488 u32(0), 489 u32(VASize), 490 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), 491 u32(0), 492 u32(0), 493 u16(0), 494 u16(0), 495 u32((is64Bit() ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES) | 496 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | 497 IMAGE_SCN_MEM_WRITE)}, 498 {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}, 499 u32(0), 500 u32(0), 501 u32(VASize), 502 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + 503 VASize), 504 u32(0), 505 u32(0), 506 u16(0), 507 u16(0), 508 u32((is64Bit() ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES) | 509 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | 510 IMAGE_SCN_MEM_WRITE)}, 511 }; 512 append(Buffer, SectionTable); 513 514 // .idata$5, ILT 515 append(Buffer, u32(0)); 516 if (is64Bit()) 517 append(Buffer, u32(0)); 518 519 // .idata$4, IAT 520 append(Buffer, u32(0)); 521 if (is64Bit()) 522 append(Buffer, u32(0)); 523 524 // Symbol Table 525 coff_symbol16 SymbolTable[NumberOfSymbols] = { 526 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 527 u32(0), 528 u16(1), 529 u16(0), 530 IMAGE_SYM_CLASS_EXTERNAL, 531 0}, 532 }; 533 SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t); 534 append(Buffer, SymbolTable); 535 536 // String Table 537 writeStringTable(Buffer, {NullThunkSymbolName}); 538 539 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; 540 return {MemoryBufferRef{F, ImportName}}; 541 } 542 543 NewArchiveMember 544 ObjectFactory::createShortImport(StringRef Sym, uint16_t Ordinal, 545 ImportType ImportType, ImportNameType NameType, 546 StringRef ExportName, MachineTypes Machine) { 547 size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs 548 if (!ExportName.empty()) 549 ImpSize += ExportName.size() + 1; 550 size_t Size = sizeof(coff_import_header) + ImpSize; 551 char *Buf = Alloc.Allocate<char>(Size); 552 memset(Buf, 0, Size); 553 char *P = Buf; 554 555 // Write short import library. 556 auto *Imp = reinterpret_cast<coff_import_header *>(P); 557 P += sizeof(*Imp); 558 Imp->Sig2 = 0xFFFF; 559 Imp->Machine = Machine; 560 Imp->SizeOfData = ImpSize; 561 if (Ordinal > 0) 562 Imp->OrdinalHint = Ordinal; 563 Imp->TypeInfo = (NameType << 2) | ImportType; 564 565 // Write symbol name and DLL name. 566 memcpy(P, Sym.data(), Sym.size()); 567 P += Sym.size() + 1; 568 memcpy(P, ImportName.data(), ImportName.size()); 569 if (!ExportName.empty()) { 570 P += ImportName.size() + 1; 571 memcpy(P, ExportName.data(), ExportName.size()); 572 } 573 574 return {MemoryBufferRef(StringRef(Buf, Size), ImportName)}; 575 } 576 577 NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym, 578 StringRef Weak, bool Imp, 579 MachineTypes Machine) { 580 std::vector<uint8_t> Buffer; 581 const uint32_t NumberOfSections = 1; 582 const uint32_t NumberOfSymbols = 5; 583 584 // COFF Header 585 coff_file_header Header{ 586 u16(Machine), 587 u16(NumberOfSections), 588 u32(0), 589 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))), 590 u32(NumberOfSymbols), 591 u16(0), 592 u16(0), 593 }; 594 append(Buffer, Header); 595 596 // Section Header Table 597 const coff_section SectionTable[NumberOfSections] = { 598 {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'}, 599 u32(0), 600 u32(0), 601 u32(0), 602 u32(0), 603 u32(0), 604 u32(0), 605 u16(0), 606 u16(0), 607 u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}}; 608 append(Buffer, SectionTable); 609 610 // Symbol Table 611 coff_symbol16 SymbolTable[NumberOfSymbols] = { 612 {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}}, 613 u32(0), 614 u16(0xFFFF), 615 u16(0), 616 IMAGE_SYM_CLASS_STATIC, 617 0}, 618 {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}}, 619 u32(0), 620 u16(0xFFFF), 621 u16(0), 622 IMAGE_SYM_CLASS_STATIC, 623 0}, 624 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 625 u32(0), 626 u16(0), 627 u16(0), 628 IMAGE_SYM_CLASS_EXTERNAL, 629 0}, 630 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 631 u32(0), 632 u16(0), 633 u16(0), 634 IMAGE_SYM_CLASS_WEAK_EXTERNAL, 635 1}, 636 {{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}}, 637 u32(0), 638 u16(0), 639 u16(0), 640 IMAGE_SYM_CLASS_NULL, 641 0}, 642 }; 643 SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t); 644 645 //__imp_ String Table 646 StringRef Prefix = Imp ? "__imp_" : ""; 647 SymbolTable[3].Name.Offset.Offset = 648 sizeof(uint32_t) + Sym.size() + Prefix.size() + 1; 649 append(Buffer, SymbolTable); 650 writeStringTable(Buffer, {(Prefix + Sym).str(), 651 (Prefix + Weak).str()}); 652 653 // Copied here so we can still use writeStringTable 654 char *Buf = Alloc.Allocate<char>(Buffer.size()); 655 memcpy(Buf, Buffer.data(), Buffer.size()); 656 return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)}; 657 } 658 659 Error writeImportLibrary(StringRef ImportName, StringRef Path, 660 ArrayRef<COFFShortExport> Exports, 661 MachineTypes Machine, bool MinGW, 662 ArrayRef<COFFShortExport> NativeExports) { 663 664 MachineTypes NativeMachine = Machine; 665 if (isArm64EC(Machine)) { 666 NativeMachine = IMAGE_FILE_MACHINE_ARM64; 667 Machine = IMAGE_FILE_MACHINE_ARM64EC; 668 } 669 670 std::vector<NewArchiveMember> Members; 671 ObjectFactory OF(llvm::sys::path::filename(ImportName), NativeMachine); 672 673 std::vector<uint8_t> ImportDescriptor; 674 Members.push_back(OF.createImportDescriptor(ImportDescriptor)); 675 676 std::vector<uint8_t> NullImportDescriptor; 677 Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor)); 678 679 std::vector<uint8_t> NullThunk; 680 Members.push_back(OF.createNullThunk(NullThunk)); 681 682 auto addExports = [&](ArrayRef<COFFShortExport> Exp, 683 MachineTypes M) -> Error { 684 StringMap<std::string> RegularImports; 685 struct Deferred { 686 std::string Name; 687 ImportType ImpType; 688 const COFFShortExport *Export; 689 }; 690 SmallVector<Deferred, 0> Renames; 691 for (const COFFShortExport &E : Exp) { 692 if (E.Private) 693 continue; 694 695 ImportType ImportType = IMPORT_CODE; 696 if (E.Data) 697 ImportType = IMPORT_DATA; 698 if (E.Constant) 699 ImportType = IMPORT_CONST; 700 701 StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName; 702 std::string Name; 703 704 if (E.ExtName.empty()) { 705 Name = std::string(SymbolName); 706 } else { 707 Expected<std::string> ReplacedName = 708 replace(SymbolName, E.Name, E.ExtName); 709 if (!ReplacedName) 710 return ReplacedName.takeError(); 711 Name.swap(*ReplacedName); 712 } 713 714 ImportNameType NameType; 715 std::string ExportName; 716 if (E.Noname) { 717 NameType = IMPORT_ORDINAL; 718 } else if (!E.ExportAs.empty()) { 719 NameType = IMPORT_NAME_EXPORTAS; 720 ExportName = E.ExportAs; 721 } else if (!E.ImportName.empty()) { 722 // If we need to import from a specific ImportName, we may need to use 723 // a weak alias (which needs another import to point at). But if we can 724 // express ImportName based on the symbol name and a specific NameType, 725 // prefer that over an alias. 726 if (Machine == IMAGE_FILE_MACHINE_I386 && 727 applyNameType(IMPORT_NAME_UNDECORATE, Name) == E.ImportName) 728 NameType = IMPORT_NAME_UNDECORATE; 729 else if (Machine == IMAGE_FILE_MACHINE_I386 && 730 applyNameType(IMPORT_NAME_NOPREFIX, Name) == E.ImportName) 731 NameType = IMPORT_NAME_NOPREFIX; 732 else if (isArm64EC(M)) { 733 NameType = IMPORT_NAME_EXPORTAS; 734 ExportName = E.ImportName; 735 } else if (Name == E.ImportName) 736 NameType = IMPORT_NAME; 737 else { 738 Deferred D; 739 D.Name = Name; 740 D.ImpType = ImportType; 741 D.Export = &E; 742 Renames.push_back(D); 743 continue; 744 } 745 } else { 746 NameType = getNameType(SymbolName, E.Name, M, MinGW); 747 } 748 749 // On ARM64EC, use EXPORTAS to import demangled name for mangled symbols. 750 if (ImportType == IMPORT_CODE && isArm64EC(M)) { 751 if (std::optional<std::string> MangledName = 752 getArm64ECMangledFunctionName(Name)) { 753 if (!E.Noname && ExportName.empty()) { 754 NameType = IMPORT_NAME_EXPORTAS; 755 ExportName.swap(Name); 756 } 757 Name = std::move(*MangledName); 758 } else if (!E.Noname && ExportName.empty()) { 759 NameType = IMPORT_NAME_EXPORTAS; 760 ExportName = std::move(*getArm64ECDemangledFunctionName(Name)); 761 } 762 } 763 764 RegularImports[applyNameType(NameType, Name)] = Name; 765 Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType, 766 NameType, ExportName, M)); 767 } 768 for (const auto &D : Renames) { 769 auto It = RegularImports.find(D.Export->ImportName); 770 if (It != RegularImports.end()) { 771 // We have a regular import entry for a symbol with the name we 772 // want to reference; produce an alias pointing at that. 773 StringRef Symbol = It->second; 774 if (D.ImpType == IMPORT_CODE) 775 Members.push_back(OF.createWeakExternal(Symbol, D.Name, false, M)); 776 Members.push_back(OF.createWeakExternal(Symbol, D.Name, true, M)); 777 } else { 778 Members.push_back(OF.createShortImport(D.Name, D.Export->Ordinal, 779 D.ImpType, IMPORT_NAME_EXPORTAS, 780 D.Export->ImportName, M)); 781 } 782 } 783 return Error::success(); 784 }; 785 786 if (Error e = addExports(Exports, Machine)) 787 return e; 788 if (Error e = addExports(NativeExports, NativeMachine)) 789 return e; 790 791 return writeArchive(Path, Members, SymtabWritingMode::NormalSymtab, 792 object::Archive::K_COFF, 793 /*Deterministic*/ true, /*Thin*/ false, 794 /*OldArchiveBuf*/ nullptr, isArm64EC(Machine)); 795 } 796 797 } // namespace object 798 } // namespace llvm 799