| //===- COFFImportFile.cpp - COFF short import file implementation ---------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines the writeImportLibrary function. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/Object/COFFImportFile.h" |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/Object/Archive.h" |
| #include "llvm/Object/ArchiveWriter.h" |
| #include "llvm/Object/COFF.h" |
| #include "llvm/Support/Error.h" |
| #include "llvm/Support/Path.h" |
| |
| #include <cstdint> |
| #include <string> |
| #include <vector> |
| |
| using namespace llvm::COFF; |
| using namespace llvm::object; |
| using namespace llvm; |
| |
| namespace llvm { |
| namespace object { |
| |
| static bool is32bit(MachineTypes Machine) { |
| switch (Machine) { |
| default: |
| llvm_unreachable("unsupported machine"); |
| case IMAGE_FILE_MACHINE_ARM64: |
| case IMAGE_FILE_MACHINE_AMD64: |
| return false; |
| case IMAGE_FILE_MACHINE_ARMNT: |
| case IMAGE_FILE_MACHINE_I386: |
| return true; |
| } |
| } |
| |
| static uint16_t getImgRelRelocation(MachineTypes Machine) { |
| switch (Machine) { |
| default: |
| llvm_unreachable("unsupported machine"); |
| case IMAGE_FILE_MACHINE_AMD64: |
| return IMAGE_REL_AMD64_ADDR32NB; |
| case IMAGE_FILE_MACHINE_ARMNT: |
| return IMAGE_REL_ARM_ADDR32NB; |
| case IMAGE_FILE_MACHINE_ARM64: |
| return IMAGE_REL_ARM64_ADDR32NB; |
| case IMAGE_FILE_MACHINE_I386: |
| return IMAGE_REL_I386_DIR32NB; |
| } |
| } |
| |
| template <class T> static void append(std::vector<uint8_t> &B, const T &Data) { |
| size_t S = B.size(); |
| B.resize(S + sizeof(T)); |
| memcpy(&B[S], &Data, sizeof(T)); |
| } |
| |
| static void writeStringTable(std::vector<uint8_t> &B, |
| ArrayRef<const std::string> Strings) { |
| // The COFF string table consists of a 4-byte value which is the size of the |
| // table, including the length field itself. This value is followed by the |
| // string content itself, which is an array of null-terminated C-style |
| // strings. The termination is important as they are referenced to by offset |
| // by the symbol entity in the file format. |
| |
| size_t Pos = B.size(); |
| size_t Offset = B.size(); |
| |
| // Skip over the length field, we will fill it in later as we will have |
| // computed the length while emitting the string content itself. |
| Pos += sizeof(uint32_t); |
| |
| for (const auto &S : Strings) { |
| B.resize(Pos + S.length() + 1); |
| strcpy(reinterpret_cast<char *>(&B[Pos]), S.c_str()); |
| Pos += S.length() + 1; |
| } |
| |
| // Backfill the length of the table now that it has been computed. |
| support::ulittle32_t Length(B.size() - Offset); |
| support::endian::write32le(&B[Offset], Length); |
| } |
| |
| static ImportNameType getNameType(StringRef Sym, StringRef ExtName, |
| MachineTypes Machine, bool MinGW) { |
| // A decorated stdcall function in MSVC is exported with the |
| // type IMPORT_NAME, and the exported function name includes the |
| // the leading underscore. In MinGW on the other hand, a decorated |
| // stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX). |
| // See the comment in isDecorated in COFFModuleDefinition.cpp for more |
| // details. |
| if (ExtName.startswith("_") && ExtName.contains('@') && !MinGW) |
| return IMPORT_NAME; |
| if (Sym != ExtName) |
| return IMPORT_NAME_UNDECORATE; |
| if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.startswith("_")) |
| return IMPORT_NAME_NOPREFIX; |
| return IMPORT_NAME; |
| } |
| |
| static Expected<std::string> replace(StringRef S, StringRef From, |
| StringRef To) { |
| size_t Pos = S.find(From); |
| |
| // From and To may be mangled, but substrings in S may not. |
| if (Pos == StringRef::npos && From.startswith("_") && To.startswith("_")) { |
| From = From.substr(1); |
| To = To.substr(1); |
| Pos = S.find(From); |
| } |
| |
| if (Pos == StringRef::npos) { |
| return make_error<StringError>( |
| StringRef(Twine(S + ": replacing '" + From + |
| "' with '" + To + "' failed").str()), object_error::parse_failed); |
| } |
| |
| return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str(); |
| } |
| |
| static const std::string NullImportDescriptorSymbolName = |
| "__NULL_IMPORT_DESCRIPTOR"; |
| |
| namespace { |
| // This class constructs various small object files necessary to support linking |
| // symbols imported from a DLL. The contents are pretty strictly defined and |
| // nearly entirely static. The details of the structures files are defined in |
| // WINNT.h and the PE/COFF specification. |
| class ObjectFactory { |
| using u16 = support::ulittle16_t; |
| using u32 = support::ulittle32_t; |
| MachineTypes Machine; |
| BumpPtrAllocator Alloc; |
| StringRef ImportName; |
| StringRef Library; |
| std::string ImportDescriptorSymbolName; |
| std::string NullThunkSymbolName; |
| |
| public: |
| ObjectFactory(StringRef S, MachineTypes M) |
| : Machine(M), ImportName(S), Library(S.drop_back(4)), |
| ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()), |
| NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {} |
| |
| // Creates an Import Descriptor. This is a small object file which contains a |
| // reference to the terminators and contains the library name (entry) for the |
| // import name table. It will force the linker to construct the necessary |
| // structure to import symbols from the DLL. |
| NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer); |
| |
| // Creates a NULL import descriptor. This is a small object file whcih |
| // contains a NULL import descriptor. It is used to terminate the imports |
| // from a specific DLL. |
| NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer); |
| |
| // Create a NULL Thunk Entry. This is a small object file which contains a |
| // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It |
| // is used to terminate the IAT and ILT. |
| NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer); |
| |
| // Create a short import file which is described in PE/COFF spec 7. Import |
| // Library Format. |
| NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal, |
| ImportType Type, ImportNameType NameType); |
| |
| // Create a weak external file which is described in PE/COFF Aux Format 3. |
| NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp); |
| }; |
| } // namespace |
| |
| NewArchiveMember |
| ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) { |
| const uint32_t NumberOfSections = 2; |
| const uint32_t NumberOfSymbols = 7; |
| const uint32_t NumberOfRelocations = 3; |
| |
| // COFF Header |
| coff_file_header Header{ |
| u16(Machine), |
| u16(NumberOfSections), |
| u32(0), |
| u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + |
| // .idata$2 |
| sizeof(coff_import_directory_table_entry) + |
| NumberOfRelocations * sizeof(coff_relocation) + |
| // .idata$4 |
| (ImportName.size() + 1)), |
| u32(NumberOfSymbols), |
| u16(0), |
| u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid), |
| }; |
| append(Buffer, Header); |
| |
| // Section Header Table |
| const coff_section SectionTable[NumberOfSections] = { |
| {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}, |
| u32(0), |
| u32(0), |
| u32(sizeof(coff_import_directory_table_entry)), |
| u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), |
| u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + |
| sizeof(coff_import_directory_table_entry)), |
| u32(0), |
| u16(NumberOfRelocations), |
| u16(0), |
| u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | |
| IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, |
| {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}, |
| u32(0), |
| u32(0), |
| u32(ImportName.size() + 1), |
| u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + |
| sizeof(coff_import_directory_table_entry) + |
| NumberOfRelocations * sizeof(coff_relocation)), |
| u32(0), |
| u32(0), |
| u16(0), |
| u16(0), |
| u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | |
| IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, |
| }; |
| append(Buffer, SectionTable); |
| |
| // .idata$2 |
| const coff_import_directory_table_entry ImportDescriptor{ |
| u32(0), u32(0), u32(0), u32(0), u32(0), |
| }; |
| append(Buffer, ImportDescriptor); |
| |
| const coff_relocation RelocationTable[NumberOfRelocations] = { |
| {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2), |
| u16(getImgRelRelocation(Machine))}, |
| {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)), |
| u32(3), u16(getImgRelRelocation(Machine))}, |
| {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)), |
| u32(4), u16(getImgRelRelocation(Machine))}, |
| }; |
| append(Buffer, RelocationTable); |
| |
| // .idata$6 |
| auto S = Buffer.size(); |
| Buffer.resize(S + ImportName.size() + 1); |
| memcpy(&Buffer[S], ImportName.data(), ImportName.size()); |
| Buffer[S + ImportName.size()] = '\0'; |
| |
| // Symbol Table |
| coff_symbol16 SymbolTable[NumberOfSymbols] = { |
| {{{0, 0, 0, 0, 0, 0, 0, 0}}, |
| u32(0), |
| u16(1), |
| u16(0), |
| IMAGE_SYM_CLASS_EXTERNAL, |
| 0}, |
| {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}}, |
| u32(0), |
| u16(1), |
| u16(0), |
| IMAGE_SYM_CLASS_SECTION, |
| 0}, |
| {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}}, |
| u32(0), |
| u16(2), |
| u16(0), |
| IMAGE_SYM_CLASS_STATIC, |
| 0}, |
| {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}}, |
| u32(0), |
| u16(0), |
| u16(0), |
| IMAGE_SYM_CLASS_SECTION, |
| 0}, |
| {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}}, |
| u32(0), |
| u16(0), |
| u16(0), |
| IMAGE_SYM_CLASS_SECTION, |
| 0}, |
| {{{0, 0, 0, 0, 0, 0, 0, 0}}, |
| u32(0), |
| u16(0), |
| u16(0), |
| IMAGE_SYM_CLASS_EXTERNAL, |
| 0}, |
| {{{0, 0, 0, 0, 0, 0, 0, 0}}, |
| u32(0), |
| u16(0), |
| u16(0), |
| IMAGE_SYM_CLASS_EXTERNAL, |
| 0}, |
| }; |
| // TODO: Name.Offset.Offset here and in the all similar places below |
| // suggests a names refactoring. Maybe StringTableOffset.Value? |
| SymbolTable[0].Name.Offset.Offset = |
| sizeof(uint32_t); |
| SymbolTable[5].Name.Offset.Offset = |
| sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1; |
| SymbolTable[6].Name.Offset.Offset = |
| sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 + |
| NullImportDescriptorSymbolName.length() + 1; |
| append(Buffer, SymbolTable); |
| |
| // String Table |
| writeStringTable(Buffer, |
| {ImportDescriptorSymbolName, NullImportDescriptorSymbolName, |
| NullThunkSymbolName}); |
| |
| StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; |
| return {MemoryBufferRef(F, ImportName)}; |
| } |
| |
| NewArchiveMember |
| ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) { |
| const uint32_t NumberOfSections = 1; |
| const uint32_t NumberOfSymbols = 1; |
| |
| // COFF Header |
| coff_file_header Header{ |
| u16(Machine), |
| u16(NumberOfSections), |
| u32(0), |
| u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + |
| // .idata$3 |
| sizeof(coff_import_directory_table_entry)), |
| u32(NumberOfSymbols), |
| u16(0), |
| u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid), |
| }; |
| append(Buffer, Header); |
| |
| // Section Header Table |
| const coff_section SectionTable[NumberOfSections] = { |
| {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'}, |
| u32(0), |
| u32(0), |
| u32(sizeof(coff_import_directory_table_entry)), |
| u32(sizeof(coff_file_header) + |
| (NumberOfSections * sizeof(coff_section))), |
| u32(0), |
| u32(0), |
| u16(0), |
| u16(0), |
| u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | |
| IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, |
| }; |
| append(Buffer, SectionTable); |
| |
| // .idata$3 |
| const coff_import_directory_table_entry ImportDescriptor{ |
| u32(0), u32(0), u32(0), u32(0), u32(0), |
| }; |
| append(Buffer, ImportDescriptor); |
| |
| // Symbol Table |
| coff_symbol16 SymbolTable[NumberOfSymbols] = { |
| {{{0, 0, 0, 0, 0, 0, 0, 0}}, |
| u32(0), |
| u16(1), |
| u16(0), |
| IMAGE_SYM_CLASS_EXTERNAL, |
| 0}, |
| }; |
| SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t); |
| append(Buffer, SymbolTable); |
| |
| // String Table |
| writeStringTable(Buffer, {NullImportDescriptorSymbolName}); |
| |
| StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; |
| return {MemoryBufferRef(F, ImportName)}; |
| } |
| |
| NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) { |
| const uint32_t NumberOfSections = 2; |
| const uint32_t NumberOfSymbols = 1; |
| uint32_t VASize = is32bit(Machine) ? 4 : 8; |
| |
| // COFF Header |
| coff_file_header Header{ |
| u16(Machine), |
| u16(NumberOfSections), |
| u32(0), |
| u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + |
| // .idata$5 |
| VASize + |
| // .idata$4 |
| VASize), |
| u32(NumberOfSymbols), |
| u16(0), |
| u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid), |
| }; |
| append(Buffer, Header); |
| |
| // Section Header Table |
| const coff_section SectionTable[NumberOfSections] = { |
| {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}, |
| u32(0), |
| u32(0), |
| u32(VASize), |
| u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), |
| u32(0), |
| u32(0), |
| u16(0), |
| u16(0), |
| u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES |
| : IMAGE_SCN_ALIGN_8BYTES) | |
| IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | |
| IMAGE_SCN_MEM_WRITE)}, |
| {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}, |
| u32(0), |
| u32(0), |
| u32(VASize), |
| u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + |
| VASize), |
| u32(0), |
| u32(0), |
| u16(0), |
| u16(0), |
| u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES |
| : IMAGE_SCN_ALIGN_8BYTES) | |
| IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | |
| IMAGE_SCN_MEM_WRITE)}, |
| }; |
| append(Buffer, SectionTable); |
| |
| // .idata$5, ILT |
| append(Buffer, u32(0)); |
| if (!is32bit(Machine)) |
| append(Buffer, u32(0)); |
| |
| // .idata$4, IAT |
| append(Buffer, u32(0)); |
| if (!is32bit(Machine)) |
| append(Buffer, u32(0)); |
| |
| // Symbol Table |
| coff_symbol16 SymbolTable[NumberOfSymbols] = { |
| {{{0, 0, 0, 0, 0, 0, 0, 0}}, |
| u32(0), |
| u16(1), |
| u16(0), |
| IMAGE_SYM_CLASS_EXTERNAL, |
| 0}, |
| }; |
| SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t); |
| append(Buffer, SymbolTable); |
| |
| // String Table |
| writeStringTable(Buffer, {NullThunkSymbolName}); |
| |
| StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; |
| return {MemoryBufferRef{F, ImportName}}; |
| } |
| |
| NewArchiveMember ObjectFactory::createShortImport(StringRef Sym, |
| uint16_t Ordinal, |
| ImportType ImportType, |
| ImportNameType NameType) { |
| size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs |
| size_t Size = sizeof(coff_import_header) + ImpSize; |
| char *Buf = Alloc.Allocate<char>(Size); |
| memset(Buf, 0, Size); |
| char *P = Buf; |
| |
| // Write short import library. |
| auto *Imp = reinterpret_cast<coff_import_header *>(P); |
| P += sizeof(*Imp); |
| Imp->Sig2 = 0xFFFF; |
| Imp->Machine = Machine; |
| Imp->SizeOfData = ImpSize; |
| if (Ordinal > 0) |
| Imp->OrdinalHint = Ordinal; |
| Imp->TypeInfo = (NameType << 2) | ImportType; |
| |
| // Write symbol name and DLL name. |
| memcpy(P, Sym.data(), Sym.size()); |
| P += Sym.size() + 1; |
| memcpy(P, ImportName.data(), ImportName.size()); |
| |
| return {MemoryBufferRef(StringRef(Buf, Size), ImportName)}; |
| } |
| |
| NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym, |
| StringRef Weak, bool Imp) { |
| std::vector<uint8_t> Buffer; |
| const uint32_t NumberOfSections = 1; |
| const uint32_t NumberOfSymbols = 5; |
| |
| // COFF Header |
| coff_file_header Header{ |
| u16(Machine), |
| u16(NumberOfSections), |
| u32(0), |
| u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))), |
| u32(NumberOfSymbols), |
| u16(0), |
| u16(0), |
| }; |
| append(Buffer, Header); |
| |
| // Section Header Table |
| const coff_section SectionTable[NumberOfSections] = { |
| {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'}, |
| u32(0), |
| u32(0), |
| u32(0), |
| u32(0), |
| u32(0), |
| u32(0), |
| u16(0), |
| u16(0), |
| u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}}; |
| append(Buffer, SectionTable); |
| |
| // Symbol Table |
| coff_symbol16 SymbolTable[NumberOfSymbols] = { |
| {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}}, |
| u32(0), |
| u16(0xFFFF), |
| u16(0), |
| IMAGE_SYM_CLASS_STATIC, |
| 0}, |
| {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}}, |
| u32(0), |
| u16(0xFFFF), |
| u16(0), |
| IMAGE_SYM_CLASS_STATIC, |
| 0}, |
| {{{0, 0, 0, 0, 0, 0, 0, 0}}, |
| u32(0), |
| u16(0), |
| u16(0), |
| IMAGE_SYM_CLASS_EXTERNAL, |
| 0}, |
| {{{0, 0, 0, 0, 0, 0, 0, 0}}, |
| u32(0), |
| u16(0), |
| u16(0), |
| IMAGE_SYM_CLASS_WEAK_EXTERNAL, |
| 1}, |
| {{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}}, |
| u32(0), |
| u16(0), |
| u16(0), |
| IMAGE_SYM_CLASS_NULL, |
| 0}, |
| }; |
| SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t); |
| |
| //__imp_ String Table |
| StringRef Prefix = Imp ? "__imp_" : ""; |
| SymbolTable[3].Name.Offset.Offset = |
| sizeof(uint32_t) + Sym.size() + Prefix.size() + 1; |
| append(Buffer, SymbolTable); |
| writeStringTable(Buffer, {(Prefix + Sym).str(), |
| (Prefix + Weak).str()}); |
| |
| // Copied here so we can still use writeStringTable |
| char *Buf = Alloc.Allocate<char>(Buffer.size()); |
| memcpy(Buf, Buffer.data(), Buffer.size()); |
| return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)}; |
| } |
| |
| Error writeImportLibrary(StringRef ImportName, StringRef Path, |
| ArrayRef<COFFShortExport> Exports, |
| MachineTypes Machine, bool MinGW) { |
| |
| std::vector<NewArchiveMember> Members; |
| ObjectFactory OF(llvm::sys::path::filename(ImportName), Machine); |
| |
| std::vector<uint8_t> ImportDescriptor; |
| Members.push_back(OF.createImportDescriptor(ImportDescriptor)); |
| |
| std::vector<uint8_t> NullImportDescriptor; |
| Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor)); |
| |
| std::vector<uint8_t> NullThunk; |
| Members.push_back(OF.createNullThunk(NullThunk)); |
| |
| for (COFFShortExport E : Exports) { |
| if (E.Private) |
| continue; |
| |
| ImportType ImportType = IMPORT_CODE; |
| if (E.Data) |
| ImportType = IMPORT_DATA; |
| if (E.Constant) |
| ImportType = IMPORT_CONST; |
| |
| StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName; |
| ImportNameType NameType = E.Noname |
| ? IMPORT_ORDINAL |
| : getNameType(SymbolName, E.Name, |
| Machine, MinGW); |
| Expected<std::string> Name = E.ExtName.empty() |
| ? SymbolName |
| : replace(SymbolName, E.Name, E.ExtName); |
| |
| if (!Name) |
| return Name.takeError(); |
| |
| if (!E.AliasTarget.empty() && *Name != E.AliasTarget) { |
| Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, false)); |
| Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, true)); |
| continue; |
| } |
| |
| Members.push_back( |
| OF.createShortImport(*Name, E.Ordinal, ImportType, NameType)); |
| } |
| |
| return writeArchive(Path, Members, /*WriteSymtab*/ true, |
| object::Archive::K_GNU, |
| /*Deterministic*/ true, /*Thin*/ false); |
| } |
| |
| } // namespace object |
| } // namespace llvm |