blob: 93631f1ad8119870223036369ce37372ef3db7e3 [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>
Reid Kleckner146eb7a2017-06-02 17:53:06 +000023#include <string>
Martell Malone375dc902017-05-20 19:56:29 +000024#include <vector>
25
26using namespace llvm::COFF;
27using namespace llvm::object;
28using namespace llvm;
29
Reid Kleckner146eb7a2017-06-02 17:53:06 +000030namespace llvm {
31namespace object {
32
33static bool is32bit(MachineTypes Machine) {
34 switch (Machine) {
Martell Malone375dc902017-05-20 19:56:29 +000035 default:
36 llvm_unreachable("unsupported machine");
Martin Storsjob9ff4192017-07-25 06:05:49 +000037 case IMAGE_FILE_MACHINE_ARM64:
Martell Malone375dc902017-05-20 19:56:29 +000038 case IMAGE_FILE_MACHINE_AMD64:
39 return false;
40 case IMAGE_FILE_MACHINE_ARMNT:
41 case IMAGE_FILE_MACHINE_I386:
42 return true;
43 }
44}
45
Reid Kleckner146eb7a2017-06-02 17:53:06 +000046static uint16_t getImgRelRelocation(MachineTypes Machine) {
47 switch (Machine) {
Martell Malone375dc902017-05-20 19:56:29 +000048 default:
49 llvm_unreachable("unsupported machine");
50 case IMAGE_FILE_MACHINE_AMD64:
51 return IMAGE_REL_AMD64_ADDR32NB;
52 case IMAGE_FILE_MACHINE_ARMNT:
53 return IMAGE_REL_ARM_ADDR32NB;
Martin Storsjob9ff4192017-07-25 06:05:49 +000054 case IMAGE_FILE_MACHINE_ARM64:
55 return IMAGE_REL_ARM64_ADDR32NB;
Martell Malone375dc902017-05-20 19:56:29 +000056 case IMAGE_FILE_MACHINE_I386:
57 return IMAGE_REL_I386_DIR32NB;
58 }
59}
60
61template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {
62 size_t S = B.size();
63 B.resize(S + sizeof(T));
64 memcpy(&B[S], &Data, sizeof(T));
65}
66
67static void writeStringTable(std::vector<uint8_t> &B,
68 ArrayRef<const std::string> Strings) {
69 // The COFF string table consists of a 4-byte value which is the size of the
70 // table, including the length field itself. This value is followed by the
71 // string content itself, which is an array of null-terminated C-style
72 // strings. The termination is important as they are referenced to by offset
73 // by the symbol entity in the file format.
74
Reid Kleckner146eb7a2017-06-02 17:53:06 +000075 size_t Pos = B.size();
76 size_t Offset = B.size();
Martell Malone375dc902017-05-20 19:56:29 +000077
78 // Skip over the length field, we will fill it in later as we will have
79 // computed the length while emitting the string content itself.
80 Pos += sizeof(uint32_t);
81
82 for (const auto &S : Strings) {
83 B.resize(Pos + S.length() + 1);
84 strcpy(reinterpret_cast<char *>(&B[Pos]), S.c_str());
85 Pos += S.length() + 1;
86 }
87
88 // Backfill the length of the table now that it has been computed.
89 support::ulittle32_t Length(B.size() - Offset);
Reid Kleckner146eb7a2017-06-02 17:53:06 +000090 support::endian::write32le(&B[Offset], Length);
Martell Malone375dc902017-05-20 19:56:29 +000091}
92
Reid Kleckner146eb7a2017-06-02 17:53:06 +000093static ImportNameType getNameType(StringRef Sym, StringRef ExtName,
94 MachineTypes Machine) {
Martell Malone375dc902017-05-20 19:56:29 +000095 if (Sym != ExtName)
96 return IMPORT_NAME_UNDECORATE;
Reid Kleckner146eb7a2017-06-02 17:53:06 +000097 if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.startswith("_"))
Martell Malone375dc902017-05-20 19:56:29 +000098 return IMPORT_NAME_NOPREFIX;
99 return IMPORT_NAME;
100}
101
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000102static Expected<std::string> replace(StringRef S, StringRef From,
103 StringRef To) {
Martell Malone375dc902017-05-20 19:56:29 +0000104 size_t Pos = S.find(From);
105
106 // From and To may be mangled, but substrings in S may not.
107 if (Pos == StringRef::npos && From.startswith("_") && To.startswith("_")) {
108 From = From.substr(1);
109 To = To.substr(1);
110 Pos = S.find(From);
111 }
112
113 if (Pos == StringRef::npos) {
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000114 return make_error<StringError>(
115 StringRef(Twine(S + ": replacing '" + From +
116 "' with '" + To + "' failed").str()), object_error::parse_failed);
Martell Malone375dc902017-05-20 19:56:29 +0000117 }
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000118
Martell Malone375dc902017-05-20 19:56:29 +0000119 return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
120}
121
122static const std::string NullImportDescriptorSymbolName =
123 "__NULL_IMPORT_DESCRIPTOR";
124
125namespace {
126// This class constructs various small object files necessary to support linking
127// symbols imported from a DLL. The contents are pretty strictly defined and
128// nearly entirely static. The details of the structures files are defined in
129// WINNT.h and the PE/COFF specification.
130class ObjectFactory {
131 using u16 = support::ulittle16_t;
132 using u32 = support::ulittle32_t;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000133 MachineTypes Machine;
Martell Malone375dc902017-05-20 19:56:29 +0000134 BumpPtrAllocator Alloc;
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000135 StringRef ImportName;
Martell Malone375dc902017-05-20 19:56:29 +0000136 StringRef Library;
137 std::string ImportDescriptorSymbolName;
138 std::string NullThunkSymbolName;
139
140public:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000141 ObjectFactory(StringRef S, MachineTypes M)
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000142 : Machine(M), ImportName(S), Library(S.drop_back(4)),
Martell Malone375dc902017-05-20 19:56:29 +0000143 ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()),
144 NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {}
145
146 // Creates an Import Descriptor. This is a small object file which contains a
147 // reference to the terminators and contains the library name (entry) for the
148 // import name table. It will force the linker to construct the necessary
149 // structure to import symbols from the DLL.
150 NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);
151
152 // Creates a NULL import descriptor. This is a small object file whcih
153 // contains a NULL import descriptor. It is used to terminate the imports
154 // from a specific DLL.
155 NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);
156
157 // Create a NULL Thunk Entry. This is a small object file which contains a
158 // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It
159 // is used to terminate the IAT and ILT.
160 NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);
161
162 // Create a short import file which is described in PE/COFF spec 7. Import
163 // Library Format.
164 NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
165 ImportType Type, ImportNameType NameType);
Martell Malone1079ef82017-07-18 21:26:38 +0000166
167 // Create a weak external file which is described in PE/COFF Aux Format 3.
168 NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp);
Martell Malone375dc902017-05-20 19:56:29 +0000169};
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000170} // namespace
Martell Malone375dc902017-05-20 19:56:29 +0000171
172NewArchiveMember
173ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
Martell Malone1079ef82017-07-18 21:26:38 +0000174 const uint32_t NumberOfSections = 2;
175 const uint32_t NumberOfSymbols = 7;
176 const uint32_t NumberOfRelocations = 3;
Martell Malone375dc902017-05-20 19:56:29 +0000177
178 // COFF Header
179 coff_file_header Header{
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000180 u16(Machine),
181 u16(NumberOfSections),
182 u32(0),
Martell Malone375dc902017-05-20 19:56:29 +0000183 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
184 // .idata$2
185 sizeof(coff_import_directory_table_entry) +
186 NumberOfRelocations * sizeof(coff_relocation) +
187 // .idata$4
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000188 (ImportName.size() + 1)),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000189 u32(NumberOfSymbols),
190 u16(0),
Galina Kistanova6532b3b2017-12-15 22:15:29 +0000191 u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
Martell Malone375dc902017-05-20 19:56:29 +0000192 };
193 append(Buffer, Header);
194
195 // Section Header Table
Martell Malone1079ef82017-07-18 21:26:38 +0000196 const coff_section SectionTable[NumberOfSections] = {
Martell Malone375dc902017-05-20 19:56:29 +0000197 {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
198 u32(0),
199 u32(0),
200 u32(sizeof(coff_import_directory_table_entry)),
201 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
202 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
203 sizeof(coff_import_directory_table_entry)),
204 u32(0),
205 u16(NumberOfRelocations),
206 u16(0),
207 u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
208 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
209 {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
210 u32(0),
211 u32(0),
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000212 u32(ImportName.size() + 1),
Martell Malone375dc902017-05-20 19:56:29 +0000213 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
214 sizeof(coff_import_directory_table_entry) +
215 NumberOfRelocations * sizeof(coff_relocation)),
216 u32(0),
217 u32(0),
218 u16(0),
219 u16(0),
220 u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
221 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
222 };
223 append(Buffer, SectionTable);
224
225 // .idata$2
Martell Malone1079ef82017-07-18 21:26:38 +0000226 const coff_import_directory_table_entry ImportDescriptor{
Martell Malone375dc902017-05-20 19:56:29 +0000227 u32(0), u32(0), u32(0), u32(0), u32(0),
228 };
229 append(Buffer, ImportDescriptor);
230
Martell Malone1079ef82017-07-18 21:26:38 +0000231 const coff_relocation RelocationTable[NumberOfRelocations] = {
Martell Malone375dc902017-05-20 19:56:29 +0000232 {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000233 u16(getImgRelRelocation(Machine))},
Martell Malone375dc902017-05-20 19:56:29 +0000234 {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000235 u32(3), u16(getImgRelRelocation(Machine))},
Martell Malone375dc902017-05-20 19:56:29 +0000236 {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000237 u32(4), u16(getImgRelRelocation(Machine))},
Martell Malone375dc902017-05-20 19:56:29 +0000238 };
239 append(Buffer, RelocationTable);
240
241 // .idata$6
242 auto S = Buffer.size();
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000243 Buffer.resize(S + ImportName.size() + 1);
244 memcpy(&Buffer[S], ImportName.data(), ImportName.size());
245 Buffer[S + ImportName.size()] = '\0';
Martell Malone375dc902017-05-20 19:56:29 +0000246
247 // Symbol Table
248 coff_symbol16 SymbolTable[NumberOfSymbols] = {
249 {{{0, 0, 0, 0, 0, 0, 0, 0}},
250 u32(0),
251 u16(1),
252 u16(0),
253 IMAGE_SYM_CLASS_EXTERNAL,
254 0},
255 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
256 u32(0),
257 u16(1),
258 u16(0),
259 IMAGE_SYM_CLASS_SECTION,
260 0},
261 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
262 u32(0),
263 u16(2),
264 u16(0),
265 IMAGE_SYM_CLASS_STATIC,
266 0},
267 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
268 u32(0),
269 u16(0),
270 u16(0),
271 IMAGE_SYM_CLASS_SECTION,
272 0},
273 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
274 u32(0),
275 u16(0),
276 u16(0),
277 IMAGE_SYM_CLASS_SECTION,
278 0},
279 {{{0, 0, 0, 0, 0, 0, 0, 0}},
280 u32(0),
281 u16(0),
282 u16(0),
283 IMAGE_SYM_CLASS_EXTERNAL,
284 0},
285 {{{0, 0, 0, 0, 0, 0, 0, 0}},
286 u32(0),
287 u16(0),
288 u16(0),
289 IMAGE_SYM_CLASS_EXTERNAL,
290 0},
291 };
Galina Kistanova415ec922017-06-08 23:35:52 +0000292 // TODO: Name.Offset.Offset here and in the all similar places below
293 // suggests a names refactoring. Maybe StringTableOffset.Value?
294 SymbolTable[0].Name.Offset.Offset =
Martell Malone375dc902017-05-20 19:56:29 +0000295 sizeof(uint32_t);
Galina Kistanova415ec922017-06-08 23:35:52 +0000296 SymbolTable[5].Name.Offset.Offset =
Martell Malone375dc902017-05-20 19:56:29 +0000297 sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
Galina Kistanova415ec922017-06-08 23:35:52 +0000298 SymbolTable[6].Name.Offset.Offset =
Martell Malone375dc902017-05-20 19:56:29 +0000299 sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
300 NullImportDescriptorSymbolName.length() + 1;
301 append(Buffer, SymbolTable);
302
303 // String Table
304 writeStringTable(Buffer,
305 {ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
306 NullThunkSymbolName});
307
308 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000309 return {MemoryBufferRef(F, ImportName)};
Martell Malone375dc902017-05-20 19:56:29 +0000310}
311
312NewArchiveMember
313ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
Martell Malone1079ef82017-07-18 21:26:38 +0000314 const uint32_t NumberOfSections = 1;
315 const uint32_t NumberOfSymbols = 1;
Martell Malone375dc902017-05-20 19:56:29 +0000316
317 // COFF Header
318 coff_file_header Header{
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000319 u16(Machine),
320 u16(NumberOfSections),
321 u32(0),
Martell Malone375dc902017-05-20 19:56:29 +0000322 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
323 // .idata$3
324 sizeof(coff_import_directory_table_entry)),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000325 u32(NumberOfSymbols),
326 u16(0),
Galina Kistanova6532b3b2017-12-15 22:15:29 +0000327 u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
Martell Malone375dc902017-05-20 19:56:29 +0000328 };
329 append(Buffer, Header);
330
331 // Section Header Table
Martell Malone1079ef82017-07-18 21:26:38 +0000332 const coff_section SectionTable[NumberOfSections] = {
Martell Malone375dc902017-05-20 19:56:29 +0000333 {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
334 u32(0),
335 u32(0),
336 u32(sizeof(coff_import_directory_table_entry)),
337 u32(sizeof(coff_file_header) +
338 (NumberOfSections * sizeof(coff_section))),
339 u32(0),
340 u32(0),
341 u16(0),
342 u16(0),
343 u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
344 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
345 };
346 append(Buffer, SectionTable);
347
348 // .idata$3
Martell Malone1079ef82017-07-18 21:26:38 +0000349 const coff_import_directory_table_entry ImportDescriptor{
Martell Malone375dc902017-05-20 19:56:29 +0000350 u32(0), u32(0), u32(0), u32(0), u32(0),
351 };
352 append(Buffer, ImportDescriptor);
353
354 // Symbol Table
355 coff_symbol16 SymbolTable[NumberOfSymbols] = {
356 {{{0, 0, 0, 0, 0, 0, 0, 0}},
357 u32(0),
358 u16(1),
359 u16(0),
360 IMAGE_SYM_CLASS_EXTERNAL,
361 0},
362 };
Galina Kistanova415ec922017-06-08 23:35:52 +0000363 SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
Martell Malone375dc902017-05-20 19:56:29 +0000364 append(Buffer, SymbolTable);
365
366 // String Table
367 writeStringTable(Buffer, {NullImportDescriptorSymbolName});
368
369 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000370 return {MemoryBufferRef(F, ImportName)};
Martell Malone375dc902017-05-20 19:56:29 +0000371}
372
373NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
Martell Malone1079ef82017-07-18 21:26:38 +0000374 const uint32_t NumberOfSections = 2;
375 const uint32_t NumberOfSymbols = 1;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000376 uint32_t VASize = is32bit(Machine) ? 4 : 8;
Martell Malone375dc902017-05-20 19:56:29 +0000377
378 // COFF Header
379 coff_file_header Header{
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000380 u16(Machine),
381 u16(NumberOfSections),
382 u32(0),
Martell Malone375dc902017-05-20 19:56:29 +0000383 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
384 // .idata$5
385 VASize +
386 // .idata$4
387 VASize),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000388 u32(NumberOfSymbols),
389 u16(0),
Galina Kistanova6532b3b2017-12-15 22:15:29 +0000390 u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
Martell Malone375dc902017-05-20 19:56:29 +0000391 };
392 append(Buffer, Header);
393
394 // Section Header Table
Martell Malone1079ef82017-07-18 21:26:38 +0000395 const coff_section SectionTable[NumberOfSections] = {
Martell Malone375dc902017-05-20 19:56:29 +0000396 {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
397 u32(0),
398 u32(0),
399 u32(VASize),
400 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
401 u32(0),
402 u32(0),
403 u16(0),
404 u16(0),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000405 u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
406 : IMAGE_SCN_ALIGN_8BYTES) |
Martell Malone375dc902017-05-20 19:56:29 +0000407 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
408 IMAGE_SCN_MEM_WRITE)},
409 {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
410 u32(0),
411 u32(0),
412 u32(VASize),
413 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
414 VASize),
415 u32(0),
416 u32(0),
417 u16(0),
418 u16(0),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000419 u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
420 : IMAGE_SCN_ALIGN_8BYTES) |
Martell Malone375dc902017-05-20 19:56:29 +0000421 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
422 IMAGE_SCN_MEM_WRITE)},
423 };
424 append(Buffer, SectionTable);
425
426 // .idata$5, ILT
427 append(Buffer, u32(0));
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000428 if (!is32bit(Machine))
Martell Malone375dc902017-05-20 19:56:29 +0000429 append(Buffer, u32(0));
430
431 // .idata$4, IAT
432 append(Buffer, u32(0));
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000433 if (!is32bit(Machine))
Martell Malone375dc902017-05-20 19:56:29 +0000434 append(Buffer, u32(0));
435
436 // Symbol Table
437 coff_symbol16 SymbolTable[NumberOfSymbols] = {
438 {{{0, 0, 0, 0, 0, 0, 0, 0}},
439 u32(0),
440 u16(1),
441 u16(0),
442 IMAGE_SYM_CLASS_EXTERNAL,
443 0},
444 };
Galina Kistanova415ec922017-06-08 23:35:52 +0000445 SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
Martell Malone375dc902017-05-20 19:56:29 +0000446 append(Buffer, SymbolTable);
447
448 // String Table
449 writeStringTable(Buffer, {NullThunkSymbolName});
450
451 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000452 return {MemoryBufferRef{F, ImportName}};
Martell Malone375dc902017-05-20 19:56:29 +0000453}
454
455NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
456 uint16_t Ordinal,
457 ImportType ImportType,
458 ImportNameType NameType) {
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000459 size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs
Martell Malone375dc902017-05-20 19:56:29 +0000460 size_t Size = sizeof(coff_import_header) + ImpSize;
461 char *Buf = Alloc.Allocate<char>(Size);
462 memset(Buf, 0, Size);
463 char *P = Buf;
464
465 // Write short import library.
466 auto *Imp = reinterpret_cast<coff_import_header *>(P);
467 P += sizeof(*Imp);
468 Imp->Sig2 = 0xFFFF;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000469 Imp->Machine = Machine;
Martell Malone375dc902017-05-20 19:56:29 +0000470 Imp->SizeOfData = ImpSize;
471 if (Ordinal > 0)
472 Imp->OrdinalHint = Ordinal;
473 Imp->TypeInfo = (NameType << 2) | ImportType;
474
475 // Write symbol name and DLL name.
476 memcpy(P, Sym.data(), Sym.size());
477 P += Sym.size() + 1;
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000478 memcpy(P, ImportName.data(), ImportName.size());
Martell Malone375dc902017-05-20 19:56:29 +0000479
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000480 return {MemoryBufferRef(StringRef(Buf, Size), ImportName)};
Martell Malone375dc902017-05-20 19:56:29 +0000481}
482
Martell Malone1079ef82017-07-18 21:26:38 +0000483NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym,
484 StringRef Weak, bool Imp) {
485 std::vector<uint8_t> Buffer;
486 const uint32_t NumberOfSections = 1;
487 const uint32_t NumberOfSymbols = 5;
488
489 // COFF Header
490 coff_file_header Header{
491 u16(0),
492 u16(NumberOfSections),
493 u32(0),
494 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))),
495 u32(NumberOfSymbols),
496 u16(0),
497 u16(0),
498 };
499 append(Buffer, Header);
500
501 // Section Header Table
502 const coff_section SectionTable[NumberOfSections] = {
503 {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'},
504 u32(0),
505 u32(0),
506 u32(0),
507 u32(0),
508 u32(0),
509 u32(0),
510 u16(0),
511 u16(0),
512 u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}};
513 append(Buffer, SectionTable);
514
515 // Symbol Table
516 coff_symbol16 SymbolTable[NumberOfSymbols] = {
517 {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},
518 u32(0),
519 u16(0xFFFF),
520 u16(0),
521 IMAGE_SYM_CLASS_STATIC,
522 0},
523 {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}},
524 u32(0),
525 u16(0xFFFF),
526 u16(0),
527 IMAGE_SYM_CLASS_STATIC,
528 0},
529 {{{0, 0, 0, 0, 0, 0, 0, 0}},
530 u32(0),
531 u16(0),
532 u16(0),
533 IMAGE_SYM_CLASS_EXTERNAL,
534 0},
535 {{{0, 0, 0, 0, 0, 0, 0, 0}},
536 u32(0),
537 u16(0),
538 u16(0),
539 IMAGE_SYM_CLASS_WEAK_EXTERNAL,
540 1},
541 {{{2, 0, 0, 0, 3, 0, 0, 0}}, u32(0), u16(0), u16(0), uint8_t(0), 0},
542 };
543 SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t);
544
545 //__imp_ String Table
Martin Storsjo4a5764e2017-07-31 11:18:41 +0000546 StringRef Prefix = Imp ? "__imp_" : "";
547 SymbolTable[3].Name.Offset.Offset =
548 sizeof(uint32_t) + Sym.size() + Prefix.size() + 1;
Martell Malone1079ef82017-07-18 21:26:38 +0000549 append(Buffer, SymbolTable);
Martin Storsjo4a5764e2017-07-31 11:18:41 +0000550 writeStringTable(Buffer, {(Prefix + Sym).str(),
551 (Prefix + Weak).str()});
Martell Malone1079ef82017-07-18 21:26:38 +0000552
553 // Copied here so we can still use writeStringTable
554 char *Buf = Alloc.Allocate<char>(Buffer.size());
555 memcpy(Buf, Buffer.data(), Buffer.size());
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000556 return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)};
Martell Malone1079ef82017-07-18 21:26:38 +0000557}
558
Rafael Espindola25cbdf22017-09-21 23:13:36 +0000559Error writeImportLibrary(StringRef ImportName, StringRef Path,
560 ArrayRef<COFFShortExport> Exports,
561 MachineTypes Machine, bool MakeWeakAliases) {
Reid Klecknerd249e4a2017-06-02 16:26:24 +0000562
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000563 std::vector<NewArchiveMember> Members;
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000564 ObjectFactory OF(llvm::sys::path::filename(ImportName), Machine);
Martell Malone375dc902017-05-20 19:56:29 +0000565
566 std::vector<uint8_t> ImportDescriptor;
567 Members.push_back(OF.createImportDescriptor(ImportDescriptor));
568
569 std::vector<uint8_t> NullImportDescriptor;
570 Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));
571
572 std::vector<uint8_t> NullThunk;
573 Members.push_back(OF.createNullThunk(NullThunk));
574
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000575 for (COFFShortExport E : Exports) {
Martell Malone375dc902017-05-20 19:56:29 +0000576 if (E.Private)
577 continue;
578
Martin Storsjoe1f120b2017-08-16 05:22:49 +0000579 if (E.isWeak() && MakeWeakAliases) {
Martell Malone1079ef82017-07-18 21:26:38 +0000580 Members.push_back(OF.createWeakExternal(E.Name, E.ExtName, false));
581 Members.push_back(OF.createWeakExternal(E.Name, E.ExtName, true));
582 continue;
583 }
584
Martell Malone375dc902017-05-20 19:56:29 +0000585 ImportType ImportType = IMPORT_CODE;
586 if (E.Data)
587 ImportType = IMPORT_DATA;
588 if (E.Constant)
589 ImportType = IMPORT_CONST;
590
Martin Storsjoa238b202017-08-16 05:13:16 +0000591 StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000592 ImportNameType NameType = getNameType(SymbolName, E.Name, Machine);
593 Expected<std::string> Name = E.ExtName.empty()
594 ? SymbolName
595 : replace(SymbolName, E.Name, E.ExtName);
596
Rafael Espindola25cbdf22017-09-21 23:13:36 +0000597 if (!Name)
598 return Name.takeError();
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000599
600 Members.push_back(
601 OF.createShortImport(*Name, E.Ordinal, ImportType, NameType));
Martell Malone375dc902017-05-20 19:56:29 +0000602 }
603
Rui Ueyama01d02652017-08-30 22:11:03 +0000604 return writeArchive(Path, Members, /*WriteSymtab*/ true,
605 object::Archive::K_GNU,
606 /*Deterministic*/ true, /*Thin*/ false);
Martell Malone375dc902017-05-20 19:56:29 +0000607}
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000608
609} // namespace object
610} // namespace llvm