COFFImportFile.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. //===- COFFImportFile.cpp - COFF short import file implementation ---------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file defines the writeImportLibrary function.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "llvm/Object/COFFImportFile.h"
  13. #include "llvm/ADT/ArrayRef.h"
  14. #include "llvm/ADT/Twine.h"
  15. #include "llvm/Object/Archive.h"
  16. #include "llvm/Object/ArchiveWriter.h"
  17. #include "llvm/Object/COFF.h"
  18. #include "llvm/Support/Allocator.h"
  19. #include "llvm/Support/Endian.h"
  20. #include "llvm/Support/Error.h"
  21. #include "llvm/Support/ErrorHandling.h"
  22. #include "llvm/Support/Path.h"
  23. #include <cstdint>
  24. #include <string>
  25. #include <vector>
  26. using namespace llvm::COFF;
  27. using namespace llvm::object;
  28. using namespace llvm;
  29. namespace llvm {
  30. namespace object {
  31. static bool is32bit(MachineTypes Machine) {
  32. switch (Machine) {
  33. default:
  34. llvm_unreachable("unsupported machine");
  35. case IMAGE_FILE_MACHINE_ARM64:
  36. case IMAGE_FILE_MACHINE_ARM64EC:
  37. case IMAGE_FILE_MACHINE_AMD64:
  38. return false;
  39. case IMAGE_FILE_MACHINE_ARMNT:
  40. case IMAGE_FILE_MACHINE_I386:
  41. return true;
  42. }
  43. }
  44. static uint16_t getImgRelRelocation(MachineTypes Machine) {
  45. switch (Machine) {
  46. default:
  47. llvm_unreachable("unsupported machine");
  48. case IMAGE_FILE_MACHINE_AMD64:
  49. return IMAGE_REL_AMD64_ADDR32NB;
  50. case IMAGE_FILE_MACHINE_ARMNT:
  51. return IMAGE_REL_ARM_ADDR32NB;
  52. case IMAGE_FILE_MACHINE_ARM64:
  53. case IMAGE_FILE_MACHINE_ARM64EC:
  54. return IMAGE_REL_ARM64_ADDR32NB;
  55. case IMAGE_FILE_MACHINE_I386:
  56. return IMAGE_REL_I386_DIR32NB;
  57. }
  58. }
  59. template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {
  60. size_t S = B.size();
  61. B.resize(S + sizeof(T));
  62. memcpy(&B[S], &Data, sizeof(T));
  63. }
  64. static void writeStringTable(std::vector<uint8_t> &B,
  65. ArrayRef<const std::string> Strings) {
  66. // The COFF string table consists of a 4-byte value which is the size of the
  67. // table, including the length field itself. This value is followed by the
  68. // string content itself, which is an array of null-terminated C-style
  69. // strings. The termination is important as they are referenced to by offset
  70. // by the symbol entity in the file format.
  71. size_t Pos = B.size();
  72. size_t Offset = B.size();
  73. // Skip over the length field, we will fill it in later as we will have
  74. // computed the length while emitting the string content itself.
  75. Pos += sizeof(uint32_t);
  76. for (const auto &S : Strings) {
  77. B.resize(Pos + S.length() + 1);
  78. strcpy(reinterpret_cast<char *>(&B[Pos]), S.c_str());
  79. Pos += S.length() + 1;
  80. }
  81. // Backfill the length of the table now that it has been computed.
  82. support::ulittle32_t Length(B.size() - Offset);
  83. support::endian::write32le(&B[Offset], Length);
  84. }
  85. static ImportNameType getNameType(StringRef Sym, StringRef ExtName,
  86. MachineTypes Machine, bool MinGW) {
  87. // A decorated stdcall function in MSVC is exported with the
  88. // type IMPORT_NAME, and the exported function name includes the
  89. // the leading underscore. In MinGW on the other hand, a decorated
  90. // stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX).
  91. // See the comment in isDecorated in COFFModuleDefinition.cpp for more
  92. // details.
  93. if (ExtName.startswith("_") && ExtName.contains('@') && !MinGW)
  94. return IMPORT_NAME;
  95. if (Sym != ExtName)
  96. return IMPORT_NAME_UNDECORATE;
  97. if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.startswith("_"))
  98. return IMPORT_NAME_NOPREFIX;
  99. return IMPORT_NAME;
  100. }
  101. static Expected<std::string> replace(StringRef S, StringRef From,
  102. StringRef To) {
  103. size_t Pos = S.find(From);
  104. // From and To may be mangled, but substrings in S may not.
  105. if (Pos == StringRef::npos && From.startswith("_") && To.startswith("_")) {
  106. From = From.substr(1);
  107. To = To.substr(1);
  108. Pos = S.find(From);
  109. }
  110. if (Pos == StringRef::npos) {
  111. return make_error<StringError>(
  112. StringRef(Twine(S + ": replacing '" + From +
  113. "' with '" + To + "' failed").str()), object_error::parse_failed);
  114. }
  115. return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
  116. }
  117. static const std::string NullImportDescriptorSymbolName =
  118. "__NULL_IMPORT_DESCRIPTOR";
  119. namespace {
  120. // This class constructs various small object files necessary to support linking
  121. // symbols imported from a DLL. The contents are pretty strictly defined and
  122. // nearly entirely static. The details of the structures files are defined in
  123. // WINNT.h and the PE/COFF specification.
  124. class ObjectFactory {
  125. using u16 = support::ulittle16_t;
  126. using u32 = support::ulittle32_t;
  127. MachineTypes Machine;
  128. BumpPtrAllocator Alloc;
  129. StringRef ImportName;
  130. StringRef Library;
  131. std::string ImportDescriptorSymbolName;
  132. std::string NullThunkSymbolName;
  133. public:
  134. ObjectFactory(StringRef S, MachineTypes M)
  135. : Machine(M), ImportName(S), Library(S.drop_back(4)),
  136. ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()),
  137. NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {}
  138. // Creates an Import Descriptor. This is a small object file which contains a
  139. // reference to the terminators and contains the library name (entry) for the
  140. // import name table. It will force the linker to construct the necessary
  141. // structure to import symbols from the DLL.
  142. NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);
  143. // Creates a NULL import descriptor. This is a small object file whcih
  144. // contains a NULL import descriptor. It is used to terminate the imports
  145. // from a specific DLL.
  146. NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);
  147. // Create a NULL Thunk Entry. This is a small object file which contains a
  148. // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It
  149. // is used to terminate the IAT and ILT.
  150. NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);
  151. // Create a short import file which is described in PE/COFF spec 7. Import
  152. // Library Format.
  153. NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
  154. ImportType Type, ImportNameType NameType);
  155. // Create a weak external file which is described in PE/COFF Aux Format 3.
  156. NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp);
  157. };
  158. } // namespace
  159. NewArchiveMember
  160. ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
  161. const uint32_t NumberOfSections = 2;
  162. const uint32_t NumberOfSymbols = 7;
  163. const uint32_t NumberOfRelocations = 3;
  164. // COFF Header
  165. coff_file_header Header{
  166. u16(Machine),
  167. u16(NumberOfSections),
  168. u32(0),
  169. u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
  170. // .idata$2
  171. sizeof(coff_import_directory_table_entry) +
  172. NumberOfRelocations * sizeof(coff_relocation) +
  173. // .idata$4
  174. (ImportName.size() + 1)),
  175. u32(NumberOfSymbols),
  176. u16(0),
  177. u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
  178. };
  179. append(Buffer, Header);
  180. // Section Header Table
  181. const coff_section SectionTable[NumberOfSections] = {
  182. {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
  183. u32(0),
  184. u32(0),
  185. u32(sizeof(coff_import_directory_table_entry)),
  186. u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
  187. u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
  188. sizeof(coff_import_directory_table_entry)),
  189. u32(0),
  190. u16(NumberOfRelocations),
  191. u16(0),
  192. u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
  193. IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
  194. {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
  195. u32(0),
  196. u32(0),
  197. u32(ImportName.size() + 1),
  198. u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
  199. sizeof(coff_import_directory_table_entry) +
  200. NumberOfRelocations * sizeof(coff_relocation)),
  201. u32(0),
  202. u32(0),
  203. u16(0),
  204. u16(0),
  205. u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
  206. IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
  207. };
  208. append(Buffer, SectionTable);
  209. // .idata$2
  210. const coff_import_directory_table_entry ImportDescriptor{
  211. u32(0), u32(0), u32(0), u32(0), u32(0),
  212. };
  213. append(Buffer, ImportDescriptor);
  214. const coff_relocation RelocationTable[NumberOfRelocations] = {
  215. {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
  216. u16(getImgRelRelocation(Machine))},
  217. {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
  218. u32(3), u16(getImgRelRelocation(Machine))},
  219. {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
  220. u32(4), u16(getImgRelRelocation(Machine))},
  221. };
  222. append(Buffer, RelocationTable);
  223. // .idata$6
  224. auto S = Buffer.size();
  225. Buffer.resize(S + ImportName.size() + 1);
  226. memcpy(&Buffer[S], ImportName.data(), ImportName.size());
  227. Buffer[S + ImportName.size()] = '\0';
  228. // Symbol Table
  229. coff_symbol16 SymbolTable[NumberOfSymbols] = {
  230. {{{0, 0, 0, 0, 0, 0, 0, 0}},
  231. u32(0),
  232. u16(1),
  233. u16(0),
  234. IMAGE_SYM_CLASS_EXTERNAL,
  235. 0},
  236. {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
  237. u32(0),
  238. u16(1),
  239. u16(0),
  240. IMAGE_SYM_CLASS_SECTION,
  241. 0},
  242. {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
  243. u32(0),
  244. u16(2),
  245. u16(0),
  246. IMAGE_SYM_CLASS_STATIC,
  247. 0},
  248. {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
  249. u32(0),
  250. u16(0),
  251. u16(0),
  252. IMAGE_SYM_CLASS_SECTION,
  253. 0},
  254. {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
  255. u32(0),
  256. u16(0),
  257. u16(0),
  258. IMAGE_SYM_CLASS_SECTION,
  259. 0},
  260. {{{0, 0, 0, 0, 0, 0, 0, 0}},
  261. u32(0),
  262. u16(0),
  263. u16(0),
  264. IMAGE_SYM_CLASS_EXTERNAL,
  265. 0},
  266. {{{0, 0, 0, 0, 0, 0, 0, 0}},
  267. u32(0),
  268. u16(0),
  269. u16(0),
  270. IMAGE_SYM_CLASS_EXTERNAL,
  271. 0},
  272. };
  273. // TODO: Name.Offset.Offset here and in the all similar places below
  274. // suggests a names refactoring. Maybe StringTableOffset.Value?
  275. SymbolTable[0].Name.Offset.Offset =
  276. sizeof(uint32_t);
  277. SymbolTable[5].Name.Offset.Offset =
  278. sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
  279. SymbolTable[6].Name.Offset.Offset =
  280. sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
  281. NullImportDescriptorSymbolName.length() + 1;
  282. append(Buffer, SymbolTable);
  283. // String Table
  284. writeStringTable(Buffer,
  285. {ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
  286. NullThunkSymbolName});
  287. StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
  288. return {MemoryBufferRef(F, ImportName)};
  289. }
  290. NewArchiveMember
  291. ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
  292. const uint32_t NumberOfSections = 1;
  293. const uint32_t NumberOfSymbols = 1;
  294. // COFF Header
  295. coff_file_header Header{
  296. u16(Machine),
  297. u16(NumberOfSections),
  298. u32(0),
  299. u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
  300. // .idata$3
  301. sizeof(coff_import_directory_table_entry)),
  302. u32(NumberOfSymbols),
  303. u16(0),
  304. u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
  305. };
  306. append(Buffer, Header);
  307. // Section Header Table
  308. const coff_section SectionTable[NumberOfSections] = {
  309. {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
  310. u32(0),
  311. u32(0),
  312. u32(sizeof(coff_import_directory_table_entry)),
  313. u32(sizeof(coff_file_header) +
  314. (NumberOfSections * sizeof(coff_section))),
  315. u32(0),
  316. u32(0),
  317. u16(0),
  318. u16(0),
  319. u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
  320. IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
  321. };
  322. append(Buffer, SectionTable);
  323. // .idata$3
  324. const coff_import_directory_table_entry ImportDescriptor{
  325. u32(0), u32(0), u32(0), u32(0), u32(0),
  326. };
  327. append(Buffer, ImportDescriptor);
  328. // Symbol Table
  329. coff_symbol16 SymbolTable[NumberOfSymbols] = {
  330. {{{0, 0, 0, 0, 0, 0, 0, 0}},
  331. u32(0),
  332. u16(1),
  333. u16(0),
  334. IMAGE_SYM_CLASS_EXTERNAL,
  335. 0},
  336. };
  337. SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
  338. append(Buffer, SymbolTable);
  339. // String Table
  340. writeStringTable(Buffer, {NullImportDescriptorSymbolName});
  341. StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
  342. return {MemoryBufferRef(F, ImportName)};
  343. }
  344. NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
  345. const uint32_t NumberOfSections = 2;
  346. const uint32_t NumberOfSymbols = 1;
  347. uint32_t VASize = is32bit(Machine) ? 4 : 8;
  348. // COFF Header
  349. coff_file_header Header{
  350. u16(Machine),
  351. u16(NumberOfSections),
  352. u32(0),
  353. u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
  354. // .idata$5
  355. VASize +
  356. // .idata$4
  357. VASize),
  358. u32(NumberOfSymbols),
  359. u16(0),
  360. u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
  361. };
  362. append(Buffer, Header);
  363. // Section Header Table
  364. const coff_section SectionTable[NumberOfSections] = {
  365. {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
  366. u32(0),
  367. u32(0),
  368. u32(VASize),
  369. u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
  370. u32(0),
  371. u32(0),
  372. u16(0),
  373. u16(0),
  374. u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
  375. : IMAGE_SCN_ALIGN_8BYTES) |
  376. IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
  377. IMAGE_SCN_MEM_WRITE)},
  378. {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
  379. u32(0),
  380. u32(0),
  381. u32(VASize),
  382. u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
  383. VASize),
  384. u32(0),
  385. u32(0),
  386. u16(0),
  387. u16(0),
  388. u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
  389. : IMAGE_SCN_ALIGN_8BYTES) |
  390. IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
  391. IMAGE_SCN_MEM_WRITE)},
  392. };
  393. append(Buffer, SectionTable);
  394. // .idata$5, ILT
  395. append(Buffer, u32(0));
  396. if (!is32bit(Machine))
  397. append(Buffer, u32(0));
  398. // .idata$4, IAT
  399. append(Buffer, u32(0));
  400. if (!is32bit(Machine))
  401. append(Buffer, u32(0));
  402. // Symbol Table
  403. coff_symbol16 SymbolTable[NumberOfSymbols] = {
  404. {{{0, 0, 0, 0, 0, 0, 0, 0}},
  405. u32(0),
  406. u16(1),
  407. u16(0),
  408. IMAGE_SYM_CLASS_EXTERNAL,
  409. 0},
  410. };
  411. SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
  412. append(Buffer, SymbolTable);
  413. // String Table
  414. writeStringTable(Buffer, {NullThunkSymbolName});
  415. StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
  416. return {MemoryBufferRef{F, ImportName}};
  417. }
  418. NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
  419. uint16_t Ordinal,
  420. ImportType ImportType,
  421. ImportNameType NameType) {
  422. size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs
  423. size_t Size = sizeof(coff_import_header) + ImpSize;
  424. char *Buf = Alloc.Allocate<char>(Size);
  425. memset(Buf, 0, Size);
  426. char *P = Buf;
  427. // Write short import library.
  428. auto *Imp = reinterpret_cast<coff_import_header *>(P);
  429. P += sizeof(*Imp);
  430. Imp->Sig2 = 0xFFFF;
  431. Imp->Machine = Machine;
  432. Imp->SizeOfData = ImpSize;
  433. if (Ordinal > 0)
  434. Imp->OrdinalHint = Ordinal;
  435. Imp->TypeInfo = (NameType << 2) | ImportType;
  436. // Write symbol name and DLL name.
  437. memcpy(P, Sym.data(), Sym.size());
  438. P += Sym.size() + 1;
  439. memcpy(P, ImportName.data(), ImportName.size());
  440. return {MemoryBufferRef(StringRef(Buf, Size), ImportName)};
  441. }
  442. NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym,
  443. StringRef Weak, bool Imp) {
  444. std::vector<uint8_t> Buffer;
  445. const uint32_t NumberOfSections = 1;
  446. const uint32_t NumberOfSymbols = 5;
  447. // COFF Header
  448. coff_file_header Header{
  449. u16(Machine),
  450. u16(NumberOfSections),
  451. u32(0),
  452. u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))),
  453. u32(NumberOfSymbols),
  454. u16(0),
  455. u16(0),
  456. };
  457. append(Buffer, Header);
  458. // Section Header Table
  459. const coff_section SectionTable[NumberOfSections] = {
  460. {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'},
  461. u32(0),
  462. u32(0),
  463. u32(0),
  464. u32(0),
  465. u32(0),
  466. u32(0),
  467. u16(0),
  468. u16(0),
  469. u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}};
  470. append(Buffer, SectionTable);
  471. // Symbol Table
  472. coff_symbol16 SymbolTable[NumberOfSymbols] = {
  473. {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},
  474. u32(0),
  475. u16(0xFFFF),
  476. u16(0),
  477. IMAGE_SYM_CLASS_STATIC,
  478. 0},
  479. {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}},
  480. u32(0),
  481. u16(0xFFFF),
  482. u16(0),
  483. IMAGE_SYM_CLASS_STATIC,
  484. 0},
  485. {{{0, 0, 0, 0, 0, 0, 0, 0}},
  486. u32(0),
  487. u16(0),
  488. u16(0),
  489. IMAGE_SYM_CLASS_EXTERNAL,
  490. 0},
  491. {{{0, 0, 0, 0, 0, 0, 0, 0}},
  492. u32(0),
  493. u16(0),
  494. u16(0),
  495. IMAGE_SYM_CLASS_WEAK_EXTERNAL,
  496. 1},
  497. {{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}},
  498. u32(0),
  499. u16(0),
  500. u16(0),
  501. IMAGE_SYM_CLASS_NULL,
  502. 0},
  503. };
  504. SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t);
  505. //__imp_ String Table
  506. StringRef Prefix = Imp ? "__imp_" : "";
  507. SymbolTable[3].Name.Offset.Offset =
  508. sizeof(uint32_t) + Sym.size() + Prefix.size() + 1;
  509. append(Buffer, SymbolTable);
  510. writeStringTable(Buffer, {(Prefix + Sym).str(),
  511. (Prefix + Weak).str()});
  512. // Copied here so we can still use writeStringTable
  513. char *Buf = Alloc.Allocate<char>(Buffer.size());
  514. memcpy(Buf, Buffer.data(), Buffer.size());
  515. return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)};
  516. }
  517. Error writeImportLibrary(StringRef ImportName, StringRef Path,
  518. ArrayRef<COFFShortExport> Exports,
  519. MachineTypes Machine, bool MinGW) {
  520. std::vector<NewArchiveMember> Members;
  521. ObjectFactory OF(llvm::sys::path::filename(ImportName), Machine);
  522. std::vector<uint8_t> ImportDescriptor;
  523. Members.push_back(OF.createImportDescriptor(ImportDescriptor));
  524. std::vector<uint8_t> NullImportDescriptor;
  525. Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));
  526. std::vector<uint8_t> NullThunk;
  527. Members.push_back(OF.createNullThunk(NullThunk));
  528. for (COFFShortExport E : Exports) {
  529. if (E.Private)
  530. continue;
  531. ImportType ImportType = IMPORT_CODE;
  532. if (E.Data)
  533. ImportType = IMPORT_DATA;
  534. if (E.Constant)
  535. ImportType = IMPORT_CONST;
  536. StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName;
  537. ImportNameType NameType = E.Noname
  538. ? IMPORT_ORDINAL
  539. : getNameType(SymbolName, E.Name,
  540. Machine, MinGW);
  541. Expected<std::string> Name = E.ExtName.empty()
  542. ? std::string(SymbolName)
  543. : replace(SymbolName, E.Name, E.ExtName);
  544. if (!Name)
  545. return Name.takeError();
  546. if (!E.AliasTarget.empty() && *Name != E.AliasTarget) {
  547. Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, false));
  548. Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, true));
  549. continue;
  550. }
  551. Members.push_back(
  552. OF.createShortImport(*Name, E.Ordinal, ImportType, NameType));
  553. }
  554. return writeArchive(Path, Members, /*WriteSymtab*/ true,
  555. object::Archive::K_GNU,
  556. /*Deterministic*/ true, /*Thin*/ false);
  557. }
  558. } // namespace object
  559. } // namespace llvm