Path: blob/main/contrib/llvm-project/llvm/lib/Object/COFFImportFile.cpp
35232 views
//===- COFFImportFile.cpp - COFF short import file implementation ---------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines the writeImportLibrary function.9//10//===----------------------------------------------------------------------===//1112#include "llvm/Object/COFFImportFile.h"13#include "llvm/ADT/ArrayRef.h"14#include "llvm/ADT/SmallVector.h"15#include "llvm/ADT/StringMap.h"16#include "llvm/ADT/Twine.h"17#include "llvm/Object/Archive.h"18#include "llvm/Object/ArchiveWriter.h"19#include "llvm/Object/COFF.h"20#include "llvm/Support/Allocator.h"21#include "llvm/Support/Endian.h"22#include "llvm/Support/Error.h"23#include "llvm/Support/ErrorHandling.h"24#include "llvm/Support/Path.h"2526#include <cstdint>27#include <string>28#include <vector>2930using namespace llvm::COFF;31using namespace llvm::object;32using namespace llvm;3334namespace llvm {35namespace object {3637StringRef COFFImportFile::getFileFormatName() const {38switch (getMachine()) {39case COFF::IMAGE_FILE_MACHINE_I386:40return "COFF-import-file-i386";41case COFF::IMAGE_FILE_MACHINE_AMD64:42return "COFF-import-file-x86-64";43case COFF::IMAGE_FILE_MACHINE_ARMNT:44return "COFF-import-file-ARM";45case COFF::IMAGE_FILE_MACHINE_ARM64:46return "COFF-import-file-ARM64";47case COFF::IMAGE_FILE_MACHINE_ARM64EC:48return "COFF-import-file-ARM64EC";49case COFF::IMAGE_FILE_MACHINE_ARM64X:50return "COFF-import-file-ARM64X";51default:52return "COFF-import-file-<unknown arch>";53}54}5556static StringRef applyNameType(ImportNameType Type, StringRef name) {57auto ltrim1 = [](StringRef s, StringRef chars) {58return !s.empty() && chars.contains(s[0]) ? s.substr(1) : s;59};6061switch (Type) {62case IMPORT_NAME_NOPREFIX:63name = ltrim1(name, "?@_");64break;65case IMPORT_NAME_UNDECORATE:66name = ltrim1(name, "?@_");67name = name.substr(0, name.find('@'));68break;69default:70break;71}72return name;73}7475StringRef COFFImportFile::getExportName() const {76const coff_import_header *hdr = getCOFFImportHeader();77StringRef name = Data.getBuffer().substr(sizeof(*hdr)).split('\0').first;7879switch (hdr->getNameType()) {80case IMPORT_ORDINAL:81name = "";82break;83case IMPORT_NAME_NOPREFIX:84case IMPORT_NAME_UNDECORATE:85name = applyNameType(static_cast<ImportNameType>(hdr->getNameType()), name);86break;87case IMPORT_NAME_EXPORTAS: {88// Skip DLL name89name = Data.getBuffer().substr(sizeof(*hdr) + name.size() + 1);90name = name.split('\0').second.split('\0').first;91break;92}93default:94break;95}9697return name;98}99100Error COFFImportFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const {101switch (Symb.p) {102case ImpSymbol:103OS << "__imp_";104break;105case ECAuxSymbol:106OS << "__imp_aux_";107break;108}109const char *Name = Data.getBufferStart() + sizeof(coff_import_header);110if (Symb.p != ECThunkSymbol && COFF::isArm64EC(getMachine())) {111if (std::optional<std::string> DemangledName =112getArm64ECDemangledFunctionName(Name)) {113OS << StringRef(*DemangledName);114return Error::success();115}116}117OS << StringRef(Name);118return Error::success();119}120121static uint16_t getImgRelRelocation(MachineTypes Machine) {122switch (Machine) {123default:124llvm_unreachable("unsupported machine");125case IMAGE_FILE_MACHINE_AMD64:126return IMAGE_REL_AMD64_ADDR32NB;127case IMAGE_FILE_MACHINE_ARMNT:128return IMAGE_REL_ARM_ADDR32NB;129case IMAGE_FILE_MACHINE_ARM64:130case IMAGE_FILE_MACHINE_ARM64EC:131case IMAGE_FILE_MACHINE_ARM64X:132return IMAGE_REL_ARM64_ADDR32NB;133case IMAGE_FILE_MACHINE_I386:134return IMAGE_REL_I386_DIR32NB;135}136}137138template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {139size_t S = B.size();140B.resize(S + sizeof(T));141memcpy(&B[S], &Data, sizeof(T));142}143144static void writeStringTable(std::vector<uint8_t> &B,145ArrayRef<const std::string_view> Strings) {146// The COFF string table consists of a 4-byte value which is the size of the147// table, including the length field itself. This value is followed by the148// string content itself, which is an array of null-terminated C-style149// strings. The termination is important as they are referenced to by offset150// by the symbol entity in the file format.151152size_t Pos = B.size();153size_t Offset = B.size();154155// Skip over the length field, we will fill it in later as we will have156// computed the length while emitting the string content itself.157Pos += sizeof(uint32_t);158159for (const auto &S : Strings) {160B.resize(Pos + S.length() + 1);161std::copy(S.begin(), S.end(), std::next(B.begin(), Pos));162B[Pos + S.length()] = 0;163Pos += S.length() + 1;164}165166// Backfill the length of the table now that it has been computed.167support::ulittle32_t Length(B.size() - Offset);168support::endian::write32le(&B[Offset], Length);169}170171static ImportNameType getNameType(StringRef Sym, StringRef ExtName,172MachineTypes Machine, bool MinGW) {173// A decorated stdcall function in MSVC is exported with the174// type IMPORT_NAME, and the exported function name includes the175// the leading underscore. In MinGW on the other hand, a decorated176// stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX).177// See the comment in isDecorated in COFFModuleDefinition.cpp for more178// details.179if (ExtName.starts_with("_") && ExtName.contains('@') && !MinGW)180return IMPORT_NAME;181if (Sym != ExtName)182return IMPORT_NAME_UNDECORATE;183if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.starts_with("_"))184return IMPORT_NAME_NOPREFIX;185return IMPORT_NAME;186}187188static Expected<std::string> replace(StringRef S, StringRef From,189StringRef To) {190size_t Pos = S.find(From);191192// From and To may be mangled, but substrings in S may not.193if (Pos == StringRef::npos && From.starts_with("_") && To.starts_with("_")) {194From = From.substr(1);195To = To.substr(1);196Pos = S.find(From);197}198199if (Pos == StringRef::npos) {200return make_error<StringError>(201StringRef(Twine(S + ": replacing '" + From +202"' with '" + To + "' failed").str()), object_error::parse_failed);203}204205return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();206}207208namespace {209// This class constructs various small object files necessary to support linking210// symbols imported from a DLL. The contents are pretty strictly defined and211// nearly entirely static. The details of the structures files are defined in212// WINNT.h and the PE/COFF specification.213class ObjectFactory {214using u16 = support::ulittle16_t;215using u32 = support::ulittle32_t;216MachineTypes NativeMachine;217BumpPtrAllocator Alloc;218StringRef ImportName;219StringRef Library;220std::string ImportDescriptorSymbolName;221std::string NullThunkSymbolName;222223public:224ObjectFactory(StringRef S, MachineTypes M)225: NativeMachine(M), ImportName(S), Library(llvm::sys::path::stem(S)),226ImportDescriptorSymbolName((ImportDescriptorPrefix + Library).str()),227NullThunkSymbolName(228(NullThunkDataPrefix + Library + NullThunkDataSuffix).str()) {}229230// Creates an Import Descriptor. This is a small object file which contains a231// reference to the terminators and contains the library name (entry) for the232// import name table. It will force the linker to construct the necessary233// structure to import symbols from the DLL.234NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);235236// Creates a NULL import descriptor. This is a small object file whcih237// contains a NULL import descriptor. It is used to terminate the imports238// from a specific DLL.239NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);240241// Create a NULL Thunk Entry. This is a small object file which contains a242// NULL Import Address Table entry and a NULL Import Lookup Table Entry. It243// is used to terminate the IAT and ILT.244NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);245246// Create a short import file which is described in PE/COFF spec 7. Import247// Library Format.248NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,249ImportType Type, ImportNameType NameType,250StringRef ExportName,251MachineTypes Machine);252253// Create a weak external file which is described in PE/COFF Aux Format 3.254NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp,255MachineTypes Machine);256257bool is64Bit() const { return COFF::is64Bit(NativeMachine); }258};259} // namespace260261NewArchiveMember262ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {263const uint32_t NumberOfSections = 2;264const uint32_t NumberOfSymbols = 7;265const uint32_t NumberOfRelocations = 3;266267// COFF Header268coff_file_header Header{269u16(NativeMachine),270u16(NumberOfSections),271u32(0),272u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +273// .idata$2274sizeof(coff_import_directory_table_entry) +275NumberOfRelocations * sizeof(coff_relocation) +276// .idata$4277(ImportName.size() + 1)),278u32(NumberOfSymbols),279u16(0),280u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE),281};282append(Buffer, Header);283284// Section Header Table285const coff_section SectionTable[NumberOfSections] = {286{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},287u32(0),288u32(0),289u32(sizeof(coff_import_directory_table_entry)),290u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),291u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +292sizeof(coff_import_directory_table_entry)),293u32(0),294u16(NumberOfRelocations),295u16(0),296u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |297IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},298{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},299u32(0),300u32(0),301u32(ImportName.size() + 1),302u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +303sizeof(coff_import_directory_table_entry) +304NumberOfRelocations * sizeof(coff_relocation)),305u32(0),306u32(0),307u16(0),308u16(0),309u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |310IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},311};312append(Buffer, SectionTable);313314// .idata$2315const coff_import_directory_table_entry ImportDescriptor{316u32(0), u32(0), u32(0), u32(0), u32(0),317};318append(Buffer, ImportDescriptor);319320const coff_relocation RelocationTable[NumberOfRelocations] = {321{u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),322u16(getImgRelRelocation(NativeMachine))},323{u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),324u32(3), u16(getImgRelRelocation(NativeMachine))},325{u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),326u32(4), u16(getImgRelRelocation(NativeMachine))},327};328append(Buffer, RelocationTable);329330// .idata$6331auto S = Buffer.size();332Buffer.resize(S + ImportName.size() + 1);333memcpy(&Buffer[S], ImportName.data(), ImportName.size());334Buffer[S + ImportName.size()] = '\0';335336// Symbol Table337coff_symbol16 SymbolTable[NumberOfSymbols] = {338{{{0, 0, 0, 0, 0, 0, 0, 0}},339u32(0),340u16(1),341u16(0),342IMAGE_SYM_CLASS_EXTERNAL,3430},344{{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},345u32(0),346u16(1),347u16(0),348IMAGE_SYM_CLASS_SECTION,3490},350{{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},351u32(0),352u16(2),353u16(0),354IMAGE_SYM_CLASS_STATIC,3550},356{{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},357u32(0),358u16(0),359u16(0),360IMAGE_SYM_CLASS_SECTION,3610},362{{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},363u32(0),364u16(0),365u16(0),366IMAGE_SYM_CLASS_SECTION,3670},368{{{0, 0, 0, 0, 0, 0, 0, 0}},369u32(0),370u16(0),371u16(0),372IMAGE_SYM_CLASS_EXTERNAL,3730},374{{{0, 0, 0, 0, 0, 0, 0, 0}},375u32(0),376u16(0),377u16(0),378IMAGE_SYM_CLASS_EXTERNAL,3790},380};381// TODO: Name.Offset.Offset here and in the all similar places below382// suggests a names refactoring. Maybe StringTableOffset.Value?383SymbolTable[0].Name.Offset.Offset =384sizeof(uint32_t);385SymbolTable[5].Name.Offset.Offset =386sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;387SymbolTable[6].Name.Offset.Offset =388sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +389NullImportDescriptorSymbolName.length() + 1;390append(Buffer, SymbolTable);391392// String Table393writeStringTable(Buffer,394{ImportDescriptorSymbolName, NullImportDescriptorSymbolName,395NullThunkSymbolName});396397StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};398return {MemoryBufferRef(F, ImportName)};399}400401NewArchiveMember402ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {403const uint32_t NumberOfSections = 1;404const uint32_t NumberOfSymbols = 1;405406// COFF Header407coff_file_header Header{408u16(NativeMachine),409u16(NumberOfSections),410u32(0),411u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +412// .idata$3413sizeof(coff_import_directory_table_entry)),414u32(NumberOfSymbols),415u16(0),416u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE),417};418append(Buffer, Header);419420// Section Header Table421const coff_section SectionTable[NumberOfSections] = {422{{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},423u32(0),424u32(0),425u32(sizeof(coff_import_directory_table_entry)),426u32(sizeof(coff_file_header) +427(NumberOfSections * sizeof(coff_section))),428u32(0),429u32(0),430u16(0),431u16(0),432u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |433IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},434};435append(Buffer, SectionTable);436437// .idata$3438const coff_import_directory_table_entry ImportDescriptor{439u32(0), u32(0), u32(0), u32(0), u32(0),440};441append(Buffer, ImportDescriptor);442443// Symbol Table444coff_symbol16 SymbolTable[NumberOfSymbols] = {445{{{0, 0, 0, 0, 0, 0, 0, 0}},446u32(0),447u16(1),448u16(0),449IMAGE_SYM_CLASS_EXTERNAL,4500},451};452SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);453append(Buffer, SymbolTable);454455// String Table456writeStringTable(Buffer, {NullImportDescriptorSymbolName});457458StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};459return {MemoryBufferRef(F, ImportName)};460}461462NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {463const uint32_t NumberOfSections = 2;464const uint32_t NumberOfSymbols = 1;465uint32_t VASize = is64Bit() ? 8 : 4;466467// COFF Header468coff_file_header Header{469u16(NativeMachine),470u16(NumberOfSections),471u32(0),472u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +473// .idata$5474VASize +475// .idata$4476VASize),477u32(NumberOfSymbols),478u16(0),479u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE),480};481append(Buffer, Header);482483// Section Header Table484const coff_section SectionTable[NumberOfSections] = {485{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},486u32(0),487u32(0),488u32(VASize),489u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),490u32(0),491u32(0),492u16(0),493u16(0),494u32((is64Bit() ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES) |495IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |496IMAGE_SCN_MEM_WRITE)},497{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},498u32(0),499u32(0),500u32(VASize),501u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +502VASize),503u32(0),504u32(0),505u16(0),506u16(0),507u32((is64Bit() ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES) |508IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |509IMAGE_SCN_MEM_WRITE)},510};511append(Buffer, SectionTable);512513// .idata$5, ILT514append(Buffer, u32(0));515if (is64Bit())516append(Buffer, u32(0));517518// .idata$4, IAT519append(Buffer, u32(0));520if (is64Bit())521append(Buffer, u32(0));522523// Symbol Table524coff_symbol16 SymbolTable[NumberOfSymbols] = {525{{{0, 0, 0, 0, 0, 0, 0, 0}},526u32(0),527u16(1),528u16(0),529IMAGE_SYM_CLASS_EXTERNAL,5300},531};532SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);533append(Buffer, SymbolTable);534535// String Table536writeStringTable(Buffer, {NullThunkSymbolName});537538StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};539return {MemoryBufferRef{F, ImportName}};540}541542NewArchiveMember543ObjectFactory::createShortImport(StringRef Sym, uint16_t Ordinal,544ImportType ImportType, ImportNameType NameType,545StringRef ExportName, MachineTypes Machine) {546size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs547if (!ExportName.empty())548ImpSize += ExportName.size() + 1;549size_t Size = sizeof(coff_import_header) + ImpSize;550char *Buf = Alloc.Allocate<char>(Size);551memset(Buf, 0, Size);552char *P = Buf;553554// Write short import library.555auto *Imp = reinterpret_cast<coff_import_header *>(P);556P += sizeof(*Imp);557Imp->Sig2 = 0xFFFF;558Imp->Machine = Machine;559Imp->SizeOfData = ImpSize;560if (Ordinal > 0)561Imp->OrdinalHint = Ordinal;562Imp->TypeInfo = (NameType << 2) | ImportType;563564// Write symbol name and DLL name.565memcpy(P, Sym.data(), Sym.size());566P += Sym.size() + 1;567memcpy(P, ImportName.data(), ImportName.size());568if (!ExportName.empty()) {569P += ImportName.size() + 1;570memcpy(P, ExportName.data(), ExportName.size());571}572573return {MemoryBufferRef(StringRef(Buf, Size), ImportName)};574}575576NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym,577StringRef Weak, bool Imp,578MachineTypes Machine) {579std::vector<uint8_t> Buffer;580const uint32_t NumberOfSections = 1;581const uint32_t NumberOfSymbols = 5;582583// COFF Header584coff_file_header Header{585u16(Machine),586u16(NumberOfSections),587u32(0),588u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))),589u32(NumberOfSymbols),590u16(0),591u16(0),592};593append(Buffer, Header);594595// Section Header Table596const coff_section SectionTable[NumberOfSections] = {597{{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'},598u32(0),599u32(0),600u32(0),601u32(0),602u32(0),603u32(0),604u16(0),605u16(0),606u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}};607append(Buffer, SectionTable);608609// Symbol Table610coff_symbol16 SymbolTable[NumberOfSymbols] = {611{{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},612u32(0),613u16(0xFFFF),614u16(0),615IMAGE_SYM_CLASS_STATIC,6160},617{{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}},618u32(0),619u16(0xFFFF),620u16(0),621IMAGE_SYM_CLASS_STATIC,6220},623{{{0, 0, 0, 0, 0, 0, 0, 0}},624u32(0),625u16(0),626u16(0),627IMAGE_SYM_CLASS_EXTERNAL,6280},629{{{0, 0, 0, 0, 0, 0, 0, 0}},630u32(0),631u16(0),632u16(0),633IMAGE_SYM_CLASS_WEAK_EXTERNAL,6341},635{{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}},636u32(0),637u16(0),638u16(0),639IMAGE_SYM_CLASS_NULL,6400},641};642SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t);643644//__imp_ String Table645StringRef Prefix = Imp ? "__imp_" : "";646SymbolTable[3].Name.Offset.Offset =647sizeof(uint32_t) + Sym.size() + Prefix.size() + 1;648append(Buffer, SymbolTable);649writeStringTable(Buffer, {(Prefix + Sym).str(),650(Prefix + Weak).str()});651652// Copied here so we can still use writeStringTable653char *Buf = Alloc.Allocate<char>(Buffer.size());654memcpy(Buf, Buffer.data(), Buffer.size());655return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)};656}657658Error writeImportLibrary(StringRef ImportName, StringRef Path,659ArrayRef<COFFShortExport> Exports,660MachineTypes Machine, bool MinGW,661ArrayRef<COFFShortExport> NativeExports) {662663MachineTypes NativeMachine = Machine;664if (isArm64EC(Machine)) {665NativeMachine = IMAGE_FILE_MACHINE_ARM64;666Machine = IMAGE_FILE_MACHINE_ARM64EC;667}668669std::vector<NewArchiveMember> Members;670ObjectFactory OF(llvm::sys::path::filename(ImportName), NativeMachine);671672std::vector<uint8_t> ImportDescriptor;673Members.push_back(OF.createImportDescriptor(ImportDescriptor));674675std::vector<uint8_t> NullImportDescriptor;676Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));677678std::vector<uint8_t> NullThunk;679Members.push_back(OF.createNullThunk(NullThunk));680681auto addExports = [&](ArrayRef<COFFShortExport> Exp,682MachineTypes M) -> Error {683StringMap<std::string> RegularImports;684struct Deferred {685std::string Name;686ImportType ImpType;687const COFFShortExport *Export;688};689SmallVector<Deferred, 0> Renames;690for (const COFFShortExport &E : Exp) {691if (E.Private)692continue;693694ImportType ImportType = IMPORT_CODE;695if (E.Data)696ImportType = IMPORT_DATA;697if (E.Constant)698ImportType = IMPORT_CONST;699700StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName;701std::string Name;702703if (E.ExtName.empty()) {704Name = std::string(SymbolName);705} else {706Expected<std::string> ReplacedName =707replace(SymbolName, E.Name, E.ExtName);708if (!ReplacedName)709return ReplacedName.takeError();710Name.swap(*ReplacedName);711}712713ImportNameType NameType;714std::string ExportName;715if (E.Noname) {716NameType = IMPORT_ORDINAL;717} else if (!E.ExportAs.empty()) {718NameType = IMPORT_NAME_EXPORTAS;719ExportName = E.ExportAs;720} else if (!E.ImportName.empty()) {721// If we need to import from a specific ImportName, we may need to use722// a weak alias (which needs another import to point at). But if we can723// express ImportName based on the symbol name and a specific NameType,724// prefer that over an alias.725if (Machine == IMAGE_FILE_MACHINE_I386 &&726applyNameType(IMPORT_NAME_UNDECORATE, Name) == E.ImportName)727NameType = IMPORT_NAME_UNDECORATE;728else if (Machine == IMAGE_FILE_MACHINE_I386 &&729applyNameType(IMPORT_NAME_NOPREFIX, Name) == E.ImportName)730NameType = IMPORT_NAME_NOPREFIX;731else if (isArm64EC(M)) {732NameType = IMPORT_NAME_EXPORTAS;733ExportName = E.ImportName;734} else if (Name == E.ImportName)735NameType = IMPORT_NAME;736else {737Deferred D;738D.Name = Name;739D.ImpType = ImportType;740D.Export = &E;741Renames.push_back(D);742continue;743}744} else {745NameType = getNameType(SymbolName, E.Name, M, MinGW);746}747748// On ARM64EC, use EXPORTAS to import demangled name for mangled symbols.749if (ImportType == IMPORT_CODE && isArm64EC(M)) {750if (std::optional<std::string> MangledName =751getArm64ECMangledFunctionName(Name)) {752if (!E.Noname && ExportName.empty()) {753NameType = IMPORT_NAME_EXPORTAS;754ExportName.swap(Name);755}756Name = std::move(*MangledName);757} else if (!E.Noname && ExportName.empty()) {758NameType = IMPORT_NAME_EXPORTAS;759ExportName = std::move(*getArm64ECDemangledFunctionName(Name));760}761}762763RegularImports[applyNameType(NameType, Name)] = Name;764Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType,765NameType, ExportName, M));766}767for (const auto &D : Renames) {768auto It = RegularImports.find(D.Export->ImportName);769if (It != RegularImports.end()) {770// We have a regular import entry for a symbol with the name we771// want to reference; produce an alias pointing at that.772StringRef Symbol = It->second;773if (D.ImpType == IMPORT_CODE)774Members.push_back(OF.createWeakExternal(Symbol, D.Name, false, M));775Members.push_back(OF.createWeakExternal(Symbol, D.Name, true, M));776} else {777Members.push_back(OF.createShortImport(D.Name, D.Export->Ordinal,778D.ImpType, IMPORT_NAME_EXPORTAS,779D.Export->ImportName, M));780}781}782return Error::success();783};784785if (Error e = addExports(Exports, Machine))786return e;787if (Error e = addExports(NativeExports, NativeMachine))788return e;789790return writeArchive(Path, Members, SymtabWritingMode::NormalSymtab,791object::Archive::K_COFF,792/*Deterministic*/ true, /*Thin*/ false,793/*OldArchiveBuf*/ nullptr, isArm64EC(Machine));794}795796} // namespace object797} // namespace llvm798799800