WindowsResource.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. //===-- WindowsResource.cpp -------------------------------------*- C++ -*-===//
  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 implements the .res file class.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "llvm/Object/WindowsResource.h"
  14. #include "llvm/Object/COFF.h"
  15. #include "llvm/Support/FileOutputBuffer.h"
  16. #include "llvm/Support/MathExtras.h"
  17. #include <ctime>
  18. #include <queue>
  19. #include <sstream>
  20. #include <system_error>
  21. using namespace llvm;
  22. using namespace object;
  23. namespace llvm {
  24. namespace object {
  25. #define RETURN_IF_ERROR(X) \
  26. if (auto EC = X) \
  27. return EC;
  28. const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t);
  29. // COFF files seem to be inconsistent with alignment between sections, just use
  30. // 8-byte because it makes everyone happy.
  31. const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t);
  32. static const size_t ResourceMagicSize = 16;
  33. static const size_t NullEntrySize = 16;
  34. uint32_t WindowsResourceParser::TreeNode::StringCount = 0;
  35. uint32_t WindowsResourceParser::TreeNode::DataCount = 0;
  36. WindowsResource::WindowsResource(MemoryBufferRef Source)
  37. : Binary(Binary::ID_WinRes, Source) {
  38. size_t LeadingSize = ResourceMagicSize + NullEntrySize;
  39. BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
  40. support::little);
  41. }
  42. Expected<std::unique_ptr<WindowsResource>>
  43. WindowsResource::createWindowsResource(MemoryBufferRef Source) {
  44. if (Source.getBufferSize() < ResourceMagicSize + NullEntrySize)
  45. return make_error<GenericBinaryError>(
  46. "File too small to be a resource file",
  47. object_error::invalid_file_type);
  48. std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source));
  49. return std::move(Ret);
  50. }
  51. Expected<ResourceEntryRef> WindowsResource::getHeadEntry() {
  52. Error Err = Error::success();
  53. auto Ref = ResourceEntryRef(BinaryStreamRef(BBS), this, Err);
  54. if (Err)
  55. return std::move(Err);
  56. return Ref;
  57. }
  58. ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref,
  59. const WindowsResource *Owner, Error &Err)
  60. : Reader(Ref), OwningRes(Owner) {
  61. if (loadNext())
  62. Err = make_error<GenericBinaryError>("Could not read first entry.\n",
  63. object_error::unexpected_eof);
  64. }
  65. Error ResourceEntryRef::moveNext(bool &End) {
  66. // Reached end of all the entries.
  67. if (Reader.bytesRemaining() == 0) {
  68. End = true;
  69. return Error::success();
  70. }
  71. RETURN_IF_ERROR(loadNext());
  72. return Error::success();
  73. }
  74. static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID,
  75. ArrayRef<UTF16> &Str, bool &IsString) {
  76. uint16_t IDFlag;
  77. RETURN_IF_ERROR(Reader.readInteger(IDFlag));
  78. IsString = IDFlag != 0xffff;
  79. if (IsString) {
  80. Reader.setOffset(
  81. Reader.getOffset() -
  82. sizeof(uint16_t)); // Re-read the bytes which we used to check the flag.
  83. RETURN_IF_ERROR(Reader.readWideString(Str));
  84. } else
  85. RETURN_IF_ERROR(Reader.readInteger(ID));
  86. return Error::success();
  87. }
  88. Error ResourceEntryRef::loadNext() {
  89. uint32_t DataSize;
  90. RETURN_IF_ERROR(Reader.readInteger(DataSize));
  91. uint32_t HeaderSize;
  92. RETURN_IF_ERROR(Reader.readInteger(HeaderSize));
  93. if (HeaderSize < MIN_HEADER_SIZE)
  94. return make_error<GenericBinaryError>("Header size is too small.",
  95. object_error::parse_failed);
  96. RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType));
  97. RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
  98. RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
  99. RETURN_IF_ERROR(Reader.readObject(Suffix));
  100. RETURN_IF_ERROR(Reader.readArray(Data, DataSize));
  101. RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
  102. return Error::success();
  103. }
  104. WindowsResourceParser::WindowsResourceParser() : Root(false) {}
  105. Error WindowsResourceParser::parse(WindowsResource *WR) {
  106. auto EntryOrErr = WR->getHeadEntry();
  107. if (!EntryOrErr)
  108. return EntryOrErr.takeError();
  109. ResourceEntryRef Entry = EntryOrErr.get();
  110. bool End = false;
  111. while (!End) {
  112. Data.push_back(Entry.getData());
  113. bool IsNewTypeString = false;
  114. bool IsNewNameString = false;
  115. Root.addEntry(Entry, IsNewTypeString, IsNewNameString);
  116. if (IsNewTypeString)
  117. StringTable.push_back(Entry.getTypeString());
  118. if (IsNewNameString)
  119. StringTable.push_back(Entry.getNameString());
  120. RETURN_IF_ERROR(Entry.moveNext(End));
  121. }
  122. return Error::success();
  123. }
  124. void WindowsResourceParser::printTree(raw_ostream &OS) const {
  125. ScopedPrinter Writer(OS);
  126. Root.print(Writer, "Resource Tree");
  127. }
  128. void WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry,
  129. bool &IsNewTypeString,
  130. bool &IsNewNameString) {
  131. TreeNode &TypeNode = addTypeNode(Entry, IsNewTypeString);
  132. TreeNode &NameNode = TypeNode.addNameNode(Entry, IsNewNameString);
  133. NameNode.addLanguageNode(Entry);
  134. }
  135. WindowsResourceParser::TreeNode::TreeNode(bool IsStringNode) {
  136. if (IsStringNode)
  137. StringIndex = StringCount++;
  138. }
  139. WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion,
  140. uint16_t MinorVersion,
  141. uint32_t Characteristics)
  142. : IsDataNode(true), MajorVersion(MajorVersion), MinorVersion(MinorVersion),
  143. Characteristics(Characteristics) {
  144. DataIndex = DataCount++;
  145. }
  146. std::unique_ptr<WindowsResourceParser::TreeNode>
  147. WindowsResourceParser::TreeNode::createStringNode() {
  148. return std::unique_ptr<TreeNode>(new TreeNode(true));
  149. }
  150. std::unique_ptr<WindowsResourceParser::TreeNode>
  151. WindowsResourceParser::TreeNode::createIDNode() {
  152. return std::unique_ptr<TreeNode>(new TreeNode(false));
  153. }
  154. std::unique_ptr<WindowsResourceParser::TreeNode>
  155. WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion,
  156. uint16_t MinorVersion,
  157. uint32_t Characteristics) {
  158. return std::unique_ptr<TreeNode>(
  159. new TreeNode(MajorVersion, MinorVersion, Characteristics));
  160. }
  161. WindowsResourceParser::TreeNode &
  162. WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry,
  163. bool &IsNewTypeString) {
  164. if (Entry.checkTypeString())
  165. return addChild(Entry.getTypeString(), IsNewTypeString);
  166. else
  167. return addChild(Entry.getTypeID());
  168. }
  169. WindowsResourceParser::TreeNode &
  170. WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry,
  171. bool &IsNewNameString) {
  172. if (Entry.checkNameString())
  173. return addChild(Entry.getNameString(), IsNewNameString);
  174. else
  175. return addChild(Entry.getNameID());
  176. }
  177. WindowsResourceParser::TreeNode &
  178. WindowsResourceParser::TreeNode::addLanguageNode(
  179. const ResourceEntryRef &Entry) {
  180. return addChild(Entry.getLanguage(), true, Entry.getMajorVersion(),
  181. Entry.getMinorVersion(), Entry.getCharacteristics());
  182. }
  183. WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addChild(
  184. uint32_t ID, bool IsDataNode, uint16_t MajorVersion, uint16_t MinorVersion,
  185. uint32_t Characteristics) {
  186. auto Child = IDChildren.find(ID);
  187. if (Child == IDChildren.end()) {
  188. auto NewChild =
  189. IsDataNode ? createDataNode(MajorVersion, MinorVersion, Characteristics)
  190. : createIDNode();
  191. WindowsResourceParser::TreeNode &Node = *NewChild;
  192. IDChildren.emplace(ID, std::move(NewChild));
  193. return Node;
  194. } else
  195. return *(Child->second);
  196. }
  197. WindowsResourceParser::TreeNode &
  198. WindowsResourceParser::TreeNode::addChild(ArrayRef<UTF16> NameRef,
  199. bool &IsNewString) {
  200. std::string NameString;
  201. ArrayRef<UTF16> CorrectedName;
  202. std::vector<UTF16> EndianCorrectedName;
  203. if (sys::IsBigEndianHost) {
  204. EndianCorrectedName.resize(NameRef.size() + 1);
  205. std::copy(NameRef.begin(), NameRef.end(), EndianCorrectedName.begin() + 1);
  206. EndianCorrectedName[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED;
  207. CorrectedName = makeArrayRef(EndianCorrectedName);
  208. } else
  209. CorrectedName = NameRef;
  210. convertUTF16ToUTF8String(CorrectedName, NameString);
  211. auto Child = StringChildren.find(NameString);
  212. if (Child == StringChildren.end()) {
  213. auto NewChild = createStringNode();
  214. IsNewString = true;
  215. WindowsResourceParser::TreeNode &Node = *NewChild;
  216. StringChildren.emplace(NameString, std::move(NewChild));
  217. return Node;
  218. } else
  219. return *(Child->second);
  220. }
  221. void WindowsResourceParser::TreeNode::print(ScopedPrinter &Writer,
  222. StringRef Name) const {
  223. ListScope NodeScope(Writer, Name);
  224. for (auto const &Child : StringChildren) {
  225. Child.second->print(Writer, Child.first);
  226. }
  227. for (auto const &Child : IDChildren) {
  228. Child.second->print(Writer, to_string(Child.first));
  229. }
  230. }
  231. // This function returns the size of the entire resource tree, including
  232. // directory tables, directory entries, and data entries. It does not include
  233. // the directory strings or the relocations of the .rsrc section.
  234. uint32_t WindowsResourceParser::TreeNode::getTreeSize() const {
  235. uint32_t Size = (IDChildren.size() + StringChildren.size()) *
  236. sizeof(coff_resource_dir_entry);
  237. // Reached a node pointing to a data entry.
  238. if (IsDataNode) {
  239. Size += sizeof(coff_resource_data_entry);
  240. return Size;
  241. }
  242. // If the node does not point to data, it must have a directory table pointing
  243. // to other nodes.
  244. Size += sizeof(coff_resource_dir_table);
  245. for (auto const &Child : StringChildren) {
  246. Size += Child.second->getTreeSize();
  247. }
  248. for (auto const &Child : IDChildren) {
  249. Size += Child.second->getTreeSize();
  250. }
  251. return Size;
  252. }
  253. class WindowsResourceCOFFWriter {
  254. public:
  255. WindowsResourceCOFFWriter(COFF::MachineTypes MachineType,
  256. const WindowsResourceParser &Parser, Error &E);
  257. std::unique_ptr<MemoryBuffer> write();
  258. private:
  259. void performFileLayout();
  260. void performSectionOneLayout();
  261. void performSectionTwoLayout();
  262. void writeCOFFHeader();
  263. void writeFirstSectionHeader();
  264. void writeSecondSectionHeader();
  265. void writeFirstSection();
  266. void writeSecondSection();
  267. void writeSymbolTable();
  268. void writeStringTable();
  269. void writeDirectoryTree();
  270. void writeDirectoryStringTable();
  271. void writeFirstSectionRelocations();
  272. std::unique_ptr<MemoryBuffer> OutputBuffer;
  273. char *BufferStart;
  274. uint64_t CurrentOffset = 0;
  275. COFF::MachineTypes MachineType;
  276. const WindowsResourceParser::TreeNode &Resources;
  277. const ArrayRef<std::vector<uint8_t>> Data;
  278. uint64_t FileSize;
  279. uint32_t SymbolTableOffset;
  280. uint32_t SectionOneSize;
  281. uint32_t SectionOneOffset;
  282. uint32_t SectionOneRelocations;
  283. uint32_t SectionTwoSize;
  284. uint32_t SectionTwoOffset;
  285. const ArrayRef<std::vector<UTF16>> StringTable;
  286. std::vector<uint32_t> StringTableOffsets;
  287. std::vector<uint32_t> DataOffsets;
  288. std::vector<uint32_t> RelocationAddresses;
  289. };
  290. WindowsResourceCOFFWriter::WindowsResourceCOFFWriter(
  291. COFF::MachineTypes MachineType, const WindowsResourceParser &Parser,
  292. Error &E)
  293. : MachineType(MachineType), Resources(Parser.getTree()),
  294. Data(Parser.getData()), StringTable(Parser.getStringTable()) {
  295. performFileLayout();
  296. OutputBuffer = MemoryBuffer::getNewMemBuffer(FileSize);
  297. }
  298. void WindowsResourceCOFFWriter::performFileLayout() {
  299. // Add size of COFF header.
  300. FileSize = COFF::Header16Size;
  301. // one .rsrc section header for directory tree, another for resource data.
  302. FileSize += 2 * COFF::SectionSize;
  303. performSectionOneLayout();
  304. performSectionTwoLayout();
  305. // We have reached the address of the symbol table.
  306. SymbolTableOffset = FileSize;
  307. FileSize += COFF::Symbol16Size; // size of the @feat.00 symbol.
  308. FileSize += 4 * COFF::Symbol16Size; // symbol + aux for each section.
  309. FileSize += Data.size() * COFF::Symbol16Size; // 1 symbol per resource.
  310. FileSize += 4; // four null bytes for the string table.
  311. }
  312. void WindowsResourceCOFFWriter::performSectionOneLayout() {
  313. SectionOneOffset = FileSize;
  314. SectionOneSize = Resources.getTreeSize();
  315. uint32_t CurrentStringOffset = SectionOneSize;
  316. uint32_t TotalStringTableSize = 0;
  317. for (auto const &String : StringTable) {
  318. StringTableOffsets.push_back(CurrentStringOffset);
  319. uint32_t StringSize = String.size() * sizeof(UTF16) + sizeof(uint16_t);
  320. CurrentStringOffset += StringSize;
  321. TotalStringTableSize += StringSize;
  322. }
  323. SectionOneSize += alignTo(TotalStringTableSize, sizeof(uint32_t));
  324. // account for the relocations of section one.
  325. SectionOneRelocations = FileSize + SectionOneSize;
  326. FileSize += SectionOneSize;
  327. FileSize +=
  328. Data.size() * COFF::RelocationSize; // one relocation for each resource.
  329. FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
  330. }
  331. void WindowsResourceCOFFWriter::performSectionTwoLayout() {
  332. // add size of .rsrc$2 section, which contains all resource data on 8-byte
  333. // alignment.
  334. SectionTwoOffset = FileSize;
  335. SectionTwoSize = 0;
  336. for (auto const &Entry : Data) {
  337. DataOffsets.push_back(SectionTwoSize);
  338. SectionTwoSize += alignTo(Entry.size(), sizeof(uint64_t));
  339. }
  340. FileSize += SectionTwoSize;
  341. FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
  342. }
  343. static std::time_t getTime() {
  344. std::time_t Now = time(nullptr);
  345. if (Now < 0 || !isUInt<32>(Now))
  346. return UINT32_MAX;
  347. return Now;
  348. }
  349. std::unique_ptr<MemoryBuffer> WindowsResourceCOFFWriter::write() {
  350. BufferStart = const_cast<char *>(OutputBuffer->getBufferStart());
  351. writeCOFFHeader();
  352. writeFirstSectionHeader();
  353. writeSecondSectionHeader();
  354. writeFirstSection();
  355. writeSecondSection();
  356. writeSymbolTable();
  357. writeStringTable();
  358. return std::move(OutputBuffer);
  359. }
  360. void WindowsResourceCOFFWriter::writeCOFFHeader() {
  361. // Write the COFF header.
  362. auto *Header = reinterpret_cast<coff_file_header *>(BufferStart);
  363. switch (MachineType) {
  364. case COFF::IMAGE_FILE_MACHINE_ARMNT:
  365. Header->Machine = COFF::IMAGE_FILE_MACHINE_ARMNT;
  366. break;
  367. case COFF::IMAGE_FILE_MACHINE_AMD64:
  368. Header->Machine = COFF::IMAGE_FILE_MACHINE_AMD64;
  369. break;
  370. case COFF::IMAGE_FILE_MACHINE_I386:
  371. Header->Machine = COFF::IMAGE_FILE_MACHINE_I386;
  372. break;
  373. default:
  374. Header->Machine = COFF::IMAGE_FILE_MACHINE_UNKNOWN;
  375. }
  376. Header->NumberOfSections = 2;
  377. Header->TimeDateStamp = getTime();
  378. Header->PointerToSymbolTable = SymbolTableOffset;
  379. // One symbol for every resource plus 2 for each section and @feat.00
  380. Header->NumberOfSymbols = Data.size() + 5;
  381. Header->SizeOfOptionalHeader = 0;
  382. Header->Characteristics = COFF::IMAGE_FILE_32BIT_MACHINE;
  383. }
  384. void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
  385. // Write the first section header.
  386. CurrentOffset += sizeof(coff_file_header);
  387. auto *SectionOneHeader =
  388. reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
  389. strncpy(SectionOneHeader->Name, ".rsrc$01", (size_t)COFF::NameSize);
  390. SectionOneHeader->VirtualSize = 0;
  391. SectionOneHeader->VirtualAddress = 0;
  392. SectionOneHeader->SizeOfRawData = SectionOneSize;
  393. SectionOneHeader->PointerToRawData = SectionOneOffset;
  394. SectionOneHeader->PointerToRelocations = SectionOneRelocations;
  395. SectionOneHeader->PointerToLinenumbers = 0;
  396. SectionOneHeader->NumberOfRelocations = Data.size();
  397. SectionOneHeader->NumberOfLinenumbers = 0;
  398. SectionOneHeader->Characteristics = COFF::IMAGE_SCN_ALIGN_1BYTES;
  399. SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
  400. SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
  401. SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
  402. }
  403. void WindowsResourceCOFFWriter::writeSecondSectionHeader() {
  404. // Write the second section header.
  405. CurrentOffset += sizeof(coff_section);
  406. auto *SectionTwoHeader =
  407. reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
  408. strncpy(SectionTwoHeader->Name, ".rsrc$02", (size_t)COFF::NameSize);
  409. SectionTwoHeader->VirtualSize = 0;
  410. SectionTwoHeader->VirtualAddress = 0;
  411. SectionTwoHeader->SizeOfRawData = SectionTwoSize;
  412. SectionTwoHeader->PointerToRawData = SectionTwoOffset;
  413. SectionTwoHeader->PointerToRelocations = 0;
  414. SectionTwoHeader->PointerToLinenumbers = 0;
  415. SectionTwoHeader->NumberOfRelocations = 0;
  416. SectionTwoHeader->NumberOfLinenumbers = 0;
  417. SectionTwoHeader->Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
  418. SectionTwoHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
  419. }
  420. void WindowsResourceCOFFWriter::writeFirstSection() {
  421. // Write section one.
  422. CurrentOffset += sizeof(coff_section);
  423. writeDirectoryTree();
  424. writeDirectoryStringTable();
  425. writeFirstSectionRelocations();
  426. CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
  427. }
  428. void WindowsResourceCOFFWriter::writeSecondSection() {
  429. // Now write the .rsrc$02 section.
  430. for (auto const &RawDataEntry : Data) {
  431. std::copy(RawDataEntry.begin(), RawDataEntry.end(),
  432. BufferStart + CurrentOffset);
  433. CurrentOffset += alignTo(RawDataEntry.size(), sizeof(uint64_t));
  434. }
  435. CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
  436. }
  437. void WindowsResourceCOFFWriter::writeSymbolTable() {
  438. // Now write the symbol table.
  439. // First, the feat symbol.
  440. auto *Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
  441. strncpy(Symbol->Name.ShortName, "@feat.00", (size_t)COFF::NameSize);
  442. Symbol->Value = 0x11;
  443. Symbol->SectionNumber = 0xffff;
  444. Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
  445. Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
  446. Symbol->NumberOfAuxSymbols = 0;
  447. CurrentOffset += sizeof(coff_symbol16);
  448. // Now write the .rsrc1 symbol + aux.
  449. Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
  450. strncpy(Symbol->Name.ShortName, ".rsrc$01", (size_t)COFF::NameSize);
  451. Symbol->Value = 0;
  452. Symbol->SectionNumber = 1;
  453. Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
  454. Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
  455. Symbol->NumberOfAuxSymbols = 1;
  456. CurrentOffset += sizeof(coff_symbol16);
  457. auto *Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
  458. CurrentOffset);
  459. Aux->Length = SectionOneSize;
  460. Aux->NumberOfRelocations = Data.size();
  461. Aux->NumberOfLinenumbers = 0;
  462. Aux->CheckSum = 0;
  463. Aux->NumberLowPart = 0;
  464. Aux->Selection = 0;
  465. CurrentOffset += sizeof(coff_aux_section_definition);
  466. // Now write the .rsrc2 symbol + aux.
  467. Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
  468. strncpy(Symbol->Name.ShortName, ".rsrc$02", (size_t)COFF::NameSize);
  469. Symbol->Value = 0;
  470. Symbol->SectionNumber = 2;
  471. Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
  472. Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
  473. Symbol->NumberOfAuxSymbols = 1;
  474. CurrentOffset += sizeof(coff_symbol16);
  475. Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
  476. CurrentOffset);
  477. Aux->Length = SectionTwoSize;
  478. Aux->NumberOfRelocations = 0;
  479. Aux->NumberOfLinenumbers = 0;
  480. Aux->CheckSum = 0;
  481. Aux->NumberLowPart = 0;
  482. Aux->Selection = 0;
  483. CurrentOffset += sizeof(coff_aux_section_definition);
  484. // Now write a symbol for each relocation.
  485. for (unsigned i = 0; i < Data.size(); i++) {
  486. char RelocationName[9];
  487. sprintf(RelocationName, "$R%06X", DataOffsets[i]);
  488. Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
  489. strncpy(Symbol->Name.ShortName, RelocationName, (size_t)COFF::NameSize);
  490. Symbol->Value = DataOffsets[i];
  491. Symbol->SectionNumber = 1;
  492. Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
  493. Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
  494. Symbol->NumberOfAuxSymbols = 0;
  495. CurrentOffset += sizeof(coff_symbol16);
  496. }
  497. }
  498. void WindowsResourceCOFFWriter::writeStringTable() {
  499. // Just 4 null bytes for the string table.
  500. auto COFFStringTable = reinterpret_cast<void *>(BufferStart + CurrentOffset);
  501. memset(COFFStringTable, 0, 4);
  502. }
  503. void WindowsResourceCOFFWriter::writeDirectoryTree() {
  504. // Traverse parsed resource tree breadth-first and write the corresponding
  505. // COFF objects.
  506. std::queue<const WindowsResourceParser::TreeNode *> Queue;
  507. Queue.push(&Resources);
  508. uint32_t NextLevelOffset =
  509. sizeof(coff_resource_dir_table) + (Resources.getStringChildren().size() +
  510. Resources.getIDChildren().size()) *
  511. sizeof(coff_resource_dir_entry);
  512. std::vector<const WindowsResourceParser::TreeNode *> DataEntriesTreeOrder;
  513. uint32_t CurrentRelativeOffset = 0;
  514. while (!Queue.empty()) {
  515. auto CurrentNode = Queue.front();
  516. Queue.pop();
  517. auto *Table = reinterpret_cast<coff_resource_dir_table *>(BufferStart +
  518. CurrentOffset);
  519. Table->Characteristics = CurrentNode->getCharacteristics();
  520. Table->TimeDateStamp = 0;
  521. Table->MajorVersion = CurrentNode->getMajorVersion();
  522. Table->MinorVersion = CurrentNode->getMinorVersion();
  523. auto &IDChildren = CurrentNode->getIDChildren();
  524. auto &StringChildren = CurrentNode->getStringChildren();
  525. Table->NumberOfNameEntries = StringChildren.size();
  526. Table->NumberOfIDEntries = IDChildren.size();
  527. CurrentOffset += sizeof(coff_resource_dir_table);
  528. CurrentRelativeOffset += sizeof(coff_resource_dir_table);
  529. // Write the directory entries immediately following each directory table.
  530. for (auto const &Child : StringChildren) {
  531. auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
  532. CurrentOffset);
  533. Entry->Identifier.NameOffset =
  534. StringTableOffsets[Child.second->getStringIndex()];
  535. if (Child.second->checkIsDataNode()) {
  536. Entry->Offset.DataEntryOffset = NextLevelOffset;
  537. NextLevelOffset += sizeof(coff_resource_data_entry);
  538. DataEntriesTreeOrder.push_back(Child.second.get());
  539. } else {
  540. Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
  541. NextLevelOffset += sizeof(coff_resource_dir_table) +
  542. (Child.second->getStringChildren().size() +
  543. Child.second->getIDChildren().size()) *
  544. sizeof(coff_resource_dir_entry);
  545. Queue.push(Child.second.get());
  546. }
  547. CurrentOffset += sizeof(coff_resource_dir_entry);
  548. CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
  549. }
  550. for (auto const &Child : IDChildren) {
  551. auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
  552. CurrentOffset);
  553. Entry->Identifier.ID = Child.first;
  554. if (Child.second->checkIsDataNode()) {
  555. Entry->Offset.DataEntryOffset = NextLevelOffset;
  556. NextLevelOffset += sizeof(coff_resource_data_entry);
  557. DataEntriesTreeOrder.push_back(Child.second.get());
  558. } else {
  559. Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
  560. NextLevelOffset += sizeof(coff_resource_dir_table) +
  561. (Child.second->getStringChildren().size() +
  562. Child.second->getIDChildren().size()) *
  563. sizeof(coff_resource_dir_entry);
  564. Queue.push(Child.second.get());
  565. }
  566. CurrentOffset += sizeof(coff_resource_dir_entry);
  567. CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
  568. }
  569. }
  570. RelocationAddresses.resize(Data.size());
  571. // Now write all the resource data entries.
  572. for (auto DataNodes : DataEntriesTreeOrder) {
  573. auto *Entry = reinterpret_cast<coff_resource_data_entry *>(BufferStart +
  574. CurrentOffset);
  575. RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset;
  576. Entry->DataRVA = 0; // Set to zero because it is a relocation.
  577. Entry->DataSize = Data[DataNodes->getDataIndex()].size();
  578. Entry->Codepage = 0;
  579. Entry->Reserved = 0;
  580. CurrentOffset += sizeof(coff_resource_data_entry);
  581. CurrentRelativeOffset += sizeof(coff_resource_data_entry);
  582. }
  583. }
  584. void WindowsResourceCOFFWriter::writeDirectoryStringTable() {
  585. // Now write the directory string table for .rsrc$01
  586. uint32_t TotalStringTableSize = 0;
  587. for (auto &String : StringTable) {
  588. uint16_t Length = String.size();
  589. support::endian::write16le(BufferStart + CurrentOffset, Length);
  590. CurrentOffset += sizeof(uint16_t);
  591. auto *Start = reinterpret_cast<UTF16 *>(BufferStart + CurrentOffset);
  592. std::copy(String.begin(), String.end(), Start);
  593. CurrentOffset += Length * sizeof(UTF16);
  594. TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t);
  595. }
  596. CurrentOffset +=
  597. alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize;
  598. }
  599. void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {
  600. // Now write the relocations for .rsrc$01
  601. // Five symbols already in table before we start, @feat.00 and 2 for each
  602. // .rsrc section.
  603. uint32_t NextSymbolIndex = 5;
  604. for (unsigned i = 0; i < Data.size(); i++) {
  605. auto *Reloc =
  606. reinterpret_cast<coff_relocation *>(BufferStart + CurrentOffset);
  607. Reloc->VirtualAddress = RelocationAddresses[i];
  608. Reloc->SymbolTableIndex = NextSymbolIndex++;
  609. switch (MachineType) {
  610. case COFF::IMAGE_FILE_MACHINE_ARMNT:
  611. Reloc->Type = COFF::IMAGE_REL_ARM_ADDR32NB;
  612. break;
  613. case COFF::IMAGE_FILE_MACHINE_AMD64:
  614. Reloc->Type = COFF::IMAGE_REL_AMD64_ADDR32NB;
  615. break;
  616. case COFF::IMAGE_FILE_MACHINE_I386:
  617. Reloc->Type = COFF::IMAGE_REL_I386_DIR32NB;
  618. break;
  619. default:
  620. Reloc->Type = 0;
  621. }
  622. CurrentOffset += sizeof(coff_relocation);
  623. }
  624. }
  625. Expected<std::unique_ptr<MemoryBuffer>>
  626. writeWindowsResourceCOFF(COFF::MachineTypes MachineType,
  627. const WindowsResourceParser &Parser) {
  628. Error E = Error::success();
  629. WindowsResourceCOFFWriter Writer(MachineType, Parser, E);
  630. if (E)
  631. return std::move(E);
  632. return Writer.write();
  633. }
  634. } // namespace object
  635. } // namespace llvm