xref: /src/contrib/llvm-project/llvm/lib/Object/COFFImportFile.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1b5630dbaSDimitry Andric //===- COFFImportFile.cpp - COFF short import file implementation ---------===//
2b5630dbaSDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b5630dbaSDimitry Andric //
7b5630dbaSDimitry Andric //===----------------------------------------------------------------------===//
8b5630dbaSDimitry Andric //
9b5630dbaSDimitry Andric // This file defines the writeImportLibrary function.
10b5630dbaSDimitry Andric //
11b5630dbaSDimitry Andric //===----------------------------------------------------------------------===//
12b5630dbaSDimitry Andric 
13b5630dbaSDimitry Andric #include "llvm/Object/COFFImportFile.h"
14b5630dbaSDimitry Andric #include "llvm/ADT/ArrayRef.h"
15ac9a064cSDimitry Andric #include "llvm/ADT/SmallVector.h"
16ac9a064cSDimitry Andric #include "llvm/ADT/StringMap.h"
17145449b1SDimitry Andric #include "llvm/ADT/Twine.h"
18b5630dbaSDimitry Andric #include "llvm/Object/Archive.h"
19b5630dbaSDimitry Andric #include "llvm/Object/ArchiveWriter.h"
20b5630dbaSDimitry Andric #include "llvm/Object/COFF.h"
21145449b1SDimitry Andric #include "llvm/Support/Allocator.h"
22145449b1SDimitry Andric #include "llvm/Support/Endian.h"
23b5630dbaSDimitry Andric #include "llvm/Support/Error.h"
24145449b1SDimitry Andric #include "llvm/Support/ErrorHandling.h"
25b5630dbaSDimitry Andric #include "llvm/Support/Path.h"
26b5630dbaSDimitry Andric 
27b5630dbaSDimitry Andric #include <cstdint>
28b5630dbaSDimitry Andric #include <string>
29b5630dbaSDimitry Andric #include <vector>
30b5630dbaSDimitry Andric 
31b5630dbaSDimitry Andric using namespace llvm::COFF;
32b5630dbaSDimitry Andric using namespace llvm::object;
33b5630dbaSDimitry Andric using namespace llvm;
34b5630dbaSDimitry Andric 
35b5630dbaSDimitry Andric namespace llvm {
36b5630dbaSDimitry Andric namespace object {
37b5630dbaSDimitry Andric 
getFileFormatName() const384df029ccSDimitry Andric StringRef COFFImportFile::getFileFormatName() const {
394df029ccSDimitry Andric   switch (getMachine()) {
404df029ccSDimitry Andric   case COFF::IMAGE_FILE_MACHINE_I386:
414df029ccSDimitry Andric     return "COFF-import-file-i386";
424df029ccSDimitry Andric   case COFF::IMAGE_FILE_MACHINE_AMD64:
434df029ccSDimitry Andric     return "COFF-import-file-x86-64";
444df029ccSDimitry Andric   case COFF::IMAGE_FILE_MACHINE_ARMNT:
454df029ccSDimitry Andric     return "COFF-import-file-ARM";
464df029ccSDimitry Andric   case COFF::IMAGE_FILE_MACHINE_ARM64:
474df029ccSDimitry Andric     return "COFF-import-file-ARM64";
484df029ccSDimitry Andric   case COFF::IMAGE_FILE_MACHINE_ARM64EC:
494df029ccSDimitry Andric     return "COFF-import-file-ARM64EC";
504df029ccSDimitry Andric   case COFF::IMAGE_FILE_MACHINE_ARM64X:
514df029ccSDimitry Andric     return "COFF-import-file-ARM64X";
524df029ccSDimitry Andric   default:
534df029ccSDimitry Andric     return "COFF-import-file-<unknown arch>";
544df029ccSDimitry Andric   }
554df029ccSDimitry Andric }
564df029ccSDimitry Andric 
applyNameType(ImportNameType Type,StringRef name)57ac9a064cSDimitry Andric static StringRef applyNameType(ImportNameType Type, StringRef name) {
58ac9a064cSDimitry Andric   auto ltrim1 = [](StringRef s, StringRef chars) {
59ac9a064cSDimitry Andric     return !s.empty() && chars.contains(s[0]) ? s.substr(1) : s;
60ac9a064cSDimitry Andric   };
61ac9a064cSDimitry Andric 
62ac9a064cSDimitry Andric   switch (Type) {
63ac9a064cSDimitry Andric   case IMPORT_NAME_NOPREFIX:
64ac9a064cSDimitry Andric     name = ltrim1(name, "?@_");
65ac9a064cSDimitry Andric     break;
66ac9a064cSDimitry Andric   case IMPORT_NAME_UNDECORATE:
67ac9a064cSDimitry Andric     name = ltrim1(name, "?@_");
68ac9a064cSDimitry Andric     name = name.substr(0, name.find('@'));
69ac9a064cSDimitry Andric     break;
70ac9a064cSDimitry Andric   default:
71ac9a064cSDimitry Andric     break;
72ac9a064cSDimitry Andric   }
73ac9a064cSDimitry Andric   return name;
74ac9a064cSDimitry Andric }
75ac9a064cSDimitry Andric 
getExportName() const76ac9a064cSDimitry Andric StringRef COFFImportFile::getExportName() const {
77ac9a064cSDimitry Andric   const coff_import_header *hdr = getCOFFImportHeader();
78ac9a064cSDimitry Andric   StringRef name = Data.getBuffer().substr(sizeof(*hdr)).split('\0').first;
79ac9a064cSDimitry Andric 
80ac9a064cSDimitry Andric   switch (hdr->getNameType()) {
81ac9a064cSDimitry Andric   case IMPORT_ORDINAL:
82ac9a064cSDimitry Andric     name = "";
83ac9a064cSDimitry Andric     break;
84ac9a064cSDimitry Andric   case IMPORT_NAME_NOPREFIX:
85ac9a064cSDimitry Andric   case IMPORT_NAME_UNDECORATE:
86ac9a064cSDimitry Andric     name = applyNameType(static_cast<ImportNameType>(hdr->getNameType()), name);
87ac9a064cSDimitry Andric     break;
88ac9a064cSDimitry Andric   case IMPORT_NAME_EXPORTAS: {
89ac9a064cSDimitry Andric     // Skip DLL name
90ac9a064cSDimitry Andric     name = Data.getBuffer().substr(sizeof(*hdr) + name.size() + 1);
91ac9a064cSDimitry Andric     name = name.split('\0').second.split('\0').first;
92ac9a064cSDimitry Andric     break;
93ac9a064cSDimitry Andric   }
94ac9a064cSDimitry Andric   default:
95ac9a064cSDimitry Andric     break;
96ac9a064cSDimitry Andric   }
97ac9a064cSDimitry Andric 
98ac9a064cSDimitry Andric   return name;
99ac9a064cSDimitry Andric }
100ac9a064cSDimitry Andric 
printSymbolName(raw_ostream & OS,DataRefImpl Symb) const101ac9a064cSDimitry Andric Error COFFImportFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const {
102ac9a064cSDimitry Andric   switch (Symb.p) {
103ac9a064cSDimitry Andric   case ImpSymbol:
104ac9a064cSDimitry Andric     OS << "__imp_";
105ac9a064cSDimitry Andric     break;
106ac9a064cSDimitry Andric   case ECAuxSymbol:
107ac9a064cSDimitry Andric     OS << "__imp_aux_";
108ac9a064cSDimitry Andric     break;
109ac9a064cSDimitry Andric   }
110ac9a064cSDimitry Andric   const char *Name = Data.getBufferStart() + sizeof(coff_import_header);
111ac9a064cSDimitry Andric   if (Symb.p != ECThunkSymbol && COFF::isArm64EC(getMachine())) {
112ac9a064cSDimitry Andric     if (std::optional<std::string> DemangledName =
113ac9a064cSDimitry Andric             getArm64ECDemangledFunctionName(Name)) {
114ac9a064cSDimitry Andric       OS << StringRef(*DemangledName);
115ac9a064cSDimitry Andric       return Error::success();
116ac9a064cSDimitry Andric     }
117ac9a064cSDimitry Andric   }
118ac9a064cSDimitry Andric   OS << StringRef(Name);
119ac9a064cSDimitry Andric   return Error::success();
120ac9a064cSDimitry Andric }
121ac9a064cSDimitry Andric 
getImgRelRelocation(MachineTypes Machine)122b5630dbaSDimitry Andric static uint16_t getImgRelRelocation(MachineTypes Machine) {
123b5630dbaSDimitry Andric   switch (Machine) {
124b5630dbaSDimitry Andric   default:
125b5630dbaSDimitry Andric     llvm_unreachable("unsupported machine");
126b5630dbaSDimitry Andric   case IMAGE_FILE_MACHINE_AMD64:
127b5630dbaSDimitry Andric     return IMAGE_REL_AMD64_ADDR32NB;
128b5630dbaSDimitry Andric   case IMAGE_FILE_MACHINE_ARMNT:
129b5630dbaSDimitry Andric     return IMAGE_REL_ARM_ADDR32NB;
130044eb2f6SDimitry Andric   case IMAGE_FILE_MACHINE_ARM64:
131e3b55780SDimitry Andric   case IMAGE_FILE_MACHINE_ARM64EC:
1327fa27ce4SDimitry Andric   case IMAGE_FILE_MACHINE_ARM64X:
133044eb2f6SDimitry Andric     return IMAGE_REL_ARM64_ADDR32NB;
134b5630dbaSDimitry Andric   case IMAGE_FILE_MACHINE_I386:
135b5630dbaSDimitry Andric     return IMAGE_REL_I386_DIR32NB;
136b5630dbaSDimitry Andric   }
137b5630dbaSDimitry Andric }
138b5630dbaSDimitry Andric 
append(std::vector<uint8_t> & B,const T & Data)139b5630dbaSDimitry Andric template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {
140b5630dbaSDimitry Andric   size_t S = B.size();
141b5630dbaSDimitry Andric   B.resize(S + sizeof(T));
142b5630dbaSDimitry Andric   memcpy(&B[S], &Data, sizeof(T));
143b5630dbaSDimitry Andric }
144b5630dbaSDimitry Andric 
writeStringTable(std::vector<uint8_t> & B,ArrayRef<const std::string_view> Strings)145b5630dbaSDimitry Andric static void writeStringTable(std::vector<uint8_t> &B,
146ac9a064cSDimitry Andric                              ArrayRef<const std::string_view> Strings) {
147b5630dbaSDimitry Andric   // The COFF string table consists of a 4-byte value which is the size of the
148b5630dbaSDimitry Andric   // table, including the length field itself.  This value is followed by the
149b5630dbaSDimitry Andric   // string content itself, which is an array of null-terminated C-style
150b5630dbaSDimitry Andric   // strings.  The termination is important as they are referenced to by offset
151b5630dbaSDimitry Andric   // by the symbol entity in the file format.
152b5630dbaSDimitry Andric 
153b5630dbaSDimitry Andric   size_t Pos = B.size();
154b5630dbaSDimitry Andric   size_t Offset = B.size();
155b5630dbaSDimitry Andric 
156b5630dbaSDimitry Andric   // Skip over the length field, we will fill it in later as we will have
157b5630dbaSDimitry Andric   // computed the length while emitting the string content itself.
158b5630dbaSDimitry Andric   Pos += sizeof(uint32_t);
159b5630dbaSDimitry Andric 
160b5630dbaSDimitry Andric   for (const auto &S : Strings) {
161b5630dbaSDimitry Andric     B.resize(Pos + S.length() + 1);
1627fa27ce4SDimitry Andric     std::copy(S.begin(), S.end(), std::next(B.begin(), Pos));
1637fa27ce4SDimitry Andric     B[Pos + S.length()] = 0;
164b5630dbaSDimitry Andric     Pos += S.length() + 1;
165b5630dbaSDimitry Andric   }
166b5630dbaSDimitry Andric 
167b5630dbaSDimitry Andric   // Backfill the length of the table now that it has been computed.
168b5630dbaSDimitry Andric   support::ulittle32_t Length(B.size() - Offset);
169b5630dbaSDimitry Andric   support::endian::write32le(&B[Offset], Length);
170b5630dbaSDimitry Andric }
171b5630dbaSDimitry Andric 
getNameType(StringRef Sym,StringRef ExtName,MachineTypes Machine,bool MinGW)172b5630dbaSDimitry Andric static ImportNameType getNameType(StringRef Sym, StringRef ExtName,
173eb11fae6SDimitry Andric                                   MachineTypes Machine, bool MinGW) {
174eb11fae6SDimitry Andric   // A decorated stdcall function in MSVC is exported with the
175eb11fae6SDimitry Andric   // type IMPORT_NAME, and the exported function name includes the
176eb11fae6SDimitry Andric   // the leading underscore. In MinGW on the other hand, a decorated
177eb11fae6SDimitry Andric   // stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX).
178eb11fae6SDimitry Andric   // See the comment in isDecorated in COFFModuleDefinition.cpp for more
179eb11fae6SDimitry Andric   // details.
180312c0ed1SDimitry Andric   if (ExtName.starts_with("_") && ExtName.contains('@') && !MinGW)
181eb11fae6SDimitry Andric     return IMPORT_NAME;
182b5630dbaSDimitry Andric   if (Sym != ExtName)
183b5630dbaSDimitry Andric     return IMPORT_NAME_UNDECORATE;
184312c0ed1SDimitry Andric   if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.starts_with("_"))
185b5630dbaSDimitry Andric     return IMPORT_NAME_NOPREFIX;
186b5630dbaSDimitry Andric   return IMPORT_NAME;
187b5630dbaSDimitry Andric }
188b5630dbaSDimitry Andric 
replace(StringRef S,StringRef From,StringRef To)189b5630dbaSDimitry Andric static Expected<std::string> replace(StringRef S, StringRef From,
190b5630dbaSDimitry Andric                                      StringRef To) {
191b5630dbaSDimitry Andric   size_t Pos = S.find(From);
192b5630dbaSDimitry Andric 
193b5630dbaSDimitry Andric   // From and To may be mangled, but substrings in S may not.
194312c0ed1SDimitry Andric   if (Pos == StringRef::npos && From.starts_with("_") && To.starts_with("_")) {
195b5630dbaSDimitry Andric     From = From.substr(1);
196b5630dbaSDimitry Andric     To = To.substr(1);
197b5630dbaSDimitry Andric     Pos = S.find(From);
198b5630dbaSDimitry Andric   }
199b5630dbaSDimitry Andric 
200b5630dbaSDimitry Andric   if (Pos == StringRef::npos) {
201b5630dbaSDimitry Andric     return make_error<StringError>(
202b5630dbaSDimitry Andric       StringRef(Twine(S + ": replacing '" + From +
203b5630dbaSDimitry Andric         "' with '" + To + "' failed").str()), object_error::parse_failed);
204b5630dbaSDimitry Andric   }
205b5630dbaSDimitry Andric 
206b5630dbaSDimitry Andric   return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
207b5630dbaSDimitry Andric }
208b5630dbaSDimitry Andric 
209b5630dbaSDimitry Andric namespace {
210b5630dbaSDimitry Andric // This class constructs various small object files necessary to support linking
211b5630dbaSDimitry Andric // symbols imported from a DLL.  The contents are pretty strictly defined and
212b5630dbaSDimitry Andric // nearly entirely static.  The details of the structures files are defined in
213b5630dbaSDimitry Andric // WINNT.h and the PE/COFF specification.
214b5630dbaSDimitry Andric class ObjectFactory {
215b5630dbaSDimitry Andric   using u16 = support::ulittle16_t;
216b5630dbaSDimitry Andric   using u32 = support::ulittle32_t;
2174df029ccSDimitry Andric   MachineTypes NativeMachine;
218b5630dbaSDimitry Andric   BumpPtrAllocator Alloc;
21993c91e39SDimitry Andric   StringRef ImportName;
220b5630dbaSDimitry Andric   StringRef Library;
221b5630dbaSDimitry Andric   std::string ImportDescriptorSymbolName;
222b5630dbaSDimitry Andric   std::string NullThunkSymbolName;
223b5630dbaSDimitry Andric 
224b5630dbaSDimitry Andric public:
ObjectFactory(StringRef S,MachineTypes M)225b5630dbaSDimitry Andric   ObjectFactory(StringRef S, MachineTypes M)
2264df029ccSDimitry Andric       : NativeMachine(M), ImportName(S), Library(llvm::sys::path::stem(S)),
227ac9a064cSDimitry Andric         ImportDescriptorSymbolName((ImportDescriptorPrefix + Library).str()),
228ac9a064cSDimitry Andric         NullThunkSymbolName(
229ac9a064cSDimitry Andric             (NullThunkDataPrefix + Library + NullThunkDataSuffix).str()) {}
230b5630dbaSDimitry Andric 
231b5630dbaSDimitry Andric   // Creates an Import Descriptor.  This is a small object file which contains a
232b5630dbaSDimitry Andric   // reference to the terminators and contains the library name (entry) for the
233b5630dbaSDimitry Andric   // import name table.  It will force the linker to construct the necessary
234b5630dbaSDimitry Andric   // structure to import symbols from the DLL.
235b5630dbaSDimitry Andric   NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);
236b5630dbaSDimitry Andric 
237b5630dbaSDimitry Andric   // Creates a NULL import descriptor.  This is a small object file whcih
238b5630dbaSDimitry Andric   // contains a NULL import descriptor.  It is used to terminate the imports
239b5630dbaSDimitry Andric   // from a specific DLL.
240b5630dbaSDimitry Andric   NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);
241b5630dbaSDimitry Andric 
242b5630dbaSDimitry Andric   // Create a NULL Thunk Entry.  This is a small object file which contains a
243b5630dbaSDimitry Andric   // NULL Import Address Table entry and a NULL Import Lookup Table Entry.  It
244b5630dbaSDimitry Andric   // is used to terminate the IAT and ILT.
245b5630dbaSDimitry Andric   NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);
246b5630dbaSDimitry Andric 
247b5630dbaSDimitry Andric   // Create a short import file which is described in PE/COFF spec 7. Import
248b5630dbaSDimitry Andric   // Library Format.
249b5630dbaSDimitry Andric   NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
2504df029ccSDimitry Andric                                      ImportType Type, ImportNameType NameType,
251ac9a064cSDimitry Andric                                      StringRef ExportName,
2524df029ccSDimitry Andric                                      MachineTypes Machine);
25393c91e39SDimitry Andric 
25493c91e39SDimitry Andric   // Create a weak external file which is described in PE/COFF Aux Format 3.
2554df029ccSDimitry Andric   NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp,
2564df029ccSDimitry Andric                                       MachineTypes Machine);
2574df029ccSDimitry Andric 
is64Bit() const2584df029ccSDimitry Andric   bool is64Bit() const { return COFF::is64Bit(NativeMachine); }
259b5630dbaSDimitry Andric };
260b5630dbaSDimitry Andric } // namespace
261b5630dbaSDimitry Andric 
262b5630dbaSDimitry Andric NewArchiveMember
createImportDescriptor(std::vector<uint8_t> & Buffer)263b5630dbaSDimitry Andric ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
26493c91e39SDimitry Andric   const uint32_t NumberOfSections = 2;
26593c91e39SDimitry Andric   const uint32_t NumberOfSymbols = 7;
26693c91e39SDimitry Andric   const uint32_t NumberOfRelocations = 3;
267b5630dbaSDimitry Andric 
268b5630dbaSDimitry Andric   // COFF Header
269b5630dbaSDimitry Andric   coff_file_header Header{
2704df029ccSDimitry Andric       u16(NativeMachine),
271b5630dbaSDimitry Andric       u16(NumberOfSections),
272b5630dbaSDimitry Andric       u32(0),
273b5630dbaSDimitry Andric       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
274b5630dbaSDimitry Andric           // .idata$2
275b5630dbaSDimitry Andric           sizeof(coff_import_directory_table_entry) +
276b5630dbaSDimitry Andric           NumberOfRelocations * sizeof(coff_relocation) +
277b5630dbaSDimitry Andric           // .idata$4
27893c91e39SDimitry Andric           (ImportName.size() + 1)),
279b5630dbaSDimitry Andric       u32(NumberOfSymbols),
280b5630dbaSDimitry Andric       u16(0),
2814df029ccSDimitry Andric       u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE),
282b5630dbaSDimitry Andric   };
283b5630dbaSDimitry Andric   append(Buffer, Header);
284b5630dbaSDimitry Andric 
285b5630dbaSDimitry Andric   // Section Header Table
28693c91e39SDimitry Andric   const coff_section SectionTable[NumberOfSections] = {
287b5630dbaSDimitry Andric       {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
288b5630dbaSDimitry Andric        u32(0),
289b5630dbaSDimitry Andric        u32(0),
290b5630dbaSDimitry Andric        u32(sizeof(coff_import_directory_table_entry)),
291b5630dbaSDimitry Andric        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
292b5630dbaSDimitry Andric        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
293b5630dbaSDimitry Andric            sizeof(coff_import_directory_table_entry)),
294b5630dbaSDimitry Andric        u32(0),
295b5630dbaSDimitry Andric        u16(NumberOfRelocations),
296b5630dbaSDimitry Andric        u16(0),
297b5630dbaSDimitry Andric        u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
298b5630dbaSDimitry Andric            IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
299b5630dbaSDimitry Andric       {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
300b5630dbaSDimitry Andric        u32(0),
301b5630dbaSDimitry Andric        u32(0),
30293c91e39SDimitry Andric        u32(ImportName.size() + 1),
303b5630dbaSDimitry Andric        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
304b5630dbaSDimitry Andric            sizeof(coff_import_directory_table_entry) +
305b5630dbaSDimitry Andric            NumberOfRelocations * sizeof(coff_relocation)),
306b5630dbaSDimitry Andric        u32(0),
307b5630dbaSDimitry Andric        u32(0),
308b5630dbaSDimitry Andric        u16(0),
309b5630dbaSDimitry Andric        u16(0),
310b5630dbaSDimitry Andric        u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
311b5630dbaSDimitry Andric            IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
312b5630dbaSDimitry Andric   };
313b5630dbaSDimitry Andric   append(Buffer, SectionTable);
314b5630dbaSDimitry Andric 
315b5630dbaSDimitry Andric   // .idata$2
31693c91e39SDimitry Andric   const coff_import_directory_table_entry ImportDescriptor{
317b5630dbaSDimitry Andric       u32(0), u32(0), u32(0), u32(0), u32(0),
318b5630dbaSDimitry Andric   };
319b5630dbaSDimitry Andric   append(Buffer, ImportDescriptor);
320b5630dbaSDimitry Andric 
32193c91e39SDimitry Andric   const coff_relocation RelocationTable[NumberOfRelocations] = {
322b5630dbaSDimitry Andric       {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
3234df029ccSDimitry Andric        u16(getImgRelRelocation(NativeMachine))},
324b5630dbaSDimitry Andric       {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
3254df029ccSDimitry Andric        u32(3), u16(getImgRelRelocation(NativeMachine))},
326b5630dbaSDimitry Andric       {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
3274df029ccSDimitry Andric        u32(4), u16(getImgRelRelocation(NativeMachine))},
328b5630dbaSDimitry Andric   };
329b5630dbaSDimitry Andric   append(Buffer, RelocationTable);
330b5630dbaSDimitry Andric 
331b5630dbaSDimitry Andric   // .idata$6
332b5630dbaSDimitry Andric   auto S = Buffer.size();
33393c91e39SDimitry Andric   Buffer.resize(S + ImportName.size() + 1);
33493c91e39SDimitry Andric   memcpy(&Buffer[S], ImportName.data(), ImportName.size());
33593c91e39SDimitry Andric   Buffer[S + ImportName.size()] = '\0';
336b5630dbaSDimitry Andric 
337b5630dbaSDimitry Andric   // Symbol Table
338b5630dbaSDimitry Andric   coff_symbol16 SymbolTable[NumberOfSymbols] = {
339b5630dbaSDimitry Andric       {{{0, 0, 0, 0, 0, 0, 0, 0}},
340b5630dbaSDimitry Andric        u32(0),
341b5630dbaSDimitry Andric        u16(1),
342b5630dbaSDimitry Andric        u16(0),
343b5630dbaSDimitry Andric        IMAGE_SYM_CLASS_EXTERNAL,
344b5630dbaSDimitry Andric        0},
345b5630dbaSDimitry Andric       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
346b5630dbaSDimitry Andric        u32(0),
347b5630dbaSDimitry Andric        u16(1),
348b5630dbaSDimitry Andric        u16(0),
349b5630dbaSDimitry Andric        IMAGE_SYM_CLASS_SECTION,
350b5630dbaSDimitry Andric        0},
351b5630dbaSDimitry Andric       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
352b5630dbaSDimitry Andric        u32(0),
353b5630dbaSDimitry Andric        u16(2),
354b5630dbaSDimitry Andric        u16(0),
355b5630dbaSDimitry Andric        IMAGE_SYM_CLASS_STATIC,
356b5630dbaSDimitry Andric        0},
357b5630dbaSDimitry Andric       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
358b5630dbaSDimitry Andric        u32(0),
359b5630dbaSDimitry Andric        u16(0),
360b5630dbaSDimitry Andric        u16(0),
361b5630dbaSDimitry Andric        IMAGE_SYM_CLASS_SECTION,
362b5630dbaSDimitry Andric        0},
363b5630dbaSDimitry Andric       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
364b5630dbaSDimitry Andric        u32(0),
365b5630dbaSDimitry Andric        u16(0),
366b5630dbaSDimitry Andric        u16(0),
367b5630dbaSDimitry Andric        IMAGE_SYM_CLASS_SECTION,
368b5630dbaSDimitry Andric        0},
369b5630dbaSDimitry Andric       {{{0, 0, 0, 0, 0, 0, 0, 0}},
370b5630dbaSDimitry Andric        u32(0),
371b5630dbaSDimitry Andric        u16(0),
372b5630dbaSDimitry Andric        u16(0),
373b5630dbaSDimitry Andric        IMAGE_SYM_CLASS_EXTERNAL,
374b5630dbaSDimitry Andric        0},
375b5630dbaSDimitry Andric       {{{0, 0, 0, 0, 0, 0, 0, 0}},
376b5630dbaSDimitry Andric        u32(0),
377b5630dbaSDimitry Andric        u16(0),
378b5630dbaSDimitry Andric        u16(0),
379b5630dbaSDimitry Andric        IMAGE_SYM_CLASS_EXTERNAL,
380b5630dbaSDimitry Andric        0},
381b5630dbaSDimitry Andric   };
3827ab83427SDimitry Andric   // TODO: Name.Offset.Offset here and in the all similar places below
3837ab83427SDimitry Andric   // suggests a names refactoring. Maybe StringTableOffset.Value?
3847ab83427SDimitry Andric   SymbolTable[0].Name.Offset.Offset =
385b5630dbaSDimitry Andric       sizeof(uint32_t);
3867ab83427SDimitry Andric   SymbolTable[5].Name.Offset.Offset =
387b5630dbaSDimitry Andric       sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
3887ab83427SDimitry Andric   SymbolTable[6].Name.Offset.Offset =
389b5630dbaSDimitry Andric       sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
390b5630dbaSDimitry Andric       NullImportDescriptorSymbolName.length() + 1;
391b5630dbaSDimitry Andric   append(Buffer, SymbolTable);
392b5630dbaSDimitry Andric 
393b5630dbaSDimitry Andric   // String Table
394b5630dbaSDimitry Andric   writeStringTable(Buffer,
395b5630dbaSDimitry Andric                    {ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
396b5630dbaSDimitry Andric                     NullThunkSymbolName});
397b5630dbaSDimitry Andric 
398b5630dbaSDimitry Andric   StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
39993c91e39SDimitry Andric   return {MemoryBufferRef(F, ImportName)};
400b5630dbaSDimitry Andric }
401b5630dbaSDimitry Andric 
402b5630dbaSDimitry Andric NewArchiveMember
createNullImportDescriptor(std::vector<uint8_t> & Buffer)403b5630dbaSDimitry Andric ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
40493c91e39SDimitry Andric   const uint32_t NumberOfSections = 1;
40593c91e39SDimitry Andric   const uint32_t NumberOfSymbols = 1;
406b5630dbaSDimitry Andric 
407b5630dbaSDimitry Andric   // COFF Header
408b5630dbaSDimitry Andric   coff_file_header Header{
4094df029ccSDimitry Andric       u16(NativeMachine),
410b5630dbaSDimitry Andric       u16(NumberOfSections),
411b5630dbaSDimitry Andric       u32(0),
412b5630dbaSDimitry Andric       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
413b5630dbaSDimitry Andric           // .idata$3
414b5630dbaSDimitry Andric           sizeof(coff_import_directory_table_entry)),
415b5630dbaSDimitry Andric       u32(NumberOfSymbols),
416b5630dbaSDimitry Andric       u16(0),
4174df029ccSDimitry Andric       u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE),
418b5630dbaSDimitry Andric   };
419b5630dbaSDimitry Andric   append(Buffer, Header);
420b5630dbaSDimitry Andric 
421b5630dbaSDimitry Andric   // Section Header Table
42293c91e39SDimitry Andric   const coff_section SectionTable[NumberOfSections] = {
423b5630dbaSDimitry Andric       {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
424b5630dbaSDimitry Andric        u32(0),
425b5630dbaSDimitry Andric        u32(0),
426b5630dbaSDimitry Andric        u32(sizeof(coff_import_directory_table_entry)),
427b5630dbaSDimitry Andric        u32(sizeof(coff_file_header) +
428b5630dbaSDimitry Andric            (NumberOfSections * sizeof(coff_section))),
429b5630dbaSDimitry Andric        u32(0),
430b5630dbaSDimitry Andric        u32(0),
431b5630dbaSDimitry Andric        u16(0),
432b5630dbaSDimitry Andric        u16(0),
433b5630dbaSDimitry Andric        u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
434b5630dbaSDimitry Andric            IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
435b5630dbaSDimitry Andric   };
436b5630dbaSDimitry Andric   append(Buffer, SectionTable);
437b5630dbaSDimitry Andric 
438b5630dbaSDimitry Andric   // .idata$3
43993c91e39SDimitry Andric   const coff_import_directory_table_entry ImportDescriptor{
440b5630dbaSDimitry Andric       u32(0), u32(0), u32(0), u32(0), u32(0),
441b5630dbaSDimitry Andric   };
442b5630dbaSDimitry Andric   append(Buffer, ImportDescriptor);
443b5630dbaSDimitry Andric 
444b5630dbaSDimitry Andric   // Symbol Table
445b5630dbaSDimitry Andric   coff_symbol16 SymbolTable[NumberOfSymbols] = {
446b5630dbaSDimitry Andric       {{{0, 0, 0, 0, 0, 0, 0, 0}},
447b5630dbaSDimitry Andric        u32(0),
448b5630dbaSDimitry Andric        u16(1),
449b5630dbaSDimitry Andric        u16(0),
450b5630dbaSDimitry Andric        IMAGE_SYM_CLASS_EXTERNAL,
451b5630dbaSDimitry Andric        0},
452b5630dbaSDimitry Andric   };
4537ab83427SDimitry Andric   SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
454b5630dbaSDimitry Andric   append(Buffer, SymbolTable);
455b5630dbaSDimitry Andric 
456b5630dbaSDimitry Andric   // String Table
457b5630dbaSDimitry Andric   writeStringTable(Buffer, {NullImportDescriptorSymbolName});
458b5630dbaSDimitry Andric 
459b5630dbaSDimitry Andric   StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
46093c91e39SDimitry Andric   return {MemoryBufferRef(F, ImportName)};
461b5630dbaSDimitry Andric }
462b5630dbaSDimitry Andric 
createNullThunk(std::vector<uint8_t> & Buffer)463b5630dbaSDimitry Andric NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
46493c91e39SDimitry Andric   const uint32_t NumberOfSections = 2;
46593c91e39SDimitry Andric   const uint32_t NumberOfSymbols = 1;
4664df029ccSDimitry Andric   uint32_t VASize = is64Bit() ? 8 : 4;
467b5630dbaSDimitry Andric 
468b5630dbaSDimitry Andric   // COFF Header
469b5630dbaSDimitry Andric   coff_file_header Header{
4704df029ccSDimitry Andric       u16(NativeMachine),
471b5630dbaSDimitry Andric       u16(NumberOfSections),
472b5630dbaSDimitry Andric       u32(0),
473b5630dbaSDimitry Andric       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
474b5630dbaSDimitry Andric           // .idata$5
475b5630dbaSDimitry Andric           VASize +
476b5630dbaSDimitry Andric           // .idata$4
477b5630dbaSDimitry Andric           VASize),
478b5630dbaSDimitry Andric       u32(NumberOfSymbols),
479b5630dbaSDimitry Andric       u16(0),
4804df029ccSDimitry Andric       u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE),
481b5630dbaSDimitry Andric   };
482b5630dbaSDimitry Andric   append(Buffer, Header);
483b5630dbaSDimitry Andric 
484b5630dbaSDimitry Andric   // Section Header Table
48593c91e39SDimitry Andric   const coff_section SectionTable[NumberOfSections] = {
486b5630dbaSDimitry Andric       {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
487b5630dbaSDimitry Andric        u32(0),
488b5630dbaSDimitry Andric        u32(0),
489b5630dbaSDimitry Andric        u32(VASize),
490b5630dbaSDimitry Andric        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
491b5630dbaSDimitry Andric        u32(0),
492b5630dbaSDimitry Andric        u32(0),
493b5630dbaSDimitry Andric        u16(0),
494b5630dbaSDimitry Andric        u16(0),
4954df029ccSDimitry Andric        u32((is64Bit() ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES) |
496b5630dbaSDimitry Andric            IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
497b5630dbaSDimitry Andric            IMAGE_SCN_MEM_WRITE)},
498b5630dbaSDimitry Andric       {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
499b5630dbaSDimitry Andric        u32(0),
500b5630dbaSDimitry Andric        u32(0),
501b5630dbaSDimitry Andric        u32(VASize),
502b5630dbaSDimitry Andric        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
503b5630dbaSDimitry Andric            VASize),
504b5630dbaSDimitry Andric        u32(0),
505b5630dbaSDimitry Andric        u32(0),
506b5630dbaSDimitry Andric        u16(0),
507b5630dbaSDimitry Andric        u16(0),
5084df029ccSDimitry Andric        u32((is64Bit() ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES) |
509b5630dbaSDimitry Andric            IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
510b5630dbaSDimitry Andric            IMAGE_SCN_MEM_WRITE)},
511b5630dbaSDimitry Andric   };
512b5630dbaSDimitry Andric   append(Buffer, SectionTable);
513b5630dbaSDimitry Andric 
514b5630dbaSDimitry Andric   // .idata$5, ILT
515b5630dbaSDimitry Andric   append(Buffer, u32(0));
5164df029ccSDimitry Andric   if (is64Bit())
517b5630dbaSDimitry Andric     append(Buffer, u32(0));
518b5630dbaSDimitry Andric 
519b5630dbaSDimitry Andric   // .idata$4, IAT
520b5630dbaSDimitry Andric   append(Buffer, u32(0));
5214df029ccSDimitry Andric   if (is64Bit())
522b5630dbaSDimitry Andric     append(Buffer, u32(0));
523b5630dbaSDimitry Andric 
524b5630dbaSDimitry Andric   // Symbol Table
525b5630dbaSDimitry Andric   coff_symbol16 SymbolTable[NumberOfSymbols] = {
526b5630dbaSDimitry Andric       {{{0, 0, 0, 0, 0, 0, 0, 0}},
527b5630dbaSDimitry Andric        u32(0),
528b5630dbaSDimitry Andric        u16(1),
529b5630dbaSDimitry Andric        u16(0),
530b5630dbaSDimitry Andric        IMAGE_SYM_CLASS_EXTERNAL,
531b5630dbaSDimitry Andric        0},
532b5630dbaSDimitry Andric   };
5337ab83427SDimitry Andric   SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
534b5630dbaSDimitry Andric   append(Buffer, SymbolTable);
535b5630dbaSDimitry Andric 
536b5630dbaSDimitry Andric   // String Table
537b5630dbaSDimitry Andric   writeStringTable(Buffer, {NullThunkSymbolName});
538b5630dbaSDimitry Andric 
539b5630dbaSDimitry Andric   StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
54093c91e39SDimitry Andric   return {MemoryBufferRef{F, ImportName}};
541b5630dbaSDimitry Andric }
542b5630dbaSDimitry Andric 
543ac9a064cSDimitry Andric NewArchiveMember
createShortImport(StringRef Sym,uint16_t Ordinal,ImportType ImportType,ImportNameType NameType,StringRef ExportName,MachineTypes Machine)544ac9a064cSDimitry Andric ObjectFactory::createShortImport(StringRef Sym, uint16_t Ordinal,
545ac9a064cSDimitry Andric                                  ImportType ImportType, ImportNameType NameType,
546ac9a064cSDimitry Andric                                  StringRef ExportName, MachineTypes Machine) {
54793c91e39SDimitry Andric   size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs
548ac9a064cSDimitry Andric   if (!ExportName.empty())
549ac9a064cSDimitry Andric     ImpSize += ExportName.size() + 1;
550b5630dbaSDimitry Andric   size_t Size = sizeof(coff_import_header) + ImpSize;
551b5630dbaSDimitry Andric   char *Buf = Alloc.Allocate<char>(Size);
552b5630dbaSDimitry Andric   memset(Buf, 0, Size);
553b5630dbaSDimitry Andric   char *P = Buf;
554b5630dbaSDimitry Andric 
555b5630dbaSDimitry Andric   // Write short import library.
556b5630dbaSDimitry Andric   auto *Imp = reinterpret_cast<coff_import_header *>(P);
557b5630dbaSDimitry Andric   P += sizeof(*Imp);
558b5630dbaSDimitry Andric   Imp->Sig2 = 0xFFFF;
559b5630dbaSDimitry Andric   Imp->Machine = Machine;
560b5630dbaSDimitry Andric   Imp->SizeOfData = ImpSize;
561b5630dbaSDimitry Andric   if (Ordinal > 0)
562b5630dbaSDimitry Andric     Imp->OrdinalHint = Ordinal;
563b5630dbaSDimitry Andric   Imp->TypeInfo = (NameType << 2) | ImportType;
564b5630dbaSDimitry Andric 
565b5630dbaSDimitry Andric   // Write symbol name and DLL name.
566b5630dbaSDimitry Andric   memcpy(P, Sym.data(), Sym.size());
567b5630dbaSDimitry Andric   P += Sym.size() + 1;
56893c91e39SDimitry Andric   memcpy(P, ImportName.data(), ImportName.size());
569ac9a064cSDimitry Andric   if (!ExportName.empty()) {
570ac9a064cSDimitry Andric     P += ImportName.size() + 1;
571ac9a064cSDimitry Andric     memcpy(P, ExportName.data(), ExportName.size());
572ac9a064cSDimitry Andric   }
573b5630dbaSDimitry Andric 
57493c91e39SDimitry Andric   return {MemoryBufferRef(StringRef(Buf, Size), ImportName)};
575b5630dbaSDimitry Andric }
576b5630dbaSDimitry Andric 
createWeakExternal(StringRef Sym,StringRef Weak,bool Imp,MachineTypes Machine)57793c91e39SDimitry Andric NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym,
5784df029ccSDimitry Andric                                                    StringRef Weak, bool Imp,
5794df029ccSDimitry Andric                                                    MachineTypes Machine) {
58093c91e39SDimitry Andric   std::vector<uint8_t> Buffer;
58193c91e39SDimitry Andric   const uint32_t NumberOfSections = 1;
58293c91e39SDimitry Andric   const uint32_t NumberOfSymbols = 5;
58393c91e39SDimitry Andric 
58493c91e39SDimitry Andric   // COFF Header
58593c91e39SDimitry Andric   coff_file_header Header{
586e6d15924SDimitry Andric       u16(Machine),
58793c91e39SDimitry Andric       u16(NumberOfSections),
58893c91e39SDimitry Andric       u32(0),
58993c91e39SDimitry Andric       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))),
59093c91e39SDimitry Andric       u32(NumberOfSymbols),
59193c91e39SDimitry Andric       u16(0),
59293c91e39SDimitry Andric       u16(0),
59393c91e39SDimitry Andric   };
59493c91e39SDimitry Andric   append(Buffer, Header);
59593c91e39SDimitry Andric 
59693c91e39SDimitry Andric   // Section Header Table
59793c91e39SDimitry Andric   const coff_section SectionTable[NumberOfSections] = {
59893c91e39SDimitry Andric       {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'},
59993c91e39SDimitry Andric        u32(0),
60093c91e39SDimitry Andric        u32(0),
60193c91e39SDimitry Andric        u32(0),
60293c91e39SDimitry Andric        u32(0),
60393c91e39SDimitry Andric        u32(0),
60493c91e39SDimitry Andric        u32(0),
60593c91e39SDimitry Andric        u16(0),
60693c91e39SDimitry Andric        u16(0),
60793c91e39SDimitry Andric        u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}};
60893c91e39SDimitry Andric   append(Buffer, SectionTable);
60993c91e39SDimitry Andric 
61093c91e39SDimitry Andric   // Symbol Table
61193c91e39SDimitry Andric   coff_symbol16 SymbolTable[NumberOfSymbols] = {
61293c91e39SDimitry Andric       {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},
61393c91e39SDimitry Andric        u32(0),
61493c91e39SDimitry Andric        u16(0xFFFF),
61593c91e39SDimitry Andric        u16(0),
61693c91e39SDimitry Andric        IMAGE_SYM_CLASS_STATIC,
61793c91e39SDimitry Andric        0},
61893c91e39SDimitry Andric       {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}},
61993c91e39SDimitry Andric        u32(0),
62093c91e39SDimitry Andric        u16(0xFFFF),
62193c91e39SDimitry Andric        u16(0),
62293c91e39SDimitry Andric        IMAGE_SYM_CLASS_STATIC,
62393c91e39SDimitry Andric        0},
62493c91e39SDimitry Andric       {{{0, 0, 0, 0, 0, 0, 0, 0}},
62593c91e39SDimitry Andric        u32(0),
62693c91e39SDimitry Andric        u16(0),
62793c91e39SDimitry Andric        u16(0),
62893c91e39SDimitry Andric        IMAGE_SYM_CLASS_EXTERNAL,
62993c91e39SDimitry Andric        0},
63093c91e39SDimitry Andric       {{{0, 0, 0, 0, 0, 0, 0, 0}},
63193c91e39SDimitry Andric        u32(0),
63293c91e39SDimitry Andric        u16(0),
63393c91e39SDimitry Andric        u16(0),
63493c91e39SDimitry Andric        IMAGE_SYM_CLASS_WEAK_EXTERNAL,
63593c91e39SDimitry Andric        1},
636eb11fae6SDimitry Andric       {{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}},
637eb11fae6SDimitry Andric        u32(0),
638eb11fae6SDimitry Andric        u16(0),
639eb11fae6SDimitry Andric        u16(0),
640eb11fae6SDimitry Andric        IMAGE_SYM_CLASS_NULL,
641eb11fae6SDimitry Andric        0},
64293c91e39SDimitry Andric   };
64393c91e39SDimitry Andric   SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t);
64493c91e39SDimitry Andric 
64593c91e39SDimitry Andric   //__imp_ String Table
6464e20bb04SDimitry Andric   StringRef Prefix = Imp ? "__imp_" : "";
6474e20bb04SDimitry Andric   SymbolTable[3].Name.Offset.Offset =
6484e20bb04SDimitry Andric       sizeof(uint32_t) + Sym.size() + Prefix.size() + 1;
64993c91e39SDimitry Andric   append(Buffer, SymbolTable);
6504e20bb04SDimitry Andric   writeStringTable(Buffer, {(Prefix + Sym).str(),
6514e20bb04SDimitry Andric                             (Prefix + Weak).str()});
65293c91e39SDimitry Andric 
65393c91e39SDimitry Andric   // Copied here so we can still use writeStringTable
65493c91e39SDimitry Andric   char *Buf = Alloc.Allocate<char>(Buffer.size());
65593c91e39SDimitry Andric   memcpy(Buf, Buffer.data(), Buffer.size());
65693c91e39SDimitry Andric   return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)};
65793c91e39SDimitry Andric }
65893c91e39SDimitry Andric 
writeImportLibrary(StringRef ImportName,StringRef Path,ArrayRef<COFFShortExport> Exports,MachineTypes Machine,bool MinGW,ArrayRef<COFFShortExport> NativeExports)659044eb2f6SDimitry Andric Error writeImportLibrary(StringRef ImportName, StringRef Path,
660b5630dbaSDimitry Andric                          ArrayRef<COFFShortExport> Exports,
661ac9a064cSDimitry Andric                          MachineTypes Machine, bool MinGW,
662ac9a064cSDimitry Andric                          ArrayRef<COFFShortExport> NativeExports) {
663b5630dbaSDimitry Andric 
664ac9a064cSDimitry Andric   MachineTypes NativeMachine = Machine;
665ac9a064cSDimitry Andric   if (isArm64EC(Machine)) {
666ac9a064cSDimitry Andric     NativeMachine = IMAGE_FILE_MACHINE_ARM64;
667ac9a064cSDimitry Andric     Machine = IMAGE_FILE_MACHINE_ARM64EC;
668ac9a064cSDimitry Andric   }
6694df029ccSDimitry Andric 
670b5630dbaSDimitry Andric   std::vector<NewArchiveMember> Members;
6714df029ccSDimitry Andric   ObjectFactory OF(llvm::sys::path::filename(ImportName), NativeMachine);
672b5630dbaSDimitry Andric 
673b5630dbaSDimitry Andric   std::vector<uint8_t> ImportDescriptor;
674b5630dbaSDimitry Andric   Members.push_back(OF.createImportDescriptor(ImportDescriptor));
675b5630dbaSDimitry Andric 
676b5630dbaSDimitry Andric   std::vector<uint8_t> NullImportDescriptor;
677b5630dbaSDimitry Andric   Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));
678b5630dbaSDimitry Andric 
679b5630dbaSDimitry Andric   std::vector<uint8_t> NullThunk;
680b5630dbaSDimitry Andric   Members.push_back(OF.createNullThunk(NullThunk));
681b5630dbaSDimitry Andric 
682ac9a064cSDimitry Andric   auto addExports = [&](ArrayRef<COFFShortExport> Exp,
683ac9a064cSDimitry Andric                         MachineTypes M) -> Error {
684ac9a064cSDimitry Andric     StringMap<std::string> RegularImports;
685ac9a064cSDimitry Andric     struct Deferred {
686ac9a064cSDimitry Andric       std::string Name;
687ac9a064cSDimitry Andric       ImportType ImpType;
688ac9a064cSDimitry Andric       const COFFShortExport *Export;
689ac9a064cSDimitry Andric     };
690ac9a064cSDimitry Andric     SmallVector<Deferred, 0> Renames;
691ac9a064cSDimitry Andric     for (const COFFShortExport &E : Exp) {
692b5630dbaSDimitry Andric       if (E.Private)
693b5630dbaSDimitry Andric         continue;
694b5630dbaSDimitry Andric 
695b5630dbaSDimitry Andric       ImportType ImportType = IMPORT_CODE;
696b5630dbaSDimitry Andric       if (E.Data)
697b5630dbaSDimitry Andric         ImportType = IMPORT_DATA;
698b5630dbaSDimitry Andric       if (E.Constant)
699b5630dbaSDimitry Andric         ImportType = IMPORT_CONST;
700b5630dbaSDimitry Andric 
70115c5c77fSDimitry Andric       StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName;
702ac9a064cSDimitry Andric       std::string Name;
703b5630dbaSDimitry Andric 
704ac9a064cSDimitry Andric       if (E.ExtName.empty()) {
705ac9a064cSDimitry Andric         Name = std::string(SymbolName);
706ac9a064cSDimitry Andric       } else {
707ac9a064cSDimitry Andric         Expected<std::string> ReplacedName =
708ac9a064cSDimitry Andric             replace(SymbolName, E.Name, E.ExtName);
709ac9a064cSDimitry Andric         if (!ReplacedName)
710ac9a064cSDimitry Andric           return ReplacedName.takeError();
711ac9a064cSDimitry Andric         Name.swap(*ReplacedName);
712ac9a064cSDimitry Andric       }
713b5630dbaSDimitry Andric 
714ac9a064cSDimitry Andric       ImportNameType NameType;
715ac9a064cSDimitry Andric       std::string ExportName;
716ac9a064cSDimitry Andric       if (E.Noname) {
717ac9a064cSDimitry Andric         NameType = IMPORT_ORDINAL;
718ac9a064cSDimitry Andric       } else if (!E.ExportAs.empty()) {
719ac9a064cSDimitry Andric         NameType = IMPORT_NAME_EXPORTAS;
720ac9a064cSDimitry Andric         ExportName = E.ExportAs;
721ac9a064cSDimitry Andric       } else if (!E.ImportName.empty()) {
722ac9a064cSDimitry Andric         // If we need to import from a specific ImportName, we may need to use
723ac9a064cSDimitry Andric         // a weak alias (which needs another import to point at). But if we can
724ac9a064cSDimitry Andric         // express ImportName based on the symbol name and a specific NameType,
725ac9a064cSDimitry Andric         // prefer that over an alias.
726ac9a064cSDimitry Andric         if (Machine == IMAGE_FILE_MACHINE_I386 &&
727ac9a064cSDimitry Andric             applyNameType(IMPORT_NAME_UNDECORATE, Name) == E.ImportName)
728ac9a064cSDimitry Andric           NameType = IMPORT_NAME_UNDECORATE;
729ac9a064cSDimitry Andric         else if (Machine == IMAGE_FILE_MACHINE_I386 &&
730ac9a064cSDimitry Andric                  applyNameType(IMPORT_NAME_NOPREFIX, Name) == E.ImportName)
731ac9a064cSDimitry Andric           NameType = IMPORT_NAME_NOPREFIX;
732ac9a064cSDimitry Andric         else if (isArm64EC(M)) {
733ac9a064cSDimitry Andric           NameType = IMPORT_NAME_EXPORTAS;
734ac9a064cSDimitry Andric           ExportName = E.ImportName;
735ac9a064cSDimitry Andric         } else if (Name == E.ImportName)
736ac9a064cSDimitry Andric           NameType = IMPORT_NAME;
737ac9a064cSDimitry Andric         else {
738ac9a064cSDimitry Andric           Deferred D;
739ac9a064cSDimitry Andric           D.Name = Name;
740ac9a064cSDimitry Andric           D.ImpType = ImportType;
741ac9a064cSDimitry Andric           D.Export = &E;
742ac9a064cSDimitry Andric           Renames.push_back(D);
743eb11fae6SDimitry Andric           continue;
744eb11fae6SDimitry Andric         }
745ac9a064cSDimitry Andric       } else {
746ac9a064cSDimitry Andric         NameType = getNameType(SymbolName, E.Name, M, MinGW);
747b5630dbaSDimitry Andric       }
748b5630dbaSDimitry Andric 
749ac9a064cSDimitry Andric       // On ARM64EC, use EXPORTAS to import demangled name for mangled symbols.
750ac9a064cSDimitry Andric       if (ImportType == IMPORT_CODE && isArm64EC(M)) {
751ac9a064cSDimitry Andric         if (std::optional<std::string> MangledName =
752ac9a064cSDimitry Andric                 getArm64ECMangledFunctionName(Name)) {
753ac9a064cSDimitry Andric           if (!E.Noname && ExportName.empty()) {
754ac9a064cSDimitry Andric             NameType = IMPORT_NAME_EXPORTAS;
755ac9a064cSDimitry Andric             ExportName.swap(Name);
756ac9a064cSDimitry Andric           }
757ac9a064cSDimitry Andric           Name = std::move(*MangledName);
758ac9a064cSDimitry Andric         } else if (!E.Noname && ExportName.empty()) {
759ac9a064cSDimitry Andric           NameType = IMPORT_NAME_EXPORTAS;
760ac9a064cSDimitry Andric           ExportName = std::move(*getArm64ECDemangledFunctionName(Name));
761ac9a064cSDimitry Andric         }
762ac9a064cSDimitry Andric       }
763ac9a064cSDimitry Andric 
764ac9a064cSDimitry Andric       RegularImports[applyNameType(NameType, Name)] = Name;
765ac9a064cSDimitry Andric       Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType,
766ac9a064cSDimitry Andric                                              NameType, ExportName, M));
767ac9a064cSDimitry Andric     }
768ac9a064cSDimitry Andric     for (const auto &D : Renames) {
769ac9a064cSDimitry Andric       auto It = RegularImports.find(D.Export->ImportName);
770ac9a064cSDimitry Andric       if (It != RegularImports.end()) {
771ac9a064cSDimitry Andric         // We have a regular import entry for a symbol with the name we
772ac9a064cSDimitry Andric         // want to reference; produce an alias pointing at that.
773ac9a064cSDimitry Andric         StringRef Symbol = It->second;
774ac9a064cSDimitry Andric         if (D.ImpType == IMPORT_CODE)
775ac9a064cSDimitry Andric           Members.push_back(OF.createWeakExternal(Symbol, D.Name, false, M));
776ac9a064cSDimitry Andric         Members.push_back(OF.createWeakExternal(Symbol, D.Name, true, M));
777ac9a064cSDimitry Andric       } else {
778ac9a064cSDimitry Andric         Members.push_back(OF.createShortImport(D.Name, D.Export->Ordinal,
779ac9a064cSDimitry Andric                                                D.ImpType, IMPORT_NAME_EXPORTAS,
780ac9a064cSDimitry Andric                                                D.Export->ImportName, M));
781ac9a064cSDimitry Andric       }
782ac9a064cSDimitry Andric     }
783ac9a064cSDimitry Andric     return Error::success();
784ac9a064cSDimitry Andric   };
785ac9a064cSDimitry Andric 
786ac9a064cSDimitry Andric   if (Error e = addExports(Exports, Machine))
787ac9a064cSDimitry Andric     return e;
788ac9a064cSDimitry Andric   if (Error e = addExports(NativeExports, NativeMachine))
789ac9a064cSDimitry Andric     return e;
790ac9a064cSDimitry Andric 
791b1c73532SDimitry Andric   return writeArchive(Path, Members, SymtabWritingMode::NormalSymtab,
792ac9a064cSDimitry Andric                       object::Archive::K_COFF,
793b1c73532SDimitry Andric                       /*Deterministic*/ true, /*Thin*/ false,
794b1c73532SDimitry Andric                       /*OldArchiveBuf*/ nullptr, isArm64EC(Machine));
795b5630dbaSDimitry Andric }
796b5630dbaSDimitry Andric 
797b5630dbaSDimitry Andric } // namespace object
798b5630dbaSDimitry Andric } // namespace llvm
799