blob: 670c4bb7dd1ee2103c95e630fd3762381239953d [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");
Martin Storsjob9ff4192017-07-25 06:05:49 +000039 case IMAGE_FILE_MACHINE_ARM64:
Martell Malone375dc902017-05-20 19:56:29 +000040 case IMAGE_FILE_MACHINE_AMD64:
41 return false;
42 case IMAGE_FILE_MACHINE_ARMNT:
43 case IMAGE_FILE_MACHINE_I386:
44 return true;
45 }
46}
47
Reid Kleckner146eb7a2017-06-02 17:53:06 +000048static uint16_t getImgRelRelocation(MachineTypes Machine) {
49 switch (Machine) {
Martell Malone375dc902017-05-20 19:56:29 +000050 default:
51 llvm_unreachable("unsupported machine");
52 case IMAGE_FILE_MACHINE_AMD64:
53 return IMAGE_REL_AMD64_ADDR32NB;
54 case IMAGE_FILE_MACHINE_ARMNT:
55 return IMAGE_REL_ARM_ADDR32NB;
Martin Storsjob9ff4192017-07-25 06:05:49 +000056 case IMAGE_FILE_MACHINE_ARM64:
57 return IMAGE_REL_ARM64_ADDR32NB;
Martell Malone375dc902017-05-20 19:56:29 +000058 case IMAGE_FILE_MACHINE_I386:
59 return IMAGE_REL_I386_DIR32NB;
60 }
61}
62
63template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {
64 size_t S = B.size();
65 B.resize(S + sizeof(T));
66 memcpy(&B[S], &Data, sizeof(T));
67}
68
69static void writeStringTable(std::vector<uint8_t> &B,
70 ArrayRef<const std::string> Strings) {
71 // The COFF string table consists of a 4-byte value which is the size of the
72 // table, including the length field itself. This value is followed by the
73 // string content itself, which is an array of null-terminated C-style
74 // strings. The termination is important as they are referenced to by offset
75 // by the symbol entity in the file format.
76
Reid Kleckner146eb7a2017-06-02 17:53:06 +000077 size_t Pos = B.size();
78 size_t Offset = B.size();
Martell Malone375dc902017-05-20 19:56:29 +000079
80 // Skip over the length field, we will fill it in later as we will have
81 // computed the length while emitting the string content itself.
82 Pos += sizeof(uint32_t);
83
84 for (const auto &S : Strings) {
85 B.resize(Pos + S.length() + 1);
86 strcpy(reinterpret_cast<char *>(&B[Pos]), S.c_str());
87 Pos += S.length() + 1;
88 }
89
90 // Backfill the length of the table now that it has been computed.
91 support::ulittle32_t Length(B.size() - Offset);
Reid Kleckner146eb7a2017-06-02 17:53:06 +000092 support::endian::write32le(&B[Offset], Length);
Martell Malone375dc902017-05-20 19:56:29 +000093}
94
Reid Kleckner146eb7a2017-06-02 17:53:06 +000095static ImportNameType getNameType(StringRef Sym, StringRef ExtName,
96 MachineTypes Machine) {
Martell Malone375dc902017-05-20 19:56:29 +000097 if (Sym != ExtName)
98 return IMPORT_NAME_UNDECORATE;
Reid Kleckner146eb7a2017-06-02 17:53:06 +000099 if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.startswith("_"))
Martell Malone375dc902017-05-20 19:56:29 +0000100 return IMPORT_NAME_NOPREFIX;
101 return IMPORT_NAME;
102}
103
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000104static Expected<std::string> replace(StringRef S, StringRef From,
105 StringRef To) {
Martell Malone375dc902017-05-20 19:56:29 +0000106 size_t Pos = S.find(From);
107
108 // From and To may be mangled, but substrings in S may not.
109 if (Pos == StringRef::npos && From.startswith("_") && To.startswith("_")) {
110 From = From.substr(1);
111 To = To.substr(1);
112 Pos = S.find(From);
113 }
114
115 if (Pos == StringRef::npos) {
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000116 return make_error<StringError>(
117 StringRef(Twine(S + ": replacing '" + From +
118 "' with '" + To + "' failed").str()), object_error::parse_failed);
Martell Malone375dc902017-05-20 19:56:29 +0000119 }
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000120
Martell Malone375dc902017-05-20 19:56:29 +0000121 return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
122}
123
124static const std::string NullImportDescriptorSymbolName =
125 "__NULL_IMPORT_DESCRIPTOR";
126
127namespace {
128// This class constructs various small object files necessary to support linking
129// symbols imported from a DLL. The contents are pretty strictly defined and
130// nearly entirely static. The details of the structures files are defined in
131// WINNT.h and the PE/COFF specification.
132class ObjectFactory {
133 using u16 = support::ulittle16_t;
134 using u32 = support::ulittle32_t;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000135 MachineTypes Machine;
Martell Malone375dc902017-05-20 19:56:29 +0000136 BumpPtrAllocator Alloc;
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000137 StringRef ImportName;
Martell Malone375dc902017-05-20 19:56:29 +0000138 StringRef Library;
139 std::string ImportDescriptorSymbolName;
140 std::string NullThunkSymbolName;
141
142public:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000143 ObjectFactory(StringRef S, MachineTypes M)
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000144 : Machine(M), ImportName(S), Library(S.drop_back(4)),
Martell Malone375dc902017-05-20 19:56:29 +0000145 ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()),
146 NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {}
147
148 // Creates an Import Descriptor. This is a small object file which contains a
149 // reference to the terminators and contains the library name (entry) for the
150 // import name table. It will force the linker to construct the necessary
151 // structure to import symbols from the DLL.
152 NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);
153
154 // Creates a NULL import descriptor. This is a small object file whcih
155 // contains a NULL import descriptor. It is used to terminate the imports
156 // from a specific DLL.
157 NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);
158
159 // Create a NULL Thunk Entry. This is a small object file which contains a
160 // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It
161 // is used to terminate the IAT and ILT.
162 NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);
163
164 // Create a short import file which is described in PE/COFF spec 7. Import
165 // Library Format.
166 NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
167 ImportType Type, ImportNameType NameType);
Martell Malone1079ef82017-07-18 21:26:38 +0000168
169 // Create a weak external file which is described in PE/COFF Aux Format 3.
170 NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp);
Martell Malone375dc902017-05-20 19:56:29 +0000171};
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000172} // namespace
Martell Malone375dc902017-05-20 19:56:29 +0000173
174NewArchiveMember
175ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
Martell Malone1079ef82017-07-18 21:26:38 +0000176 const uint32_t NumberOfSections = 2;
177 const uint32_t NumberOfSymbols = 7;
178 const uint32_t NumberOfRelocations = 3;
Martell Malone375dc902017-05-20 19:56:29 +0000179
180 // COFF Header
181 coff_file_header Header{
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000182 u16(Machine),
183 u16(NumberOfSections),
184 u32(0),
Martell Malone375dc902017-05-20 19:56:29 +0000185 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
186 // .idata$2
187 sizeof(coff_import_directory_table_entry) +
188 NumberOfRelocations * sizeof(coff_relocation) +
189 // .idata$4
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000190 (ImportName.size() + 1)),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000191 u32(NumberOfSymbols),
192 u16(0),
193 u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : 0),
Martell Malone375dc902017-05-20 19:56:29 +0000194 };
195 append(Buffer, Header);
196
197 // Section Header Table
Martell Malone1079ef82017-07-18 21:26:38 +0000198 const coff_section SectionTable[NumberOfSections] = {
Martell Malone375dc902017-05-20 19:56:29 +0000199 {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
200 u32(0),
201 u32(0),
202 u32(sizeof(coff_import_directory_table_entry)),
203 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
204 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
205 sizeof(coff_import_directory_table_entry)),
206 u32(0),
207 u16(NumberOfRelocations),
208 u16(0),
209 u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
210 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
211 {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
212 u32(0),
213 u32(0),
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000214 u32(ImportName.size() + 1),
Martell Malone375dc902017-05-20 19:56:29 +0000215 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
216 sizeof(coff_import_directory_table_entry) +
217 NumberOfRelocations * sizeof(coff_relocation)),
218 u32(0),
219 u32(0),
220 u16(0),
221 u16(0),
222 u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
223 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
224 };
225 append(Buffer, SectionTable);
226
227 // .idata$2
Martell Malone1079ef82017-07-18 21:26:38 +0000228 const coff_import_directory_table_entry ImportDescriptor{
Martell Malone375dc902017-05-20 19:56:29 +0000229 u32(0), u32(0), u32(0), u32(0), u32(0),
230 };
231 append(Buffer, ImportDescriptor);
232
Martell Malone1079ef82017-07-18 21:26:38 +0000233 const coff_relocation RelocationTable[NumberOfRelocations] = {
Martell Malone375dc902017-05-20 19:56:29 +0000234 {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000235 u16(getImgRelRelocation(Machine))},
Martell Malone375dc902017-05-20 19:56:29 +0000236 {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000237 u32(3), u16(getImgRelRelocation(Machine))},
Martell Malone375dc902017-05-20 19:56:29 +0000238 {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000239 u32(4), u16(getImgRelRelocation(Machine))},
Martell Malone375dc902017-05-20 19:56:29 +0000240 };
241 append(Buffer, RelocationTable);
242
243 // .idata$6
244 auto S = Buffer.size();
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000245 Buffer.resize(S + ImportName.size() + 1);
246 memcpy(&Buffer[S], ImportName.data(), ImportName.size());
247 Buffer[S + ImportName.size()] = '\0';
Martell Malone375dc902017-05-20 19:56:29 +0000248
249 // Symbol Table
250 coff_symbol16 SymbolTable[NumberOfSymbols] = {
251 {{{0, 0, 0, 0, 0, 0, 0, 0}},
252 u32(0),
253 u16(1),
254 u16(0),
255 IMAGE_SYM_CLASS_EXTERNAL,
256 0},
257 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
258 u32(0),
259 u16(1),
260 u16(0),
261 IMAGE_SYM_CLASS_SECTION,
262 0},
263 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
264 u32(0),
265 u16(2),
266 u16(0),
267 IMAGE_SYM_CLASS_STATIC,
268 0},
269 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
270 u32(0),
271 u16(0),
272 u16(0),
273 IMAGE_SYM_CLASS_SECTION,
274 0},
275 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
276 u32(0),
277 u16(0),
278 u16(0),
279 IMAGE_SYM_CLASS_SECTION,
280 0},
281 {{{0, 0, 0, 0, 0, 0, 0, 0}},
282 u32(0),
283 u16(0),
284 u16(0),
285 IMAGE_SYM_CLASS_EXTERNAL,
286 0},
287 {{{0, 0, 0, 0, 0, 0, 0, 0}},
288 u32(0),
289 u16(0),
290 u16(0),
291 IMAGE_SYM_CLASS_EXTERNAL,
292 0},
293 };
Galina Kistanova415ec922017-06-08 23:35:52 +0000294 // TODO: Name.Offset.Offset here and in the all similar places below
295 // suggests a names refactoring. Maybe StringTableOffset.Value?
296 SymbolTable[0].Name.Offset.Offset =
Martell Malone375dc902017-05-20 19:56:29 +0000297 sizeof(uint32_t);
Galina Kistanova415ec922017-06-08 23:35:52 +0000298 SymbolTable[5].Name.Offset.Offset =
Martell Malone375dc902017-05-20 19:56:29 +0000299 sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
Galina Kistanova415ec922017-06-08 23:35:52 +0000300 SymbolTable[6].Name.Offset.Offset =
Martell Malone375dc902017-05-20 19:56:29 +0000301 sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
302 NullImportDescriptorSymbolName.length() + 1;
303 append(Buffer, SymbolTable);
304
305 // String Table
306 writeStringTable(Buffer,
307 {ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
308 NullThunkSymbolName});
309
310 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000311 return {MemoryBufferRef(F, ImportName)};
Martell Malone375dc902017-05-20 19:56:29 +0000312}
313
314NewArchiveMember
315ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
Martell Malone1079ef82017-07-18 21:26:38 +0000316 const uint32_t NumberOfSections = 1;
317 const uint32_t NumberOfSymbols = 1;
Martell Malone375dc902017-05-20 19:56:29 +0000318
319 // COFF Header
320 coff_file_header Header{
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000321 u16(Machine),
322 u16(NumberOfSections),
323 u32(0),
Martell Malone375dc902017-05-20 19:56:29 +0000324 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
325 // .idata$3
326 sizeof(coff_import_directory_table_entry)),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000327 u32(NumberOfSymbols),
328 u16(0),
329 u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : 0),
Martell Malone375dc902017-05-20 19:56:29 +0000330 };
331 append(Buffer, Header);
332
333 // Section Header Table
Martell Malone1079ef82017-07-18 21:26:38 +0000334 const coff_section SectionTable[NumberOfSections] = {
Martell Malone375dc902017-05-20 19:56:29 +0000335 {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
336 u32(0),
337 u32(0),
338 u32(sizeof(coff_import_directory_table_entry)),
339 u32(sizeof(coff_file_header) +
340 (NumberOfSections * sizeof(coff_section))),
341 u32(0),
342 u32(0),
343 u16(0),
344 u16(0),
345 u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
346 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
347 };
348 append(Buffer, SectionTable);
349
350 // .idata$3
Martell Malone1079ef82017-07-18 21:26:38 +0000351 const coff_import_directory_table_entry ImportDescriptor{
Martell Malone375dc902017-05-20 19:56:29 +0000352 u32(0), u32(0), u32(0), u32(0), u32(0),
353 };
354 append(Buffer, ImportDescriptor);
355
356 // Symbol Table
357 coff_symbol16 SymbolTable[NumberOfSymbols] = {
358 {{{0, 0, 0, 0, 0, 0, 0, 0}},
359 u32(0),
360 u16(1),
361 u16(0),
362 IMAGE_SYM_CLASS_EXTERNAL,
363 0},
364 };
Galina Kistanova415ec922017-06-08 23:35:52 +0000365 SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
Martell Malone375dc902017-05-20 19:56:29 +0000366 append(Buffer, SymbolTable);
367
368 // String Table
369 writeStringTable(Buffer, {NullImportDescriptorSymbolName});
370
371 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000372 return {MemoryBufferRef(F, ImportName)};
Martell Malone375dc902017-05-20 19:56:29 +0000373}
374
375NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
Martell Malone1079ef82017-07-18 21:26:38 +0000376 const uint32_t NumberOfSections = 2;
377 const uint32_t NumberOfSymbols = 1;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000378 uint32_t VASize = is32bit(Machine) ? 4 : 8;
Martell Malone375dc902017-05-20 19:56:29 +0000379
380 // COFF Header
381 coff_file_header Header{
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000382 u16(Machine),
383 u16(NumberOfSections),
384 u32(0),
Martell Malone375dc902017-05-20 19:56:29 +0000385 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
386 // .idata$5
387 VASize +
388 // .idata$4
389 VASize),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000390 u32(NumberOfSymbols),
391 u16(0),
392 u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : 0),
Martell Malone375dc902017-05-20 19:56:29 +0000393 };
394 append(Buffer, Header);
395
396 // Section Header Table
Martell Malone1079ef82017-07-18 21:26:38 +0000397 const coff_section SectionTable[NumberOfSections] = {
Martell Malone375dc902017-05-20 19:56:29 +0000398 {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
399 u32(0),
400 u32(0),
401 u32(VASize),
402 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
403 u32(0),
404 u32(0),
405 u16(0),
406 u16(0),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000407 u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
408 : IMAGE_SCN_ALIGN_8BYTES) |
Martell Malone375dc902017-05-20 19:56:29 +0000409 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
410 IMAGE_SCN_MEM_WRITE)},
411 {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
412 u32(0),
413 u32(0),
414 u32(VASize),
415 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
416 VASize),
417 u32(0),
418 u32(0),
419 u16(0),
420 u16(0),
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000421 u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
422 : IMAGE_SCN_ALIGN_8BYTES) |
Martell Malone375dc902017-05-20 19:56:29 +0000423 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
424 IMAGE_SCN_MEM_WRITE)},
425 };
426 append(Buffer, SectionTable);
427
428 // .idata$5, ILT
429 append(Buffer, u32(0));
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000430 if (!is32bit(Machine))
Martell Malone375dc902017-05-20 19:56:29 +0000431 append(Buffer, u32(0));
432
433 // .idata$4, IAT
434 append(Buffer, u32(0));
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000435 if (!is32bit(Machine))
Martell Malone375dc902017-05-20 19:56:29 +0000436 append(Buffer, u32(0));
437
438 // Symbol Table
439 coff_symbol16 SymbolTable[NumberOfSymbols] = {
440 {{{0, 0, 0, 0, 0, 0, 0, 0}},
441 u32(0),
442 u16(1),
443 u16(0),
444 IMAGE_SYM_CLASS_EXTERNAL,
445 0},
446 };
Galina Kistanova415ec922017-06-08 23:35:52 +0000447 SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
Martell Malone375dc902017-05-20 19:56:29 +0000448 append(Buffer, SymbolTable);
449
450 // String Table
451 writeStringTable(Buffer, {NullThunkSymbolName});
452
453 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000454 return {MemoryBufferRef{F, ImportName}};
Martell Malone375dc902017-05-20 19:56:29 +0000455}
456
457NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
458 uint16_t Ordinal,
459 ImportType ImportType,
460 ImportNameType NameType) {
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000461 size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs
Martell Malone375dc902017-05-20 19:56:29 +0000462 size_t Size = sizeof(coff_import_header) + ImpSize;
463 char *Buf = Alloc.Allocate<char>(Size);
464 memset(Buf, 0, Size);
465 char *P = Buf;
466
467 // Write short import library.
468 auto *Imp = reinterpret_cast<coff_import_header *>(P);
469 P += sizeof(*Imp);
470 Imp->Sig2 = 0xFFFF;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000471 Imp->Machine = Machine;
Martell Malone375dc902017-05-20 19:56:29 +0000472 Imp->SizeOfData = ImpSize;
473 if (Ordinal > 0)
474 Imp->OrdinalHint = Ordinal;
475 Imp->TypeInfo = (NameType << 2) | ImportType;
476
477 // Write symbol name and DLL name.
478 memcpy(P, Sym.data(), Sym.size());
479 P += Sym.size() + 1;
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000480 memcpy(P, ImportName.data(), ImportName.size());
Martell Malone375dc902017-05-20 19:56:29 +0000481
Saleem Abdulrasool0f83a892017-07-18 22:11:01 +0000482 return {MemoryBufferRef(StringRef(Buf, Size), ImportName)};
Martell Malone375dc902017-05-20 19:56:29 +0000483}
484
Martell Malone1079ef82017-07-18 21:26:38 +0000485NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym,
486 StringRef Weak, bool Imp) {
487 std::vector<uint8_t> Buffer;
488 const uint32_t NumberOfSections = 1;
489 const uint32_t NumberOfSymbols = 5;
490
491 // COFF Header
492 coff_file_header Header{
493 u16(0),
494 u16(NumberOfSections),
495 u32(0),
496 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))),
497 u32(NumberOfSymbols),
498 u16(0),
499 u16(0),
500 };
501 append(Buffer, Header);
502
503 // Section Header Table
504 const coff_section SectionTable[NumberOfSections] = {
505 {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'},
506 u32(0),
507 u32(0),
508 u32(0),
509 u32(0),
510 u32(0),
511 u32(0),
512 u16(0),
513 u16(0),
514 u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}};
515 append(Buffer, SectionTable);
516
517 // Symbol Table
518 coff_symbol16 SymbolTable[NumberOfSymbols] = {
519 {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},
520 u32(0),
521 u16(0xFFFF),
522 u16(0),
523 IMAGE_SYM_CLASS_STATIC,
524 0},
525 {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}},
526 u32(0),
527 u16(0xFFFF),
528 u16(0),
529 IMAGE_SYM_CLASS_STATIC,
530 0},
531 {{{0, 0, 0, 0, 0, 0, 0, 0}},
532 u32(0),
533 u16(0),
534 u16(0),
535 IMAGE_SYM_CLASS_EXTERNAL,
536 0},
537 {{{0, 0, 0, 0, 0, 0, 0, 0}},
538 u32(0),
539 u16(0),
540 u16(0),
541 IMAGE_SYM_CLASS_WEAK_EXTERNAL,
542 1},
543 {{{2, 0, 0, 0, 3, 0, 0, 0}}, u32(0), u16(0), u16(0), uint8_t(0), 0},
544 };
545 SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t);
546
547 //__imp_ String Table
Martin Storsjo4a5764e2017-07-31 11:18:41 +0000548 StringRef Prefix = Imp ? "__imp_" : "";
549 SymbolTable[3].Name.Offset.Offset =
550 sizeof(uint32_t) + Sym.size() + Prefix.size() + 1;
Martell Malone1079ef82017-07-18 21:26:38 +0000551 append(Buffer, SymbolTable);
Martin Storsjo4a5764e2017-07-31 11:18:41 +0000552 writeStringTable(Buffer, {(Prefix + Sym).str(),
553 (Prefix + Weak).str()});
Martell Malone1079ef82017-07-18 21:26:38 +0000554
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