]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/Object/COFFImportFile.cpp
Merge llvm, clang, lld, lldb, compiler-rt and libc++ r303571, and update
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / Object / COFFImportFile.cpp
1 //===- COFFImportFile.cpp - COFF short import file implementation ---------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines the writeImportLibrary function.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "llvm/Object/COFFImportFile.h"
15 #include "llvm/ADT/ArrayRef.h"
16 #include "llvm/Object/Archive.h"
17 #include "llvm/Object/ArchiveWriter.h"
18 #include "llvm/Object/COFF.h"
19 #include "llvm/Support/Error.h"
20 #include "llvm/Support/Path.h"
21
22 #include <cstdint>
23 #include <map>
24 #include <set>
25 #include <string>
26 #include <vector>
27
28 using namespace llvm::COFF;
29 using namespace llvm::object;
30 using namespace llvm;
31
32 namespace llvm {
33 namespace object {
34
35 static bool is32bit(MachineTypes Machine) {
36   switch (Machine) {
37   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
47 static uint16_t getImgRelRelocation(MachineTypes Machine) {
48   switch (Machine) {
49   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
60 template <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
66 static 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
74   size_t Pos = B.size();
75   size_t Offset = B.size();
76
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);
89   support::endian::write32le(&B[Offset], Length);
90 }
91
92 static ImportNameType getNameType(StringRef Sym, StringRef ExtName,
93                                   MachineTypes Machine) {
94   if (Sym != ExtName)
95     return IMPORT_NAME_UNDECORATE;
96   if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.startswith("_"))
97     return IMPORT_NAME_NOPREFIX;
98   return IMPORT_NAME;
99 }
100
101 static Expected<std::string> replace(StringRef S, StringRef From,
102                                      StringRef To) {
103   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) {
113     return make_error<StringError>(
114       StringRef(Twine(S + ": replacing '" + From +
115         "' with '" + To + "' failed").str()), object_error::parse_failed);
116   }
117
118   return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
119 }
120
121 static const std::string NullImportDescriptorSymbolName =
122     "__NULL_IMPORT_DESCRIPTOR";
123
124 namespace {
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.
129 class ObjectFactory {
130   using u16 = support::ulittle16_t;
131   using u32 = support::ulittle32_t;
132   MachineTypes Machine;
133   BumpPtrAllocator Alloc;
134   StringRef DLLName;
135   StringRef Library;
136   std::string ImportDescriptorSymbolName;
137   std::string NullThunkSymbolName;
138
139 public:
140   ObjectFactory(StringRef S, MachineTypes M)
141       : Machine(M), DLLName(S), Library(S.drop_back(4)),
142         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);
165 };
166 } // namespace
167
168 NewArchiveMember
169 ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
170   static const uint32_t NumberOfSections = 2;
171   static const uint32_t NumberOfSymbols = 7;
172   static const uint32_t NumberOfRelocations = 3;
173
174   // COFF Header
175   coff_file_header Header{
176       u16(Machine),
177       u16(NumberOfSections),
178       u32(0),
179       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
180           // .idata$2
181           sizeof(coff_import_directory_table_entry) +
182           NumberOfRelocations * sizeof(coff_relocation) +
183           // .idata$4
184           (DLLName.size() + 1)),
185       u32(NumberOfSymbols),
186       u16(0),
187       u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : 0),
188   };
189   append(Buffer, Header);
190
191   // Section Header Table
192   static const coff_section SectionTable[NumberOfSections] = {
193       {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
194        u32(0),
195        u32(0),
196        u32(sizeof(coff_import_directory_table_entry)),
197        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
198        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
199            sizeof(coff_import_directory_table_entry)),
200        u32(0),
201        u16(NumberOfRelocations),
202        u16(0),
203        u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
204            IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
205       {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
206        u32(0),
207        u32(0),
208        u32(DLLName.size() + 1),
209        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
210            sizeof(coff_import_directory_table_entry) +
211            NumberOfRelocations * sizeof(coff_relocation)),
212        u32(0),
213        u32(0),
214        u16(0),
215        u16(0),
216        u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
217            IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
218   };
219   append(Buffer, SectionTable);
220
221   // .idata$2
222   static const coff_import_directory_table_entry ImportDescriptor{
223       u32(0), u32(0), u32(0), u32(0), u32(0),
224   };
225   append(Buffer, ImportDescriptor);
226
227   static const coff_relocation RelocationTable[NumberOfRelocations] = {
228       {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
229        u16(getImgRelRelocation(Machine))},
230       {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
231        u32(3), u16(getImgRelRelocation(Machine))},
232       {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
233        u32(4), u16(getImgRelRelocation(Machine))},
234   };
235   append(Buffer, RelocationTable);
236
237   // .idata$6
238   auto S = Buffer.size();
239   Buffer.resize(S + DLLName.size() + 1);
240   memcpy(&Buffer[S], DLLName.data(), DLLName.size());
241   Buffer[S + DLLName.size()] = '\0';
242
243   // Symbol Table
244   coff_symbol16 SymbolTable[NumberOfSymbols] = {
245       {{{0, 0, 0, 0, 0, 0, 0, 0}},
246        u32(0),
247        u16(1),
248        u16(0),
249        IMAGE_SYM_CLASS_EXTERNAL,
250        0},
251       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
252        u32(0),
253        u16(1),
254        u16(0),
255        IMAGE_SYM_CLASS_SECTION,
256        0},
257       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
258        u32(0),
259        u16(2),
260        u16(0),
261        IMAGE_SYM_CLASS_STATIC,
262        0},
263       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
264        u32(0),
265        u16(0),
266        u16(0),
267        IMAGE_SYM_CLASS_SECTION,
268        0},
269       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
270        u32(0),
271        u16(0),
272        u16(0),
273        IMAGE_SYM_CLASS_SECTION,
274        0},
275       {{{0, 0, 0, 0, 0, 0, 0, 0}},
276        u32(0),
277        u16(0),
278        u16(0),
279        IMAGE_SYM_CLASS_EXTERNAL,
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   };
288   reinterpret_cast<StringTableOffset &>(SymbolTable[0].Name).Offset =
289       sizeof(uint32_t);
290   reinterpret_cast<StringTableOffset &>(SymbolTable[5].Name).Offset =
291       sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
292   reinterpret_cast<StringTableOffset &>(SymbolTable[6].Name).Offset =
293       sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
294       NullImportDescriptorSymbolName.length() + 1;
295   append(Buffer, SymbolTable);
296
297   // String Table
298   writeStringTable(Buffer,
299                    {ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
300                     NullThunkSymbolName});
301
302   StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
303   return {MemoryBufferRef(F, DLLName)};
304 }
305
306 NewArchiveMember
307 ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
308   static const uint32_t NumberOfSections = 1;
309   static const uint32_t NumberOfSymbols = 1;
310
311   // COFF Header
312   coff_file_header Header{
313       u16(Machine),
314       u16(NumberOfSections),
315       u32(0),
316       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
317           // .idata$3
318           sizeof(coff_import_directory_table_entry)),
319       u32(NumberOfSymbols),
320       u16(0),
321       u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : 0),
322   };
323   append(Buffer, Header);
324
325   // Section Header Table
326   static const coff_section SectionTable[NumberOfSections] = {
327       {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
328        u32(0),
329        u32(0),
330        u32(sizeof(coff_import_directory_table_entry)),
331        u32(sizeof(coff_file_header) +
332            (NumberOfSections * sizeof(coff_section))),
333        u32(0),
334        u32(0),
335        u16(0),
336        u16(0),
337        u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
338            IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
339   };
340   append(Buffer, SectionTable);
341
342   // .idata$3
343   static const coff_import_directory_table_entry ImportDescriptor{
344       u32(0), u32(0), u32(0), u32(0), u32(0),
345   };
346   append(Buffer, ImportDescriptor);
347
348   // Symbol Table
349   coff_symbol16 SymbolTable[NumberOfSymbols] = {
350       {{{0, 0, 0, 0, 0, 0, 0, 0}},
351        u32(0),
352        u16(1),
353        u16(0),
354        IMAGE_SYM_CLASS_EXTERNAL,
355        0},
356   };
357   reinterpret_cast<StringTableOffset &>(SymbolTable[0].Name).Offset =
358       sizeof(uint32_t);
359   append(Buffer, SymbolTable);
360
361   // String Table
362   writeStringTable(Buffer, {NullImportDescriptorSymbolName});
363
364   StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
365   return {MemoryBufferRef(F, DLLName)};
366 }
367
368 NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
369   static const uint32_t NumberOfSections = 2;
370   static const uint32_t NumberOfSymbols = 1;
371   uint32_t VASize = is32bit(Machine) ? 4 : 8;
372
373   // COFF Header
374   coff_file_header Header{
375       u16(Machine),
376       u16(NumberOfSections),
377       u32(0),
378       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
379           // .idata$5
380           VASize +
381           // .idata$4
382           VASize),
383       u32(NumberOfSymbols),
384       u16(0),
385       u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : 0),
386   };
387   append(Buffer, Header);
388
389   // Section Header Table
390   static const coff_section SectionTable[NumberOfSections] = {
391       {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
392        u32(0),
393        u32(0),
394        u32(VASize),
395        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
396        u32(0),
397        u32(0),
398        u16(0),
399        u16(0),
400        u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
401                              : IMAGE_SCN_ALIGN_8BYTES) |
402            IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
403            IMAGE_SCN_MEM_WRITE)},
404       {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
405        u32(0),
406        u32(0),
407        u32(VASize),
408        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
409            VASize),
410        u32(0),
411        u32(0),
412        u16(0),
413        u16(0),
414        u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
415                              : IMAGE_SCN_ALIGN_8BYTES) |
416            IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
417            IMAGE_SCN_MEM_WRITE)},
418   };
419   append(Buffer, SectionTable);
420
421   // .idata$5, ILT
422   append(Buffer, u32(0));
423   if (!is32bit(Machine))
424     append(Buffer, u32(0));
425
426   // .idata$4, IAT
427   append(Buffer, u32(0));
428   if (!is32bit(Machine))
429     append(Buffer, u32(0));
430
431   // Symbol Table
432   coff_symbol16 SymbolTable[NumberOfSymbols] = {
433       {{{0, 0, 0, 0, 0, 0, 0, 0}},
434        u32(0),
435        u16(1),
436        u16(0),
437        IMAGE_SYM_CLASS_EXTERNAL,
438        0},
439   };
440   reinterpret_cast<StringTableOffset &>(SymbolTable[0].Name).Offset =
441       sizeof(uint32_t);
442   append(Buffer, SymbolTable);
443
444   // String Table
445   writeStringTable(Buffer, {NullThunkSymbolName});
446
447   StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
448   return {MemoryBufferRef{F, DLLName}};
449 }
450
451 NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
452                                                   uint16_t Ordinal,
453                                                   ImportType ImportType,
454                                                   ImportNameType NameType) {
455   size_t ImpSize = DLLName.size() + Sym.size() + 2; // +2 for NULs
456   size_t Size = sizeof(coff_import_header) + ImpSize;
457   char *Buf = Alloc.Allocate<char>(Size);
458   memset(Buf, 0, Size);
459   char *P = Buf;
460
461   // Write short import library.
462   auto *Imp = reinterpret_cast<coff_import_header *>(P);
463   P += sizeof(*Imp);
464   Imp->Sig2 = 0xFFFF;
465   Imp->Machine = Machine;
466   Imp->SizeOfData = ImpSize;
467   if (Ordinal > 0)
468     Imp->OrdinalHint = Ordinal;
469   Imp->TypeInfo = (NameType << 2) | ImportType;
470
471   // Write symbol name and DLL name.
472   memcpy(P, Sym.data(), Sym.size());
473   P += Sym.size() + 1;
474   memcpy(P, DLLName.data(), DLLName.size());
475
476   return {MemoryBufferRef(StringRef(Buf, Size), DLLName)};
477 }
478
479 std::error_code writeImportLibrary(StringRef DLLName, StringRef Path,
480                                    ArrayRef<COFFShortExport> Exports,
481                                    MachineTypes Machine) {
482
483   std::vector<NewArchiveMember> Members;
484   ObjectFactory OF(llvm::sys::path::filename(DLLName), Machine);
485
486   std::vector<uint8_t> ImportDescriptor;
487   Members.push_back(OF.createImportDescriptor(ImportDescriptor));
488
489   std::vector<uint8_t> NullImportDescriptor;
490   Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));
491
492   std::vector<uint8_t> NullThunk;
493   Members.push_back(OF.createNullThunk(NullThunk));
494
495   for (COFFShortExport E : Exports) {
496     if (E.Private)
497       continue;
498
499     ImportType ImportType = IMPORT_CODE;
500     if (E.Data)
501       ImportType = IMPORT_DATA;
502     if (E.Constant)
503       ImportType = IMPORT_CONST;
504
505     StringRef SymbolName = E.isWeak() ? E.ExtName : E.Name;
506     ImportNameType NameType = getNameType(SymbolName, E.Name, Machine);
507     Expected<std::string> Name = E.ExtName.empty()
508                                      ? SymbolName
509                                      : replace(SymbolName, E.Name, E.ExtName);
510
511     if (!Name) {
512       return errorToErrorCode(Name.takeError());
513     }
514
515     Members.push_back(
516         OF.createShortImport(*Name, E.Ordinal, ImportType, NameType));
517   }
518
519   std::pair<StringRef, std::error_code> Result =
520       writeArchive(Path, Members, /*WriteSymtab*/ true, object::Archive::K_GNU,
521                    /*Deterministic*/ true, /*Thin*/ false);
522
523   return Result.second;
524 }
525
526 } // namespace object
527 } // namespace llvm