brintos

brintos / llvm-project-archived public Read only

0
0
Text · 25.8 KiB · 5ef5ea3 Raw
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