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