XCOFFEmitter.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  1. //===- yaml2xcoff - Convert YAML to a xcoff object file -------------------===//
  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. /// \file
  10. /// The xcoff component of yaml2obj.
  11. ///
  12. //===----------------------------------------------------------------------===//
  13. #include "llvm/ADT/DenseMap.h"
  14. #include "llvm/BinaryFormat/XCOFF.h"
  15. #include "llvm/MC/StringTableBuilder.h"
  16. #include "llvm/Object/XCOFFObjectFile.h"
  17. #include "llvm/ObjectYAML/ObjectYAML.h"
  18. #include "llvm/ObjectYAML/yaml2obj.h"
  19. #include "llvm/Support/EndianStream.h"
  20. #include "llvm/Support/LEB128.h"
  21. #include "llvm/Support/MemoryBuffer.h"
  22. #include "llvm/Support/raw_ostream.h"
  23. using namespace llvm;
  24. namespace {
  25. constexpr unsigned DefaultSectionAlign = 4;
  26. constexpr int16_t MaxSectionIndex = INT16_MAX;
  27. constexpr uint32_t MaxRawDataSize = UINT32_MAX;
  28. class XCOFFWriter {
  29. public:
  30. XCOFFWriter(XCOFFYAML::Object &Obj, raw_ostream &OS, yaml::ErrorHandler EH)
  31. : Obj(Obj), W(OS, support::big), ErrHandler(EH),
  32. StrTblBuilder(StringTableBuilder::XCOFF) {
  33. Is64Bit = Obj.Header.Magic == (llvm::yaml::Hex16)XCOFF::XCOFF64;
  34. }
  35. bool writeXCOFF();
  36. private:
  37. bool nameShouldBeInStringTable(StringRef SymbolName);
  38. bool initFileHeader(uint64_t CurrentOffset);
  39. void initAuxFileHeader();
  40. bool initSectionHeader(uint64_t &CurrentOffset);
  41. bool initRelocations(uint64_t &CurrentOffset);
  42. bool initStringTable();
  43. bool assignAddressesAndIndices();
  44. void writeFileHeader();
  45. void writeAuxFileHeader();
  46. void writeSectionHeader();
  47. bool writeSectionData();
  48. bool writeRelocations();
  49. bool writeSymbols();
  50. void writeStringTable();
  51. void writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym);
  52. void writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym);
  53. void writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym);
  54. void writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym);
  55. void writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym);
  56. void writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym);
  57. void writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym);
  58. void writeAuxSymbol(const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym);
  59. XCOFFYAML::Object &Obj;
  60. bool Is64Bit = false;
  61. support::endian::Writer W;
  62. yaml::ErrorHandler ErrHandler;
  63. StringTableBuilder StrTblBuilder;
  64. uint64_t StartOffset;
  65. // Map the section name to its corrresponding section index.
  66. DenseMap<StringRef, int16_t> SectionIndexMap = {
  67. {StringRef("N_DEBUG"), XCOFF::N_DEBUG},
  68. {StringRef("N_ABS"), XCOFF::N_ABS},
  69. {StringRef("N_UNDEF"), XCOFF::N_UNDEF}};
  70. XCOFFYAML::FileHeader InitFileHdr = Obj.Header;
  71. XCOFFYAML::AuxiliaryHeader InitAuxFileHdr;
  72. std::vector<XCOFFYAML::Section> InitSections = Obj.Sections;
  73. };
  74. static void writeName(StringRef StrName, support::endian::Writer W) {
  75. char Name[XCOFF::NameSize];
  76. memset(Name, 0, XCOFF::NameSize);
  77. char SrcName[] = "";
  78. memcpy(Name, StrName.size() ? StrName.data() : SrcName, StrName.size());
  79. ArrayRef<char> NameRef(Name, XCOFF::NameSize);
  80. W.write(NameRef);
  81. }
  82. bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) {
  83. // For XCOFF64: The symbol name is always in the string table.
  84. return (SymbolName.size() > XCOFF::NameSize) || Is64Bit;
  85. }
  86. bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) {
  87. for (XCOFFYAML::Section &InitSection : InitSections) {
  88. if (!InitSection.Relocations.empty()) {
  89. InitSection.NumberOfRelocations = InitSection.Relocations.size();
  90. InitSection.FileOffsetToRelocations = CurrentOffset;
  91. uint64_t RelSize = Is64Bit ? XCOFF::RelocationSerializationSize64
  92. : XCOFF::RelocationSerializationSize32;
  93. CurrentOffset += InitSection.NumberOfRelocations * RelSize;
  94. if (CurrentOffset > MaxRawDataSize) {
  95. ErrHandler("maximum object size of" + Twine(MaxRawDataSize) +
  96. "exceeded when writing relocation data");
  97. return false;
  98. }
  99. }
  100. }
  101. return true;
  102. }
  103. bool XCOFFWriter::initSectionHeader(uint64_t &CurrentOffset) {
  104. uint64_t CurrentSecAddr = 0;
  105. for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {
  106. if (CurrentOffset > MaxRawDataSize) {
  107. ErrHandler("maximum object size of" + Twine(MaxRawDataSize) +
  108. "exceeded when writing section data");
  109. return false;
  110. }
  111. // Assign indices for sections.
  112. if (InitSections[I].SectionName.size() &&
  113. !SectionIndexMap[InitSections[I].SectionName]) {
  114. // The section index starts from 1.
  115. SectionIndexMap[InitSections[I].SectionName] = I + 1;
  116. if ((I + 1) > MaxSectionIndex) {
  117. ErrHandler("exceeded the maximum permitted section index of " +
  118. Twine(MaxSectionIndex));
  119. return false;
  120. }
  121. }
  122. // Calculate the physical/virtual address. This field should contain 0 for
  123. // all sections except the text, data and bss sections.
  124. if (InitSections[I].Flags != XCOFF::STYP_TEXT &&
  125. InitSections[I].Flags != XCOFF::STYP_DATA &&
  126. InitSections[I].Flags != XCOFF::STYP_BSS)
  127. InitSections[I].Address = 0;
  128. else
  129. InitSections[I].Address = CurrentSecAddr;
  130. // Calculate the FileOffsetToData and data size for sections.
  131. if (InitSections[I].SectionData.binary_size()) {
  132. InitSections[I].FileOffsetToData = CurrentOffset;
  133. CurrentOffset += InitSections[I].SectionData.binary_size();
  134. // Ensure the offset is aligned to DefaultSectionAlign.
  135. CurrentOffset = alignTo(CurrentOffset, DefaultSectionAlign);
  136. InitSections[I].Size = CurrentOffset - InitSections[I].FileOffsetToData;
  137. CurrentSecAddr += InitSections[I].Size;
  138. }
  139. }
  140. return initRelocations(CurrentOffset);
  141. }
  142. bool XCOFFWriter::initStringTable() {
  143. if (Obj.StrTbl.RawContent) {
  144. size_t RawSize = Obj.StrTbl.RawContent->binary_size();
  145. if (Obj.StrTbl.Strings || Obj.StrTbl.Length) {
  146. ErrHandler(
  147. "can't specify Strings or Length when RawContent is specified");
  148. return false;
  149. }
  150. if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < RawSize) {
  151. ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) +
  152. ") is less than the RawContent data size (" + Twine(RawSize) +
  153. ")");
  154. return false;
  155. }
  156. return true;
  157. }
  158. if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize <= 3) {
  159. ErrHandler("ContentSize shouldn't be less than 4 without RawContent");
  160. return false;
  161. }
  162. // Build the string table.
  163. StrTblBuilder.clear();
  164. if (Obj.StrTbl.Strings) {
  165. // All specified strings should be added to the string table.
  166. for (StringRef StringEnt : *Obj.StrTbl.Strings)
  167. StrTblBuilder.add(StringEnt);
  168. size_t StrTblIdx = 0;
  169. size_t NumOfStrings = Obj.StrTbl.Strings->size();
  170. for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
  171. if (nameShouldBeInStringTable(YamlSym.SymbolName)) {
  172. if (StrTblIdx < NumOfStrings) {
  173. // Overwrite the symbol name with the specified string.
  174. YamlSym.SymbolName = (*Obj.StrTbl.Strings)[StrTblIdx];
  175. ++StrTblIdx;
  176. } else
  177. // Names that are not overwritten are still stored in the string
  178. // table.
  179. StrTblBuilder.add(YamlSym.SymbolName);
  180. }
  181. }
  182. } else {
  183. for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
  184. if (nameShouldBeInStringTable(YamlSym.SymbolName))
  185. StrTblBuilder.add(YamlSym.SymbolName);
  186. }
  187. }
  188. // Check if the file name in the File Auxiliary Entry should be added to the
  189. // string table.
  190. for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
  191. for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym :
  192. YamlSym.AuxEntries) {
  193. if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get()))
  194. if (nameShouldBeInStringTable(AS->FileNameOrString.value_or("")))
  195. StrTblBuilder.add(AS->FileNameOrString.value_or(""));
  196. }
  197. }
  198. StrTblBuilder.finalize();
  199. size_t StrTblSize = StrTblBuilder.getSize();
  200. if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < StrTblSize) {
  201. ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) +
  202. ") is less than the size of the data that would otherwise be "
  203. "written (" +
  204. Twine(StrTblSize) + ")");
  205. return false;
  206. }
  207. return true;
  208. }
  209. bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset) {
  210. // The default format of the object file is XCOFF32.
  211. InitFileHdr.Magic = XCOFF::XCOFF32;
  212. InitFileHdr.NumberOfSections = Obj.Sections.size();
  213. InitFileHdr.NumberOfSymTableEntries = Obj.Symbols.size();
  214. for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
  215. uint32_t AuxCount = YamlSym.AuxEntries.size();
  216. if (YamlSym.NumberOfAuxEntries && *YamlSym.NumberOfAuxEntries < AuxCount) {
  217. ErrHandler("specified NumberOfAuxEntries " +
  218. Twine(static_cast<uint32_t>(*YamlSym.NumberOfAuxEntries)) +
  219. " is less than the actual number "
  220. "of auxiliary entries " +
  221. Twine(AuxCount));
  222. return false;
  223. }
  224. YamlSym.NumberOfAuxEntries = YamlSym.NumberOfAuxEntries.value_or(AuxCount);
  225. // Add the number of auxiliary symbols to the total number.
  226. InitFileHdr.NumberOfSymTableEntries += *YamlSym.NumberOfAuxEntries;
  227. }
  228. // Calculate SymbolTableOffset for the file header.
  229. if (InitFileHdr.NumberOfSymTableEntries) {
  230. InitFileHdr.SymbolTableOffset = CurrentOffset;
  231. CurrentOffset +=
  232. InitFileHdr.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize;
  233. if (CurrentOffset > MaxRawDataSize) {
  234. ErrHandler("maximum object size of" + Twine(MaxRawDataSize) +
  235. "exceeded when writing symbols");
  236. return false;
  237. }
  238. }
  239. // TODO: Calculate FileOffsetToLineNumbers when line number supported.
  240. return true;
  241. }
  242. void XCOFFWriter::initAuxFileHeader() {
  243. InitAuxFileHdr = *Obj.AuxHeader;
  244. // In general, an object file might contain multiple sections of a given type,
  245. // but in a loadable module, there must be exactly one .text, .data, .bss, and
  246. // .loader section. A loadable object might also have one .tdata section and
  247. // one .tbss section.
  248. // Set these section-related values if not set explicitly. We assume that the
  249. // input YAML matches the format of the loadable object, but if multiple input
  250. // sections still have the same type, the first section with that type
  251. // prevails.
  252. for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {
  253. switch (InitSections[I].Flags) {
  254. case XCOFF::STYP_TEXT:
  255. if (!InitAuxFileHdr.TextSize)
  256. InitAuxFileHdr.TextSize = InitSections[I].Size;
  257. if (!InitAuxFileHdr.TextStartAddr)
  258. InitAuxFileHdr.TextStartAddr = InitSections[I].Address;
  259. if (!InitAuxFileHdr.SecNumOfText)
  260. InitAuxFileHdr.SecNumOfText = I + 1;
  261. break;
  262. case XCOFF::STYP_DATA:
  263. if (!InitAuxFileHdr.InitDataSize)
  264. InitAuxFileHdr.InitDataSize = InitSections[I].Size;
  265. if (!InitAuxFileHdr.DataStartAddr)
  266. InitAuxFileHdr.DataStartAddr = InitSections[I].Address;
  267. if (!InitAuxFileHdr.SecNumOfData)
  268. InitAuxFileHdr.SecNumOfData = I + 1;
  269. break;
  270. case XCOFF::STYP_BSS:
  271. if (!InitAuxFileHdr.BssDataSize)
  272. InitAuxFileHdr.BssDataSize = InitSections[I].Size;
  273. if (!InitAuxFileHdr.SecNumOfBSS)
  274. InitAuxFileHdr.SecNumOfBSS = I + 1;
  275. break;
  276. case XCOFF::STYP_TDATA:
  277. if (!InitAuxFileHdr.SecNumOfTData)
  278. InitAuxFileHdr.SecNumOfTData = I + 1;
  279. break;
  280. case XCOFF::STYP_TBSS:
  281. if (!InitAuxFileHdr.SecNumOfTBSS)
  282. InitAuxFileHdr.SecNumOfTBSS = I + 1;
  283. break;
  284. case XCOFF::STYP_LOADER:
  285. if (!InitAuxFileHdr.SecNumOfLoader)
  286. InitAuxFileHdr.SecNumOfLoader = I + 1;
  287. break;
  288. default:
  289. break;
  290. }
  291. }
  292. }
  293. bool XCOFFWriter::assignAddressesAndIndices() {
  294. uint64_t FileHdrSize =
  295. Is64Bit ? XCOFF::FileHeaderSize64 : XCOFF::FileHeaderSize32;
  296. uint64_t AuxFileHdrSize = 0;
  297. if (Obj.AuxHeader)
  298. AuxFileHdrSize = Obj.Header.AuxHeaderSize
  299. ? Obj.Header.AuxHeaderSize
  300. : (Is64Bit ? XCOFF::AuxFileHeaderSize64
  301. : XCOFF::AuxFileHeaderSize32);
  302. uint64_t SecHdrSize =
  303. Is64Bit ? XCOFF::SectionHeaderSize64 : XCOFF::SectionHeaderSize32;
  304. uint64_t CurrentOffset =
  305. FileHdrSize + AuxFileHdrSize + InitSections.size() * SecHdrSize;
  306. // Calculate section header info.
  307. if (!initSectionHeader(CurrentOffset))
  308. return false;
  309. InitFileHdr.AuxHeaderSize = AuxFileHdrSize;
  310. // Calculate file header info.
  311. if (!initFileHeader(CurrentOffset))
  312. return false;
  313. // Initialize the auxiliary file header.
  314. if (Obj.AuxHeader)
  315. initAuxFileHeader();
  316. // Initialize the string table.
  317. return initStringTable();
  318. }
  319. void XCOFFWriter::writeFileHeader() {
  320. W.write<uint16_t>(Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic);
  321. W.write<uint16_t>(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections
  322. : InitFileHdr.NumberOfSections);
  323. W.write<int32_t>(Obj.Header.TimeStamp);
  324. if (Is64Bit) {
  325. W.write<uint64_t>(Obj.Header.SymbolTableOffset
  326. ? Obj.Header.SymbolTableOffset
  327. : InitFileHdr.SymbolTableOffset);
  328. W.write<uint16_t>(InitFileHdr.AuxHeaderSize);
  329. W.write<uint16_t>(Obj.Header.Flags);
  330. W.write<int32_t>(Obj.Header.NumberOfSymTableEntries
  331. ? Obj.Header.NumberOfSymTableEntries
  332. : InitFileHdr.NumberOfSymTableEntries);
  333. } else {
  334. W.write<uint32_t>(Obj.Header.SymbolTableOffset
  335. ? Obj.Header.SymbolTableOffset
  336. : InitFileHdr.SymbolTableOffset);
  337. W.write<int32_t>(Obj.Header.NumberOfSymTableEntries
  338. ? Obj.Header.NumberOfSymTableEntries
  339. : InitFileHdr.NumberOfSymTableEntries);
  340. W.write<uint16_t>(InitFileHdr.AuxHeaderSize);
  341. W.write<uint16_t>(Obj.Header.Flags);
  342. }
  343. }
  344. void XCOFFWriter::writeAuxFileHeader() {
  345. W.write<uint16_t>(InitAuxFileHdr.Magic.value_or(yaml::Hex16(1)));
  346. W.write<uint16_t>(InitAuxFileHdr.Version.value_or(yaml::Hex16(1)));
  347. if (Is64Bit) {
  348. W.OS.write_zeros(4); // Reserved for debugger.
  349. W.write<uint64_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0)));
  350. W.write<uint64_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0)));
  351. W.write<uint64_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0)));
  352. } else {
  353. W.write<uint32_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0)));
  354. W.write<uint32_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0)));
  355. W.write<uint32_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0)));
  356. W.write<uint32_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0)));
  357. W.write<uint32_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0)));
  358. W.write<uint32_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0)));
  359. W.write<uint32_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0)));
  360. }
  361. W.write<uint16_t>(InitAuxFileHdr.SecNumOfEntryPoint.value_or(0));
  362. W.write<uint16_t>(InitAuxFileHdr.SecNumOfText.value_or(0));
  363. W.write<uint16_t>(InitAuxFileHdr.SecNumOfData.value_or(0));
  364. W.write<uint16_t>(InitAuxFileHdr.SecNumOfTOC.value_or(0));
  365. W.write<uint16_t>(InitAuxFileHdr.SecNumOfLoader.value_or(0));
  366. W.write<uint16_t>(InitAuxFileHdr.SecNumOfBSS.value_or(0));
  367. W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfText.value_or(yaml::Hex16(0)));
  368. W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfData.value_or(yaml::Hex16(0)));
  369. W.write<uint16_t>(InitAuxFileHdr.ModuleType.value_or(yaml::Hex16(0)));
  370. W.write<uint8_t>(InitAuxFileHdr.CpuFlag.value_or(yaml::Hex8(0)));
  371. W.write<uint8_t>(0); // Reserved for CPU type.
  372. if (Is64Bit) {
  373. W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0)));
  374. W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0)));
  375. W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0)));
  376. W.write<uint8_t>(
  377. InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0x80)));
  378. W.write<uint64_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0)));
  379. W.write<uint64_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0)));
  380. W.write<uint64_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0)));
  381. W.write<uint64_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0)));
  382. W.write<uint64_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0)));
  383. W.write<uint64_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0)));
  384. } else {
  385. W.write<uint32_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0)));
  386. W.write<uint32_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0)));
  387. W.OS.write_zeros(4); // Reserved for debugger.
  388. W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0)));
  389. W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0)));
  390. W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0)));
  391. W.write<uint8_t>(
  392. InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0)));
  393. }
  394. W.write<uint16_t>(InitAuxFileHdr.SecNumOfTData.value_or(0));
  395. W.write<uint16_t>(InitAuxFileHdr.SecNumOfTBSS.value_or(0));
  396. if (Is64Bit) {
  397. W.write<uint16_t>(
  398. InitAuxFileHdr.Flag.value_or(yaml::Hex16(XCOFF::SHR_SYMTAB)));
  399. if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize64)
  400. W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize64);
  401. } else if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize32) {
  402. W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize32);
  403. }
  404. }
  405. void XCOFFWriter::writeSectionHeader() {
  406. for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {
  407. XCOFFYAML::Section YamlSec = Obj.Sections[I];
  408. XCOFFYAML::Section DerivedSec = InitSections[I];
  409. writeName(YamlSec.SectionName, W);
  410. // Virtual address is the same as physical address.
  411. uint64_t SectionAddress =
  412. YamlSec.Address ? YamlSec.Address : DerivedSec.Address;
  413. if (Is64Bit) {
  414. W.write<uint64_t>(SectionAddress); // Physical address
  415. W.write<uint64_t>(SectionAddress); // Virtual address
  416. W.write<uint64_t>(YamlSec.Size ? YamlSec.Size : DerivedSec.Size);
  417. W.write<uint64_t>(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData
  418. : DerivedSec.FileOffsetToData);
  419. W.write<uint64_t>(YamlSec.FileOffsetToRelocations
  420. ? YamlSec.FileOffsetToRelocations
  421. : DerivedSec.FileOffsetToRelocations);
  422. W.write<uint64_t>(YamlSec.FileOffsetToLineNumbers);
  423. W.write<uint32_t>(YamlSec.NumberOfRelocations
  424. ? YamlSec.NumberOfRelocations
  425. : DerivedSec.NumberOfRelocations);
  426. W.write<uint32_t>(YamlSec.NumberOfLineNumbers);
  427. W.write<int32_t>(YamlSec.Flags);
  428. W.OS.write_zeros(4);
  429. } else {
  430. W.write<uint32_t>(SectionAddress); // Physical address
  431. W.write<uint32_t>(SectionAddress); // Virtual address
  432. W.write<uint32_t>(YamlSec.Size ? YamlSec.Size : DerivedSec.Size);
  433. W.write<uint32_t>(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData
  434. : DerivedSec.FileOffsetToData);
  435. W.write<uint32_t>(YamlSec.FileOffsetToRelocations
  436. ? YamlSec.FileOffsetToRelocations
  437. : DerivedSec.FileOffsetToRelocations);
  438. W.write<uint32_t>(YamlSec.FileOffsetToLineNumbers);
  439. W.write<uint16_t>(YamlSec.NumberOfRelocations
  440. ? YamlSec.NumberOfRelocations
  441. : DerivedSec.NumberOfRelocations);
  442. W.write<uint16_t>(YamlSec.NumberOfLineNumbers);
  443. W.write<int32_t>(YamlSec.Flags);
  444. }
  445. }
  446. }
  447. bool XCOFFWriter::writeSectionData() {
  448. for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {
  449. XCOFFYAML::Section YamlSec = Obj.Sections[I];
  450. if (YamlSec.SectionData.binary_size()) {
  451. // Fill the padding size with zeros.
  452. int64_t PaddingSize =
  453. InitSections[I].FileOffsetToData - (W.OS.tell() - StartOffset);
  454. if (PaddingSize < 0) {
  455. ErrHandler("redundant data was written before section data");
  456. return false;
  457. }
  458. W.OS.write_zeros(PaddingSize);
  459. YamlSec.SectionData.writeAsBinary(W.OS);
  460. }
  461. }
  462. return true;
  463. }
  464. bool XCOFFWriter::writeRelocations() {
  465. for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {
  466. XCOFFYAML::Section YamlSec = Obj.Sections[I];
  467. if (!YamlSec.Relocations.empty()) {
  468. int64_t PaddingSize =
  469. InitSections[I].FileOffsetToRelocations - (W.OS.tell() - StartOffset);
  470. if (PaddingSize < 0) {
  471. ErrHandler("redundant data was written before relocations");
  472. return false;
  473. }
  474. W.OS.write_zeros(PaddingSize);
  475. for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) {
  476. if (Is64Bit)
  477. W.write<uint64_t>(YamlRel.VirtualAddress);
  478. else
  479. W.write<uint32_t>(YamlRel.VirtualAddress);
  480. W.write<uint32_t>(YamlRel.SymbolIndex);
  481. W.write<uint8_t>(YamlRel.Info);
  482. W.write<uint8_t>(YamlRel.Type);
  483. }
  484. }
  485. }
  486. return true;
  487. }
  488. void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym) {
  489. if (Is64Bit) {
  490. W.write<uint32_t>(AuxSym.SectionOrLengthLo.value_or(0));
  491. W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0));
  492. W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0));
  493. W.write<uint8_t>(AuxSym.SymbolAlignmentAndType.value_or(0));
  494. W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR));
  495. W.write<uint32_t>(AuxSym.SectionOrLengthHi.value_or(0));
  496. W.write<uint8_t>(0);
  497. W.write<uint8_t>(XCOFF::AUX_CSECT);
  498. } else {
  499. W.write<uint32_t>(AuxSym.SectionOrLength.value_or(0));
  500. W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0));
  501. W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0));
  502. W.write<uint8_t>(AuxSym.SymbolAlignmentAndType.value_or(0));
  503. W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR));
  504. W.write<uint32_t>(AuxSym.StabInfoIndex.value_or(0));
  505. W.write<uint16_t>(AuxSym.StabSectNum.value_or(0));
  506. }
  507. }
  508. void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym) {
  509. assert(Is64Bit && "can't write the exception auxiliary symbol for XCOFF32");
  510. W.write<uint64_t>(AuxSym.OffsetToExceptionTbl.value_or(0));
  511. W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0));
  512. W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0));
  513. W.write<uint8_t>(0);
  514. W.write<uint8_t>(XCOFF::AUX_EXCEPT);
  515. }
  516. void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym) {
  517. if (Is64Bit) {
  518. W.write<uint64_t>(AuxSym.PtrToLineNum.value_or(0));
  519. W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0));
  520. W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0));
  521. W.write<uint8_t>(0);
  522. W.write<uint8_t>(XCOFF::AUX_FCN);
  523. } else {
  524. W.write<uint32_t>(AuxSym.OffsetToExceptionTbl.value_or(0));
  525. W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0));
  526. W.write<uint32_t>(AuxSym.PtrToLineNum.value_or(0));
  527. W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0));
  528. W.OS.write_zeros(2);
  529. }
  530. }
  531. void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym) {
  532. StringRef FileName = AuxSym.FileNameOrString.value_or("");
  533. if (nameShouldBeInStringTable(FileName)) {
  534. W.write<int32_t>(0);
  535. W.write<uint32_t>(StrTblBuilder.getOffset(FileName));
  536. } else {
  537. writeName(FileName, W);
  538. }
  539. W.OS.write_zeros(XCOFF::FileNamePadSize);
  540. W.write<uint8_t>(AuxSym.FileStringType.value_or(XCOFF::XFT_FN));
  541. if (Is64Bit) {
  542. W.OS.write_zeros(2);
  543. W.write<uint8_t>(XCOFF::AUX_FILE);
  544. } else {
  545. W.OS.write_zeros(3);
  546. }
  547. }
  548. void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym) {
  549. if (Is64Bit) {
  550. W.write<uint32_t>(AuxSym.LineNum.value_or(0));
  551. W.OS.write_zeros(13);
  552. W.write<uint8_t>(XCOFF::AUX_SYM);
  553. } else {
  554. W.OS.write_zeros(2);
  555. W.write<uint16_t>(AuxSym.LineNumHi.value_or(0));
  556. W.write<uint16_t>(AuxSym.LineNumLo.value_or(0));
  557. W.OS.write_zeros(12);
  558. }
  559. }
  560. void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym) {
  561. if (Is64Bit) {
  562. W.write<uint64_t>(AuxSym.LengthOfSectionPortion.value_or(0));
  563. W.write<uint64_t>(AuxSym.NumberOfRelocEnt.value_or(0));
  564. W.write<uint8_t>(0);
  565. W.write<uint8_t>(XCOFF::AUX_SECT);
  566. } else {
  567. W.write<uint32_t>(AuxSym.LengthOfSectionPortion.value_or(0));
  568. W.OS.write_zeros(4);
  569. W.write<uint32_t>(AuxSym.NumberOfRelocEnt.value_or(0));
  570. W.OS.write_zeros(6);
  571. }
  572. }
  573. void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym) {
  574. assert(!Is64Bit && "can't write the stat auxiliary symbol for XCOFF64");
  575. W.write<uint32_t>(AuxSym.SectionLength.value_or(0));
  576. W.write<uint16_t>(AuxSym.NumberOfRelocEnt.value_or(0));
  577. W.write<uint16_t>(AuxSym.NumberOfLineNum.value_or(0));
  578. W.OS.write_zeros(10);
  579. }
  580. void XCOFFWriter::writeAuxSymbol(
  581. const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym) {
  582. if (auto AS = dyn_cast<XCOFFYAML::CsectAuxEnt>(AuxSym.get()))
  583. writeAuxSymbol(*AS);
  584. else if (auto AS = dyn_cast<XCOFFYAML::FunctionAuxEnt>(AuxSym.get()))
  585. writeAuxSymbol(*AS);
  586. else if (auto AS = dyn_cast<XCOFFYAML::ExcpetionAuxEnt>(AuxSym.get()))
  587. writeAuxSymbol(*AS);
  588. else if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get()))
  589. writeAuxSymbol(*AS);
  590. else if (auto AS = dyn_cast<XCOFFYAML::BlockAuxEnt>(AuxSym.get()))
  591. writeAuxSymbol(*AS);
  592. else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForDWARF>(AuxSym.get()))
  593. writeAuxSymbol(*AS);
  594. else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForStat>(AuxSym.get()))
  595. writeAuxSymbol(*AS);
  596. else
  597. llvm_unreachable("unknown auxiliary symbol type");
  598. }
  599. bool XCOFFWriter::writeSymbols() {
  600. int64_t PaddingSize =
  601. (uint64_t)InitFileHdr.SymbolTableOffset - (W.OS.tell() - StartOffset);
  602. if (PaddingSize < 0) {
  603. ErrHandler("redundant data was written before symbols");
  604. return false;
  605. }
  606. W.OS.write_zeros(PaddingSize);
  607. for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
  608. if (Is64Bit) {
  609. W.write<uint64_t>(YamlSym.Value);
  610. W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName));
  611. } else {
  612. if (nameShouldBeInStringTable(YamlSym.SymbolName)) {
  613. // For XCOFF32: A value of 0 indicates that the symbol name is in the
  614. // string table.
  615. W.write<int32_t>(0);
  616. W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName));
  617. } else {
  618. writeName(YamlSym.SymbolName, W);
  619. }
  620. W.write<uint32_t>(YamlSym.Value);
  621. }
  622. if (YamlSym.SectionName) {
  623. if (!SectionIndexMap.count(*YamlSym.SectionName)) {
  624. ErrHandler("the SectionName " + *YamlSym.SectionName +
  625. " specified in the symbol does not exist");
  626. return false;
  627. }
  628. if (YamlSym.SectionIndex &&
  629. SectionIndexMap[*YamlSym.SectionName] != *YamlSym.SectionIndex) {
  630. ErrHandler("the SectionName " + *YamlSym.SectionName +
  631. " and the SectionIndex (" + Twine(*YamlSym.SectionIndex) +
  632. ") refer to different sections");
  633. return false;
  634. }
  635. W.write<int16_t>(SectionIndexMap[*YamlSym.SectionName]);
  636. } else {
  637. W.write<int16_t>(YamlSym.SectionIndex ? *YamlSym.SectionIndex : 0);
  638. }
  639. W.write<uint16_t>(YamlSym.Type);
  640. W.write<uint8_t>(YamlSym.StorageClass);
  641. uint8_t NumOfAuxSym = YamlSym.NumberOfAuxEntries.value_or(0);
  642. W.write<uint8_t>(NumOfAuxSym);
  643. if (!NumOfAuxSym && !YamlSym.AuxEntries.size())
  644. continue;
  645. // Now write auxiliary entries.
  646. if (!YamlSym.AuxEntries.size()) {
  647. W.OS.write_zeros(XCOFF::SymbolTableEntrySize * NumOfAuxSym);
  648. } else {
  649. for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym :
  650. YamlSym.AuxEntries) {
  651. writeAuxSymbol(AuxSym);
  652. }
  653. // Pad with zeros.
  654. if (NumOfAuxSym > YamlSym.AuxEntries.size())
  655. W.OS.write_zeros(XCOFF::SymbolTableEntrySize *
  656. (NumOfAuxSym - YamlSym.AuxEntries.size()));
  657. }
  658. }
  659. return true;
  660. }
  661. void XCOFFWriter::writeStringTable() {
  662. if (Obj.StrTbl.RawContent) {
  663. Obj.StrTbl.RawContent->writeAsBinary(W.OS);
  664. if (Obj.StrTbl.ContentSize) {
  665. assert(*Obj.StrTbl.ContentSize >= Obj.StrTbl.RawContent->binary_size() &&
  666. "Specified ContentSize is less than the RawContent size.");
  667. W.OS.write_zeros(*Obj.StrTbl.ContentSize -
  668. Obj.StrTbl.RawContent->binary_size());
  669. }
  670. return;
  671. }
  672. size_t StrTblBuilderSize = StrTblBuilder.getSize();
  673. // If neither Length nor ContentSize is specified, write the StrTblBuilder
  674. // directly, which contains the auto-generated Length value.
  675. if (!Obj.StrTbl.Length && !Obj.StrTbl.ContentSize) {
  676. if (StrTblBuilderSize <= 4)
  677. return;
  678. StrTblBuilder.write(W.OS);
  679. return;
  680. }
  681. // Serialize the string table's content to a temporary buffer.
  682. std::unique_ptr<WritableMemoryBuffer> Buf =
  683. WritableMemoryBuffer::getNewMemBuffer(StrTblBuilderSize);
  684. uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart());
  685. StrTblBuilder.write(Ptr);
  686. // Replace the first 4 bytes, which contain the auto-generated Length value,
  687. // with the specified value.
  688. memset(Ptr, 0, 4);
  689. support::endian::write32be(Ptr, Obj.StrTbl.Length ? *Obj.StrTbl.Length
  690. : *Obj.StrTbl.ContentSize);
  691. // Copy the buffer content to the actual output stream.
  692. W.OS.write(Buf->getBufferStart(), Buf->getBufferSize());
  693. // Add zeros as padding after strings.
  694. if (Obj.StrTbl.ContentSize) {
  695. assert(*Obj.StrTbl.ContentSize >= StrTblBuilderSize &&
  696. "Specified ContentSize is less than the StringTableBuilder size.");
  697. W.OS.write_zeros(*Obj.StrTbl.ContentSize - StrTblBuilderSize);
  698. }
  699. }
  700. bool XCOFFWriter::writeXCOFF() {
  701. if (!assignAddressesAndIndices())
  702. return false;
  703. StartOffset = W.OS.tell();
  704. writeFileHeader();
  705. if (Obj.AuxHeader)
  706. writeAuxFileHeader();
  707. if (!Obj.Sections.empty()) {
  708. writeSectionHeader();
  709. if (!writeSectionData())
  710. return false;
  711. if (!writeRelocations())
  712. return false;
  713. }
  714. if (!Obj.Symbols.empty() && !writeSymbols())
  715. return false;
  716. writeStringTable();
  717. return true;
  718. }
  719. } // end anonymous namespace
  720. namespace llvm {
  721. namespace yaml {
  722. bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH) {
  723. XCOFFWriter Writer(Doc, Out, EH);
  724. return Writer.writeXCOFF();
  725. }
  726. } // namespace yaml
  727. } // namespace llvm