1d8866befSDimitry Andric //===- COFFImportFile.cpp - COFF short import file implementation ---------===//
2d8866befSDimitry Andric //
3d8866befSDimitry Andric //                     The LLVM Compiler Infrastructure
4d8866befSDimitry Andric //
5d8866befSDimitry Andric // This file is distributed under the University of Illinois Open Source
6d8866befSDimitry Andric // License. See LICENSE.TXT for details.
7d8866befSDimitry Andric //
8d8866befSDimitry Andric //===----------------------------------------------------------------------===//
9d8866befSDimitry Andric //
10d8866befSDimitry Andric // This file defines the writeImportLibrary function.
11d8866befSDimitry Andric //
12d8866befSDimitry Andric //===----------------------------------------------------------------------===//
13d8866befSDimitry Andric 
14d8866befSDimitry Andric #include "llvm/Object/COFFImportFile.h"
15d8866befSDimitry Andric #include "llvm/ADT/ArrayRef.h"
16d8866befSDimitry Andric #include "llvm/Object/Archive.h"
17d8866befSDimitry Andric #include "llvm/Object/ArchiveWriter.h"
18d8866befSDimitry Andric #include "llvm/Object/COFF.h"
19d8866befSDimitry Andric #include "llvm/Support/Error.h"
20d8866befSDimitry Andric #include "llvm/Support/Path.h"
21d8866befSDimitry Andric 
22d8866befSDimitry Andric #include <cstdint>
23d8866befSDimitry Andric #include <string>
24d8866befSDimitry Andric #include <vector>
25d8866befSDimitry Andric 
26d8866befSDimitry Andric using namespace llvm::COFF;
27d8866befSDimitry Andric using namespace llvm::object;
28d8866befSDimitry Andric using namespace llvm;
29d8866befSDimitry Andric 
30d8866befSDimitry Andric namespace llvm {
31d8866befSDimitry Andric namespace object {
32d8866befSDimitry Andric 
is32bit(MachineTypes Machine)33d8866befSDimitry Andric static bool is32bit(MachineTypes Machine) {
34d8866befSDimitry Andric   switch (Machine) {
35d8866befSDimitry Andric   default:
36d8866befSDimitry Andric     llvm_unreachable("unsupported machine");
372cab237bSDimitry Andric   case IMAGE_FILE_MACHINE_ARM64:
38d8866befSDimitry Andric   case IMAGE_FILE_MACHINE_AMD64:
39d8866befSDimitry Andric     return false;
40d8866befSDimitry Andric   case IMAGE_FILE_MACHINE_ARMNT:
41d8866befSDimitry Andric   case IMAGE_FILE_MACHINE_I386:
42d8866befSDimitry Andric     return true;
43d8866befSDimitry Andric   }
44d8866befSDimitry Andric }
45d8866befSDimitry Andric 
getImgRelRelocation(MachineTypes Machine)46d8866befSDimitry Andric static uint16_t getImgRelRelocation(MachineTypes Machine) {
47d8866befSDimitry Andric   switch (Machine) {
48d8866befSDimitry Andric   default:
49d8866befSDimitry Andric     llvm_unreachable("unsupported machine");
50d8866befSDimitry Andric   case IMAGE_FILE_MACHINE_AMD64:
51d8866befSDimitry Andric     return IMAGE_REL_AMD64_ADDR32NB;
52d8866befSDimitry Andric   case IMAGE_FILE_MACHINE_ARMNT:
53d8866befSDimitry Andric     return IMAGE_REL_ARM_ADDR32NB;
542cab237bSDimitry Andric   case IMAGE_FILE_MACHINE_ARM64:
552cab237bSDimitry Andric     return IMAGE_REL_ARM64_ADDR32NB;
56d8866befSDimitry Andric   case IMAGE_FILE_MACHINE_I386:
57d8866befSDimitry Andric     return IMAGE_REL_I386_DIR32NB;
58d8866befSDimitry Andric   }
59d8866befSDimitry Andric }
60d8866befSDimitry Andric 
append(std::vector<uint8_t> & B,const T & Data)61d8866befSDimitry Andric template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {
62d8866befSDimitry Andric   size_t S = B.size();
63d8866befSDimitry Andric   B.resize(S + sizeof(T));
64d8866befSDimitry Andric   memcpy(&B[S], &Data, sizeof(T));
65d8866befSDimitry Andric }
66d8866befSDimitry Andric 
writeStringTable(std::vector<uint8_t> & B,ArrayRef<const std::string> Strings)67d8866befSDimitry Andric static void writeStringTable(std::vector<uint8_t> &B,
68d8866befSDimitry Andric                              ArrayRef<const std::string> Strings) {
69d8866befSDimitry Andric   // The COFF string table consists of a 4-byte value which is the size of the
70d8866befSDimitry Andric   // table, including the length field itself.  This value is followed by the
71d8866befSDimitry Andric   // string content itself, which is an array of null-terminated C-style
72d8866befSDimitry Andric   // strings.  The termination is important as they are referenced to by offset
73d8866befSDimitry Andric   // by the symbol entity in the file format.
74d8866befSDimitry Andric 
75d8866befSDimitry Andric   size_t Pos = B.size();
76d8866befSDimitry Andric   size_t Offset = B.size();
77d8866befSDimitry Andric 
78d8866befSDimitry Andric   // Skip over the length field, we will fill it in later as we will have
79d8866befSDimitry Andric   // computed the length while emitting the string content itself.
80d8866befSDimitry Andric   Pos += sizeof(uint32_t);
81d8866befSDimitry Andric 
82d8866befSDimitry Andric   for (const auto &S : Strings) {
83d8866befSDimitry Andric     B.resize(Pos + S.length() + 1);
84d8866befSDimitry Andric     strcpy(reinterpret_cast<char *>(&B[Pos]), S.c_str());
85d8866befSDimitry Andric     Pos += S.length() + 1;
86d8866befSDimitry Andric   }
87d8866befSDimitry Andric 
88d8866befSDimitry Andric   // Backfill the length of the table now that it has been computed.
89d8866befSDimitry Andric   support::ulittle32_t Length(B.size() - Offset);
90d8866befSDimitry Andric   support::endian::write32le(&B[Offset], Length);
91d8866befSDimitry Andric }
92d8866befSDimitry Andric 
getNameType(StringRef Sym,StringRef ExtName,MachineTypes Machine,bool MinGW)93d8866befSDimitry Andric static ImportNameType getNameType(StringRef Sym, StringRef ExtName,
944ba319b5SDimitry Andric                                   MachineTypes Machine, bool MinGW) {
954ba319b5SDimitry Andric   // A decorated stdcall function in MSVC is exported with the
964ba319b5SDimitry Andric   // type IMPORT_NAME, and the exported function name includes the
974ba319b5SDimitry Andric   // the leading underscore. In MinGW on the other hand, a decorated
984ba319b5SDimitry Andric   // stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX).
994ba319b5SDimitry Andric   // See the comment in isDecorated in COFFModuleDefinition.cpp for more
1004ba319b5SDimitry Andric   // details.
1014ba319b5SDimitry Andric   if (ExtName.startswith("_") && ExtName.contains('@') && !MinGW)
1024ba319b5SDimitry Andric     return IMPORT_NAME;
103d8866befSDimitry Andric   if (Sym != ExtName)
104d8866befSDimitry Andric     return IMPORT_NAME_UNDECORATE;
105d8866befSDimitry Andric   if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.startswith("_"))
106d8866befSDimitry Andric     return IMPORT_NAME_NOPREFIX;
107d8866befSDimitry Andric   return IMPORT_NAME;
108d8866befSDimitry Andric }
109d8866befSDimitry Andric 
replace(StringRef S,StringRef From,StringRef To)110d8866befSDimitry Andric static Expected<std::string> replace(StringRef S, StringRef From,
111d8866befSDimitry Andric                                      StringRef To) {
112d8866befSDimitry Andric   size_t Pos = S.find(From);
113d8866befSDimitry Andric 
114d8866befSDimitry Andric   // From and To may be mangled, but substrings in S may not.
115d8866befSDimitry Andric   if (Pos == StringRef::npos && From.startswith("_") && To.startswith("_")) {
116d8866befSDimitry Andric     From = From.substr(1);
117d8866befSDimitry Andric     To = To.substr(1);
118d8866befSDimitry Andric     Pos = S.find(From);
119d8866befSDimitry Andric   }
120d8866befSDimitry Andric 
121d8866befSDimitry Andric   if (Pos == StringRef::npos) {
122d8866befSDimitry Andric     return make_error<StringError>(
123d8866befSDimitry Andric       StringRef(Twine(S + ": replacing '" + From +
124d8866befSDimitry Andric         "' with '" + To + "' failed").str()), object_error::parse_failed);
125d8866befSDimitry Andric   }
126d8866befSDimitry Andric 
127d8866befSDimitry Andric   return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
128d8866befSDimitry Andric }
129d8866befSDimitry Andric 
130d8866befSDimitry Andric static const std::string NullImportDescriptorSymbolName =
131d8866befSDimitry Andric     "__NULL_IMPORT_DESCRIPTOR";
132d8866befSDimitry Andric 
133d8866befSDimitry Andric namespace {
134d8866befSDimitry Andric // This class constructs various small object files necessary to support linking
135d8866befSDimitry Andric // symbols imported from a DLL.  The contents are pretty strictly defined and
136d8866befSDimitry Andric // nearly entirely static.  The details of the structures files are defined in
137d8866befSDimitry Andric // WINNT.h and the PE/COFF specification.
138d8866befSDimitry Andric class ObjectFactory {
139d8866befSDimitry Andric   using u16 = support::ulittle16_t;
140d8866befSDimitry Andric   using u32 = support::ulittle32_t;
141d8866befSDimitry Andric   MachineTypes Machine;
142d8866befSDimitry Andric   BumpPtrAllocator Alloc;
143b40b48b8SDimitry Andric   StringRef ImportName;
144d8866befSDimitry Andric   StringRef Library;
145d8866befSDimitry Andric   std::string ImportDescriptorSymbolName;
146d8866befSDimitry Andric   std::string NullThunkSymbolName;
147d8866befSDimitry Andric 
148d8866befSDimitry Andric public:
ObjectFactory(StringRef S,MachineTypes M)149d8866befSDimitry Andric   ObjectFactory(StringRef S, MachineTypes M)
150b40b48b8SDimitry Andric       : Machine(M), ImportName(S), Library(S.drop_back(4)),
151d8866befSDimitry Andric         ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()),
152d8866befSDimitry Andric         NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {}
153d8866befSDimitry Andric 
154d8866befSDimitry Andric   // Creates an Import Descriptor.  This is a small object file which contains a
155d8866befSDimitry Andric   // reference to the terminators and contains the library name (entry) for the
156d8866befSDimitry Andric   // import name table.  It will force the linker to construct the necessary
157d8866befSDimitry Andric   // structure to import symbols from the DLL.
158d8866befSDimitry Andric   NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);
159d8866befSDimitry Andric 
160d8866befSDimitry Andric   // Creates a NULL import descriptor.  This is a small object file whcih
161d8866befSDimitry Andric   // contains a NULL import descriptor.  It is used to terminate the imports
162d8866befSDimitry Andric   // from a specific DLL.
163d8866befSDimitry Andric   NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);
164d8866befSDimitry Andric 
165d8866befSDimitry Andric   // Create a NULL Thunk Entry.  This is a small object file which contains a
166d8866befSDimitry Andric   // NULL Import Address Table entry and a NULL Import Lookup Table Entry.  It
167d8866befSDimitry Andric   // is used to terminate the IAT and ILT.
168d8866befSDimitry Andric   NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);
169d8866befSDimitry Andric 
170d8866befSDimitry Andric   // Create a short import file which is described in PE/COFF spec 7. Import
171d8866befSDimitry Andric   // Library Format.
172d8866befSDimitry Andric   NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
173d8866befSDimitry Andric                                      ImportType Type, ImportNameType NameType);
174b40b48b8SDimitry Andric 
175b40b48b8SDimitry Andric   // Create a weak external file which is described in PE/COFF Aux Format 3.
176b40b48b8SDimitry Andric   NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp);
177d8866befSDimitry Andric };
178d8866befSDimitry Andric } // namespace
179d8866befSDimitry Andric 
180d8866befSDimitry Andric NewArchiveMember
createImportDescriptor(std::vector<uint8_t> & Buffer)181d8866befSDimitry Andric ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
182b40b48b8SDimitry Andric   const uint32_t NumberOfSections = 2;
183b40b48b8SDimitry Andric   const uint32_t NumberOfSymbols = 7;
184b40b48b8SDimitry Andric   const uint32_t NumberOfRelocations = 3;
185d8866befSDimitry Andric 
186d8866befSDimitry Andric   // COFF Header
187d8866befSDimitry Andric   coff_file_header Header{
188d8866befSDimitry Andric       u16(Machine),
189d8866befSDimitry Andric       u16(NumberOfSections),
190d8866befSDimitry Andric       u32(0),
191d8866befSDimitry Andric       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
192d8866befSDimitry Andric           // .idata$2
193d8866befSDimitry Andric           sizeof(coff_import_directory_table_entry) +
194d8866befSDimitry Andric           NumberOfRelocations * sizeof(coff_relocation) +
195d8866befSDimitry Andric           // .idata$4
196b40b48b8SDimitry Andric           (ImportName.size() + 1)),
197d8866befSDimitry Andric       u32(NumberOfSymbols),
198d8866befSDimitry Andric       u16(0),
1992cab237bSDimitry Andric       u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
200d8866befSDimitry Andric   };
201d8866befSDimitry Andric   append(Buffer, Header);
202d8866befSDimitry Andric 
203d8866befSDimitry Andric   // Section Header Table
204b40b48b8SDimitry Andric   const coff_section SectionTable[NumberOfSections] = {
205d8866befSDimitry Andric       {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
206d8866befSDimitry Andric        u32(0),
207d8866befSDimitry Andric        u32(0),
208d8866befSDimitry Andric        u32(sizeof(coff_import_directory_table_entry)),
209d8866befSDimitry Andric        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
210d8866befSDimitry Andric        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
211d8866befSDimitry Andric            sizeof(coff_import_directory_table_entry)),
212d8866befSDimitry Andric        u32(0),
213d8866befSDimitry Andric        u16(NumberOfRelocations),
214d8866befSDimitry Andric        u16(0),
215d8866befSDimitry Andric        u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
216d8866befSDimitry Andric            IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
217d8866befSDimitry Andric       {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
218d8866befSDimitry Andric        u32(0),
219d8866befSDimitry Andric        u32(0),
220b40b48b8SDimitry Andric        u32(ImportName.size() + 1),
221d8866befSDimitry Andric        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
222d8866befSDimitry Andric            sizeof(coff_import_directory_table_entry) +
223d8866befSDimitry Andric            NumberOfRelocations * sizeof(coff_relocation)),
224d8866befSDimitry Andric        u32(0),
225d8866befSDimitry Andric        u32(0),
226d8866befSDimitry Andric        u16(0),
227d8866befSDimitry Andric        u16(0),
228d8866befSDimitry Andric        u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
229d8866befSDimitry Andric            IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
230d8866befSDimitry Andric   };
231d8866befSDimitry Andric   append(Buffer, SectionTable);
232d8866befSDimitry Andric 
233d8866befSDimitry Andric   // .idata$2
234b40b48b8SDimitry Andric   const coff_import_directory_table_entry ImportDescriptor{
235d8866befSDimitry Andric       u32(0), u32(0), u32(0), u32(0), u32(0),
236d8866befSDimitry Andric   };
237d8866befSDimitry Andric   append(Buffer, ImportDescriptor);
238d8866befSDimitry Andric 
239b40b48b8SDimitry Andric   const coff_relocation RelocationTable[NumberOfRelocations] = {
240d8866befSDimitry Andric       {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
241d8866befSDimitry Andric        u16(getImgRelRelocation(Machine))},
242d8866befSDimitry Andric       {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
243d8866befSDimitry Andric        u32(3), u16(getImgRelRelocation(Machine))},
244d8866befSDimitry Andric       {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
245d8866befSDimitry Andric        u32(4), u16(getImgRelRelocation(Machine))},
246d8866befSDimitry Andric   };
247d8866befSDimitry Andric   append(Buffer, RelocationTable);
248d8866befSDimitry Andric 
249d8866befSDimitry Andric   // .idata$6
250d8866befSDimitry Andric   auto S = Buffer.size();
251b40b48b8SDimitry Andric   Buffer.resize(S + ImportName.size() + 1);
252b40b48b8SDimitry Andric   memcpy(&Buffer[S], ImportName.data(), ImportName.size());
253b40b48b8SDimitry Andric   Buffer[S + ImportName.size()] = '\0';
254d8866befSDimitry Andric 
255d8866befSDimitry Andric   // Symbol Table
256d8866befSDimitry Andric   coff_symbol16 SymbolTable[NumberOfSymbols] = {
257d8866befSDimitry Andric       {{{0, 0, 0, 0, 0, 0, 0, 0}},
258d8866befSDimitry Andric        u32(0),
259d8866befSDimitry Andric        u16(1),
260d8866befSDimitry Andric        u16(0),
261d8866befSDimitry Andric        IMAGE_SYM_CLASS_EXTERNAL,
262d8866befSDimitry Andric        0},
263d8866befSDimitry Andric       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
264d8866befSDimitry Andric        u32(0),
265d8866befSDimitry Andric        u16(1),
266d8866befSDimitry Andric        u16(0),
267d8866befSDimitry Andric        IMAGE_SYM_CLASS_SECTION,
268d8866befSDimitry Andric        0},
269d8866befSDimitry Andric       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
270d8866befSDimitry Andric        u32(0),
271d8866befSDimitry Andric        u16(2),
272d8866befSDimitry Andric        u16(0),
273d8866befSDimitry Andric        IMAGE_SYM_CLASS_STATIC,
274d8866befSDimitry Andric        0},
275d8866befSDimitry Andric       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
276d8866befSDimitry Andric        u32(0),
277d8866befSDimitry Andric        u16(0),
278d8866befSDimitry Andric        u16(0),
279d8866befSDimitry Andric        IMAGE_SYM_CLASS_SECTION,
280d8866befSDimitry Andric        0},
281d8866befSDimitry Andric       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
282d8866befSDimitry Andric        u32(0),
283d8866befSDimitry Andric        u16(0),
284d8866befSDimitry Andric        u16(0),
285d8866befSDimitry Andric        IMAGE_SYM_CLASS_SECTION,
286d8866befSDimitry Andric        0},
287d8866befSDimitry Andric       {{{0, 0, 0, 0, 0, 0, 0, 0}},
288d8866befSDimitry Andric        u32(0),
289d8866befSDimitry Andric        u16(0),
290d8866befSDimitry Andric        u16(0),
291d8866befSDimitry Andric        IMAGE_SYM_CLASS_EXTERNAL,
292d8866befSDimitry Andric        0},
293d8866befSDimitry Andric       {{{0, 0, 0, 0, 0, 0, 0, 0}},
294d8866befSDimitry Andric        u32(0),
295d8866befSDimitry Andric        u16(0),
296d8866befSDimitry Andric        u16(0),
297d8866befSDimitry Andric        IMAGE_SYM_CLASS_EXTERNAL,
298d8866befSDimitry Andric        0},
299d8866befSDimitry Andric   };
300db17bf38SDimitry Andric   // TODO: Name.Offset.Offset here and in the all similar places below
301db17bf38SDimitry Andric   // suggests a names refactoring. Maybe StringTableOffset.Value?
302db17bf38SDimitry Andric   SymbolTable[0].Name.Offset.Offset =
303d8866befSDimitry Andric       sizeof(uint32_t);
304db17bf38SDimitry Andric   SymbolTable[5].Name.Offset.Offset =
305d8866befSDimitry Andric       sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
306db17bf38SDimitry Andric   SymbolTable[6].Name.Offset.Offset =
307d8866befSDimitry Andric       sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
308d8866befSDimitry Andric       NullImportDescriptorSymbolName.length() + 1;
309d8866befSDimitry Andric   append(Buffer, SymbolTable);
310d8866befSDimitry Andric 
311d8866befSDimitry Andric   // String Table
312d8866befSDimitry Andric   writeStringTable(Buffer,
313d8866befSDimitry Andric                    {ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
314d8866befSDimitry Andric                     NullThunkSymbolName});
315d8866befSDimitry Andric 
316d8866befSDimitry Andric   StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
317b40b48b8SDimitry Andric   return {MemoryBufferRef(F, ImportName)};
318d8866befSDimitry Andric }
319d8866befSDimitry Andric 
320d8866befSDimitry Andric NewArchiveMember
createNullImportDescriptor(std::vector<uint8_t> & Buffer)321d8866befSDimitry Andric ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
322b40b48b8SDimitry Andric   const uint32_t NumberOfSections = 1;
323b40b48b8SDimitry Andric   const uint32_t NumberOfSymbols = 1;
324d8866befSDimitry Andric 
325d8866befSDimitry Andric   // COFF Header
326d8866befSDimitry Andric   coff_file_header Header{
327d8866befSDimitry Andric       u16(Machine),
328d8866befSDimitry Andric       u16(NumberOfSections),
329d8866befSDimitry Andric       u32(0),
330d8866befSDimitry Andric       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
331d8866befSDimitry Andric           // .idata$3
332d8866befSDimitry Andric           sizeof(coff_import_directory_table_entry)),
333d8866befSDimitry Andric       u32(NumberOfSymbols),
334d8866befSDimitry Andric       u16(0),
3352cab237bSDimitry Andric       u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
336d8866befSDimitry Andric   };
337d8866befSDimitry Andric   append(Buffer, Header);
338d8866befSDimitry Andric 
339d8866befSDimitry Andric   // Section Header Table
340b40b48b8SDimitry Andric   const coff_section SectionTable[NumberOfSections] = {
341d8866befSDimitry Andric       {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
342d8866befSDimitry Andric        u32(0),
343d8866befSDimitry Andric        u32(0),
344d8866befSDimitry Andric        u32(sizeof(coff_import_directory_table_entry)),
345d8866befSDimitry Andric        u32(sizeof(coff_file_header) +
346d8866befSDimitry Andric            (NumberOfSections * sizeof(coff_section))),
347d8866befSDimitry Andric        u32(0),
348d8866befSDimitry Andric        u32(0),
349d8866befSDimitry Andric        u16(0),
350d8866befSDimitry Andric        u16(0),
351d8866befSDimitry Andric        u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
352d8866befSDimitry Andric            IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
353d8866befSDimitry Andric   };
354d8866befSDimitry Andric   append(Buffer, SectionTable);
355d8866befSDimitry Andric 
356d8866befSDimitry Andric   // .idata$3
357b40b48b8SDimitry Andric   const coff_import_directory_table_entry ImportDescriptor{
358d8866befSDimitry Andric       u32(0), u32(0), u32(0), u32(0), u32(0),
359d8866befSDimitry Andric   };
360d8866befSDimitry Andric   append(Buffer, ImportDescriptor);
361d8866befSDimitry Andric 
362d8866befSDimitry Andric   // Symbol Table
363d8866befSDimitry Andric   coff_symbol16 SymbolTable[NumberOfSymbols] = {
364d8866befSDimitry Andric       {{{0, 0, 0, 0, 0, 0, 0, 0}},
365d8866befSDimitry Andric        u32(0),
366d8866befSDimitry Andric        u16(1),
367d8866befSDimitry Andric        u16(0),
368d8866befSDimitry Andric        IMAGE_SYM_CLASS_EXTERNAL,
369d8866befSDimitry Andric        0},
370d8866befSDimitry Andric   };
371db17bf38SDimitry Andric   SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
372d8866befSDimitry Andric   append(Buffer, SymbolTable);
373d8866befSDimitry Andric 
374d8866befSDimitry Andric   // String Table
375d8866befSDimitry Andric   writeStringTable(Buffer, {NullImportDescriptorSymbolName});
376d8866befSDimitry Andric 
377d8866befSDimitry Andric   StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
378b40b48b8SDimitry Andric   return {MemoryBufferRef(F, ImportName)};
379d8866befSDimitry Andric }
380d8866befSDimitry Andric 
createNullThunk(std::vector<uint8_t> & Buffer)381d8866befSDimitry Andric NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
382b40b48b8SDimitry Andric   const uint32_t NumberOfSections = 2;
383b40b48b8SDimitry Andric   const uint32_t NumberOfSymbols = 1;
384d8866befSDimitry Andric   uint32_t VASize = is32bit(Machine) ? 4 : 8;
385d8866befSDimitry Andric 
386d8866befSDimitry Andric   // COFF Header
387d8866befSDimitry Andric   coff_file_header Header{
388d8866befSDimitry Andric       u16(Machine),
389d8866befSDimitry Andric       u16(NumberOfSections),
390d8866befSDimitry Andric       u32(0),
391d8866befSDimitry Andric       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
392d8866befSDimitry Andric           // .idata$5
393d8866befSDimitry Andric           VASize +
394d8866befSDimitry Andric           // .idata$4
395d8866befSDimitry Andric           VASize),
396d8866befSDimitry Andric       u32(NumberOfSymbols),
397d8866befSDimitry Andric       u16(0),
3982cab237bSDimitry Andric       u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
399d8866befSDimitry Andric   };
400d8866befSDimitry Andric   append(Buffer, Header);
401d8866befSDimitry Andric 
402d8866befSDimitry Andric   // Section Header Table
403b40b48b8SDimitry Andric   const coff_section SectionTable[NumberOfSections] = {
404d8866befSDimitry Andric       {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
405d8866befSDimitry Andric        u32(0),
406d8866befSDimitry Andric        u32(0),
407d8866befSDimitry Andric        u32(VASize),
408d8866befSDimitry Andric        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
409d8866befSDimitry Andric        u32(0),
410d8866befSDimitry Andric        u32(0),
411d8866befSDimitry Andric        u16(0),
412d8866befSDimitry Andric        u16(0),
413d8866befSDimitry Andric        u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
414d8866befSDimitry Andric                              : IMAGE_SCN_ALIGN_8BYTES) |
415d8866befSDimitry Andric            IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
416d8866befSDimitry Andric            IMAGE_SCN_MEM_WRITE)},
417d8866befSDimitry Andric       {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
418d8866befSDimitry Andric        u32(0),
419d8866befSDimitry Andric        u32(0),
420d8866befSDimitry Andric        u32(VASize),
421d8866befSDimitry Andric        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
422d8866befSDimitry Andric            VASize),
423d8866befSDimitry Andric        u32(0),
424d8866befSDimitry Andric        u32(0),
425d8866befSDimitry Andric        u16(0),
426d8866befSDimitry Andric        u16(0),
427d8866befSDimitry Andric        u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
428d8866befSDimitry Andric                              : IMAGE_SCN_ALIGN_8BYTES) |
429d8866befSDimitry Andric            IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
430d8866befSDimitry Andric            IMAGE_SCN_MEM_WRITE)},
431d8866befSDimitry Andric   };
432d8866befSDimitry Andric   append(Buffer, SectionTable);
433d8866befSDimitry Andric 
434d8866befSDimitry Andric   // .idata$5, ILT
435d8866befSDimitry Andric   append(Buffer, u32(0));
436d8866befSDimitry Andric   if (!is32bit(Machine))
437d8866befSDimitry Andric     append(Buffer, u32(0));
438d8866befSDimitry Andric 
439d8866befSDimitry Andric   // .idata$4, IAT
440d8866befSDimitry Andric   append(Buffer, u32(0));
441d8866befSDimitry Andric   if (!is32bit(Machine))
442d8866befSDimitry Andric     append(Buffer, u32(0));
443d8866befSDimitry Andric 
444d8866befSDimitry Andric   // Symbol Table
445d8866befSDimitry Andric   coff_symbol16 SymbolTable[NumberOfSymbols] = {
446d8866befSDimitry Andric       {{{0, 0, 0, 0, 0, 0, 0, 0}},
447d8866befSDimitry Andric        u32(0),
448d8866befSDimitry Andric        u16(1),
449d8866befSDimitry Andric        u16(0),
450d8866befSDimitry Andric        IMAGE_SYM_CLASS_EXTERNAL,
451d8866befSDimitry Andric        0},
452d8866befSDimitry Andric   };
453db17bf38SDimitry Andric   SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
454d8866befSDimitry Andric   append(Buffer, SymbolTable);
455d8866befSDimitry Andric 
456d8866befSDimitry Andric   // String Table
457d8866befSDimitry Andric   writeStringTable(Buffer, {NullThunkSymbolName});
458d8866befSDimitry Andric 
459d8866befSDimitry Andric   StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
460b40b48b8SDimitry Andric   return {MemoryBufferRef{F, ImportName}};
461d8866befSDimitry Andric }
462d8866befSDimitry Andric 
createShortImport(StringRef Sym,uint16_t Ordinal,ImportType ImportType,ImportNameType NameType)463d8866befSDimitry Andric NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
464d8866befSDimitry Andric                                                   uint16_t Ordinal,
465d8866befSDimitry Andric                                                   ImportType ImportType,
466d8866befSDimitry Andric                                                   ImportNameType NameType) {
467b40b48b8SDimitry Andric   size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs
468d8866befSDimitry Andric   size_t Size = sizeof(coff_import_header) + ImpSize;
469d8866befSDimitry Andric   char *Buf = Alloc.Allocate<char>(Size);
470d8866befSDimitry Andric   memset(Buf, 0, Size);
471d8866befSDimitry Andric   char *P = Buf;
472d8866befSDimitry Andric 
473d8866befSDimitry Andric   // Write short import library.
474d8866befSDimitry Andric   auto *Imp = reinterpret_cast<coff_import_header *>(P);
475d8866befSDimitry Andric   P += sizeof(*Imp);
476d8866befSDimitry Andric   Imp->Sig2 = 0xFFFF;
477d8866befSDimitry Andric   Imp->Machine = Machine;
478d8866befSDimitry Andric   Imp->SizeOfData = ImpSize;
479d8866befSDimitry Andric   if (Ordinal > 0)
480d8866befSDimitry Andric     Imp->OrdinalHint = Ordinal;
481d8866befSDimitry Andric   Imp->TypeInfo = (NameType << 2) | ImportType;
482d8866befSDimitry Andric 
483d8866befSDimitry Andric   // Write symbol name and DLL name.
484d8866befSDimitry Andric   memcpy(P, Sym.data(), Sym.size());
485d8866befSDimitry Andric   P += Sym.size() + 1;
486b40b48b8SDimitry Andric   memcpy(P, ImportName.data(), ImportName.size());
487d8866befSDimitry Andric 
488b40b48b8SDimitry Andric   return {MemoryBufferRef(StringRef(Buf, Size), ImportName)};
489d8866befSDimitry Andric }
490d8866befSDimitry Andric 
createWeakExternal(StringRef Sym,StringRef Weak,bool Imp)491b40b48b8SDimitry Andric NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym,
492b40b48b8SDimitry Andric                                                    StringRef Weak, bool Imp) {
493b40b48b8SDimitry Andric   std::vector<uint8_t> Buffer;
494b40b48b8SDimitry Andric   const uint32_t NumberOfSections = 1;
495b40b48b8SDimitry Andric   const uint32_t NumberOfSymbols = 5;
496b40b48b8SDimitry Andric 
497b40b48b8SDimitry Andric   // COFF Header
498b40b48b8SDimitry Andric   coff_file_header Header{
499*85573313SDimitry Andric       u16(Machine),
500b40b48b8SDimitry Andric       u16(NumberOfSections),
501b40b48b8SDimitry Andric       u32(0),
502b40b48b8SDimitry Andric       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))),
503b40b48b8SDimitry Andric       u32(NumberOfSymbols),
504b40b48b8SDimitry Andric       u16(0),
505b40b48b8SDimitry Andric       u16(0),
506b40b48b8SDimitry Andric   };
507b40b48b8SDimitry Andric   append(Buffer, Header);
508b40b48b8SDimitry Andric 
509b40b48b8SDimitry Andric   // Section Header Table
510b40b48b8SDimitry Andric   const coff_section SectionTable[NumberOfSections] = {
511b40b48b8SDimitry Andric       {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'},
512b40b48b8SDimitry Andric        u32(0),
513b40b48b8SDimitry Andric        u32(0),
514b40b48b8SDimitry Andric        u32(0),
515b40b48b8SDimitry Andric        u32(0),
516b40b48b8SDimitry Andric        u32(0),
517b40b48b8SDimitry Andric        u32(0),
518b40b48b8SDimitry Andric        u16(0),
519b40b48b8SDimitry Andric        u16(0),
520b40b48b8SDimitry Andric        u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}};
521b40b48b8SDimitry Andric   append(Buffer, SectionTable);
522b40b48b8SDimitry Andric 
523b40b48b8SDimitry Andric   // Symbol Table
524b40b48b8SDimitry Andric   coff_symbol16 SymbolTable[NumberOfSymbols] = {
525b40b48b8SDimitry Andric       {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},
526b40b48b8SDimitry Andric        u32(0),
527b40b48b8SDimitry Andric        u16(0xFFFF),
528b40b48b8SDimitry Andric        u16(0),
529b40b48b8SDimitry Andric        IMAGE_SYM_CLASS_STATIC,
530b40b48b8SDimitry Andric        0},
531b40b48b8SDimitry Andric       {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}},
532b40b48b8SDimitry Andric        u32(0),
533b40b48b8SDimitry Andric        u16(0xFFFF),
534b40b48b8SDimitry Andric        u16(0),
535b40b48b8SDimitry Andric        IMAGE_SYM_CLASS_STATIC,
536b40b48b8SDimitry Andric        0},
537b40b48b8SDimitry Andric       {{{0, 0, 0, 0, 0, 0, 0, 0}},
538b40b48b8SDimitry Andric        u32(0),
539b40b48b8SDimitry Andric        u16(0),
540b40b48b8SDimitry Andric        u16(0),
541b40b48b8SDimitry Andric        IMAGE_SYM_CLASS_EXTERNAL,
542b40b48b8SDimitry Andric        0},
543b40b48b8SDimitry Andric       {{{0, 0, 0, 0, 0, 0, 0, 0}},
544b40b48b8SDimitry Andric        u32(0),
545b40b48b8SDimitry Andric        u16(0),
546b40b48b8SDimitry Andric        u16(0),
547b40b48b8SDimitry Andric        IMAGE_SYM_CLASS_WEAK_EXTERNAL,
548b40b48b8SDimitry Andric        1},
5494ba319b5SDimitry Andric       {{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}},
5504ba319b5SDimitry Andric        u32(0),
5514ba319b5SDimitry Andric        u16(0),
5524ba319b5SDimitry Andric        u16(0),
5534ba319b5SDimitry Andric        IMAGE_SYM_CLASS_NULL,
5544ba319b5SDimitry Andric        0},
555b40b48b8SDimitry Andric   };
556b40b48b8SDimitry Andric   SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t);
557b40b48b8SDimitry Andric 
558b40b48b8SDimitry Andric   //__imp_ String Table
5599dc417c3SDimitry Andric   StringRef Prefix = Imp ? "__imp_" : "";
5609dc417c3SDimitry Andric   SymbolTable[3].Name.Offset.Offset =
5619dc417c3SDimitry Andric       sizeof(uint32_t) + Sym.size() + Prefix.size() + 1;
562b40b48b8SDimitry Andric   append(Buffer, SymbolTable);
5639dc417c3SDimitry Andric   writeStringTable(Buffer, {(Prefix + Sym).str(),
5649dc417c3SDimitry Andric                             (Prefix + Weak).str()});
565b40b48b8SDimitry Andric 
566b40b48b8SDimitry Andric   // Copied here so we can still use writeStringTable
567b40b48b8SDimitry Andric   char *Buf = Alloc.Allocate<char>(Buffer.size());
568b40b48b8SDimitry Andric   memcpy(Buf, Buffer.data(), Buffer.size());
569b40b48b8SDimitry Andric   return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)};
570b40b48b8SDimitry Andric }
571b40b48b8SDimitry Andric 
writeImportLibrary(StringRef ImportName,StringRef Path,ArrayRef<COFFShortExport> Exports,MachineTypes Machine,bool MinGW)5722cab237bSDimitry Andric Error writeImportLibrary(StringRef ImportName, StringRef Path,
573d8866befSDimitry Andric                          ArrayRef<COFFShortExport> Exports,
5744ba319b5SDimitry Andric                          MachineTypes Machine, bool MinGW) {
575d8866befSDimitry Andric 
576d8866befSDimitry Andric   std::vector<NewArchiveMember> Members;
577b40b48b8SDimitry Andric   ObjectFactory OF(llvm::sys::path::filename(ImportName), Machine);
578d8866befSDimitry Andric 
579d8866befSDimitry Andric   std::vector<uint8_t> ImportDescriptor;
580d8866befSDimitry Andric   Members.push_back(OF.createImportDescriptor(ImportDescriptor));
581d8866befSDimitry Andric 
582d8866befSDimitry Andric   std::vector<uint8_t> NullImportDescriptor;
583d8866befSDimitry Andric   Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));
584d8866befSDimitry Andric 
585d8866befSDimitry Andric   std::vector<uint8_t> NullThunk;
586d8866befSDimitry Andric   Members.push_back(OF.createNullThunk(NullThunk));
587d8866befSDimitry Andric 
588d8866befSDimitry Andric   for (COFFShortExport E : Exports) {
589d8866befSDimitry Andric     if (E.Private)
590d8866befSDimitry Andric       continue;
591d8866befSDimitry Andric 
592d8866befSDimitry Andric     ImportType ImportType = IMPORT_CODE;
593d8866befSDimitry Andric     if (E.Data)
594d8866befSDimitry Andric       ImportType = IMPORT_DATA;
595d8866befSDimitry Andric     if (E.Constant)
596d8866befSDimitry Andric       ImportType = IMPORT_CONST;
597d8866befSDimitry Andric 
5980554abf0SDimitry Andric     StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName;
5994ba319b5SDimitry Andric     ImportNameType NameType = getNameType(SymbolName, E.Name, Machine, MinGW);
600d8866befSDimitry Andric     Expected<std::string> Name = E.ExtName.empty()
601d8866befSDimitry Andric                                      ? SymbolName
602d8866befSDimitry Andric                                      : replace(SymbolName, E.Name, E.ExtName);
603d8866befSDimitry Andric 
6042cab237bSDimitry Andric     if (!Name)
6052cab237bSDimitry Andric       return Name.takeError();
606d8866befSDimitry Andric 
6074ba319b5SDimitry Andric     if (!E.AliasTarget.empty() && *Name != E.AliasTarget) {
6084ba319b5SDimitry Andric       Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, false));
6094ba319b5SDimitry Andric       Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, true));
6104ba319b5SDimitry Andric       continue;
6114ba319b5SDimitry Andric     }
6124ba319b5SDimitry Andric 
613d8866befSDimitry Andric     Members.push_back(
614d8866befSDimitry Andric         OF.createShortImport(*Name, E.Ordinal, ImportType, NameType));
615d8866befSDimitry Andric   }
616d8866befSDimitry Andric 
6172cab237bSDimitry Andric   return writeArchive(Path, Members, /*WriteSymtab*/ true,
6182cab237bSDimitry Andric                       object::Archive::K_GNU,
619d8866befSDimitry Andric                       /*Deterministic*/ true, /*Thin*/ false);
620d8866befSDimitry Andric }
621d8866befSDimitry Andric 
622d8866befSDimitry Andric } // namespace object
623d8866befSDimitry Andric } // namespace llvm
624