1 //===- yaml2xcoff - Convert YAML to a xcoff object file -------------------===//
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
7 //===----------------------------------------------------------------------===//
10 /// The xcoff component of yaml2obj.
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"
25 using namespace llvm::object
;
29 constexpr unsigned DefaultSectionAlign
= 4;
30 constexpr int16_t MaxSectionIndex
= INT16_MAX
;
31 constexpr uint32_t MaxRawDataSize
= UINT32_MAX
;
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
;
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();
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
;
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
);
90 memcpy(Name
, StrName
.size() ? StrName
.data() : SrcName
, StrName
.size());
91 ArrayRef
<char> NameRef(Name
, XCOFF::NameSize
);
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");
128 CurrentOffset
= InitSection
.FileOffsetToRelocations
;
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
));
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
));
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
;
177 case XCOFF::STYP_BSS
:
178 if (!InitSections
[I
].Address
)
179 InitSections
[I
].Address
= CurrentEndDataAddr
;
181 case XCOFF::STYP_TDATA
:
182 CurrentEndTDataAddr
= InitSections
[I
].Address
+ InitSections
[I
].Size
;
184 case XCOFF::STYP_TBSS
:
185 if (!InitSections
[I
].Address
)
186 InitSections
[I
].Address
= CurrentEndTDataAddr
;
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");
199 CurrentOffset
= InitSections
[I
].FileOffsetToData
;
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
) + ")");
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");
219 unsigned Mask
= Is64Bit
? XCOFFSectionHeader64::SectionFlagsTypeMask
220 : XCOFFSectionHeader32::SectionFlagsTypeMask
;
221 if (DWARFSubtype
& Mask
) {
222 ErrHandler("the low-order bits of DWARFSectionSubtype must be 0");
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
) {
236 "can't specify Strings or Length when RawContent is specified");
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
) +
247 if (Obj
.StrTbl
.ContentSize
&& *Obj
.StrTbl
.ContentSize
<= 3) {
248 ErrHandler("ContentSize shouldn't be less than 4 without RawContent");
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
];
269 // Names that are not overwritten are still stored in the string
271 StrTblBuilder
.add(YamlSym
.SymbolName
);
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
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 "
299 Twine(StrTblSize
) + ")");
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 " +
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");
335 CurrentOffset
= Obj
.Header
.SymbolTableOffset
;
337 InitFileHdr
.SymbolTableOffset
= CurrentOffset
;
339 InitFileHdr
.NumberOfSymTableEntries
* XCOFF::SymbolTableEntrySize
;
340 if (CurrentOffset
> MaxRawDataSize
) {
341 ErrHandler("maximum object size of " + Twine(MaxRawDataSize
) +
342 " exceeded when writing symbols");
346 // TODO: Calculate FileOffsetToLineNumbers when line number supported.
350 void XCOFFWriter::initAuxFileHeader() {
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
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;
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;
379 case XCOFF::STYP_BSS
:
380 if (!InitAuxFileHdr
.BssDataSize
)
381 InitAuxFileHdr
.BssDataSize
= InitSections
[I
].Size
;
382 if (!InitAuxFileHdr
.SecNumOfBSS
)
383 InitAuxFileHdr
.SecNumOfBSS
= I
+ 1;
385 case XCOFF::STYP_TDATA
:
386 if (!InitAuxFileHdr
.SecNumOfTData
)
387 InitAuxFileHdr
.SecNumOfTData
= I
+ 1;
389 case XCOFF::STYP_TBSS
:
390 if (!InitAuxFileHdr
.SecNumOfTBSS
)
391 InitAuxFileHdr
.SecNumOfTBSS
= I
+ 1;
393 case XCOFF::STYP_LOADER
:
394 if (!InitAuxFileHdr
.SecNumOfLoader
)
395 InitAuxFileHdr
.SecNumOfLoader
= I
+ 1;
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
)
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
))
425 // Calculate file header info.
426 if (!initFileHeader(CurrentOffset
))
428 InitFileHdr
.AuxHeaderSize
= AuxFileHdrSize
;
430 // Initialize the auxiliary file header.
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
);
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
);
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)));
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)));
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
)
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.
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)));
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)));
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)));
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));
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
);
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
);
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
);
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");
568 W
.OS
.write_zeros(PaddingSize
);
569 YamlSec
.SectionData
.writeAsBinary(W
.OS
);
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");
585 W
.OS
.write_zeros(PaddingSize
);
586 for (const XCOFFYAML::Relocation
&YamlRel
: YamlSec
.Relocations
) {
588 W
.write
<uint64_t>(YamlRel
.VirtualAddress
);
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
);
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");
608 SymAlignAndType
= *AuxSym
.SymbolAlignmentAndType
;
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
));
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
));
629 SymAlignAndType
|= (*AuxSym
.SymbolAlignment
630 << XCOFFCsectAuxRef::SymbolAlignmentBitOffset
);
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));
641 W
.write
<uint8_t>(XCOFF::AUX_CSECT
);
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));
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));
660 W
.write
<uint8_t>(XCOFF::AUX_EXCEPT
);
664 bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt
&AuxSym
) {
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));
670 W
.write
<uint8_t>(XCOFF::AUX_FCN
);
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));
681 bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FileAuxEnt
&AuxSym
) {
682 StringRef FileName
= AuxSym
.FileNameOrString
.value_or("");
683 if (nameShouldBeInStringTable(FileName
)) {
685 W
.write
<uint32_t>(StrTblBuilder
.getOffset(FileName
));
687 writeName(FileName
, W
);
689 W
.OS
.write_zeros(XCOFF::FileNamePadSize
);
690 W
.write
<uint8_t>(AuxSym
.FileStringType
.value_or(XCOFF::XFT_FN
));
693 W
.write
<uint8_t>(XCOFF::AUX_FILE
);
700 bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::BlockAuxEnt
&AuxSym
) {
702 W
.write
<uint32_t>(AuxSym
.LineNum
.value_or(0));
703 W
.OS
.write_zeros(13);
704 W
.write
<uint8_t>(XCOFF::AUX_SYM
);
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);
714 bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF
&AuxSym
) {
716 W
.write
<uint64_t>(AuxSym
.LengthOfSectionPortion
.value_or(0));
717 W
.write
<uint64_t>(AuxSym
.NumberOfRelocEnt
.value_or(0));
719 W
.write
<uint8_t>(XCOFF::AUX_SECT
);
721 W
.write
<uint32_t>(AuxSym
.LengthOfSectionPortion
.value_or(0));
723 W
.write
<uint32_t>(AuxSym
.NumberOfRelocEnt
.value_or(0));
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);
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");
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");
765 W
.OS
.write_zeros(PaddingSize
);
766 for (const XCOFFYAML::Symbol
&YamlSym
: Obj
.Symbols
) {
768 W
.write
<uint64_t>(YamlSym
.Value
);
769 W
.write
<uint32_t>(StrTblBuilder
.getOffset(YamlSym
.SymbolName
));
771 if (nameShouldBeInStringTable(YamlSym
.SymbolName
)) {
772 // For XCOFF32: A value of 0 indicates that the symbol name is in the
775 W
.write
<uint32_t>(StrTblBuilder
.getOffset(YamlSym
.SymbolName
));
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");
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");
794 W
.write
<int16_t>(SectionIndexMap
[*YamlSym
.SectionName
]);
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())
807 // Now write auxiliary entries.
808 if (!YamlSym
.AuxEntries
.size()) {
809 W
.OS
.write_zeros(XCOFF::SymbolTableEntrySize
* NumOfAuxSym
);
811 for (const std::unique_ptr
<XCOFFYAML::AuxSymbolEnt
> &AuxSym
:
812 YamlSym
.AuxEntries
) {
813 if (!writeAuxSymbol(AuxSym
))
817 if (NumOfAuxSym
> YamlSym
.AuxEntries
.size())
818 W
.OS
.write_zeros(XCOFF::SymbolTableEntrySize
*
819 (NumOfAuxSym
- YamlSym
.AuxEntries
.size()));
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());
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)
843 StrTblBuilder
.write(W
.OS
);
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.
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())
870 StartOffset
= W
.OS
.tell();
872 if (InitFileHdr
.AuxHeaderSize
)
873 writeAuxFileHeader();
874 if (!Obj
.Sections
.empty()) {
875 writeSectionHeaders();
876 if (!writeSectionData())
878 if (!writeRelocations())
881 if (!Obj
.Symbols
.empty() && !writeSymbols())
887 } // end anonymous namespace
892 bool yaml2xcoff(XCOFFYAML::Object
&Doc
, raw_ostream
&Out
, ErrorHandler EH
) {
893 XCOFFWriter
Writer(Doc
, Out
, EH
);
894 return Writer
.writeXCOFF();