1146eb7a6SReid Kleckner //===- COFFImportFile.cpp - COFF short import file implementation ---------===//
2146eb7a6SReid Kleckner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6146eb7a6SReid Kleckner //
7146eb7a6SReid Kleckner //===----------------------------------------------------------------------===//
8146eb7a6SReid Kleckner //
9146eb7a6SReid Kleckner // This file defines the writeImportLibrary function.
10146eb7a6SReid Kleckner //
11146eb7a6SReid Kleckner //===----------------------------------------------------------------------===//
12146eb7a6SReid Kleckner
13146eb7a6SReid Kleckner #include "llvm/Object/COFFImportFile.h"
14146eb7a6SReid Kleckner #include "llvm/ADT/ArrayRef.h"
15*e72c195fSserge-sans-paille #include "llvm/ADT/Twine.h"
16146eb7a6SReid Kleckner #include "llvm/Object/Archive.h"
17146eb7a6SReid Kleckner #include "llvm/Object/ArchiveWriter.h"
18146eb7a6SReid Kleckner #include "llvm/Object/COFF.h"
19*e72c195fSserge-sans-paille #include "llvm/Support/Allocator.h"
20*e72c195fSserge-sans-paille #include "llvm/Support/Endian.h"
21146eb7a6SReid Kleckner #include "llvm/Support/Error.h"
22*e72c195fSserge-sans-paille #include "llvm/Support/ErrorHandling.h"
23146eb7a6SReid Kleckner #include "llvm/Support/Path.h"
24146eb7a6SReid Kleckner
25146eb7a6SReid Kleckner #include <cstdint>
26146eb7a6SReid Kleckner #include <string>
27146eb7a6SReid Kleckner #include <vector>
28146eb7a6SReid Kleckner
29146eb7a6SReid Kleckner using namespace llvm::COFF;
30146eb7a6SReid Kleckner using namespace llvm::object;
31146eb7a6SReid Kleckner using namespace llvm;
32146eb7a6SReid Kleckner
33146eb7a6SReid Kleckner namespace llvm {
34146eb7a6SReid Kleckner namespace object {
35146eb7a6SReid Kleckner
is32bit(MachineTypes Machine)36146eb7a6SReid Kleckner static bool is32bit(MachineTypes Machine) {
37146eb7a6SReid Kleckner switch (Machine) {
38146eb7a6SReid Kleckner default:
39146eb7a6SReid Kleckner llvm_unreachable("unsupported machine");
40b9ff4191SMartin Storsjo case IMAGE_FILE_MACHINE_ARM64:
41146eb7a6SReid Kleckner case IMAGE_FILE_MACHINE_AMD64:
42146eb7a6SReid Kleckner return false;
43146eb7a6SReid Kleckner case IMAGE_FILE_MACHINE_ARMNT:
44146eb7a6SReid Kleckner case IMAGE_FILE_MACHINE_I386:
45146eb7a6SReid Kleckner return true;
46146eb7a6SReid Kleckner }
47146eb7a6SReid Kleckner }
48146eb7a6SReid Kleckner
getImgRelRelocation(MachineTypes Machine)49146eb7a6SReid Kleckner static uint16_t getImgRelRelocation(MachineTypes Machine) {
50146eb7a6SReid Kleckner switch (Machine) {
51146eb7a6SReid Kleckner default:
52146eb7a6SReid Kleckner llvm_unreachable("unsupported machine");
53146eb7a6SReid Kleckner case IMAGE_FILE_MACHINE_AMD64:
54146eb7a6SReid Kleckner return IMAGE_REL_AMD64_ADDR32NB;
55146eb7a6SReid Kleckner case IMAGE_FILE_MACHINE_ARMNT:
56146eb7a6SReid Kleckner return IMAGE_REL_ARM_ADDR32NB;
57b9ff4191SMartin Storsjo case IMAGE_FILE_MACHINE_ARM64:
58b9ff4191SMartin Storsjo return IMAGE_REL_ARM64_ADDR32NB;
59146eb7a6SReid Kleckner case IMAGE_FILE_MACHINE_I386:
60146eb7a6SReid Kleckner return IMAGE_REL_I386_DIR32NB;
61146eb7a6SReid Kleckner }
62146eb7a6SReid Kleckner }
63146eb7a6SReid Kleckner
append(std::vector<uint8_t> & B,const T & Data)64146eb7a6SReid Kleckner template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {
65146eb7a6SReid Kleckner size_t S = B.size();
66146eb7a6SReid Kleckner B.resize(S + sizeof(T));
67146eb7a6SReid Kleckner memcpy(&B[S], &Data, sizeof(T));
68146eb7a6SReid Kleckner }
69146eb7a6SReid Kleckner
writeStringTable(std::vector<uint8_t> & B,ArrayRef<const std::string> Strings)70146eb7a6SReid Kleckner static void writeStringTable(std::vector<uint8_t> &B,
71146eb7a6SReid Kleckner ArrayRef<const std::string> Strings) {
72146eb7a6SReid Kleckner // The COFF string table consists of a 4-byte value which is the size of the
73146eb7a6SReid Kleckner // table, including the length field itself. This value is followed by the
74146eb7a6SReid Kleckner // string content itself, which is an array of null-terminated C-style
75146eb7a6SReid Kleckner // strings. The termination is important as they are referenced to by offset
76146eb7a6SReid Kleckner // by the symbol entity in the file format.
77146eb7a6SReid Kleckner
78146eb7a6SReid Kleckner size_t Pos = B.size();
79146eb7a6SReid Kleckner size_t Offset = B.size();
80146eb7a6SReid Kleckner
81146eb7a6SReid Kleckner // Skip over the length field, we will fill it in later as we will have
82146eb7a6SReid Kleckner // computed the length while emitting the string content itself.
83146eb7a6SReid Kleckner Pos += sizeof(uint32_t);
84146eb7a6SReid Kleckner
85146eb7a6SReid Kleckner for (const auto &S : Strings) {
86146eb7a6SReid Kleckner B.resize(Pos + S.length() + 1);
87146eb7a6SReid Kleckner strcpy(reinterpret_cast<char *>(&B[Pos]), S.c_str());
88146eb7a6SReid Kleckner Pos += S.length() + 1;
89146eb7a6SReid Kleckner }
90146eb7a6SReid Kleckner
91146eb7a6SReid Kleckner // Backfill the length of the table now that it has been computed.
92146eb7a6SReid Kleckner support::ulittle32_t Length(B.size() - Offset);
93146eb7a6SReid Kleckner support::endian::write32le(&B[Offset], Length);
94146eb7a6SReid Kleckner }
95146eb7a6SReid Kleckner
getNameType(StringRef Sym,StringRef ExtName,MachineTypes Machine,bool MinGW)96146eb7a6SReid Kleckner static ImportNameType getNameType(StringRef Sym, StringRef ExtName,
97f641d0d4SMartin Storsjo MachineTypes Machine, bool MinGW) {
98f641d0d4SMartin Storsjo // A decorated stdcall function in MSVC is exported with the
99f641d0d4SMartin Storsjo // type IMPORT_NAME, and the exported function name includes the
100f641d0d4SMartin Storsjo // the leading underscore. In MinGW on the other hand, a decorated
101f641d0d4SMartin Storsjo // stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX).
102f641d0d4SMartin Storsjo // See the comment in isDecorated in COFFModuleDefinition.cpp for more
103f641d0d4SMartin Storsjo // details.
104f641d0d4SMartin Storsjo if (ExtName.startswith("_") && ExtName.contains('@') && !MinGW)
105f641d0d4SMartin Storsjo return IMPORT_NAME;
106146eb7a6SReid Kleckner if (Sym != ExtName)
107146eb7a6SReid Kleckner return IMPORT_NAME_UNDECORATE;
108146eb7a6SReid Kleckner if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.startswith("_"))
109146eb7a6SReid Kleckner return IMPORT_NAME_NOPREFIX;
110146eb7a6SReid Kleckner return IMPORT_NAME;
111146eb7a6SReid Kleckner }
112146eb7a6SReid Kleckner
replace(StringRef S,StringRef From,StringRef To)113146eb7a6SReid Kleckner static Expected<std::string> replace(StringRef S, StringRef From,
114146eb7a6SReid Kleckner StringRef To) {
115146eb7a6SReid Kleckner size_t Pos = S.find(From);
116146eb7a6SReid Kleckner
117146eb7a6SReid Kleckner // From and To may be mangled, but substrings in S may not.
118146eb7a6SReid Kleckner if (Pos == StringRef::npos && From.startswith("_") && To.startswith("_")) {
119146eb7a6SReid Kleckner From = From.substr(1);
120146eb7a6SReid Kleckner To = To.substr(1);
121146eb7a6SReid Kleckner Pos = S.find(From);
122146eb7a6SReid Kleckner }
123146eb7a6SReid Kleckner
124146eb7a6SReid Kleckner if (Pos == StringRef::npos) {
125146eb7a6SReid Kleckner return make_error<StringError>(
126146eb7a6SReid Kleckner StringRef(Twine(S + ": replacing '" + From +
127146eb7a6SReid Kleckner "' with '" + To + "' failed").str()), object_error::parse_failed);
128146eb7a6SReid Kleckner }
129146eb7a6SReid Kleckner
130146eb7a6SReid Kleckner return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
131146eb7a6SReid Kleckner }
132146eb7a6SReid Kleckner
133146eb7a6SReid Kleckner static const std::string NullImportDescriptorSymbolName =
134146eb7a6SReid Kleckner "__NULL_IMPORT_DESCRIPTOR";
135146eb7a6SReid Kleckner
136146eb7a6SReid Kleckner namespace {
137146eb7a6SReid Kleckner // This class constructs various small object files necessary to support linking
138146eb7a6SReid Kleckner // symbols imported from a DLL. The contents are pretty strictly defined and
139146eb7a6SReid Kleckner // nearly entirely static. The details of the structures files are defined in
140146eb7a6SReid Kleckner // WINNT.h and the PE/COFF specification.
141146eb7a6SReid Kleckner class ObjectFactory {
142146eb7a6SReid Kleckner using u16 = support::ulittle16_t;
143146eb7a6SReid Kleckner using u32 = support::ulittle32_t;
144146eb7a6SReid Kleckner MachineTypes Machine;
145146eb7a6SReid Kleckner BumpPtrAllocator Alloc;
1460f83a894SSaleem Abdulrasool StringRef ImportName;
147146eb7a6SReid Kleckner StringRef Library;
148146eb7a6SReid Kleckner std::string ImportDescriptorSymbolName;
149146eb7a6SReid Kleckner std::string NullThunkSymbolName;
150146eb7a6SReid Kleckner
151146eb7a6SReid Kleckner public:
ObjectFactory(StringRef S,MachineTypes M)152146eb7a6SReid Kleckner ObjectFactory(StringRef S, MachineTypes M)
1530f83a894SSaleem Abdulrasool : Machine(M), ImportName(S), Library(S.drop_back(4)),
154146eb7a6SReid Kleckner ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()),
155146eb7a6SReid Kleckner NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {}
156146eb7a6SReid Kleckner
157146eb7a6SReid Kleckner // Creates an Import Descriptor. This is a small object file which contains a
158146eb7a6SReid Kleckner // reference to the terminators and contains the library name (entry) for the
159146eb7a6SReid Kleckner // import name table. It will force the linker to construct the necessary
160146eb7a6SReid Kleckner // structure to import symbols from the DLL.
161146eb7a6SReid Kleckner NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);
162146eb7a6SReid Kleckner
163146eb7a6SReid Kleckner // Creates a NULL import descriptor. This is a small object file whcih
164146eb7a6SReid Kleckner // contains a NULL import descriptor. It is used to terminate the imports
165146eb7a6SReid Kleckner // from a specific DLL.
166146eb7a6SReid Kleckner NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);
167146eb7a6SReid Kleckner
168146eb7a6SReid Kleckner // Create a NULL Thunk Entry. This is a small object file which contains a
169146eb7a6SReid Kleckner // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It
170146eb7a6SReid Kleckner // is used to terminate the IAT and ILT.
171146eb7a6SReid Kleckner NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);
172146eb7a6SReid Kleckner
173146eb7a6SReid Kleckner // Create a short import file which is described in PE/COFF spec 7. Import
174146eb7a6SReid Kleckner // Library Format.
175146eb7a6SReid Kleckner NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
176146eb7a6SReid Kleckner ImportType Type, ImportNameType NameType);
1771079ef8dSMartell Malone
1781079ef8dSMartell Malone // Create a weak external file which is described in PE/COFF Aux Format 3.
1791079ef8dSMartell Malone NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp);
180146eb7a6SReid Kleckner };
181146eb7a6SReid Kleckner } // namespace
182146eb7a6SReid Kleckner
183146eb7a6SReid Kleckner NewArchiveMember
createImportDescriptor(std::vector<uint8_t> & Buffer)184146eb7a6SReid Kleckner ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
1851079ef8dSMartell Malone const uint32_t NumberOfSections = 2;
1861079ef8dSMartell Malone const uint32_t NumberOfSymbols = 7;
1871079ef8dSMartell Malone const uint32_t NumberOfRelocations = 3;
188146eb7a6SReid Kleckner
189146eb7a6SReid Kleckner // COFF Header
190146eb7a6SReid Kleckner coff_file_header Header{
191146eb7a6SReid Kleckner u16(Machine),
192146eb7a6SReid Kleckner u16(NumberOfSections),
193146eb7a6SReid Kleckner u32(0),
194146eb7a6SReid Kleckner u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
195146eb7a6SReid Kleckner // .idata$2
196146eb7a6SReid Kleckner sizeof(coff_import_directory_table_entry) +
197146eb7a6SReid Kleckner NumberOfRelocations * sizeof(coff_relocation) +
198146eb7a6SReid Kleckner // .idata$4
1990f83a894SSaleem Abdulrasool (ImportName.size() + 1)),
200146eb7a6SReid Kleckner u32(NumberOfSymbols),
201146eb7a6SReid Kleckner u16(0),
2026532b3b9SGalina Kistanova u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
203146eb7a6SReid Kleckner };
204146eb7a6SReid Kleckner append(Buffer, Header);
205146eb7a6SReid Kleckner
206146eb7a6SReid Kleckner // Section Header Table
2071079ef8dSMartell Malone const coff_section SectionTable[NumberOfSections] = {
208146eb7a6SReid Kleckner {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
209146eb7a6SReid Kleckner u32(0),
210146eb7a6SReid Kleckner u32(0),
211146eb7a6SReid Kleckner u32(sizeof(coff_import_directory_table_entry)),
212146eb7a6SReid Kleckner u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
213146eb7a6SReid Kleckner u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
214146eb7a6SReid Kleckner sizeof(coff_import_directory_table_entry)),
215146eb7a6SReid Kleckner u32(0),
216146eb7a6SReid Kleckner u16(NumberOfRelocations),
217146eb7a6SReid Kleckner u16(0),
218146eb7a6SReid Kleckner u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
219146eb7a6SReid Kleckner IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
220146eb7a6SReid Kleckner {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
221146eb7a6SReid Kleckner u32(0),
222146eb7a6SReid Kleckner u32(0),
2230f83a894SSaleem Abdulrasool u32(ImportName.size() + 1),
224146eb7a6SReid Kleckner u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
225146eb7a6SReid Kleckner sizeof(coff_import_directory_table_entry) +
226146eb7a6SReid Kleckner NumberOfRelocations * sizeof(coff_relocation)),
227146eb7a6SReid Kleckner u32(0),
228146eb7a6SReid Kleckner u32(0),
229146eb7a6SReid Kleckner u16(0),
230146eb7a6SReid Kleckner u16(0),
231146eb7a6SReid Kleckner u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
232146eb7a6SReid Kleckner IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
233146eb7a6SReid Kleckner };
234146eb7a6SReid Kleckner append(Buffer, SectionTable);
235146eb7a6SReid Kleckner
236146eb7a6SReid Kleckner // .idata$2
2371079ef8dSMartell Malone const coff_import_directory_table_entry ImportDescriptor{
238146eb7a6SReid Kleckner u32(0), u32(0), u32(0), u32(0), u32(0),
239146eb7a6SReid Kleckner };
240146eb7a6SReid Kleckner append(Buffer, ImportDescriptor);
241146eb7a6SReid Kleckner
2421079ef8dSMartell Malone const coff_relocation RelocationTable[NumberOfRelocations] = {
243146eb7a6SReid Kleckner {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
244146eb7a6SReid Kleckner u16(getImgRelRelocation(Machine))},
245146eb7a6SReid Kleckner {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
246146eb7a6SReid Kleckner u32(3), u16(getImgRelRelocation(Machine))},
247146eb7a6SReid Kleckner {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
248146eb7a6SReid Kleckner u32(4), u16(getImgRelRelocation(Machine))},
249146eb7a6SReid Kleckner };
250146eb7a6SReid Kleckner append(Buffer, RelocationTable);
251146eb7a6SReid Kleckner
252146eb7a6SReid Kleckner // .idata$6
253146eb7a6SReid Kleckner auto S = Buffer.size();
2540f83a894SSaleem Abdulrasool Buffer.resize(S + ImportName.size() + 1);
2550f83a894SSaleem Abdulrasool memcpy(&Buffer[S], ImportName.data(), ImportName.size());
2560f83a894SSaleem Abdulrasool Buffer[S + ImportName.size()] = '\0';
257146eb7a6SReid Kleckner
258146eb7a6SReid Kleckner // Symbol Table
259146eb7a6SReid Kleckner coff_symbol16 SymbolTable[NumberOfSymbols] = {
260146eb7a6SReid Kleckner {{{0, 0, 0, 0, 0, 0, 0, 0}},
261146eb7a6SReid Kleckner u32(0),
262146eb7a6SReid Kleckner u16(1),
263146eb7a6SReid Kleckner u16(0),
264146eb7a6SReid Kleckner IMAGE_SYM_CLASS_EXTERNAL,
265146eb7a6SReid Kleckner 0},
266146eb7a6SReid Kleckner {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
267146eb7a6SReid Kleckner u32(0),
268146eb7a6SReid Kleckner u16(1),
269146eb7a6SReid Kleckner u16(0),
270146eb7a6SReid Kleckner IMAGE_SYM_CLASS_SECTION,
271146eb7a6SReid Kleckner 0},
272146eb7a6SReid Kleckner {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
273146eb7a6SReid Kleckner u32(0),
274146eb7a6SReid Kleckner u16(2),
275146eb7a6SReid Kleckner u16(0),
276146eb7a6SReid Kleckner IMAGE_SYM_CLASS_STATIC,
277146eb7a6SReid Kleckner 0},
278146eb7a6SReid Kleckner {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
279146eb7a6SReid Kleckner u32(0),
280146eb7a6SReid Kleckner u16(0),
281146eb7a6SReid Kleckner u16(0),
282146eb7a6SReid Kleckner IMAGE_SYM_CLASS_SECTION,
283146eb7a6SReid Kleckner 0},
284146eb7a6SReid Kleckner {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
285146eb7a6SReid Kleckner u32(0),
286146eb7a6SReid Kleckner u16(0),
287146eb7a6SReid Kleckner u16(0),
288146eb7a6SReid Kleckner IMAGE_SYM_CLASS_SECTION,
289146eb7a6SReid Kleckner 0},
290146eb7a6SReid Kleckner {{{0, 0, 0, 0, 0, 0, 0, 0}},
291146eb7a6SReid Kleckner u32(0),
292146eb7a6SReid Kleckner u16(0),
293146eb7a6SReid Kleckner u16(0),
294146eb7a6SReid Kleckner IMAGE_SYM_CLASS_EXTERNAL,
295146eb7a6SReid Kleckner 0},
296146eb7a6SReid Kleckner {{{0, 0, 0, 0, 0, 0, 0, 0}},
297146eb7a6SReid Kleckner u32(0),
298146eb7a6SReid Kleckner u16(0),
299146eb7a6SReid Kleckner u16(0),
300146eb7a6SReid Kleckner IMAGE_SYM_CLASS_EXTERNAL,
301146eb7a6SReid Kleckner 0},
302146eb7a6SReid Kleckner };
303415ec926SGalina Kistanova // TODO: Name.Offset.Offset here and in the all similar places below
304415ec926SGalina Kistanova // suggests a names refactoring. Maybe StringTableOffset.Value?
305415ec926SGalina Kistanova SymbolTable[0].Name.Offset.Offset =
306146eb7a6SReid Kleckner sizeof(uint32_t);
307415ec926SGalina Kistanova SymbolTable[5].Name.Offset.Offset =
308146eb7a6SReid Kleckner sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
309415ec926SGalina Kistanova SymbolTable[6].Name.Offset.Offset =
310146eb7a6SReid Kleckner sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
311146eb7a6SReid Kleckner NullImportDescriptorSymbolName.length() + 1;
312146eb7a6SReid Kleckner append(Buffer, SymbolTable);
313146eb7a6SReid Kleckner
314146eb7a6SReid Kleckner // String Table
315146eb7a6SReid Kleckner writeStringTable(Buffer,
316146eb7a6SReid Kleckner {ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
317146eb7a6SReid Kleckner NullThunkSymbolName});
318146eb7a6SReid Kleckner
319146eb7a6SReid Kleckner StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
3200f83a894SSaleem Abdulrasool return {MemoryBufferRef(F, ImportName)};
321146eb7a6SReid Kleckner }
322146eb7a6SReid Kleckner
323146eb7a6SReid Kleckner NewArchiveMember
createNullImportDescriptor(std::vector<uint8_t> & Buffer)324146eb7a6SReid Kleckner ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
3251079ef8dSMartell Malone const uint32_t NumberOfSections = 1;
3261079ef8dSMartell Malone const uint32_t NumberOfSymbols = 1;
327146eb7a6SReid Kleckner
328146eb7a6SReid Kleckner // COFF Header
329146eb7a6SReid Kleckner coff_file_header Header{
330146eb7a6SReid Kleckner u16(Machine),
331146eb7a6SReid Kleckner u16(NumberOfSections),
332146eb7a6SReid Kleckner u32(0),
333146eb7a6SReid Kleckner u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
334146eb7a6SReid Kleckner // .idata$3
335146eb7a6SReid Kleckner sizeof(coff_import_directory_table_entry)),
336146eb7a6SReid Kleckner u32(NumberOfSymbols),
337146eb7a6SReid Kleckner u16(0),
3386532b3b9SGalina Kistanova u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
339146eb7a6SReid Kleckner };
340146eb7a6SReid Kleckner append(Buffer, Header);
341146eb7a6SReid Kleckner
342146eb7a6SReid Kleckner // Section Header Table
3431079ef8dSMartell Malone const coff_section SectionTable[NumberOfSections] = {
344146eb7a6SReid Kleckner {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
345146eb7a6SReid Kleckner u32(0),
346146eb7a6SReid Kleckner u32(0),
347146eb7a6SReid Kleckner u32(sizeof(coff_import_directory_table_entry)),
348146eb7a6SReid Kleckner u32(sizeof(coff_file_header) +
349146eb7a6SReid Kleckner (NumberOfSections * sizeof(coff_section))),
350146eb7a6SReid Kleckner u32(0),
351146eb7a6SReid Kleckner u32(0),
352146eb7a6SReid Kleckner u16(0),
353146eb7a6SReid Kleckner u16(0),
354146eb7a6SReid Kleckner u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
355146eb7a6SReid Kleckner IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
356146eb7a6SReid Kleckner };
357146eb7a6SReid Kleckner append(Buffer, SectionTable);
358146eb7a6SReid Kleckner
359146eb7a6SReid Kleckner // .idata$3
3601079ef8dSMartell Malone const coff_import_directory_table_entry ImportDescriptor{
361146eb7a6SReid Kleckner u32(0), u32(0), u32(0), u32(0), u32(0),
362146eb7a6SReid Kleckner };
363146eb7a6SReid Kleckner append(Buffer, ImportDescriptor);
364146eb7a6SReid Kleckner
365146eb7a6SReid Kleckner // Symbol Table
366146eb7a6SReid Kleckner coff_symbol16 SymbolTable[NumberOfSymbols] = {
367146eb7a6SReid Kleckner {{{0, 0, 0, 0, 0, 0, 0, 0}},
368146eb7a6SReid Kleckner u32(0),
369146eb7a6SReid Kleckner u16(1),
370146eb7a6SReid Kleckner u16(0),
371146eb7a6SReid Kleckner IMAGE_SYM_CLASS_EXTERNAL,
372146eb7a6SReid Kleckner 0},
373146eb7a6SReid Kleckner };
374415ec926SGalina Kistanova SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
375146eb7a6SReid Kleckner append(Buffer, SymbolTable);
376146eb7a6SReid Kleckner
377146eb7a6SReid Kleckner // String Table
378146eb7a6SReid Kleckner writeStringTable(Buffer, {NullImportDescriptorSymbolName});
379146eb7a6SReid Kleckner
380146eb7a6SReid Kleckner StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
3810f83a894SSaleem Abdulrasool return {MemoryBufferRef(F, ImportName)};
382146eb7a6SReid Kleckner }
383146eb7a6SReid Kleckner
createNullThunk(std::vector<uint8_t> & Buffer)384146eb7a6SReid Kleckner NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
3851079ef8dSMartell Malone const uint32_t NumberOfSections = 2;
3861079ef8dSMartell Malone const uint32_t NumberOfSymbols = 1;
387146eb7a6SReid Kleckner uint32_t VASize = is32bit(Machine) ? 4 : 8;
388146eb7a6SReid Kleckner
389146eb7a6SReid Kleckner // COFF Header
390146eb7a6SReid Kleckner coff_file_header Header{
391146eb7a6SReid Kleckner u16(Machine),
392146eb7a6SReid Kleckner u16(NumberOfSections),
393146eb7a6SReid Kleckner u32(0),
394146eb7a6SReid Kleckner u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
395146eb7a6SReid Kleckner // .idata$5
396146eb7a6SReid Kleckner VASize +
397146eb7a6SReid Kleckner // .idata$4
398146eb7a6SReid Kleckner VASize),
399146eb7a6SReid Kleckner u32(NumberOfSymbols),
400146eb7a6SReid Kleckner u16(0),
4016532b3b9SGalina Kistanova u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
402146eb7a6SReid Kleckner };
403146eb7a6SReid Kleckner append(Buffer, Header);
404146eb7a6SReid Kleckner
405146eb7a6SReid Kleckner // Section Header Table
4061079ef8dSMartell Malone const coff_section SectionTable[NumberOfSections] = {
407146eb7a6SReid Kleckner {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
408146eb7a6SReid Kleckner u32(0),
409146eb7a6SReid Kleckner u32(0),
410146eb7a6SReid Kleckner u32(VASize),
411146eb7a6SReid Kleckner u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
412146eb7a6SReid Kleckner u32(0),
413146eb7a6SReid Kleckner u32(0),
414146eb7a6SReid Kleckner u16(0),
415146eb7a6SReid Kleckner u16(0),
416146eb7a6SReid Kleckner u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
417146eb7a6SReid Kleckner : IMAGE_SCN_ALIGN_8BYTES) |
418146eb7a6SReid Kleckner IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
419146eb7a6SReid Kleckner IMAGE_SCN_MEM_WRITE)},
420146eb7a6SReid Kleckner {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
421146eb7a6SReid Kleckner u32(0),
422146eb7a6SReid Kleckner u32(0),
423146eb7a6SReid Kleckner u32(VASize),
424146eb7a6SReid Kleckner u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
425146eb7a6SReid Kleckner VASize),
426146eb7a6SReid Kleckner u32(0),
427146eb7a6SReid Kleckner u32(0),
428146eb7a6SReid Kleckner u16(0),
429146eb7a6SReid Kleckner u16(0),
430146eb7a6SReid Kleckner u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
431146eb7a6SReid Kleckner : IMAGE_SCN_ALIGN_8BYTES) |
432146eb7a6SReid Kleckner IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
433146eb7a6SReid Kleckner IMAGE_SCN_MEM_WRITE)},
434146eb7a6SReid Kleckner };
435146eb7a6SReid Kleckner append(Buffer, SectionTable);
436146eb7a6SReid Kleckner
437146eb7a6SReid Kleckner // .idata$5, ILT
438146eb7a6SReid Kleckner append(Buffer, u32(0));
439146eb7a6SReid Kleckner if (!is32bit(Machine))
440146eb7a6SReid Kleckner append(Buffer, u32(0));
441146eb7a6SReid Kleckner
442146eb7a6SReid Kleckner // .idata$4, IAT
443146eb7a6SReid Kleckner append(Buffer, u32(0));
444146eb7a6SReid Kleckner if (!is32bit(Machine))
445146eb7a6SReid Kleckner append(Buffer, u32(0));
446146eb7a6SReid Kleckner
447146eb7a6SReid Kleckner // Symbol Table
448146eb7a6SReid Kleckner coff_symbol16 SymbolTable[NumberOfSymbols] = {
449146eb7a6SReid Kleckner {{{0, 0, 0, 0, 0, 0, 0, 0}},
450146eb7a6SReid Kleckner u32(0),
451146eb7a6SReid Kleckner u16(1),
452146eb7a6SReid Kleckner u16(0),
453146eb7a6SReid Kleckner IMAGE_SYM_CLASS_EXTERNAL,
454146eb7a6SReid Kleckner 0},
455146eb7a6SReid Kleckner };
456415ec926SGalina Kistanova SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
457146eb7a6SReid Kleckner append(Buffer, SymbolTable);
458146eb7a6SReid Kleckner
459146eb7a6SReid Kleckner // String Table
460146eb7a6SReid Kleckner writeStringTable(Buffer, {NullThunkSymbolName});
461146eb7a6SReid Kleckner
462146eb7a6SReid Kleckner StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
4630f83a894SSaleem Abdulrasool return {MemoryBufferRef{F, ImportName}};
464146eb7a6SReid Kleckner }
465146eb7a6SReid Kleckner
createShortImport(StringRef Sym,uint16_t Ordinal,ImportType ImportType,ImportNameType NameType)466146eb7a6SReid Kleckner NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
467146eb7a6SReid Kleckner uint16_t Ordinal,
468146eb7a6SReid Kleckner ImportType ImportType,
469146eb7a6SReid Kleckner ImportNameType NameType) {
4700f83a894SSaleem Abdulrasool size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs
471146eb7a6SReid Kleckner size_t Size = sizeof(coff_import_header) + ImpSize;
472146eb7a6SReid Kleckner char *Buf = Alloc.Allocate<char>(Size);
473146eb7a6SReid Kleckner memset(Buf, 0, Size);
474146eb7a6SReid Kleckner char *P = Buf;
475146eb7a6SReid Kleckner
476146eb7a6SReid Kleckner // Write short import library.
477146eb7a6SReid Kleckner auto *Imp = reinterpret_cast<coff_import_header *>(P);
478146eb7a6SReid Kleckner P += sizeof(*Imp);
479146eb7a6SReid Kleckner Imp->Sig2 = 0xFFFF;
480146eb7a6SReid Kleckner Imp->Machine = Machine;
481146eb7a6SReid Kleckner Imp->SizeOfData = ImpSize;
482146eb7a6SReid Kleckner if (Ordinal > 0)
483146eb7a6SReid Kleckner Imp->OrdinalHint = Ordinal;
484146eb7a6SReid Kleckner Imp->TypeInfo = (NameType << 2) | ImportType;
485146eb7a6SReid Kleckner
486146eb7a6SReid Kleckner // Write symbol name and DLL name.
487146eb7a6SReid Kleckner memcpy(P, Sym.data(), Sym.size());
488146eb7a6SReid Kleckner P += Sym.size() + 1;
4890f83a894SSaleem Abdulrasool memcpy(P, ImportName.data(), ImportName.size());
490146eb7a6SReid Kleckner
4910f83a894SSaleem Abdulrasool return {MemoryBufferRef(StringRef(Buf, Size), ImportName)};
492146eb7a6SReid Kleckner }
493146eb7a6SReid Kleckner
createWeakExternal(StringRef Sym,StringRef Weak,bool Imp)4941079ef8dSMartell Malone NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym,
4951079ef8dSMartell Malone StringRef Weak, bool Imp) {
4961079ef8dSMartell Malone std::vector<uint8_t> Buffer;
4971079ef8dSMartell Malone const uint32_t NumberOfSections = 1;
4981079ef8dSMartell Malone const uint32_t NumberOfSymbols = 5;
4991079ef8dSMartell Malone
5001079ef8dSMartell Malone // COFF Header
5011079ef8dSMartell Malone coff_file_header Header{
502146db440SMartin Storsjo u16(Machine),
5031079ef8dSMartell Malone u16(NumberOfSections),
5041079ef8dSMartell Malone u32(0),
5051079ef8dSMartell Malone u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))),
5061079ef8dSMartell Malone u32(NumberOfSymbols),
5071079ef8dSMartell Malone u16(0),
5081079ef8dSMartell Malone u16(0),
5091079ef8dSMartell Malone };
5101079ef8dSMartell Malone append(Buffer, Header);
5111079ef8dSMartell Malone
5121079ef8dSMartell Malone // Section Header Table
5131079ef8dSMartell Malone const coff_section SectionTable[NumberOfSections] = {
5141079ef8dSMartell Malone {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'},
5151079ef8dSMartell Malone u32(0),
5161079ef8dSMartell Malone u32(0),
5171079ef8dSMartell Malone u32(0),
5181079ef8dSMartell Malone u32(0),
5191079ef8dSMartell Malone u32(0),
5201079ef8dSMartell Malone u32(0),
5211079ef8dSMartell Malone u16(0),
5221079ef8dSMartell Malone u16(0),
5231079ef8dSMartell Malone u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}};
5241079ef8dSMartell Malone append(Buffer, SectionTable);
5251079ef8dSMartell Malone
5261079ef8dSMartell Malone // Symbol Table
5271079ef8dSMartell Malone coff_symbol16 SymbolTable[NumberOfSymbols] = {
5281079ef8dSMartell Malone {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},
5291079ef8dSMartell Malone u32(0),
5301079ef8dSMartell Malone u16(0xFFFF),
5311079ef8dSMartell Malone u16(0),
5321079ef8dSMartell Malone IMAGE_SYM_CLASS_STATIC,
5331079ef8dSMartell Malone 0},
5341079ef8dSMartell Malone {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}},
5351079ef8dSMartell Malone u32(0),
5361079ef8dSMartell Malone u16(0xFFFF),
5371079ef8dSMartell Malone u16(0),
5381079ef8dSMartell Malone IMAGE_SYM_CLASS_STATIC,
5391079ef8dSMartell Malone 0},
5401079ef8dSMartell Malone {{{0, 0, 0, 0, 0, 0, 0, 0}},
5411079ef8dSMartell Malone u32(0),
5421079ef8dSMartell Malone u16(0),
5431079ef8dSMartell Malone u16(0),
5441079ef8dSMartell Malone IMAGE_SYM_CLASS_EXTERNAL,
5451079ef8dSMartell Malone 0},
5461079ef8dSMartell Malone {{{0, 0, 0, 0, 0, 0, 0, 0}},
5471079ef8dSMartell Malone u32(0),
5481079ef8dSMartell Malone u16(0),
5491079ef8dSMartell Malone u16(0),
5501079ef8dSMartell Malone IMAGE_SYM_CLASS_WEAK_EXTERNAL,
5511079ef8dSMartell Malone 1},
552509f1668SMartin Storsjo {{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}},
553509f1668SMartin Storsjo u32(0),
554509f1668SMartin Storsjo u16(0),
555509f1668SMartin Storsjo u16(0),
556509f1668SMartin Storsjo IMAGE_SYM_CLASS_NULL,
557509f1668SMartin Storsjo 0},
5581079ef8dSMartell Malone };
5591079ef8dSMartell Malone SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t);
5601079ef8dSMartell Malone
5611079ef8dSMartell Malone //__imp_ String Table
5624a5764e3SMartin Storsjo StringRef Prefix = Imp ? "__imp_" : "";
5634a5764e3SMartin Storsjo SymbolTable[3].Name.Offset.Offset =
5644a5764e3SMartin Storsjo sizeof(uint32_t) + Sym.size() + Prefix.size() + 1;
5651079ef8dSMartell Malone append(Buffer, SymbolTable);
5664a5764e3SMartin Storsjo writeStringTable(Buffer, {(Prefix + Sym).str(),
5674a5764e3SMartin Storsjo (Prefix + Weak).str()});
5681079ef8dSMartell Malone
5691079ef8dSMartell Malone // Copied here so we can still use writeStringTable
5701079ef8dSMartell Malone char *Buf = Alloc.Allocate<char>(Buffer.size());
5711079ef8dSMartell Malone memcpy(Buf, Buffer.data(), Buffer.size());
5720f83a894SSaleem Abdulrasool return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)};
5731079ef8dSMartell Malone }
5741079ef8dSMartell Malone
writeImportLibrary(StringRef ImportName,StringRef Path,ArrayRef<COFFShortExport> Exports,MachineTypes Machine,bool MinGW)57525cbdf25SRafael Espindola Error writeImportLibrary(StringRef ImportName, StringRef Path,
576146eb7a6SReid Kleckner ArrayRef<COFFShortExport> Exports,
577284ab80fSMartin Storsjo MachineTypes Machine, bool MinGW) {
578146eb7a6SReid Kleckner
579146eb7a6SReid Kleckner std::vector<NewArchiveMember> Members;
5800f83a894SSaleem Abdulrasool ObjectFactory OF(llvm::sys::path::filename(ImportName), Machine);
581146eb7a6SReid Kleckner
582146eb7a6SReid Kleckner std::vector<uint8_t> ImportDescriptor;
583146eb7a6SReid Kleckner Members.push_back(OF.createImportDescriptor(ImportDescriptor));
584146eb7a6SReid Kleckner
585146eb7a6SReid Kleckner std::vector<uint8_t> NullImportDescriptor;
586146eb7a6SReid Kleckner Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));
587146eb7a6SReid Kleckner
588146eb7a6SReid Kleckner std::vector<uint8_t> NullThunk;
589146eb7a6SReid Kleckner Members.push_back(OF.createNullThunk(NullThunk));
590146eb7a6SReid Kleckner
591146eb7a6SReid Kleckner for (COFFShortExport E : Exports) {
592146eb7a6SReid Kleckner if (E.Private)
593146eb7a6SReid Kleckner continue;
594146eb7a6SReid Kleckner
595146eb7a6SReid Kleckner ImportType ImportType = IMPORT_CODE;
596146eb7a6SReid Kleckner if (E.Data)
597146eb7a6SReid Kleckner ImportType = IMPORT_DATA;
598146eb7a6SReid Kleckner if (E.Constant)
599146eb7a6SReid Kleckner ImportType = IMPORT_CONST;
600146eb7a6SReid Kleckner
601a238b20eSMartin Storsjo StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName;
602de6038b2SMartin Storsjo ImportNameType NameType = E.Noname
603de6038b2SMartin Storsjo ? IMPORT_ORDINAL
604de6038b2SMartin Storsjo : getNameType(SymbolName, E.Name,
605de6038b2SMartin Storsjo Machine, MinGW);
606146eb7a6SReid Kleckner Expected<std::string> Name = E.ExtName.empty()
607adcd0268SBenjamin Kramer ? std::string(SymbolName)
608146eb7a6SReid Kleckner : replace(SymbolName, E.Name, E.ExtName);
609146eb7a6SReid Kleckner
61025cbdf25SRafael Espindola if (!Name)
61125cbdf25SRafael Espindola return Name.takeError();
612146eb7a6SReid Kleckner
613284ab80fSMartin Storsjo if (!E.AliasTarget.empty() && *Name != E.AliasTarget) {
614284ab80fSMartin Storsjo Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, false));
615284ab80fSMartin Storsjo Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, true));
616284ab80fSMartin Storsjo continue;
617284ab80fSMartin Storsjo }
618284ab80fSMartin Storsjo
619146eb7a6SReid Kleckner Members.push_back(
620146eb7a6SReid Kleckner OF.createShortImport(*Name, E.Ordinal, ImportType, NameType));
621146eb7a6SReid Kleckner }
622146eb7a6SReid Kleckner
62301d02651SRui Ueyama return writeArchive(Path, Members, /*WriteSymtab*/ true,
62401d02651SRui Ueyama object::Archive::K_GNU,
625146eb7a6SReid Kleckner /*Deterministic*/ true, /*Thin*/ false);
626146eb7a6SReid Kleckner }
627146eb7a6SReid Kleckner
628146eb7a6SReid Kleckner } // namespace object
629146eb7a6SReid Kleckner } // namespace llvm
630