1146eb7a6SReid Kleckner //===- COFFImportFile.cpp - COFF short import file implementation ---------===//
2146eb7a6SReid Kleckner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6146eb7a6SReid Kleckner //
7146eb7a6SReid Kleckner //===----------------------------------------------------------------------===//
8146eb7a6SReid Kleckner //
9146eb7a6SReid Kleckner // This file defines the writeImportLibrary function.
10146eb7a6SReid Kleckner //
11146eb7a6SReid Kleckner //===----------------------------------------------------------------------===//
12146eb7a6SReid Kleckner 
13146eb7a6SReid Kleckner #include "llvm/Object/COFFImportFile.h"
14146eb7a6SReid Kleckner #include "llvm/ADT/ArrayRef.h"
15*e72c195fSserge-sans-paille #include "llvm/ADT/Twine.h"
16146eb7a6SReid Kleckner #include "llvm/Object/Archive.h"
17146eb7a6SReid Kleckner #include "llvm/Object/ArchiveWriter.h"
18146eb7a6SReid Kleckner #include "llvm/Object/COFF.h"
19*e72c195fSserge-sans-paille #include "llvm/Support/Allocator.h"
20*e72c195fSserge-sans-paille #include "llvm/Support/Endian.h"
21146eb7a6SReid Kleckner #include "llvm/Support/Error.h"
22*e72c195fSserge-sans-paille #include "llvm/Support/ErrorHandling.h"
23146eb7a6SReid Kleckner #include "llvm/Support/Path.h"
24146eb7a6SReid Kleckner 
25146eb7a6SReid Kleckner #include <cstdint>
26146eb7a6SReid Kleckner #include <string>
27146eb7a6SReid Kleckner #include <vector>
28146eb7a6SReid Kleckner 
29146eb7a6SReid Kleckner using namespace llvm::COFF;
30146eb7a6SReid Kleckner using namespace llvm::object;
31146eb7a6SReid Kleckner using namespace llvm;
32146eb7a6SReid Kleckner 
33146eb7a6SReid Kleckner namespace llvm {
34146eb7a6SReid Kleckner namespace object {
35146eb7a6SReid Kleckner 
is32bit(MachineTypes Machine)36146eb7a6SReid Kleckner static bool is32bit(MachineTypes Machine) {
37146eb7a6SReid Kleckner   switch (Machine) {
38146eb7a6SReid Kleckner   default:
39146eb7a6SReid Kleckner     llvm_unreachable("unsupported machine");
40b9ff4191SMartin Storsjo   case IMAGE_FILE_MACHINE_ARM64:
41146eb7a6SReid Kleckner   case IMAGE_FILE_MACHINE_AMD64:
42146eb7a6SReid Kleckner     return false;
43146eb7a6SReid Kleckner   case IMAGE_FILE_MACHINE_ARMNT:
44146eb7a6SReid Kleckner   case IMAGE_FILE_MACHINE_I386:
45146eb7a6SReid Kleckner     return true;
46146eb7a6SReid Kleckner   }
47146eb7a6SReid Kleckner }
48146eb7a6SReid Kleckner 
getImgRelRelocation(MachineTypes Machine)49146eb7a6SReid Kleckner static uint16_t getImgRelRelocation(MachineTypes Machine) {
50146eb7a6SReid Kleckner   switch (Machine) {
51146eb7a6SReid Kleckner   default:
52146eb7a6SReid Kleckner     llvm_unreachable("unsupported machine");
53146eb7a6SReid Kleckner   case IMAGE_FILE_MACHINE_AMD64:
54146eb7a6SReid Kleckner     return IMAGE_REL_AMD64_ADDR32NB;
55146eb7a6SReid Kleckner   case IMAGE_FILE_MACHINE_ARMNT:
56146eb7a6SReid Kleckner     return IMAGE_REL_ARM_ADDR32NB;
57b9ff4191SMartin Storsjo   case IMAGE_FILE_MACHINE_ARM64:
58b9ff4191SMartin Storsjo     return IMAGE_REL_ARM64_ADDR32NB;
59146eb7a6SReid Kleckner   case IMAGE_FILE_MACHINE_I386:
60146eb7a6SReid Kleckner     return IMAGE_REL_I386_DIR32NB;
61146eb7a6SReid Kleckner   }
62146eb7a6SReid Kleckner }
63146eb7a6SReid Kleckner 
append(std::vector<uint8_t> & B,const T & Data)64146eb7a6SReid Kleckner template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {
65146eb7a6SReid Kleckner   size_t S = B.size();
66146eb7a6SReid Kleckner   B.resize(S + sizeof(T));
67146eb7a6SReid Kleckner   memcpy(&B[S], &Data, sizeof(T));
68146eb7a6SReid Kleckner }
69146eb7a6SReid Kleckner 
writeStringTable(std::vector<uint8_t> & B,ArrayRef<const std::string> Strings)70146eb7a6SReid Kleckner static void writeStringTable(std::vector<uint8_t> &B,
71146eb7a6SReid Kleckner                              ArrayRef<const std::string> Strings) {
72146eb7a6SReid Kleckner   // The COFF string table consists of a 4-byte value which is the size of the
73146eb7a6SReid Kleckner   // table, including the length field itself.  This value is followed by the
74146eb7a6SReid Kleckner   // string content itself, which is an array of null-terminated C-style
75146eb7a6SReid Kleckner   // strings.  The termination is important as they are referenced to by offset
76146eb7a6SReid Kleckner   // by the symbol entity in the file format.
77146eb7a6SReid Kleckner 
78146eb7a6SReid Kleckner   size_t Pos = B.size();
79146eb7a6SReid Kleckner   size_t Offset = B.size();
80146eb7a6SReid Kleckner 
81146eb7a6SReid Kleckner   // Skip over the length field, we will fill it in later as we will have
82146eb7a6SReid Kleckner   // computed the length while emitting the string content itself.
83146eb7a6SReid Kleckner   Pos += sizeof(uint32_t);
84146eb7a6SReid Kleckner 
85146eb7a6SReid Kleckner   for (const auto &S : Strings) {
86146eb7a6SReid Kleckner     B.resize(Pos + S.length() + 1);
87146eb7a6SReid Kleckner     strcpy(reinterpret_cast<char *>(&B[Pos]), S.c_str());
88146eb7a6SReid Kleckner     Pos += S.length() + 1;
89146eb7a6SReid Kleckner   }
90146eb7a6SReid Kleckner 
91146eb7a6SReid Kleckner   // Backfill the length of the table now that it has been computed.
92146eb7a6SReid Kleckner   support::ulittle32_t Length(B.size() - Offset);
93146eb7a6SReid Kleckner   support::endian::write32le(&B[Offset], Length);
94146eb7a6SReid Kleckner }
95146eb7a6SReid Kleckner 
getNameType(StringRef Sym,StringRef ExtName,MachineTypes Machine,bool MinGW)96146eb7a6SReid Kleckner static ImportNameType getNameType(StringRef Sym, StringRef ExtName,
97f641d0d4SMartin Storsjo                                   MachineTypes Machine, bool MinGW) {
98f641d0d4SMartin Storsjo   // A decorated stdcall function in MSVC is exported with the
99f641d0d4SMartin Storsjo   // type IMPORT_NAME, and the exported function name includes the
100f641d0d4SMartin Storsjo   // the leading underscore. In MinGW on the other hand, a decorated
101f641d0d4SMartin Storsjo   // stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX).
102f641d0d4SMartin Storsjo   // See the comment in isDecorated in COFFModuleDefinition.cpp for more
103f641d0d4SMartin Storsjo   // details.
104f641d0d4SMartin Storsjo   if (ExtName.startswith("_") && ExtName.contains('@') && !MinGW)
105f641d0d4SMartin Storsjo     return IMPORT_NAME;
106146eb7a6SReid Kleckner   if (Sym != ExtName)
107146eb7a6SReid Kleckner     return IMPORT_NAME_UNDECORATE;
108146eb7a6SReid Kleckner   if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.startswith("_"))
109146eb7a6SReid Kleckner     return IMPORT_NAME_NOPREFIX;
110146eb7a6SReid Kleckner   return IMPORT_NAME;
111146eb7a6SReid Kleckner }
112146eb7a6SReid Kleckner 
replace(StringRef S,StringRef From,StringRef To)113146eb7a6SReid Kleckner static Expected<std::string> replace(StringRef S, StringRef From,
114146eb7a6SReid Kleckner                                      StringRef To) {
115146eb7a6SReid Kleckner   size_t Pos = S.find(From);
116146eb7a6SReid Kleckner 
117146eb7a6SReid Kleckner   // From and To may be mangled, but substrings in S may not.
118146eb7a6SReid Kleckner   if (Pos == StringRef::npos && From.startswith("_") && To.startswith("_")) {
119146eb7a6SReid Kleckner     From = From.substr(1);
120146eb7a6SReid Kleckner     To = To.substr(1);
121146eb7a6SReid Kleckner     Pos = S.find(From);
122146eb7a6SReid Kleckner   }
123146eb7a6SReid Kleckner 
124146eb7a6SReid Kleckner   if (Pos == StringRef::npos) {
125146eb7a6SReid Kleckner     return make_error<StringError>(
126146eb7a6SReid Kleckner       StringRef(Twine(S + ": replacing '" + From +
127146eb7a6SReid Kleckner         "' with '" + To + "' failed").str()), object_error::parse_failed);
128146eb7a6SReid Kleckner   }
129146eb7a6SReid Kleckner 
130146eb7a6SReid Kleckner   return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
131146eb7a6SReid Kleckner }
132146eb7a6SReid Kleckner 
133146eb7a6SReid Kleckner static const std::string NullImportDescriptorSymbolName =
134146eb7a6SReid Kleckner     "__NULL_IMPORT_DESCRIPTOR";
135146eb7a6SReid Kleckner 
136146eb7a6SReid Kleckner namespace {
137146eb7a6SReid Kleckner // This class constructs various small object files necessary to support linking
138146eb7a6SReid Kleckner // symbols imported from a DLL.  The contents are pretty strictly defined and
139146eb7a6SReid Kleckner // nearly entirely static.  The details of the structures files are defined in
140146eb7a6SReid Kleckner // WINNT.h and the PE/COFF specification.
141146eb7a6SReid Kleckner class ObjectFactory {
142146eb7a6SReid Kleckner   using u16 = support::ulittle16_t;
143146eb7a6SReid Kleckner   using u32 = support::ulittle32_t;
144146eb7a6SReid Kleckner   MachineTypes Machine;
145146eb7a6SReid Kleckner   BumpPtrAllocator Alloc;
1460f83a894SSaleem Abdulrasool   StringRef ImportName;
147146eb7a6SReid Kleckner   StringRef Library;
148146eb7a6SReid Kleckner   std::string ImportDescriptorSymbolName;
149146eb7a6SReid Kleckner   std::string NullThunkSymbolName;
150146eb7a6SReid Kleckner 
151146eb7a6SReid Kleckner public:
ObjectFactory(StringRef S,MachineTypes M)152146eb7a6SReid Kleckner   ObjectFactory(StringRef S, MachineTypes M)
1530f83a894SSaleem Abdulrasool       : Machine(M), ImportName(S), Library(S.drop_back(4)),
154146eb7a6SReid Kleckner         ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()),
155146eb7a6SReid Kleckner         NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {}
156146eb7a6SReid Kleckner 
157146eb7a6SReid Kleckner   // Creates an Import Descriptor.  This is a small object file which contains a
158146eb7a6SReid Kleckner   // reference to the terminators and contains the library name (entry) for the
159146eb7a6SReid Kleckner   // import name table.  It will force the linker to construct the necessary
160146eb7a6SReid Kleckner   // structure to import symbols from the DLL.
161146eb7a6SReid Kleckner   NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);
162146eb7a6SReid Kleckner 
163146eb7a6SReid Kleckner   // Creates a NULL import descriptor.  This is a small object file whcih
164146eb7a6SReid Kleckner   // contains a NULL import descriptor.  It is used to terminate the imports
165146eb7a6SReid Kleckner   // from a specific DLL.
166146eb7a6SReid Kleckner   NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);
167146eb7a6SReid Kleckner 
168146eb7a6SReid Kleckner   // Create a NULL Thunk Entry.  This is a small object file which contains a
169146eb7a6SReid Kleckner   // NULL Import Address Table entry and a NULL Import Lookup Table Entry.  It
170146eb7a6SReid Kleckner   // is used to terminate the IAT and ILT.
171146eb7a6SReid Kleckner   NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);
172146eb7a6SReid Kleckner 
173146eb7a6SReid Kleckner   // Create a short import file which is described in PE/COFF spec 7. Import
174146eb7a6SReid Kleckner   // Library Format.
175146eb7a6SReid Kleckner   NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
176146eb7a6SReid Kleckner                                      ImportType Type, ImportNameType NameType);
1771079ef8dSMartell Malone 
1781079ef8dSMartell Malone   // Create a weak external file which is described in PE/COFF Aux Format 3.
1791079ef8dSMartell Malone   NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp);
180146eb7a6SReid Kleckner };
181146eb7a6SReid Kleckner } // namespace
182146eb7a6SReid Kleckner 
183146eb7a6SReid Kleckner NewArchiveMember
createImportDescriptor(std::vector<uint8_t> & Buffer)184146eb7a6SReid Kleckner ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
1851079ef8dSMartell Malone   const uint32_t NumberOfSections = 2;
1861079ef8dSMartell Malone   const uint32_t NumberOfSymbols = 7;
1871079ef8dSMartell Malone   const uint32_t NumberOfRelocations = 3;
188146eb7a6SReid Kleckner 
189146eb7a6SReid Kleckner   // COFF Header
190146eb7a6SReid Kleckner   coff_file_header Header{
191146eb7a6SReid Kleckner       u16(Machine),
192146eb7a6SReid Kleckner       u16(NumberOfSections),
193146eb7a6SReid Kleckner       u32(0),
194146eb7a6SReid Kleckner       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
195146eb7a6SReid Kleckner           // .idata$2
196146eb7a6SReid Kleckner           sizeof(coff_import_directory_table_entry) +
197146eb7a6SReid Kleckner           NumberOfRelocations * sizeof(coff_relocation) +
198146eb7a6SReid Kleckner           // .idata$4
1990f83a894SSaleem Abdulrasool           (ImportName.size() + 1)),
200146eb7a6SReid Kleckner       u32(NumberOfSymbols),
201146eb7a6SReid Kleckner       u16(0),
2026532b3b9SGalina Kistanova       u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
203146eb7a6SReid Kleckner   };
204146eb7a6SReid Kleckner   append(Buffer, Header);
205146eb7a6SReid Kleckner 
206146eb7a6SReid Kleckner   // Section Header Table
2071079ef8dSMartell Malone   const coff_section SectionTable[NumberOfSections] = {
208146eb7a6SReid Kleckner       {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
209146eb7a6SReid Kleckner        u32(0),
210146eb7a6SReid Kleckner        u32(0),
211146eb7a6SReid Kleckner        u32(sizeof(coff_import_directory_table_entry)),
212146eb7a6SReid Kleckner        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
213146eb7a6SReid Kleckner        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
214146eb7a6SReid Kleckner            sizeof(coff_import_directory_table_entry)),
215146eb7a6SReid Kleckner        u32(0),
216146eb7a6SReid Kleckner        u16(NumberOfRelocations),
217146eb7a6SReid Kleckner        u16(0),
218146eb7a6SReid Kleckner        u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
219146eb7a6SReid Kleckner            IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
220146eb7a6SReid Kleckner       {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
221146eb7a6SReid Kleckner        u32(0),
222146eb7a6SReid Kleckner        u32(0),
2230f83a894SSaleem Abdulrasool        u32(ImportName.size() + 1),
224146eb7a6SReid Kleckner        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
225146eb7a6SReid Kleckner            sizeof(coff_import_directory_table_entry) +
226146eb7a6SReid Kleckner            NumberOfRelocations * sizeof(coff_relocation)),
227146eb7a6SReid Kleckner        u32(0),
228146eb7a6SReid Kleckner        u32(0),
229146eb7a6SReid Kleckner        u16(0),
230146eb7a6SReid Kleckner        u16(0),
231146eb7a6SReid Kleckner        u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
232146eb7a6SReid Kleckner            IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
233146eb7a6SReid Kleckner   };
234146eb7a6SReid Kleckner   append(Buffer, SectionTable);
235146eb7a6SReid Kleckner 
236146eb7a6SReid Kleckner   // .idata$2
2371079ef8dSMartell Malone   const coff_import_directory_table_entry ImportDescriptor{
238146eb7a6SReid Kleckner       u32(0), u32(0), u32(0), u32(0), u32(0),
239146eb7a6SReid Kleckner   };
240146eb7a6SReid Kleckner   append(Buffer, ImportDescriptor);
241146eb7a6SReid Kleckner 
2421079ef8dSMartell Malone   const coff_relocation RelocationTable[NumberOfRelocations] = {
243146eb7a6SReid Kleckner       {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
244146eb7a6SReid Kleckner        u16(getImgRelRelocation(Machine))},
245146eb7a6SReid Kleckner       {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
246146eb7a6SReid Kleckner        u32(3), u16(getImgRelRelocation(Machine))},
247146eb7a6SReid Kleckner       {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
248146eb7a6SReid Kleckner        u32(4), u16(getImgRelRelocation(Machine))},
249146eb7a6SReid Kleckner   };
250146eb7a6SReid Kleckner   append(Buffer, RelocationTable);
251146eb7a6SReid Kleckner 
252146eb7a6SReid Kleckner   // .idata$6
253146eb7a6SReid Kleckner   auto S = Buffer.size();
2540f83a894SSaleem Abdulrasool   Buffer.resize(S + ImportName.size() + 1);
2550f83a894SSaleem Abdulrasool   memcpy(&Buffer[S], ImportName.data(), ImportName.size());
2560f83a894SSaleem Abdulrasool   Buffer[S + ImportName.size()] = '\0';
257146eb7a6SReid Kleckner 
258146eb7a6SReid Kleckner   // Symbol Table
259146eb7a6SReid Kleckner   coff_symbol16 SymbolTable[NumberOfSymbols] = {
260146eb7a6SReid Kleckner       {{{0, 0, 0, 0, 0, 0, 0, 0}},
261146eb7a6SReid Kleckner        u32(0),
262146eb7a6SReid Kleckner        u16(1),
263146eb7a6SReid Kleckner        u16(0),
264146eb7a6SReid Kleckner        IMAGE_SYM_CLASS_EXTERNAL,
265146eb7a6SReid Kleckner        0},
266146eb7a6SReid Kleckner       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
267146eb7a6SReid Kleckner        u32(0),
268146eb7a6SReid Kleckner        u16(1),
269146eb7a6SReid Kleckner        u16(0),
270146eb7a6SReid Kleckner        IMAGE_SYM_CLASS_SECTION,
271146eb7a6SReid Kleckner        0},
272146eb7a6SReid Kleckner       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
273146eb7a6SReid Kleckner        u32(0),
274146eb7a6SReid Kleckner        u16(2),
275146eb7a6SReid Kleckner        u16(0),
276146eb7a6SReid Kleckner        IMAGE_SYM_CLASS_STATIC,
277146eb7a6SReid Kleckner        0},
278146eb7a6SReid Kleckner       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
279146eb7a6SReid Kleckner        u32(0),
280146eb7a6SReid Kleckner        u16(0),
281146eb7a6SReid Kleckner        u16(0),
282146eb7a6SReid Kleckner        IMAGE_SYM_CLASS_SECTION,
283146eb7a6SReid Kleckner        0},
284146eb7a6SReid Kleckner       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
285146eb7a6SReid Kleckner        u32(0),
286146eb7a6SReid Kleckner        u16(0),
287146eb7a6SReid Kleckner        u16(0),
288146eb7a6SReid Kleckner        IMAGE_SYM_CLASS_SECTION,
289146eb7a6SReid Kleckner        0},
290146eb7a6SReid Kleckner       {{{0, 0, 0, 0, 0, 0, 0, 0}},
291146eb7a6SReid Kleckner        u32(0),
292146eb7a6SReid Kleckner        u16(0),
293146eb7a6SReid Kleckner        u16(0),
294146eb7a6SReid Kleckner        IMAGE_SYM_CLASS_EXTERNAL,
295146eb7a6SReid Kleckner        0},
296146eb7a6SReid Kleckner       {{{0, 0, 0, 0, 0, 0, 0, 0}},
297146eb7a6SReid Kleckner        u32(0),
298146eb7a6SReid Kleckner        u16(0),
299146eb7a6SReid Kleckner        u16(0),
300146eb7a6SReid Kleckner        IMAGE_SYM_CLASS_EXTERNAL,
301146eb7a6SReid Kleckner        0},
302146eb7a6SReid Kleckner   };
303415ec926SGalina Kistanova   // TODO: Name.Offset.Offset here and in the all similar places below
304415ec926SGalina Kistanova   // suggests a names refactoring. Maybe StringTableOffset.Value?
305415ec926SGalina Kistanova   SymbolTable[0].Name.Offset.Offset =
306146eb7a6SReid Kleckner       sizeof(uint32_t);
307415ec926SGalina Kistanova   SymbolTable[5].Name.Offset.Offset =
308146eb7a6SReid Kleckner       sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
309415ec926SGalina Kistanova   SymbolTable[6].Name.Offset.Offset =
310146eb7a6SReid Kleckner       sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
311146eb7a6SReid Kleckner       NullImportDescriptorSymbolName.length() + 1;
312146eb7a6SReid Kleckner   append(Buffer, SymbolTable);
313146eb7a6SReid Kleckner 
314146eb7a6SReid Kleckner   // String Table
315146eb7a6SReid Kleckner   writeStringTable(Buffer,
316146eb7a6SReid Kleckner                    {ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
317146eb7a6SReid Kleckner                     NullThunkSymbolName});
318146eb7a6SReid Kleckner 
319146eb7a6SReid Kleckner   StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
3200f83a894SSaleem Abdulrasool   return {MemoryBufferRef(F, ImportName)};
321146eb7a6SReid Kleckner }
322146eb7a6SReid Kleckner 
323146eb7a6SReid Kleckner NewArchiveMember
createNullImportDescriptor(std::vector<uint8_t> & Buffer)324146eb7a6SReid Kleckner ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
3251079ef8dSMartell Malone   const uint32_t NumberOfSections = 1;
3261079ef8dSMartell Malone   const uint32_t NumberOfSymbols = 1;
327146eb7a6SReid Kleckner 
328146eb7a6SReid Kleckner   // COFF Header
329146eb7a6SReid Kleckner   coff_file_header Header{
330146eb7a6SReid Kleckner       u16(Machine),
331146eb7a6SReid Kleckner       u16(NumberOfSections),
332146eb7a6SReid Kleckner       u32(0),
333146eb7a6SReid Kleckner       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
334146eb7a6SReid Kleckner           // .idata$3
335146eb7a6SReid Kleckner           sizeof(coff_import_directory_table_entry)),
336146eb7a6SReid Kleckner       u32(NumberOfSymbols),
337146eb7a6SReid Kleckner       u16(0),
3386532b3b9SGalina Kistanova       u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
339146eb7a6SReid Kleckner   };
340146eb7a6SReid Kleckner   append(Buffer, Header);
341146eb7a6SReid Kleckner 
342146eb7a6SReid Kleckner   // Section Header Table
3431079ef8dSMartell Malone   const coff_section SectionTable[NumberOfSections] = {
344146eb7a6SReid Kleckner       {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
345146eb7a6SReid Kleckner        u32(0),
346146eb7a6SReid Kleckner        u32(0),
347146eb7a6SReid Kleckner        u32(sizeof(coff_import_directory_table_entry)),
348146eb7a6SReid Kleckner        u32(sizeof(coff_file_header) +
349146eb7a6SReid Kleckner            (NumberOfSections * sizeof(coff_section))),
350146eb7a6SReid Kleckner        u32(0),
351146eb7a6SReid Kleckner        u32(0),
352146eb7a6SReid Kleckner        u16(0),
353146eb7a6SReid Kleckner        u16(0),
354146eb7a6SReid Kleckner        u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
355146eb7a6SReid Kleckner            IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
356146eb7a6SReid Kleckner   };
357146eb7a6SReid Kleckner   append(Buffer, SectionTable);
358146eb7a6SReid Kleckner 
359146eb7a6SReid Kleckner   // .idata$3
3601079ef8dSMartell Malone   const coff_import_directory_table_entry ImportDescriptor{
361146eb7a6SReid Kleckner       u32(0), u32(0), u32(0), u32(0), u32(0),
362146eb7a6SReid Kleckner   };
363146eb7a6SReid Kleckner   append(Buffer, ImportDescriptor);
364146eb7a6SReid Kleckner 
365146eb7a6SReid Kleckner   // Symbol Table
366146eb7a6SReid Kleckner   coff_symbol16 SymbolTable[NumberOfSymbols] = {
367146eb7a6SReid Kleckner       {{{0, 0, 0, 0, 0, 0, 0, 0}},
368146eb7a6SReid Kleckner        u32(0),
369146eb7a6SReid Kleckner        u16(1),
370146eb7a6SReid Kleckner        u16(0),
371146eb7a6SReid Kleckner        IMAGE_SYM_CLASS_EXTERNAL,
372146eb7a6SReid Kleckner        0},
373146eb7a6SReid Kleckner   };
374415ec926SGalina Kistanova   SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
375146eb7a6SReid Kleckner   append(Buffer, SymbolTable);
376146eb7a6SReid Kleckner 
377146eb7a6SReid Kleckner   // String Table
378146eb7a6SReid Kleckner   writeStringTable(Buffer, {NullImportDescriptorSymbolName});
379146eb7a6SReid Kleckner 
380146eb7a6SReid Kleckner   StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
3810f83a894SSaleem Abdulrasool   return {MemoryBufferRef(F, ImportName)};
382146eb7a6SReid Kleckner }
383146eb7a6SReid Kleckner 
createNullThunk(std::vector<uint8_t> & Buffer)384146eb7a6SReid Kleckner NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
3851079ef8dSMartell Malone   const uint32_t NumberOfSections = 2;
3861079ef8dSMartell Malone   const uint32_t NumberOfSymbols = 1;
387146eb7a6SReid Kleckner   uint32_t VASize = is32bit(Machine) ? 4 : 8;
388146eb7a6SReid Kleckner 
389146eb7a6SReid Kleckner   // COFF Header
390146eb7a6SReid Kleckner   coff_file_header Header{
391146eb7a6SReid Kleckner       u16(Machine),
392146eb7a6SReid Kleckner       u16(NumberOfSections),
393146eb7a6SReid Kleckner       u32(0),
394146eb7a6SReid Kleckner       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
395146eb7a6SReid Kleckner           // .idata$5
396146eb7a6SReid Kleckner           VASize +
397146eb7a6SReid Kleckner           // .idata$4
398146eb7a6SReid Kleckner           VASize),
399146eb7a6SReid Kleckner       u32(NumberOfSymbols),
400146eb7a6SReid Kleckner       u16(0),
4016532b3b9SGalina Kistanova       u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
402146eb7a6SReid Kleckner   };
403146eb7a6SReid Kleckner   append(Buffer, Header);
404146eb7a6SReid Kleckner 
405146eb7a6SReid Kleckner   // Section Header Table
4061079ef8dSMartell Malone   const coff_section SectionTable[NumberOfSections] = {
407146eb7a6SReid Kleckner       {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
408146eb7a6SReid Kleckner        u32(0),
409146eb7a6SReid Kleckner        u32(0),
410146eb7a6SReid Kleckner        u32(VASize),
411146eb7a6SReid Kleckner        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
412146eb7a6SReid Kleckner        u32(0),
413146eb7a6SReid Kleckner        u32(0),
414146eb7a6SReid Kleckner        u16(0),
415146eb7a6SReid Kleckner        u16(0),
416146eb7a6SReid Kleckner        u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
417146eb7a6SReid Kleckner                              : IMAGE_SCN_ALIGN_8BYTES) |
418146eb7a6SReid Kleckner            IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
419146eb7a6SReid Kleckner            IMAGE_SCN_MEM_WRITE)},
420146eb7a6SReid Kleckner       {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
421146eb7a6SReid Kleckner        u32(0),
422146eb7a6SReid Kleckner        u32(0),
423146eb7a6SReid Kleckner        u32(VASize),
424146eb7a6SReid Kleckner        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
425146eb7a6SReid Kleckner            VASize),
426146eb7a6SReid Kleckner        u32(0),
427146eb7a6SReid Kleckner        u32(0),
428146eb7a6SReid Kleckner        u16(0),
429146eb7a6SReid Kleckner        u16(0),
430146eb7a6SReid Kleckner        u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
431146eb7a6SReid Kleckner                              : IMAGE_SCN_ALIGN_8BYTES) |
432146eb7a6SReid Kleckner            IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
433146eb7a6SReid Kleckner            IMAGE_SCN_MEM_WRITE)},
434146eb7a6SReid Kleckner   };
435146eb7a6SReid Kleckner   append(Buffer, SectionTable);
436146eb7a6SReid Kleckner 
437146eb7a6SReid Kleckner   // .idata$5, ILT
438146eb7a6SReid Kleckner   append(Buffer, u32(0));
439146eb7a6SReid Kleckner   if (!is32bit(Machine))
440146eb7a6SReid Kleckner     append(Buffer, u32(0));
441146eb7a6SReid Kleckner 
442146eb7a6SReid Kleckner   // .idata$4, IAT
443146eb7a6SReid Kleckner   append(Buffer, u32(0));
444146eb7a6SReid Kleckner   if (!is32bit(Machine))
445146eb7a6SReid Kleckner     append(Buffer, u32(0));
446146eb7a6SReid Kleckner 
447146eb7a6SReid Kleckner   // Symbol Table
448146eb7a6SReid Kleckner   coff_symbol16 SymbolTable[NumberOfSymbols] = {
449146eb7a6SReid Kleckner       {{{0, 0, 0, 0, 0, 0, 0, 0}},
450146eb7a6SReid Kleckner        u32(0),
451146eb7a6SReid Kleckner        u16(1),
452146eb7a6SReid Kleckner        u16(0),
453146eb7a6SReid Kleckner        IMAGE_SYM_CLASS_EXTERNAL,
454146eb7a6SReid Kleckner        0},
455146eb7a6SReid Kleckner   };
456415ec926SGalina Kistanova   SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
457146eb7a6SReid Kleckner   append(Buffer, SymbolTable);
458146eb7a6SReid Kleckner 
459146eb7a6SReid Kleckner   // String Table
460146eb7a6SReid Kleckner   writeStringTable(Buffer, {NullThunkSymbolName});
461146eb7a6SReid Kleckner 
462146eb7a6SReid Kleckner   StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
4630f83a894SSaleem Abdulrasool   return {MemoryBufferRef{F, ImportName}};
464146eb7a6SReid Kleckner }
465146eb7a6SReid Kleckner 
createShortImport(StringRef Sym,uint16_t Ordinal,ImportType ImportType,ImportNameType NameType)466146eb7a6SReid Kleckner NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
467146eb7a6SReid Kleckner                                                   uint16_t Ordinal,
468146eb7a6SReid Kleckner                                                   ImportType ImportType,
469146eb7a6SReid Kleckner                                                   ImportNameType NameType) {
4700f83a894SSaleem Abdulrasool   size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs
471146eb7a6SReid Kleckner   size_t Size = sizeof(coff_import_header) + ImpSize;
472146eb7a6SReid Kleckner   char *Buf = Alloc.Allocate<char>(Size);
473146eb7a6SReid Kleckner   memset(Buf, 0, Size);
474146eb7a6SReid Kleckner   char *P = Buf;
475146eb7a6SReid Kleckner 
476146eb7a6SReid Kleckner   // Write short import library.
477146eb7a6SReid Kleckner   auto *Imp = reinterpret_cast<coff_import_header *>(P);
478146eb7a6SReid Kleckner   P += sizeof(*Imp);
479146eb7a6SReid Kleckner   Imp->Sig2 = 0xFFFF;
480146eb7a6SReid Kleckner   Imp->Machine = Machine;
481146eb7a6SReid Kleckner   Imp->SizeOfData = ImpSize;
482146eb7a6SReid Kleckner   if (Ordinal > 0)
483146eb7a6SReid Kleckner     Imp->OrdinalHint = Ordinal;
484146eb7a6SReid Kleckner   Imp->TypeInfo = (NameType << 2) | ImportType;
485146eb7a6SReid Kleckner 
486146eb7a6SReid Kleckner   // Write symbol name and DLL name.
487146eb7a6SReid Kleckner   memcpy(P, Sym.data(), Sym.size());
488146eb7a6SReid Kleckner   P += Sym.size() + 1;
4890f83a894SSaleem Abdulrasool   memcpy(P, ImportName.data(), ImportName.size());
490146eb7a6SReid Kleckner 
4910f83a894SSaleem Abdulrasool   return {MemoryBufferRef(StringRef(Buf, Size), ImportName)};
492146eb7a6SReid Kleckner }
493146eb7a6SReid Kleckner 
createWeakExternal(StringRef Sym,StringRef Weak,bool Imp)4941079ef8dSMartell Malone NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym,
4951079ef8dSMartell Malone                                                    StringRef Weak, bool Imp) {
4961079ef8dSMartell Malone   std::vector<uint8_t> Buffer;
4971079ef8dSMartell Malone   const uint32_t NumberOfSections = 1;
4981079ef8dSMartell Malone   const uint32_t NumberOfSymbols = 5;
4991079ef8dSMartell Malone 
5001079ef8dSMartell Malone   // COFF Header
5011079ef8dSMartell Malone   coff_file_header Header{
502146db440SMartin Storsjo       u16(Machine),
5031079ef8dSMartell Malone       u16(NumberOfSections),
5041079ef8dSMartell Malone       u32(0),
5051079ef8dSMartell Malone       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))),
5061079ef8dSMartell Malone       u32(NumberOfSymbols),
5071079ef8dSMartell Malone       u16(0),
5081079ef8dSMartell Malone       u16(0),
5091079ef8dSMartell Malone   };
5101079ef8dSMartell Malone   append(Buffer, Header);
5111079ef8dSMartell Malone 
5121079ef8dSMartell Malone   // Section Header Table
5131079ef8dSMartell Malone   const coff_section SectionTable[NumberOfSections] = {
5141079ef8dSMartell Malone       {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'},
5151079ef8dSMartell Malone        u32(0),
5161079ef8dSMartell Malone        u32(0),
5171079ef8dSMartell Malone        u32(0),
5181079ef8dSMartell Malone        u32(0),
5191079ef8dSMartell Malone        u32(0),
5201079ef8dSMartell Malone        u32(0),
5211079ef8dSMartell Malone        u16(0),
5221079ef8dSMartell Malone        u16(0),
5231079ef8dSMartell Malone        u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}};
5241079ef8dSMartell Malone   append(Buffer, SectionTable);
5251079ef8dSMartell Malone 
5261079ef8dSMartell Malone   // Symbol Table
5271079ef8dSMartell Malone   coff_symbol16 SymbolTable[NumberOfSymbols] = {
5281079ef8dSMartell Malone       {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},
5291079ef8dSMartell Malone        u32(0),
5301079ef8dSMartell Malone        u16(0xFFFF),
5311079ef8dSMartell Malone        u16(0),
5321079ef8dSMartell Malone        IMAGE_SYM_CLASS_STATIC,
5331079ef8dSMartell Malone        0},
5341079ef8dSMartell Malone       {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}},
5351079ef8dSMartell Malone        u32(0),
5361079ef8dSMartell Malone        u16(0xFFFF),
5371079ef8dSMartell Malone        u16(0),
5381079ef8dSMartell Malone        IMAGE_SYM_CLASS_STATIC,
5391079ef8dSMartell Malone        0},
5401079ef8dSMartell Malone       {{{0, 0, 0, 0, 0, 0, 0, 0}},
5411079ef8dSMartell Malone        u32(0),
5421079ef8dSMartell Malone        u16(0),
5431079ef8dSMartell Malone        u16(0),
5441079ef8dSMartell Malone        IMAGE_SYM_CLASS_EXTERNAL,
5451079ef8dSMartell Malone        0},
5461079ef8dSMartell Malone       {{{0, 0, 0, 0, 0, 0, 0, 0}},
5471079ef8dSMartell Malone        u32(0),
5481079ef8dSMartell Malone        u16(0),
5491079ef8dSMartell Malone        u16(0),
5501079ef8dSMartell Malone        IMAGE_SYM_CLASS_WEAK_EXTERNAL,
5511079ef8dSMartell Malone        1},
552509f1668SMartin Storsjo       {{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}},
553509f1668SMartin Storsjo        u32(0),
554509f1668SMartin Storsjo        u16(0),
555509f1668SMartin Storsjo        u16(0),
556509f1668SMartin Storsjo        IMAGE_SYM_CLASS_NULL,
557509f1668SMartin Storsjo        0},
5581079ef8dSMartell Malone   };
5591079ef8dSMartell Malone   SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t);
5601079ef8dSMartell Malone 
5611079ef8dSMartell Malone   //__imp_ String Table
5624a5764e3SMartin Storsjo   StringRef Prefix = Imp ? "__imp_" : "";
5634a5764e3SMartin Storsjo   SymbolTable[3].Name.Offset.Offset =
5644a5764e3SMartin Storsjo       sizeof(uint32_t) + Sym.size() + Prefix.size() + 1;
5651079ef8dSMartell Malone   append(Buffer, SymbolTable);
5664a5764e3SMartin Storsjo   writeStringTable(Buffer, {(Prefix + Sym).str(),
5674a5764e3SMartin Storsjo                             (Prefix + Weak).str()});
5681079ef8dSMartell Malone 
5691079ef8dSMartell Malone   // Copied here so we can still use writeStringTable
5701079ef8dSMartell Malone   char *Buf = Alloc.Allocate<char>(Buffer.size());
5711079ef8dSMartell Malone   memcpy(Buf, Buffer.data(), Buffer.size());
5720f83a894SSaleem Abdulrasool   return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)};
5731079ef8dSMartell Malone }
5741079ef8dSMartell Malone 
writeImportLibrary(StringRef ImportName,StringRef Path,ArrayRef<COFFShortExport> Exports,MachineTypes Machine,bool MinGW)57525cbdf25SRafael Espindola Error writeImportLibrary(StringRef ImportName, StringRef Path,
576146eb7a6SReid Kleckner                          ArrayRef<COFFShortExport> Exports,
577284ab80fSMartin Storsjo                          MachineTypes Machine, bool MinGW) {
578146eb7a6SReid Kleckner 
579146eb7a6SReid Kleckner   std::vector<NewArchiveMember> Members;
5800f83a894SSaleem Abdulrasool   ObjectFactory OF(llvm::sys::path::filename(ImportName), Machine);
581146eb7a6SReid Kleckner 
582146eb7a6SReid Kleckner   std::vector<uint8_t> ImportDescriptor;
583146eb7a6SReid Kleckner   Members.push_back(OF.createImportDescriptor(ImportDescriptor));
584146eb7a6SReid Kleckner 
585146eb7a6SReid Kleckner   std::vector<uint8_t> NullImportDescriptor;
586146eb7a6SReid Kleckner   Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));
587146eb7a6SReid Kleckner 
588146eb7a6SReid Kleckner   std::vector<uint8_t> NullThunk;
589146eb7a6SReid Kleckner   Members.push_back(OF.createNullThunk(NullThunk));
590146eb7a6SReid Kleckner 
591146eb7a6SReid Kleckner   for (COFFShortExport E : Exports) {
592146eb7a6SReid Kleckner     if (E.Private)
593146eb7a6SReid Kleckner       continue;
594146eb7a6SReid Kleckner 
595146eb7a6SReid Kleckner     ImportType ImportType = IMPORT_CODE;
596146eb7a6SReid Kleckner     if (E.Data)
597146eb7a6SReid Kleckner       ImportType = IMPORT_DATA;
598146eb7a6SReid Kleckner     if (E.Constant)
599146eb7a6SReid Kleckner       ImportType = IMPORT_CONST;
600146eb7a6SReid Kleckner 
601a238b20eSMartin Storsjo     StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName;
602de6038b2SMartin Storsjo     ImportNameType NameType = E.Noname
603de6038b2SMartin Storsjo                                   ? IMPORT_ORDINAL
604de6038b2SMartin Storsjo                                   : getNameType(SymbolName, E.Name,
605de6038b2SMartin Storsjo                                                 Machine, MinGW);
606146eb7a6SReid Kleckner     Expected<std::string> Name = E.ExtName.empty()
607adcd0268SBenjamin Kramer                                      ? std::string(SymbolName)
608146eb7a6SReid Kleckner                                      : replace(SymbolName, E.Name, E.ExtName);
609146eb7a6SReid Kleckner 
61025cbdf25SRafael Espindola     if (!Name)
61125cbdf25SRafael Espindola       return Name.takeError();
612146eb7a6SReid Kleckner 
613284ab80fSMartin Storsjo     if (!E.AliasTarget.empty() && *Name != E.AliasTarget) {
614284ab80fSMartin Storsjo       Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, false));
615284ab80fSMartin Storsjo       Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, true));
616284ab80fSMartin Storsjo       continue;
617284ab80fSMartin Storsjo     }
618284ab80fSMartin Storsjo 
619146eb7a6SReid Kleckner     Members.push_back(
620146eb7a6SReid Kleckner         OF.createShortImport(*Name, E.Ordinal, ImportType, NameType));
621146eb7a6SReid Kleckner   }
622146eb7a6SReid Kleckner 
62301d02651SRui Ueyama   return writeArchive(Path, Members, /*WriteSymtab*/ true,
62401d02651SRui Ueyama                       object::Archive::K_GNU,
625146eb7a6SReid Kleckner                       /*Deterministic*/ true, /*Thin*/ false);
626146eb7a6SReid Kleckner }
627146eb7a6SReid Kleckner 
628146eb7a6SReid Kleckner } // namespace object
629146eb7a6SReid Kleckner } // namespace llvm
630