blob: d1f46fdfa292e7da78765948e25db69d480b79ea [file] [log] [blame]
Reid Kleckner146eb7a2017-06-02 17:53:06 +00001//===- COFFImportFile.cpp - COFF short import file implementation ---------===//
Martell Malone375dc902017-05-20 19:56:29 +00002//
Reid Kleckner146eb7a2017-06-02 17:53:06 +00003// The LLVM Compiler Infrastructure
Martell Malone375dc902017-05-20 19:56:29 +00004//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
Reid Kleckner146eb7a2017-06-02 17:53:06 +000010// This file defines the writeImportLibrary function.
Martell Malone375dc902017-05-20 19:56:29 +000011//
12//===----------------------------------------------------------------------===//
13
Reid Kleckner146eb7a2017-06-02 17:53:06 +000014#include "llvm/Object/COFFImportFile.h"
15#include "llvm/ADT/ArrayRef.h"
Martell Malone375dc902017-05-20 19:56:29 +000016#include "llvm/Object/Archive.h"
17#include "llvm/Object/ArchiveWriter.h"
18#include "llvm/Object/COFF.h"
Reid Kleckner146eb7a2017-06-02 17:53:06 +000019#include "llvm/Support/Error.h"
Martell Malone375dc902017-05-20 19:56:29 +000020#include "llvm/Support/Path.h"
21
Reid Kleckner146eb7a2017-06-02 17:53:06 +000022#include <cstdint>
23#include <map>
24#include <set>
25#include <string>
Martell Malone375dc902017-05-20 19:56:29 +000026#include <vector>
27
28using namespace llvm::COFF;
29using namespace llvm::object;
30using namespace llvm;
31
Reid Kleckner146eb7a2017-06-02 17:53:06 +000032namespace llvm {
33namespace object {
34
35static bool is32bit(MachineTypes Machine) {
36 switch (Machine) {
Martell Malone375dc902017-05-20 19:56:29 +000037 default:
38 llvm_unreachable("unsupported machine");
39 case IMAGE_FILE_MACHINE_AMD64:
40 return false;
41 case IMAGE_FILE_MACHINE_ARMNT:
42 case IMAGE_FILE_MACHINE_I386:
43 return true;
44 }
45}
46
Reid Kleckner146eb7a2017-06-02 17:53:06 +000047static uint16_t getImgRelRelocation(MachineTypes Machine) {
48 switch (Machine) {
Martell Malone375dc902017-05-20 19:56:29 +000049 default:
50 llvm_unreachable("unsupported machine");
51 case IMAGE_FILE_MACHINE_AMD64:
52 return IMAGE_REL_AMD64_ADDR32NB;
53 case IMAGE_FILE_MACHINE_ARMNT:
54 return IMAGE_REL_ARM_ADDR32NB;
55 case IMAGE_FILE_MACHINE_I386:
56 return IMAGE_REL_I386_DIR32NB;
57 }
58}
59
60template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {
61 size_t S = B.size();
62 B.resize(S + sizeof(T));
63 memcpy(&B[S], &Data, sizeof(T));
64}
65
66static void writeStringTable(std::vector<uint8_t> &B,
67 ArrayRef<const std::string> Strings) {
68 // The COFF string table consists of a 4-byte value which is the size of the
69 // table, including the length field itself. This value is followed by the
70 // string content itself, which is an array of null-terminated C-style
71 // strings. The termination is important as they are referenced to by offset
72 // by the symbol entity in the file format.
73
Reid Kleckner146eb7a2017-06-02 17:53:06 +000074 size_t Pos = B.size();
75 size_t Offset = B.size();
Martell Malone375dc902017-05-20 19:56:29 +000076
77 // Skip over the length field, we will fill it in later as we will have
78 // computed the length while emitting the string content itself.
79 Pos += sizeof(uint32_t);
80
81 for (const auto &S : Strings) {
82 B.resize(Pos + S.length() + 1);
83 strcpy(reinterpret_cast<char *>(&B[Pos]), S.c_str());
84 Pos += S.length() + 1;
85 }
86
87 // Backfill the length of the table now that it has been computed.
88 support::ulittle32_t Length(B.size() - Offset);
Reid Kleckner146eb7a2017-06-02 17:53:06 +000089 support::endian::write32le(&B[Offset], Length);
Martell Malone375dc902017-05-20 19:56:29 +000090}
91
Reid Kleckner146eb7a2017-06-02 17:53:06 +000092static ImportNameType getNameType(StringRef Sym, StringRef ExtName,
93 MachineTypes Machine) {
Martell Malone375dc902017-05-20 19:56:29 +000094 if (Sym != ExtName)
95 return IMPORT_NAME_UNDECORATE;
Reid Kleckner146eb7a2017-06-02 17:53:06 +000096 if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.startswith("_"))
Martell Malone375dc902017-05-20 19:56:29 +000097 return IMPORT_NAME_NOPREFIX;
98 return IMPORT_NAME;
99}
100
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000101static Expected<std::string> replace(StringRef S, StringRef From,
102 StringRef To) {
Martell Malone375dc902017-05-20 19:56:29 +0000103 size_t Pos = S.find(From);
104
105 // From and To may be mangled, but substrings in S may not.
106 if (Pos == StringRef::npos && From.startswith("_") && To.startswith("_")) {
107 From = From.substr(1);
108 To = To.substr(1);
109 Pos = S.find(From);
110 }
111
112 if (Pos == StringRef::npos) {
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000113 return make_error<StringError>(
114 StringRef(Twine(S + ": replacing '" + From +
115 "' with '" + To + "' failed").str()), object_error::parse_failed);
Martell Malone375dc902017-05-20 19:56:29 +0000116 }
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000117
Martell Malone375dc902017-05-20 19:56:29 +0000118 return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
119}
120
121static const std::string NullImportDescriptorSymbolName =
122 "__NULL_IMPORT_DESCRIPTOR";
123
124namespace {
125// This class constructs various small object files necessary to support linking
126// symbols imported from a DLL. The contents are pretty strictly defined and
127// nearly entirely static. The details of the structures files are defined in
128// WINNT.h and the PE/COFF specification.
129class ObjectFactory {
130 using u16 = support::ulittle16_t;
131 using u32 = support::ulittle32_t;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000132 MachineTypes Machine;
Martell Malone375dc902017-05-20 19:56:29 +0000133 BumpPtrAllocator Alloc;
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000134 StringRef ImportName;
Martell Malone375dc902017-05-20 19:56:29 +0000135 StringRef Library;
136 std::string ImportDescriptorSymbolName;
137 std::string NullThunkSymbolName;
138
139public:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000140 ObjectFactory(StringRef S, MachineTypes M)
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000141 : Machine(M), ImportName(S), Library(S.drop_back(4)),
Martell Malone375dc902017-05-20 19:56:29 +0000142 ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()),
143 NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {}
144
145 // Creates an Import Descriptor. This is a small object file which contains a
146 // reference to the terminators and contains the library name (entry) for the
147 // import name table. It will force the linker to construct the necessary
148 // structure to import symbols from the DLL.
149 NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);
150
151 // Creates a NULL import descriptor. This is a small object file whcih
152 // contains a NULL import descriptor. It is used to terminate the imports
153 // from a specific DLL.
154 NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);
155
156 // Create a NULL Thunk Entry. This is a small object file which contains a
157 // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It
158 // is used to terminate the IAT and ILT.
159 NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);
160
161 // Create a short import file which is described in PE/COFF spec 7. Import
162 // Library Format.
163 NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
164 ImportType Type, ImportNameType NameType);
Martell Malone1079ef82017-07-18 21:26:38 +0000165
166 // Create a weak external file which is described in PE/COFF Aux Format 3.
167 NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp);
Martell Malone375dc902017-05-20 19:56:29 +0000168};
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000169} // namespace
Martell Malone375dc902017-05-20 19:56:29 +0000170
171NewArchiveMember
172ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
Martell Malone1079ef82017-07-18 21:26:38 +0000173 const uint32_t NumberOfSections = 2;
174 const uint32_t NumberOfSymbols = 7;
175 const uint32_t NumberOfRelocations = 3;
Martell Malone375dc902017-05-20 19:56:29 +0000176
177 // COFF Header
178 coff_file_header Header{
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000179 u16(Machine),
180 u16(NumberOfSections),
181 u32(0),
Martell Malone375dc902017-05-20 19:56:29 +0000182 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
183 // .idata$2
184 sizeof(coff_import_directory_table_entry) +
185 NumberOfRelocations * sizeof(coff_relocation) +
186 // .idata$4
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000187 (ImportName.size() + 1)),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000188 u32(NumberOfSymbols),
189 u16(0),
190 u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : 0),
Martell Malone375dc902017-05-20 19:56:29 +0000191 };
192 append(Buffer, Header);
193
194 // Section Header Table
Martell Malone1079ef82017-07-18 21:26:38 +0000195 const coff_section SectionTable[NumberOfSections] = {
Martell Malone375dc902017-05-20 19:56:29 +0000196 {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
197 u32(0),
198 u32(0),
199 u32(sizeof(coff_import_directory_table_entry)),
200 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
201 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
202 sizeof(coff_import_directory_table_entry)),
203 u32(0),
204 u16(NumberOfRelocations),
205 u16(0),
206 u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
207 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
208 {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
209 u32(0),
210 u32(0),
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000211 u32(ImportName.size() + 1),
Martell Malone375dc902017-05-20 19:56:29 +0000212 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
213 sizeof(coff_import_directory_table_entry) +
214 NumberOfRelocations * sizeof(coff_relocation)),
215 u32(0),
216 u32(0),
217 u16(0),
218 u16(0),
219 u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
220 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
221 };
222 append(Buffer, SectionTable);
223
224 // .idata$2
Martell Malone1079ef82017-07-18 21:26:38 +0000225 const coff_import_directory_table_entry ImportDescriptor{
Martell Malone375dc902017-05-20 19:56:29 +0000226 u32(0), u32(0), u32(0), u32(0), u32(0),
227 };
228 append(Buffer, ImportDescriptor);
229
Martell Malone1079ef82017-07-18 21:26:38 +0000230 const coff_relocation RelocationTable[NumberOfRelocations] = {
Martell Malone375dc902017-05-20 19:56:29 +0000231 {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000232 u16(getImgRelRelocation(Machine))},
Martell Malone375dc902017-05-20 19:56:29 +0000233 {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000234 u32(3), u16(getImgRelRelocation(Machine))},
Martell Malone375dc902017-05-20 19:56:29 +0000235 {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000236 u32(4), u16(getImgRelRelocation(Machine))},
Martell Malone375dc902017-05-20 19:56:29 +0000237 };
238 append(Buffer, RelocationTable);
239
240 // .idata$6
241 auto S = Buffer.size();
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000242 Buffer.resize(S + ImportName.size() + 1);
243 memcpy(&Buffer[S], ImportName.data(), ImportName.size());
244 Buffer[S + ImportName.size()] = '\0';
Martell Malone375dc902017-05-20 19:56:29 +0000245
246 // Symbol Table
247 coff_symbol16 SymbolTable[NumberOfSymbols] = {
248 {{{0, 0, 0, 0, 0, 0, 0, 0}},
249 u32(0),
250 u16(1),
251 u16(0),
252 IMAGE_SYM_CLASS_EXTERNAL,
253 0},
254 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
255 u32(0),
256 u16(1),
257 u16(0),
258 IMAGE_SYM_CLASS_SECTION,
259 0},
260 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
261 u32(0),
262 u16(2),
263 u16(0),
264 IMAGE_SYM_CLASS_STATIC,
265 0},
266 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
267 u32(0),
268 u16(0),
269 u16(0),
270 IMAGE_SYM_CLASS_SECTION,
271 0},
272 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
273 u32(0),
274 u16(0),
275 u16(0),
276 IMAGE_SYM_CLASS_SECTION,
277 0},
278 {{{0, 0, 0, 0, 0, 0, 0, 0}},
279 u32(0),
280 u16(0),
281 u16(0),
282 IMAGE_SYM_CLASS_EXTERNAL,
283 0},
284 {{{0, 0, 0, 0, 0, 0, 0, 0}},
285 u32(0),
286 u16(0),
287 u16(0),
288 IMAGE_SYM_CLASS_EXTERNAL,
289 0},
290 };
Galina Kistanova415ec922017-06-08 23:35:52 +0000291 // TODO: Name.Offset.Offset here and in the all similar places below
292 // suggests a names refactoring. Maybe StringTableOffset.Value?
293 SymbolTable[0].Name.Offset.Offset =
Martell Malone375dc902017-05-20 19:56:29 +0000294 sizeof(uint32_t);
Galina Kistanova415ec922017-06-08 23:35:52 +0000295 SymbolTable[5].Name.Offset.Offset =
Martell Malone375dc902017-05-20 19:56:29 +0000296 sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
Galina Kistanova415ec922017-06-08 23:35:52 +0000297 SymbolTable[6].Name.Offset.Offset =
Martell Malone375dc902017-05-20 19:56:29 +0000298 sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
299 NullImportDescriptorSymbolName.length() + 1;
300 append(Buffer, SymbolTable);
301
302 // String Table
303 writeStringTable(Buffer,
304 {ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
305 NullThunkSymbolName});
306
307 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000308 return {MemoryBufferRef(F, ImportName)};
Martell Malone375dc902017-05-20 19:56:29 +0000309}
310
311NewArchiveMember
312ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
Martell Malone1079ef82017-07-18 21:26:38 +0000313 const uint32_t NumberOfSections = 1;
314 const uint32_t NumberOfSymbols = 1;
Martell Malone375dc902017-05-20 19:56:29 +0000315
316 // COFF Header
317 coff_file_header Header{
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000318 u16(Machine),
319 u16(NumberOfSections),
320 u32(0),
Martell Malone375dc902017-05-20 19:56:29 +0000321 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
322 // .idata$3
323 sizeof(coff_import_directory_table_entry)),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000324 u32(NumberOfSymbols),
325 u16(0),
326 u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : 0),
Martell Malone375dc902017-05-20 19:56:29 +0000327 };
328 append(Buffer, Header);
329
330 // Section Header Table
Martell Malone1079ef82017-07-18 21:26:38 +0000331 const coff_section SectionTable[NumberOfSections] = {
Martell Malone375dc902017-05-20 19:56:29 +0000332 {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
333 u32(0),
334 u32(0),
335 u32(sizeof(coff_import_directory_table_entry)),
336 u32(sizeof(coff_file_header) +
337 (NumberOfSections * sizeof(coff_section))),
338 u32(0),
339 u32(0),
340 u16(0),
341 u16(0),
342 u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
343 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
344 };
345 append(Buffer, SectionTable);
346
347 // .idata$3
Martell Malone1079ef82017-07-18 21:26:38 +0000348 const coff_import_directory_table_entry ImportDescriptor{
Martell Malone375dc902017-05-20 19:56:29 +0000349 u32(0), u32(0), u32(0), u32(0), u32(0),
350 };
351 append(Buffer, ImportDescriptor);
352
353 // Symbol Table
354 coff_symbol16 SymbolTable[NumberOfSymbols] = {
355 {{{0, 0, 0, 0, 0, 0, 0, 0}},
356 u32(0),
357 u16(1),
358 u16(0),
359 IMAGE_SYM_CLASS_EXTERNAL,
360 0},
361 };
Galina Kistanova415ec922017-06-08 23:35:52 +0000362 SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
Martell Malone375dc902017-05-20 19:56:29 +0000363 append(Buffer, SymbolTable);
364
365 // String Table
366 writeStringTable(Buffer, {NullImportDescriptorSymbolName});
367
368 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000369 return {MemoryBufferRef(F, ImportName)};
Martell Malone375dc902017-05-20 19:56:29 +0000370}
371
372NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
Martell Malone1079ef82017-07-18 21:26:38 +0000373 const uint32_t NumberOfSections = 2;
374 const uint32_t NumberOfSymbols = 1;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000375 uint32_t VASize = is32bit(Machine) ? 4 : 8;
Martell Malone375dc902017-05-20 19:56:29 +0000376
377 // COFF Header
378 coff_file_header Header{
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000379 u16(Machine),
380 u16(NumberOfSections),
381 u32(0),
Martell Malone375dc902017-05-20 19:56:29 +0000382 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
383 // .idata$5
384 VASize +
385 // .idata$4
386 VASize),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000387 u32(NumberOfSymbols),
388 u16(0),
389 u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : 0),
Martell Malone375dc902017-05-20 19:56:29 +0000390 };
391 append(Buffer, Header);
392
393 // Section Header Table
Martell Malone1079ef82017-07-18 21:26:38 +0000394 const coff_section SectionTable[NumberOfSections] = {
Martell Malone375dc902017-05-20 19:56:29 +0000395 {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
396 u32(0),
397 u32(0),
398 u32(VASize),
399 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
400 u32(0),
401 u32(0),
402 u16(0),
403 u16(0),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000404 u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
405 : IMAGE_SCN_ALIGN_8BYTES) |
Martell Malone375dc902017-05-20 19:56:29 +0000406 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
407 IMAGE_SCN_MEM_WRITE)},
408 {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
409 u32(0),
410 u32(0),
411 u32(VASize),
412 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
413 VASize),
414 u32(0),
415 u32(0),
416 u16(0),
417 u16(0),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000418 u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
419 : IMAGE_SCN_ALIGN_8BYTES) |
Martell Malone375dc902017-05-20 19:56:29 +0000420 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
421 IMAGE_SCN_MEM_WRITE)},
422 };
423 append(Buffer, SectionTable);
424
425 // .idata$5, ILT
426 append(Buffer, u32(0));
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000427 if (!is32bit(Machine))
Martell Malone375dc902017-05-20 19:56:29 +0000428 append(Buffer, u32(0));
429
430 // .idata$4, IAT
431 append(Buffer, u32(0));
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000432 if (!is32bit(Machine))
Martell Malone375dc902017-05-20 19:56:29 +0000433 append(Buffer, u32(0));
434
435 // Symbol Table
436 coff_symbol16 SymbolTable[NumberOfSymbols] = {
437 {{{0, 0, 0, 0, 0, 0, 0, 0}},
438 u32(0),
439 u16(1),
440 u16(0),
441 IMAGE_SYM_CLASS_EXTERNAL,
442 0},
443 };
Galina Kistanova415ec922017-06-08 23:35:52 +0000444 SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
Martell Malone375dc902017-05-20 19:56:29 +0000445 append(Buffer, SymbolTable);
446
447 // String Table
448 writeStringTable(Buffer, {NullThunkSymbolName});
449
450 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000451 return {MemoryBufferRef{F, ImportName}};
Martell Malone375dc902017-05-20 19:56:29 +0000452}
453
454NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
455 uint16_t Ordinal,
456 ImportType ImportType,
457 ImportNameType NameType) {
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000458 size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs
Martell Malone375dc902017-05-20 19:56:29 +0000459 size_t Size = sizeof(coff_import_header) + ImpSize;
460 char *Buf = Alloc.Allocate<char>(Size);
461 memset(Buf, 0, Size);
462 char *P = Buf;
463
464 // Write short import library.
465 auto *Imp = reinterpret_cast<coff_import_header *>(P);
466 P += sizeof(*Imp);
467 Imp->Sig2 = 0xFFFF;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000468 Imp->Machine = Machine;
Martell Malone375dc902017-05-20 19:56:29 +0000469 Imp->SizeOfData = ImpSize;
470 if (Ordinal > 0)
471 Imp->OrdinalHint = Ordinal;
472 Imp->TypeInfo = (NameType << 2) | ImportType;
473
474 // Write symbol name and DLL name.
475 memcpy(P, Sym.data(), Sym.size());
476 P += Sym.size() + 1;
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000477 memcpy(P, ImportName.data(), ImportName.size());
Martell Malone375dc902017-05-20 19:56:29 +0000478
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000479 return {MemoryBufferRef(StringRef(Buf, Size), ImportName)};
Martell Malone375dc902017-05-20 19:56:29 +0000480}
481
Martell Malone1079ef82017-07-18 21:26:38 +0000482NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym,
483 StringRef Weak, bool Imp) {
484 std::vector<uint8_t> Buffer;
485 const uint32_t NumberOfSections = 1;
486 const uint32_t NumberOfSymbols = 5;
487
488 // COFF Header
489 coff_file_header Header{
490 u16(0),
491 u16(NumberOfSections),
492 u32(0),
493 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))),
494 u32(NumberOfSymbols),
495 u16(0),
496 u16(0),
497 };
498 append(Buffer, Header);
499
500 // Section Header Table
501 const coff_section SectionTable[NumberOfSections] = {
502 {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'},
503 u32(0),
504 u32(0),
505 u32(0),
506 u32(0),
507 u32(0),
508 u32(0),
509 u16(0),
510 u16(0),
511 u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}};
512 append(Buffer, SectionTable);
513
514 // Symbol Table
515 coff_symbol16 SymbolTable[NumberOfSymbols] = {
516 {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},
517 u32(0),
518 u16(0xFFFF),
519 u16(0),
520 IMAGE_SYM_CLASS_STATIC,
521 0},
522 {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}},
523 u32(0),
524 u16(0xFFFF),
525 u16(0),
526 IMAGE_SYM_CLASS_STATIC,
527 0},
528 {{{0, 0, 0, 0, 0, 0, 0, 0}},
529 u32(0),
530 u16(0),
531 u16(0),
532 IMAGE_SYM_CLASS_EXTERNAL,
533 0},
534 {{{0, 0, 0, 0, 0, 0, 0, 0}},
535 u32(0),
536 u16(0),
537 u16(0),
538 IMAGE_SYM_CLASS_WEAK_EXTERNAL,
539 1},
540 {{{2, 0, 0, 0, 3, 0, 0, 0}}, u32(0), u16(0), u16(0), uint8_t(0), 0},
541 };
542 SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t);
543
544 //__imp_ String Table
545 if (Imp) {
546 SymbolTable[3].Name.Offset.Offset = sizeof(uint32_t) + Sym.size() + 7;
547 writeStringTable(Buffer, {std::string("__imp_").append(Sym),
548 std::string("__imp_").append(Weak)});
549 } else {
550 SymbolTable[3].Name.Offset.Offset = sizeof(uint32_t) + Sym.size() + 1;
551 writeStringTable(Buffer, {Sym, Weak});
552 }
553 append(Buffer, SymbolTable);
554
555 // Copied here so we can still use writeStringTable
556 char *Buf = Alloc.Allocate<char>(Buffer.size());
557 memcpy(Buf, Buffer.data(), Buffer.size());
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000558 return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)};
Martell Malone1079ef82017-07-18 21:26:38 +0000559}
560
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000561std::error_code writeImportLibrary(StringRef ImportName, StringRef Path,
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000562 ArrayRef<COFFShortExport> Exports,
563 MachineTypes Machine) {
Reid Klecknerd249e4a2017-06-02 16:26:24 +0000564
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000565 std::vector<NewArchiveMember> Members;
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000566 ObjectFactory OF(llvm::sys::path::filename(ImportName), Machine);
Martell Malone375dc902017-05-20 19:56:29 +0000567
568 std::vector<uint8_t> ImportDescriptor;
569 Members.push_back(OF.createImportDescriptor(ImportDescriptor));
570
571 std::vector<uint8_t> NullImportDescriptor;
572 Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));
573
574 std::vector<uint8_t> NullThunk;
575 Members.push_back(OF.createNullThunk(NullThunk));
576
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000577 for (COFFShortExport E : Exports) {
Martell Malone375dc902017-05-20 19:56:29 +0000578 if (E.Private)
579 continue;
580
Martell Malone1079ef82017-07-18 21:26:38 +0000581 if (E.isWeak()) {
582 Members.push_back(OF.createWeakExternal(E.Name, E.ExtName, false));
583 Members.push_back(OF.createWeakExternal(E.Name, E.ExtName, true));
584 continue;
585 }
586
Martell Malone375dc902017-05-20 19:56:29 +0000587 ImportType ImportType = IMPORT_CODE;
588 if (E.Data)
589 ImportType = IMPORT_DATA;
590 if (E.Constant)
591 ImportType = IMPORT_CONST;
592
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000593 StringRef SymbolName = E.isWeak() ? E.ExtName : E.Name;
594 ImportNameType NameType = getNameType(SymbolName, E.Name, Machine);
595 Expected<std::string> Name = E.ExtName.empty()
596 ? SymbolName
597 : replace(SymbolName, E.Name, E.ExtName);
598
599 if (!Name) {
600 return errorToErrorCode(Name.takeError());
601 }
602
603 Members.push_back(
604 OF.createShortImport(*Name, E.Ordinal, ImportType, NameType));
Martell Malone375dc902017-05-20 19:56:29 +0000605 }
606
607 std::pair<StringRef, std::error_code> Result =
608 writeArchive(Path, Members, /*WriteSymtab*/ true, object::Archive::K_GNU,
609 /*Deterministic*/ true, /*Thin*/ false);
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000610
611 return Result.second;
Martell Malone375dc902017-05-20 19:56:29 +0000612}
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000613
614} // namespace object
615} // namespace llvm