WindowsResource.cpp 26 KB

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