[lld/COFF] Demangle symbol name in discarded section relocation error message (#119726)
[llvm-project.git] / llvm / lib / ObjectYAML / XCOFFEmitter.cpp
blobf3a9fb188f51d4bb5040b3eb3e0406fe3cb6a5e9
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 //===----------------------------------------------------------------------===//
14 #include "llvm/ADT/DenseMap.h"
15 #include "llvm/BinaryFormat/XCOFF.h"
16 #include "llvm/MC/StringTableBuilder.h"
17 #include "llvm/Object/XCOFFObjectFile.h"
18 #include "llvm/ObjectYAML/ObjectYAML.h"
19 #include "llvm/ObjectYAML/yaml2obj.h"
20 #include "llvm/Support/EndianStream.h"
21 #include "llvm/Support/MemoryBuffer.h"
22 #include "llvm/Support/raw_ostream.h"
24 using namespace llvm;
25 using namespace llvm::object;
27 namespace {
29 constexpr unsigned DefaultSectionAlign = 4;
30 constexpr int16_t MaxSectionIndex = INT16_MAX;
31 constexpr uint32_t MaxRawDataSize = UINT32_MAX;
33 class XCOFFWriter {
34 public:
35 XCOFFWriter(XCOFFYAML::Object &Obj, raw_ostream &OS, yaml::ErrorHandler EH)
36 : Obj(Obj), W(OS, llvm::endianness::big), ErrHandler(EH),
37 StrTblBuilder(StringTableBuilder::XCOFF) {
38 Is64Bit = Obj.Header.Magic == (llvm::yaml::Hex16)XCOFF::XCOFF64;
40 bool writeXCOFF();
42 private:
43 void reportOverwrite(uint64_t currentOffset, uint64_t specifiedOffset,
44 const Twine &fieldName);
45 bool nameShouldBeInStringTable(StringRef SymbolName);
46 bool initFileHeader(uint64_t CurrentOffset);
47 void initAuxFileHeader();
48 bool initSectionHeaders(uint64_t &CurrentOffset);
49 bool initRelocations(uint64_t &CurrentOffset);
50 bool initStringTable();
51 bool assignAddressesAndIndices();
53 void writeFileHeader();
54 void writeAuxFileHeader();
55 void writeSectionHeaders();
56 bool writeSectionData();
57 bool writeRelocations();
58 bool writeSymbols();
59 void writeStringTable();
61 bool writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym);
62 bool writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym);
63 bool writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym);
64 bool writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym);
65 bool writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym);
66 bool writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym);
67 bool writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym);
68 bool writeAuxSymbol(const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym);
70 XCOFFYAML::Object &Obj;
71 bool Is64Bit = false;
72 support::endian::Writer W;
73 yaml::ErrorHandler ErrHandler;
74 StringTableBuilder StrTblBuilder;
75 uint64_t StartOffset = 0u;
76 // Map the section name to its corrresponding section index.
77 DenseMap<StringRef, int16_t> SectionIndexMap = {
78 {StringRef("N_DEBUG"), XCOFF::N_DEBUG},
79 {StringRef("N_ABS"), XCOFF::N_ABS},
80 {StringRef("N_UNDEF"), XCOFF::N_UNDEF}};
81 XCOFFYAML::FileHeader InitFileHdr = Obj.Header;
82 XCOFFYAML::AuxiliaryHeader InitAuxFileHdr;
83 std::vector<XCOFFYAML::Section> InitSections = Obj.Sections;
86 static void writeName(StringRef StrName, support::endian::Writer W) {
87 char Name[XCOFF::NameSize];
88 memset(Name, 0, XCOFF::NameSize);
89 char SrcName[] = "";
90 memcpy(Name, StrName.size() ? StrName.data() : SrcName, StrName.size());
91 ArrayRef<char> NameRef(Name, XCOFF::NameSize);
92 W.write(NameRef);
95 void XCOFFWriter::reportOverwrite(uint64_t CurrentOffset,
96 uint64_t specifiedOffset,
97 const Twine &fieldName) {
98 ErrHandler("current file offset (" + Twine(CurrentOffset) +
99 ") is bigger than the specified " + fieldName + " (" +
100 Twine(specifiedOffset) + ") ");
103 bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) {
104 // For XCOFF64: The symbol name is always in the string table.
105 return (SymbolName.size() > XCOFF::NameSize) || Is64Bit;
108 bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) {
109 for (XCOFFYAML::Section &InitSection : InitSections) {
110 if (!InitSection.Relocations.empty()) {
111 uint64_t RelSize = Is64Bit ? XCOFF::RelocationSerializationSize64
112 : XCOFF::RelocationSerializationSize32;
113 uint64_t UsedSize = RelSize * InitSection.Relocations.size();
115 // If NumberOfRelocations was specified, we use it, even if it's
116 // not consistent with the number of provided relocations.
117 if (!InitSection.NumberOfRelocations)
118 InitSection.NumberOfRelocations = InitSection.Relocations.size();
120 // If the YAML file specified an offset to relocations, we use it.
121 if (InitSection.FileOffsetToRelocations) {
122 if (CurrentOffset > InitSection.FileOffsetToRelocations) {
123 reportOverwrite(CurrentOffset, InitSection.FileOffsetToRelocations,
124 "FileOffsetToRelocations for the " +
125 InitSection.SectionName + " section");
126 return false;
128 CurrentOffset = InitSection.FileOffsetToRelocations;
129 } else
130 InitSection.FileOffsetToRelocations = CurrentOffset;
131 CurrentOffset += UsedSize;
132 if (CurrentOffset > MaxRawDataSize) {
133 ErrHandler("maximum object size (" + Twine(MaxRawDataSize) +
134 ") exceeded when writing relocation data for section " +
135 Twine(InitSection.SectionName));
136 return false;
140 return true;
143 bool XCOFFWriter::initSectionHeaders(uint64_t &CurrentOffset) {
144 uint64_t CurrentEndDataAddr = 0;
145 uint64_t CurrentEndTDataAddr = 0;
146 for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {
147 // Assign indices for sections.
148 if (InitSections[I].SectionName.size() &&
149 !SectionIndexMap[InitSections[I].SectionName]) {
150 // The section index starts from 1.
151 SectionIndexMap[InitSections[I].SectionName] = I + 1;
152 if ((I + 1) > MaxSectionIndex) {
153 ErrHandler("exceeded the maximum permitted section index of " +
154 Twine(MaxSectionIndex));
155 return false;
159 if (!InitSections[I].Size)
160 InitSections[I].Size = InitSections[I].SectionData.binary_size();
162 // Section data addresses (physical/virtual) are related to symbol
163 // addresses and alignments. Furthermore, it is possible to specify the
164 // same starting addresses for the .text, .data, and .tdata sections.
165 // Without examining all the symbols and their addreses and alignments,
166 // it is not possible to compute valid section addresses. The only
167 // condition required by XCOFF is that the .bss section immediately
168 // follows the .data section, and the .tbss section immediately follows
169 // the .tdata section. Therefore, we only assign addresses to the .bss
170 // and .tbss sections if they do not already have non-zero addresses.
171 // (If the YAML file is being used to generate a valid object file, we
172 // expect all section addresses to be specified explicitly.)
173 switch (InitSections[I].Flags) {
174 case XCOFF::STYP_DATA:
175 CurrentEndDataAddr = InitSections[I].Address + InitSections[I].Size;
176 break;
177 case XCOFF::STYP_BSS:
178 if (!InitSections[I].Address)
179 InitSections[I].Address = CurrentEndDataAddr;
180 break;
181 case XCOFF::STYP_TDATA:
182 CurrentEndTDataAddr = InitSections[I].Address + InitSections[I].Size;
183 break;
184 case XCOFF::STYP_TBSS:
185 if (!InitSections[I].Address)
186 InitSections[I].Address = CurrentEndTDataAddr;
187 break;
190 if (InitSections[I].SectionData.binary_size()) {
191 if (InitSections[I].FileOffsetToData) {
192 // Use the providedFileOffsetToData.
193 if (CurrentOffset > InitSections[I].FileOffsetToData) {
194 reportOverwrite(CurrentOffset, InitSections[I].FileOffsetToData,
195 "FileOffsetToData for the " +
196 InitSections[I].SectionName + " section");
197 return false;
199 CurrentOffset = InitSections[I].FileOffsetToData;
200 } else {
201 CurrentOffset = alignTo(CurrentOffset, DefaultSectionAlign);
202 InitSections[I].FileOffsetToData = CurrentOffset;
204 CurrentOffset += InitSections[I].SectionData.binary_size();
205 if (CurrentOffset > MaxRawDataSize) {
206 ErrHandler("maximum object size (" + Twine(MaxRawDataSize) +
207 ") exceeded when writing data for section " + Twine(I + 1) +
208 " (" + Twine(InitSections[I].SectionName) + ")");
209 return false;
212 if (InitSections[I].SectionSubtype) {
213 uint32_t DWARFSubtype =
214 static_cast<uint32_t>(*InitSections[I].SectionSubtype);
215 if (InitSections[I].Flags != XCOFF::STYP_DWARF) {
216 ErrHandler("a DWARFSectionSubtype is only allowed for a DWARF section");
217 return false;
219 unsigned Mask = Is64Bit ? XCOFFSectionHeader64::SectionFlagsTypeMask
220 : XCOFFSectionHeader32::SectionFlagsTypeMask;
221 if (DWARFSubtype & Mask) {
222 ErrHandler("the low-order bits of DWARFSectionSubtype must be 0");
223 return false;
225 InitSections[I].Flags |= DWARFSubtype;
228 return initRelocations(CurrentOffset);
231 bool XCOFFWriter::initStringTable() {
232 if (Obj.StrTbl.RawContent) {
233 size_t RawSize = Obj.StrTbl.RawContent->binary_size();
234 if (Obj.StrTbl.Strings || Obj.StrTbl.Length) {
235 ErrHandler(
236 "can't specify Strings or Length when RawContent is specified");
237 return false;
239 if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < RawSize) {
240 ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) +
241 ") is less than the RawContent data size (" + Twine(RawSize) +
242 ")");
243 return false;
245 return true;
247 if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize <= 3) {
248 ErrHandler("ContentSize shouldn't be less than 4 without RawContent");
249 return false;
252 // Build the string table.
253 StrTblBuilder.clear();
255 if (Obj.StrTbl.Strings) {
256 // Add all specified strings to the string table.
257 for (StringRef StringEnt : *Obj.StrTbl.Strings)
258 StrTblBuilder.add(StringEnt);
260 size_t StrTblIdx = 0;
261 size_t NumOfStrings = Obj.StrTbl.Strings->size();
262 for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
263 if (nameShouldBeInStringTable(YamlSym.SymbolName)) {
264 if (StrTblIdx < NumOfStrings) {
265 // Overwrite the symbol name with the specified string.
266 YamlSym.SymbolName = (*Obj.StrTbl.Strings)[StrTblIdx];
267 ++StrTblIdx;
268 } else
269 // Names that are not overwritten are still stored in the string
270 // table.
271 StrTblBuilder.add(YamlSym.SymbolName);
274 } else {
275 for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
276 if (nameShouldBeInStringTable(YamlSym.SymbolName))
277 StrTblBuilder.add(YamlSym.SymbolName);
281 // Check if the file name in the File Auxiliary Entry should be added to the
282 // string table.
283 for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
284 for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym :
285 YamlSym.AuxEntries) {
286 if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get()))
287 if (nameShouldBeInStringTable(AS->FileNameOrString.value_or("")))
288 StrTblBuilder.add(AS->FileNameOrString.value_or(""));
292 StrTblBuilder.finalize();
294 size_t StrTblSize = StrTblBuilder.getSize();
295 if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < StrTblSize) {
296 ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) +
297 ") is less than the size of the data that would otherwise be "
298 "written (" +
299 Twine(StrTblSize) + ")");
300 return false;
303 return true;
306 bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset) {
307 // The default format of the object file is XCOFF32.
308 InitFileHdr.Magic = XCOFF::XCOFF32;
309 InitFileHdr.NumberOfSections = Obj.Sections.size();
310 InitFileHdr.NumberOfSymTableEntries = Obj.Symbols.size();
312 for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
313 uint32_t AuxCount = YamlSym.AuxEntries.size();
314 if (YamlSym.NumberOfAuxEntries && *YamlSym.NumberOfAuxEntries < AuxCount) {
315 ErrHandler("specified NumberOfAuxEntries " +
316 Twine(static_cast<uint32_t>(*YamlSym.NumberOfAuxEntries)) +
317 " is less than the actual number "
318 "of auxiliary entries " +
319 Twine(AuxCount));
320 return false;
322 YamlSym.NumberOfAuxEntries = YamlSym.NumberOfAuxEntries.value_or(AuxCount);
323 // Add the number of auxiliary symbols to the total number.
324 InitFileHdr.NumberOfSymTableEntries += *YamlSym.NumberOfAuxEntries;
327 // Calculate SymbolTableOffset for the file header.
328 if (InitFileHdr.NumberOfSymTableEntries) {
329 if (Obj.Header.SymbolTableOffset) {
330 if (CurrentOffset > Obj.Header.SymbolTableOffset) {
331 reportOverwrite(CurrentOffset, Obj.Header.SymbolTableOffset,
332 "SymbolTableOffset");
333 return false;
335 CurrentOffset = Obj.Header.SymbolTableOffset;
337 InitFileHdr.SymbolTableOffset = CurrentOffset;
338 CurrentOffset +=
339 InitFileHdr.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize;
340 if (CurrentOffset > MaxRawDataSize) {
341 ErrHandler("maximum object size of " + Twine(MaxRawDataSize) +
342 " exceeded when writing symbols");
343 return false;
346 // TODO: Calculate FileOffsetToLineNumbers when line number supported.
347 return true;
350 void XCOFFWriter::initAuxFileHeader() {
351 if (Obj.AuxHeader)
352 InitAuxFileHdr = *Obj.AuxHeader;
353 // In general, an object file might contain multiple sections of a given type,
354 // but in a loadable module, there must be exactly one .text, .data, .bss, and
355 // .loader section. A loadable object might also have one .tdata section and
356 // one .tbss section.
357 // Set these section-related values if not set explicitly. We assume that the
358 // input YAML matches the format of the loadable object, but if multiple input
359 // sections still have the same type, the first section with that type
360 // prevails.
361 for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {
362 switch (InitSections[I].Flags) {
363 case XCOFF::STYP_TEXT:
364 if (!InitAuxFileHdr.TextSize)
365 InitAuxFileHdr.TextSize = InitSections[I].Size;
366 if (!InitAuxFileHdr.TextStartAddr)
367 InitAuxFileHdr.TextStartAddr = InitSections[I].Address;
368 if (!InitAuxFileHdr.SecNumOfText)
369 InitAuxFileHdr.SecNumOfText = I + 1;
370 break;
371 case XCOFF::STYP_DATA:
372 if (!InitAuxFileHdr.InitDataSize)
373 InitAuxFileHdr.InitDataSize = InitSections[I].Size;
374 if (!InitAuxFileHdr.DataStartAddr)
375 InitAuxFileHdr.DataStartAddr = InitSections[I].Address;
376 if (!InitAuxFileHdr.SecNumOfData)
377 InitAuxFileHdr.SecNumOfData = I + 1;
378 break;
379 case XCOFF::STYP_BSS:
380 if (!InitAuxFileHdr.BssDataSize)
381 InitAuxFileHdr.BssDataSize = InitSections[I].Size;
382 if (!InitAuxFileHdr.SecNumOfBSS)
383 InitAuxFileHdr.SecNumOfBSS = I + 1;
384 break;
385 case XCOFF::STYP_TDATA:
386 if (!InitAuxFileHdr.SecNumOfTData)
387 InitAuxFileHdr.SecNumOfTData = I + 1;
388 break;
389 case XCOFF::STYP_TBSS:
390 if (!InitAuxFileHdr.SecNumOfTBSS)
391 InitAuxFileHdr.SecNumOfTBSS = I + 1;
392 break;
393 case XCOFF::STYP_LOADER:
394 if (!InitAuxFileHdr.SecNumOfLoader)
395 InitAuxFileHdr.SecNumOfLoader = I + 1;
396 break;
397 default:
398 break;
403 bool XCOFFWriter::assignAddressesAndIndices() {
404 uint64_t FileHdrSize =
405 Is64Bit ? XCOFF::FileHeaderSize64 : XCOFF::FileHeaderSize32;
407 // If AuxHeaderSize is specified in the YAML file, we construct
408 // an auxiliary header.
409 uint64_t AuxFileHdrSize = 0;
411 if (Obj.Header.AuxHeaderSize)
412 AuxFileHdrSize = Obj.Header.AuxHeaderSize;
413 else if (Obj.AuxHeader)
414 AuxFileHdrSize =
415 (Is64Bit ? XCOFF::AuxFileHeaderSize64 : XCOFF::AuxFileHeaderSize32);
416 uint64_t SecHdrSize =
417 Is64Bit ? XCOFF::SectionHeaderSize64 : XCOFF::SectionHeaderSize32;
418 uint64_t CurrentOffset =
419 FileHdrSize + AuxFileHdrSize + InitSections.size() * SecHdrSize;
421 // Calculate section header info.
422 if (!initSectionHeaders(CurrentOffset))
423 return false;
425 // Calculate file header info.
426 if (!initFileHeader(CurrentOffset))
427 return false;
428 InitFileHdr.AuxHeaderSize = AuxFileHdrSize;
430 // Initialize the auxiliary file header.
431 if (AuxFileHdrSize)
432 initAuxFileHeader();
434 // Initialize the string table.
435 return initStringTable();
438 void XCOFFWriter::writeFileHeader() {
439 W.write<uint16_t>(Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic);
440 W.write<uint16_t>(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections
441 : InitFileHdr.NumberOfSections);
442 W.write<int32_t>(Obj.Header.TimeStamp);
443 if (Is64Bit) {
444 W.write<uint64_t>(InitFileHdr.SymbolTableOffset);
445 W.write<uint16_t>(InitFileHdr.AuxHeaderSize);
446 W.write<uint16_t>(Obj.Header.Flags);
447 W.write<int32_t>(Obj.Header.NumberOfSymTableEntries
448 ? Obj.Header.NumberOfSymTableEntries
449 : InitFileHdr.NumberOfSymTableEntries);
450 } else {
451 W.write<uint32_t>(InitFileHdr.SymbolTableOffset);
452 W.write<int32_t>(Obj.Header.NumberOfSymTableEntries
453 ? Obj.Header.NumberOfSymTableEntries
454 : InitFileHdr.NumberOfSymTableEntries);
455 W.write<uint16_t>(InitFileHdr.AuxHeaderSize);
456 W.write<uint16_t>(Obj.Header.Flags);
460 void XCOFFWriter::writeAuxFileHeader() {
461 W.write<uint16_t>(InitAuxFileHdr.Magic.value_or(yaml::Hex16(1)));
462 W.write<uint16_t>(InitAuxFileHdr.Version.value_or(yaml::Hex16(1)));
463 if (Is64Bit) {
464 W.OS.write_zeros(4); // Reserved for debugger.
465 W.write<uint64_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0)));
466 W.write<uint64_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0)));
467 W.write<uint64_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0)));
468 } else {
469 W.write<uint32_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0)));
470 W.write<uint32_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0)));
471 W.write<uint32_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0)));
472 W.write<uint32_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0)));
473 W.write<uint32_t>(InitAuxFileHdr.TextStartAddr.value_or(yaml::Hex64(0)));
474 W.write<uint32_t>(InitAuxFileHdr.DataStartAddr.value_or(yaml::Hex64(0)));
475 // A short 32-bit auxiliary header ends here.
476 if (InitFileHdr.AuxHeaderSize == XCOFF::AuxFileHeaderSizeShort)
477 return;
478 W.write<uint32_t>(InitAuxFileHdr.TOCAnchorAddr.value_or(yaml::Hex64(0)));
480 W.write<uint16_t>(InitAuxFileHdr.SecNumOfEntryPoint.value_or(0));
481 W.write<uint16_t>(InitAuxFileHdr.SecNumOfText.value_or(0));
482 W.write<uint16_t>(InitAuxFileHdr.SecNumOfData.value_or(0));
483 W.write<uint16_t>(InitAuxFileHdr.SecNumOfTOC.value_or(0));
484 W.write<uint16_t>(InitAuxFileHdr.SecNumOfLoader.value_or(0));
485 W.write<uint16_t>(InitAuxFileHdr.SecNumOfBSS.value_or(0));
486 W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfText.value_or(yaml::Hex16(0)));
487 W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfData.value_or(yaml::Hex16(0)));
488 W.write<uint16_t>(InitAuxFileHdr.ModuleType.value_or(yaml::Hex16(0)));
489 W.write<uint8_t>(InitAuxFileHdr.CpuFlag.value_or(yaml::Hex8(0)));
490 W.write<uint8_t>(0); // Reserved for CPU type.
491 if (Is64Bit) {
492 W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0)));
493 W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0)));
494 W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0)));
495 W.write<uint8_t>(
496 InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0x80)));
497 W.write<uint64_t>(InitAuxFileHdr.TextSize.value_or(yaml::Hex64(0)));
498 W.write<uint64_t>(InitAuxFileHdr.InitDataSize.value_or(yaml::Hex64(0)));
499 W.write<uint64_t>(InitAuxFileHdr.BssDataSize.value_or(yaml::Hex64(0)));
500 W.write<uint64_t>(InitAuxFileHdr.EntryPointAddr.value_or(yaml::Hex64(0)));
501 W.write<uint64_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0)));
502 W.write<uint64_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0)));
503 } else {
504 W.write<uint32_t>(InitAuxFileHdr.MaxStackSize.value_or(yaml::Hex64(0)));
505 W.write<uint32_t>(InitAuxFileHdr.MaxDataSize.value_or(yaml::Hex64(0)));
506 W.OS.write_zeros(4); // Reserved for debugger.
507 W.write<uint8_t>(InitAuxFileHdr.TextPageSize.value_or(yaml::Hex8(0)));
508 W.write<uint8_t>(InitAuxFileHdr.DataPageSize.value_or(yaml::Hex8(0)));
509 W.write<uint8_t>(InitAuxFileHdr.StackPageSize.value_or(yaml::Hex8(0)));
510 W.write<uint8_t>(
511 InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0)));
513 W.write<uint16_t>(InitAuxFileHdr.SecNumOfTData.value_or(0));
514 W.write<uint16_t>(InitAuxFileHdr.SecNumOfTBSS.value_or(0));
515 if (Is64Bit) {
516 W.write<uint16_t>(
517 InitAuxFileHdr.Flag.value_or(yaml::Hex16(XCOFF::SHR_SYMTAB)));
518 if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize64)
519 W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize64);
520 } else {
521 if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize32)
522 W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize32);
526 void XCOFFWriter::writeSectionHeaders() {
527 for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {
528 XCOFFYAML::Section DerivedSec = InitSections[I];
529 writeName(DerivedSec.SectionName, W);
530 if (Is64Bit) {
531 // Virtual address is the same as physical address.
532 W.write<uint64_t>(DerivedSec.Address); // Physical address
533 W.write<uint64_t>(DerivedSec.Address); // Virtual address
534 W.write<uint64_t>(DerivedSec.Size);
535 W.write<uint64_t>(DerivedSec.FileOffsetToData);
536 W.write<uint64_t>(DerivedSec.FileOffsetToRelocations);
537 W.write<uint64_t>(DerivedSec.FileOffsetToLineNumbers);
538 W.write<uint32_t>(DerivedSec.NumberOfRelocations);
539 W.write<uint32_t>(DerivedSec.NumberOfLineNumbers);
540 W.write<int32_t>(DerivedSec.Flags);
541 W.OS.write_zeros(4);
542 } else {
543 // Virtual address is the same as physical address.
544 W.write<uint32_t>(DerivedSec.Address); // Physical address
545 W.write<uint32_t>(DerivedSec.Address); // Virtual address
546 W.write<uint32_t>(DerivedSec.Size);
547 W.write<uint32_t>(DerivedSec.FileOffsetToData);
548 W.write<uint32_t>(DerivedSec.FileOffsetToRelocations);
549 W.write<uint32_t>(DerivedSec.FileOffsetToLineNumbers);
550 W.write<uint16_t>(DerivedSec.NumberOfRelocations);
551 W.write<uint16_t>(DerivedSec.NumberOfLineNumbers);
552 W.write<int32_t>(DerivedSec.Flags);
557 bool XCOFFWriter::writeSectionData() {
558 for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {
559 XCOFFYAML::Section YamlSec = Obj.Sections[I];
560 if (YamlSec.SectionData.binary_size()) {
561 // Fill the padding size with zeros.
562 int64_t PaddingSize = (uint64_t)InitSections[I].FileOffsetToData -
563 (W.OS.tell() - StartOffset);
564 if (PaddingSize < 0) {
565 ErrHandler("redundant data was written before section data");
566 return false;
568 W.OS.write_zeros(PaddingSize);
569 YamlSec.SectionData.writeAsBinary(W.OS);
572 return true;
575 bool XCOFFWriter::writeRelocations() {
576 for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {
577 XCOFFYAML::Section YamlSec = Obj.Sections[I];
578 if (!YamlSec.Relocations.empty()) {
579 int64_t PaddingSize =
580 InitSections[I].FileOffsetToRelocations - (W.OS.tell() - StartOffset);
581 if (PaddingSize < 0) {
582 ErrHandler("redundant data was written before relocations");
583 return false;
585 W.OS.write_zeros(PaddingSize);
586 for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) {
587 if (Is64Bit)
588 W.write<uint64_t>(YamlRel.VirtualAddress);
589 else
590 W.write<uint32_t>(YamlRel.VirtualAddress);
591 W.write<uint32_t>(YamlRel.SymbolIndex);
592 W.write<uint8_t>(YamlRel.Info);
593 W.write<uint8_t>(YamlRel.Type);
597 return true;
600 bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym) {
601 uint8_t SymAlignAndType = 0;
602 if (AuxSym.SymbolAlignmentAndType) {
603 if (AuxSym.SymbolType || AuxSym.SymbolAlignment) {
604 ErrHandler("cannot specify SymbolType or SymbolAlignment if "
605 "SymbolAlignmentAndType is specified");
606 return false;
608 SymAlignAndType = *AuxSym.SymbolAlignmentAndType;
609 } else {
610 if (AuxSym.SymbolType) {
611 uint8_t SymbolType = *AuxSym.SymbolType;
612 if (SymbolType & ~XCOFFCsectAuxRef::SymbolTypeMask) {
613 ErrHandler("symbol type must be less than " +
614 Twine(1 + XCOFFCsectAuxRef::SymbolTypeMask));
615 return false;
617 SymAlignAndType = SymbolType;
619 if (AuxSym.SymbolAlignment) {
620 const uint8_t ShiftedSymbolAlignmentMask =
621 XCOFFCsectAuxRef::SymbolAlignmentMask >>
622 XCOFFCsectAuxRef::SymbolAlignmentBitOffset;
624 if (*AuxSym.SymbolAlignment & ~ShiftedSymbolAlignmentMask) {
625 ErrHandler("symbol alignment must be less than " +
626 Twine(1 + ShiftedSymbolAlignmentMask));
627 return false;
629 SymAlignAndType |= (*AuxSym.SymbolAlignment
630 << XCOFFCsectAuxRef::SymbolAlignmentBitOffset);
633 if (Is64Bit) {
634 W.write<uint32_t>(AuxSym.SectionOrLengthLo.value_or(0));
635 W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0));
636 W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0));
637 W.write<uint8_t>(SymAlignAndType);
638 W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR));
639 W.write<uint32_t>(AuxSym.SectionOrLengthHi.value_or(0));
640 W.write<uint8_t>(0);
641 W.write<uint8_t>(XCOFF::AUX_CSECT);
642 } else {
643 W.write<uint32_t>(AuxSym.SectionOrLength.value_or(0));
644 W.write<uint32_t>(AuxSym.ParameterHashIndex.value_or(0));
645 W.write<uint16_t>(AuxSym.TypeChkSectNum.value_or(0));
646 W.write<uint8_t>(SymAlignAndType);
647 W.write<uint8_t>(AuxSym.StorageMappingClass.value_or(XCOFF::XMC_PR));
648 W.write<uint32_t>(AuxSym.StabInfoIndex.value_or(0));
649 W.write<uint16_t>(AuxSym.StabSectNum.value_or(0));
651 return true;
654 bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt &AuxSym) {
655 assert(Is64Bit && "can't write the exception auxiliary symbol for XCOFF32");
656 W.write<uint64_t>(AuxSym.OffsetToExceptionTbl.value_or(0));
657 W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0));
658 W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0));
659 W.write<uint8_t>(0);
660 W.write<uint8_t>(XCOFF::AUX_EXCEPT);
661 return true;
664 bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym) {
665 if (Is64Bit) {
666 W.write<uint64_t>(AuxSym.PtrToLineNum.value_or(0));
667 W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0));
668 W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0));
669 W.write<uint8_t>(0);
670 W.write<uint8_t>(XCOFF::AUX_FCN);
671 } else {
672 W.write<uint32_t>(AuxSym.OffsetToExceptionTbl.value_or(0));
673 W.write<uint32_t>(AuxSym.SizeOfFunction.value_or(0));
674 W.write<uint32_t>(AuxSym.PtrToLineNum.value_or(0));
675 W.write<uint32_t>(AuxSym.SymIdxOfNextBeyond.value_or(0));
676 W.OS.write_zeros(2);
678 return true;
681 bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym) {
682 StringRef FileName = AuxSym.FileNameOrString.value_or("");
683 if (nameShouldBeInStringTable(FileName)) {
684 W.write<int32_t>(0);
685 W.write<uint32_t>(StrTblBuilder.getOffset(FileName));
686 } else {
687 writeName(FileName, W);
689 W.OS.write_zeros(XCOFF::FileNamePadSize);
690 W.write<uint8_t>(AuxSym.FileStringType.value_or(XCOFF::XFT_FN));
691 if (Is64Bit) {
692 W.OS.write_zeros(2);
693 W.write<uint8_t>(XCOFF::AUX_FILE);
694 } else {
695 W.OS.write_zeros(3);
697 return true;
700 bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym) {
701 if (Is64Bit) {
702 W.write<uint32_t>(AuxSym.LineNum.value_or(0));
703 W.OS.write_zeros(13);
704 W.write<uint8_t>(XCOFF::AUX_SYM);
705 } else {
706 W.OS.write_zeros(2);
707 W.write<uint16_t>(AuxSym.LineNumHi.value_or(0));
708 W.write<uint16_t>(AuxSym.LineNumLo.value_or(0));
709 W.OS.write_zeros(12);
711 return true;
714 bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym) {
715 if (Is64Bit) {
716 W.write<uint64_t>(AuxSym.LengthOfSectionPortion.value_or(0));
717 W.write<uint64_t>(AuxSym.NumberOfRelocEnt.value_or(0));
718 W.write<uint8_t>(0);
719 W.write<uint8_t>(XCOFF::AUX_SECT);
720 } else {
721 W.write<uint32_t>(AuxSym.LengthOfSectionPortion.value_or(0));
722 W.OS.write_zeros(4);
723 W.write<uint32_t>(AuxSym.NumberOfRelocEnt.value_or(0));
724 W.OS.write_zeros(6);
726 return true;
729 bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat &AuxSym) {
730 assert(!Is64Bit && "can't write the stat auxiliary symbol for XCOFF64");
731 W.write<uint32_t>(AuxSym.SectionLength.value_or(0));
732 W.write<uint16_t>(AuxSym.NumberOfRelocEnt.value_or(0));
733 W.write<uint16_t>(AuxSym.NumberOfLineNum.value_or(0));
734 W.OS.write_zeros(10);
735 return true;
738 bool XCOFFWriter::writeAuxSymbol(
739 const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym) {
740 if (auto AS = dyn_cast<XCOFFYAML::CsectAuxEnt>(AuxSym.get()))
741 return writeAuxSymbol(*AS);
742 else if (auto AS = dyn_cast<XCOFFYAML::FunctionAuxEnt>(AuxSym.get()))
743 return writeAuxSymbol(*AS);
744 else if (auto AS = dyn_cast<XCOFFYAML::ExcpetionAuxEnt>(AuxSym.get()))
745 return writeAuxSymbol(*AS);
746 else if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get()))
747 return writeAuxSymbol(*AS);
748 else if (auto AS = dyn_cast<XCOFFYAML::BlockAuxEnt>(AuxSym.get()))
749 return writeAuxSymbol(*AS);
750 else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForDWARF>(AuxSym.get()))
751 return writeAuxSymbol(*AS);
752 else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForStat>(AuxSym.get()))
753 return writeAuxSymbol(*AS);
754 llvm_unreachable("unknown auxiliary symbol type");
755 return false;
758 bool XCOFFWriter::writeSymbols() {
759 int64_t PaddingSize =
760 InitFileHdr.SymbolTableOffset - (W.OS.tell() - StartOffset);
761 if (PaddingSize < 0) {
762 ErrHandler("redundant data was written before symbols");
763 return false;
765 W.OS.write_zeros(PaddingSize);
766 for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
767 if (Is64Bit) {
768 W.write<uint64_t>(YamlSym.Value);
769 W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName));
770 } else {
771 if (nameShouldBeInStringTable(YamlSym.SymbolName)) {
772 // For XCOFF32: A value of 0 indicates that the symbol name is in the
773 // string table.
774 W.write<int32_t>(0);
775 W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName));
776 } else {
777 writeName(YamlSym.SymbolName, W);
779 W.write<uint32_t>(YamlSym.Value);
781 if (YamlSym.SectionName) {
782 if (!SectionIndexMap.count(*YamlSym.SectionName)) {
783 ErrHandler("the SectionName " + *YamlSym.SectionName +
784 " specified in the symbol does not exist");
785 return false;
787 if (YamlSym.SectionIndex &&
788 SectionIndexMap[*YamlSym.SectionName] != *YamlSym.SectionIndex) {
789 ErrHandler("the SectionName " + *YamlSym.SectionName +
790 " and the SectionIndex (" + Twine(*YamlSym.SectionIndex) +
791 ") refer to different sections");
792 return false;
794 W.write<int16_t>(SectionIndexMap[*YamlSym.SectionName]);
795 } else {
796 W.write<int16_t>(YamlSym.SectionIndex.value_or(0));
798 W.write<uint16_t>(YamlSym.Type);
799 W.write<uint8_t>(YamlSym.StorageClass);
801 uint8_t NumOfAuxSym = YamlSym.NumberOfAuxEntries.value_or(0);
802 W.write<uint8_t>(NumOfAuxSym);
804 if (!NumOfAuxSym && !YamlSym.AuxEntries.size())
805 continue;
807 // Now write auxiliary entries.
808 if (!YamlSym.AuxEntries.size()) {
809 W.OS.write_zeros(XCOFF::SymbolTableEntrySize * NumOfAuxSym);
810 } else {
811 for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym :
812 YamlSym.AuxEntries) {
813 if (!writeAuxSymbol(AuxSym))
814 return false;
816 // Pad with zeros.
817 if (NumOfAuxSym > YamlSym.AuxEntries.size())
818 W.OS.write_zeros(XCOFF::SymbolTableEntrySize *
819 (NumOfAuxSym - YamlSym.AuxEntries.size()));
822 return true;
825 void XCOFFWriter::writeStringTable() {
826 if (Obj.StrTbl.RawContent) {
827 Obj.StrTbl.RawContent->writeAsBinary(W.OS);
828 if (Obj.StrTbl.ContentSize) {
829 assert(*Obj.StrTbl.ContentSize >= Obj.StrTbl.RawContent->binary_size() &&
830 "Specified ContentSize is less than the RawContent size.");
831 W.OS.write_zeros(*Obj.StrTbl.ContentSize -
832 Obj.StrTbl.RawContent->binary_size());
834 return;
837 size_t StrTblBuilderSize = StrTblBuilder.getSize();
838 // If neither Length nor ContentSize is specified, write the StrTblBuilder
839 // directly, which contains the auto-generated Length value.
840 if (!Obj.StrTbl.Length && !Obj.StrTbl.ContentSize) {
841 if (StrTblBuilderSize <= 4)
842 return;
843 StrTblBuilder.write(W.OS);
844 return;
847 // Serialize the string table's content to a temporary buffer.
848 std::unique_ptr<WritableMemoryBuffer> Buf =
849 WritableMemoryBuffer::getNewMemBuffer(StrTblBuilderSize);
850 uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart());
851 StrTblBuilder.write(Ptr);
852 // Replace the first 4 bytes, which contain the auto-generated Length value,
853 // with the specified value.
854 memset(Ptr, 0, 4);
855 support::endian::write32be(Ptr, Obj.StrTbl.Length ? *Obj.StrTbl.Length
856 : *Obj.StrTbl.ContentSize);
857 // Copy the buffer content to the actual output stream.
858 W.OS.write(Buf->getBufferStart(), Buf->getBufferSize());
859 // Add zeros as padding after strings.
860 if (Obj.StrTbl.ContentSize) {
861 assert(*Obj.StrTbl.ContentSize >= StrTblBuilderSize &&
862 "Specified ContentSize is less than the StringTableBuilder size.");
863 W.OS.write_zeros(*Obj.StrTbl.ContentSize - StrTblBuilderSize);
867 bool XCOFFWriter::writeXCOFF() {
868 if (!assignAddressesAndIndices())
869 return false;
870 StartOffset = W.OS.tell();
871 writeFileHeader();
872 if (InitFileHdr.AuxHeaderSize)
873 writeAuxFileHeader();
874 if (!Obj.Sections.empty()) {
875 writeSectionHeaders();
876 if (!writeSectionData())
877 return false;
878 if (!writeRelocations())
879 return false;
881 if (!Obj.Symbols.empty() && !writeSymbols())
882 return false;
883 writeStringTable();
884 return true;
887 } // end anonymous namespace
889 namespace llvm {
890 namespace yaml {
892 bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH) {
893 XCOFFWriter Writer(Doc, Out, EH);
894 return Writer.writeXCOFF();
897 } // namespace yaml
898 } // namespace llvm