1 //===- COFFImportFile.cpp - COFF short import file implementation ---------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines the writeImportLibrary function.
12 //===----------------------------------------------------------------------===//
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"
28 using namespace llvm::COFF;
29 using namespace llvm::object;
35 static bool is32bit(MachineTypes Machine) {
38 llvm_unreachable("unsupported machine");
39 case IMAGE_FILE_MACHINE_AMD64:
41 case IMAGE_FILE_MACHINE_ARMNT:
42 case IMAGE_FILE_MACHINE_I386:
47 static uint16_t getImgRelRelocation(MachineTypes Machine) {
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;
60 template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {
62 B.resize(S + sizeof(T));
63 memcpy(&B[S], &Data, sizeof(T));
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.
74 size_t Pos = B.size();
75 size_t Offset = B.size();
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);
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;
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);
92 static ImportNameType getNameType(StringRef Sym, StringRef ExtName,
93 MachineTypes Machine) {
95 return IMPORT_NAME_UNDECORATE;
96 if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.startswith("_"))
97 return IMPORT_NAME_NOPREFIX;
101 static Expected<std::string> replace(StringRef S, StringRef From,
103 size_t Pos = S.find(From);
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);
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);
118 return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
121 static const std::string NullImportDescriptorSymbolName =
122 "__NULL_IMPORT_DESCRIPTOR";
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 ImportName;
136 std::string ImportDescriptorSymbolName;
137 std::string NullThunkSymbolName;
140 ObjectFactory(StringRef S, MachineTypes M)
141 : Machine(M), ImportName(S), Library(S.drop_back(4)),
142 ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()),
143 NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {}
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);
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);
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);
161 // Create a short import file which is described in PE/COFF spec 7. Import
163 NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
164 ImportType Type, ImportNameType NameType);
166 // Create a weak external file which is described in PE/COFF Aux Format 3.
167 NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp);
172 ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
173 const uint32_t NumberOfSections = 2;
174 const uint32_t NumberOfSymbols = 7;
175 const uint32_t NumberOfRelocations = 3;
178 coff_file_header Header{
180 u16(NumberOfSections),
182 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
184 sizeof(coff_import_directory_table_entry) +
185 NumberOfRelocations * sizeof(coff_relocation) +
187 (ImportName.size() + 1)),
188 u32(NumberOfSymbols),
190 u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : 0),
192 append(Buffer, Header);
194 // Section Header Table
195 const coff_section SectionTable[NumberOfSections] = {
196 {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
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)),
204 u16(NumberOfRelocations),
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'},
211 u32(ImportName.size() + 1),
212 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
213 sizeof(coff_import_directory_table_entry) +
214 NumberOfRelocations * sizeof(coff_relocation)),
219 u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
220 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
222 append(Buffer, SectionTable);
225 const coff_import_directory_table_entry ImportDescriptor{
226 u32(0), u32(0), u32(0), u32(0), u32(0),
228 append(Buffer, ImportDescriptor);
230 const coff_relocation RelocationTable[NumberOfRelocations] = {
231 {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
232 u16(getImgRelRelocation(Machine))},
233 {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
234 u32(3), u16(getImgRelRelocation(Machine))},
235 {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
236 u32(4), u16(getImgRelRelocation(Machine))},
238 append(Buffer, RelocationTable);
241 auto S = Buffer.size();
242 Buffer.resize(S + ImportName.size() + 1);
243 memcpy(&Buffer[S], ImportName.data(), ImportName.size());
244 Buffer[S + ImportName.size()] = '\0';
247 coff_symbol16 SymbolTable[NumberOfSymbols] = {
248 {{{0, 0, 0, 0, 0, 0, 0, 0}},
252 IMAGE_SYM_CLASS_EXTERNAL,
254 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
258 IMAGE_SYM_CLASS_SECTION,
260 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
264 IMAGE_SYM_CLASS_STATIC,
266 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
270 IMAGE_SYM_CLASS_SECTION,
272 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
276 IMAGE_SYM_CLASS_SECTION,
278 {{{0, 0, 0, 0, 0, 0, 0, 0}},
282 IMAGE_SYM_CLASS_EXTERNAL,
284 {{{0, 0, 0, 0, 0, 0, 0, 0}},
288 IMAGE_SYM_CLASS_EXTERNAL,
291 // 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 =
295 SymbolTable[5].Name.Offset.Offset =
296 sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
297 SymbolTable[6].Name.Offset.Offset =
298 sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
299 NullImportDescriptorSymbolName.length() + 1;
300 append(Buffer, SymbolTable);
303 writeStringTable(Buffer,
304 {ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
305 NullThunkSymbolName});
307 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
308 return {MemoryBufferRef(F, ImportName)};
312 ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
313 const uint32_t NumberOfSections = 1;
314 const uint32_t NumberOfSymbols = 1;
317 coff_file_header Header{
319 u16(NumberOfSections),
321 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
323 sizeof(coff_import_directory_table_entry)),
324 u32(NumberOfSymbols),
326 u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : 0),
328 append(Buffer, Header);
330 // Section Header Table
331 const coff_section SectionTable[NumberOfSections] = {
332 {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
335 u32(sizeof(coff_import_directory_table_entry)),
336 u32(sizeof(coff_file_header) +
337 (NumberOfSections * sizeof(coff_section))),
342 u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
343 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
345 append(Buffer, SectionTable);
348 const coff_import_directory_table_entry ImportDescriptor{
349 u32(0), u32(0), u32(0), u32(0), u32(0),
351 append(Buffer, ImportDescriptor);
354 coff_symbol16 SymbolTable[NumberOfSymbols] = {
355 {{{0, 0, 0, 0, 0, 0, 0, 0}},
359 IMAGE_SYM_CLASS_EXTERNAL,
362 SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
363 append(Buffer, SymbolTable);
366 writeStringTable(Buffer, {NullImportDescriptorSymbolName});
368 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
369 return {MemoryBufferRef(F, ImportName)};
372 NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
373 const uint32_t NumberOfSections = 2;
374 const uint32_t NumberOfSymbols = 1;
375 uint32_t VASize = is32bit(Machine) ? 4 : 8;
378 coff_file_header Header{
380 u16(NumberOfSections),
382 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
387 u32(NumberOfSymbols),
389 u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : 0),
391 append(Buffer, Header);
393 // Section Header Table
394 const coff_section SectionTable[NumberOfSections] = {
395 {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
399 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
404 u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
405 : IMAGE_SCN_ALIGN_8BYTES) |
406 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
407 IMAGE_SCN_MEM_WRITE)},
408 {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
412 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
418 u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
419 : IMAGE_SCN_ALIGN_8BYTES) |
420 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
421 IMAGE_SCN_MEM_WRITE)},
423 append(Buffer, SectionTable);
426 append(Buffer, u32(0));
427 if (!is32bit(Machine))
428 append(Buffer, u32(0));
431 append(Buffer, u32(0));
432 if (!is32bit(Machine))
433 append(Buffer, u32(0));
436 coff_symbol16 SymbolTable[NumberOfSymbols] = {
437 {{{0, 0, 0, 0, 0, 0, 0, 0}},
441 IMAGE_SYM_CLASS_EXTERNAL,
444 SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
445 append(Buffer, SymbolTable);
448 writeStringTable(Buffer, {NullThunkSymbolName});
450 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
451 return {MemoryBufferRef{F, ImportName}};
454 NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
456 ImportType ImportType,
457 ImportNameType NameType) {
458 size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs
459 size_t Size = sizeof(coff_import_header) + ImpSize;
460 char *Buf = Alloc.Allocate<char>(Size);
461 memset(Buf, 0, Size);
464 // Write short import library.
465 auto *Imp = reinterpret_cast<coff_import_header *>(P);
468 Imp->Machine = Machine;
469 Imp->SizeOfData = ImpSize;
471 Imp->OrdinalHint = Ordinal;
472 Imp->TypeInfo = (NameType << 2) | ImportType;
474 // Write symbol name and DLL name.
475 memcpy(P, Sym.data(), Sym.size());
477 memcpy(P, ImportName.data(), ImportName.size());
479 return {MemoryBufferRef(StringRef(Buf, Size), ImportName)};
482 NewArchiveMember 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;
489 coff_file_header Header{
491 u16(NumberOfSections),
493 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))),
494 u32(NumberOfSymbols),
498 append(Buffer, Header);
500 // Section Header Table
501 const coff_section SectionTable[NumberOfSections] = {
502 {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'},
511 u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}};
512 append(Buffer, SectionTable);
515 coff_symbol16 SymbolTable[NumberOfSymbols] = {
516 {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},
520 IMAGE_SYM_CLASS_STATIC,
522 {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}},
526 IMAGE_SYM_CLASS_STATIC,
528 {{{0, 0, 0, 0, 0, 0, 0, 0}},
532 IMAGE_SYM_CLASS_EXTERNAL,
534 {{{0, 0, 0, 0, 0, 0, 0, 0}},
538 IMAGE_SYM_CLASS_WEAK_EXTERNAL,
540 {{{2, 0, 0, 0, 3, 0, 0, 0}}, u32(0), u16(0), u16(0), uint8_t(0), 0},
542 SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t);
544 //__imp_ String Table
545 StringRef Prefix = Imp ? "__imp_" : "";
546 SymbolTable[3].Name.Offset.Offset =
547 sizeof(uint32_t) + Sym.size() + Prefix.size() + 1;
548 append(Buffer, SymbolTable);
549 writeStringTable(Buffer, {(Prefix + Sym).str(),
550 (Prefix + Weak).str()});
552 // Copied here so we can still use writeStringTable
553 char *Buf = Alloc.Allocate<char>(Buffer.size());
554 memcpy(Buf, Buffer.data(), Buffer.size());
555 return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)};
558 std::error_code writeImportLibrary(StringRef ImportName, StringRef Path,
559 ArrayRef<COFFShortExport> Exports,
560 MachineTypes Machine, bool MakeWeakAliases) {
562 std::vector<NewArchiveMember> Members;
563 ObjectFactory OF(llvm::sys::path::filename(ImportName), Machine);
565 std::vector<uint8_t> ImportDescriptor;
566 Members.push_back(OF.createImportDescriptor(ImportDescriptor));
568 std::vector<uint8_t> NullImportDescriptor;
569 Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));
571 std::vector<uint8_t> NullThunk;
572 Members.push_back(OF.createNullThunk(NullThunk));
574 for (COFFShortExport E : Exports) {
578 if (E.isWeak() && MakeWeakAliases) {
579 Members.push_back(OF.createWeakExternal(E.Name, E.ExtName, false));
580 Members.push_back(OF.createWeakExternal(E.Name, E.ExtName, true));
584 ImportType ImportType = IMPORT_CODE;
586 ImportType = IMPORT_DATA;
588 ImportType = IMPORT_CONST;
590 StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName;
591 ImportNameType NameType = getNameType(SymbolName, E.Name, Machine);
592 Expected<std::string> Name = E.ExtName.empty()
594 : replace(SymbolName, E.Name, E.ExtName);
597 return errorToErrorCode(Name.takeError());
601 OF.createShortImport(*Name, E.Ordinal, ImportType, NameType));
604 std::pair<StringRef, std::error_code> Result =
605 writeArchive(Path, Members, /*WriteSymtab*/ true, object::Archive::K_GNU,
606 /*Deterministic*/ true, /*Thin*/ false);
608 return Result.second;
611 } // namespace object