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/LEB128.h"
22 #include "llvm/Support/MemoryBuffer.h"
23 #include "llvm/Support/raw_ostream.h"
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 bool nameShouldBeInStringTable(StringRef SymbolName
);
44 bool initFileHeader(uint64_t CurrentOffset
);
45 void initAuxFileHeader();
46 bool initSectionHeader(uint64_t &CurrentOffset
);
47 bool initRelocations(uint64_t &CurrentOffset
);
48 bool initStringTable();
49 bool assignAddressesAndIndices();
51 void writeFileHeader();
52 void writeAuxFileHeader();
53 void writeSectionHeader();
54 bool writeSectionData();
55 bool writeRelocations();
57 void writeStringTable();
59 void writeAuxSymbol(const XCOFFYAML::CsectAuxEnt
&AuxSym
);
60 void writeAuxSymbol(const XCOFFYAML::FileAuxEnt
&AuxSym
);
61 void writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt
&AuxSym
);
62 void writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt
&AuxSym
);
63 void writeAuxSymbol(const XCOFFYAML::BlockAuxEnt
&AuxSym
);
64 void writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF
&AuxSym
);
65 void writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat
&AuxSym
);
66 void writeAuxSymbol(const std::unique_ptr
<XCOFFYAML::AuxSymbolEnt
> &AuxSym
);
68 XCOFFYAML::Object
&Obj
;
70 support::endian::Writer W
;
71 yaml::ErrorHandler ErrHandler
;
72 StringTableBuilder StrTblBuilder
;
73 uint64_t StartOffset
= 0u;
74 // Map the section name to its corrresponding section index.
75 DenseMap
<StringRef
, int16_t> SectionIndexMap
= {
76 {StringRef("N_DEBUG"), XCOFF::N_DEBUG
},
77 {StringRef("N_ABS"), XCOFF::N_ABS
},
78 {StringRef("N_UNDEF"), XCOFF::N_UNDEF
}};
79 XCOFFYAML::FileHeader InitFileHdr
= Obj
.Header
;
80 XCOFFYAML::AuxiliaryHeader InitAuxFileHdr
;
81 std::vector
<XCOFFYAML::Section
> InitSections
= Obj
.Sections
;
84 static void writeName(StringRef StrName
, support::endian::Writer W
) {
85 char Name
[XCOFF::NameSize
];
86 memset(Name
, 0, XCOFF::NameSize
);
88 memcpy(Name
, StrName
.size() ? StrName
.data() : SrcName
, StrName
.size());
89 ArrayRef
<char> NameRef(Name
, XCOFF::NameSize
);
93 bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName
) {
94 // For XCOFF64: The symbol name is always in the string table.
95 return (SymbolName
.size() > XCOFF::NameSize
) || Is64Bit
;
98 bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset
) {
99 for (XCOFFYAML::Section
&InitSection
: InitSections
) {
100 if (!InitSection
.Relocations
.empty()) {
101 InitSection
.NumberOfRelocations
= InitSection
.Relocations
.size();
102 InitSection
.FileOffsetToRelocations
= CurrentOffset
;
103 uint64_t RelSize
= Is64Bit
? XCOFF::RelocationSerializationSize64
104 : XCOFF::RelocationSerializationSize32
;
105 CurrentOffset
+= InitSection
.NumberOfRelocations
* RelSize
;
106 if (CurrentOffset
> MaxRawDataSize
) {
107 ErrHandler("maximum object size of" + Twine(MaxRawDataSize
) +
108 "exceeded when writing relocation data");
116 bool XCOFFWriter::initSectionHeader(uint64_t &CurrentOffset
) {
117 uint64_t CurrentSecAddr
= 0;
118 for (uint16_t I
= 0, E
= InitSections
.size(); I
< E
; ++I
) {
119 if (CurrentOffset
> MaxRawDataSize
) {
120 ErrHandler("maximum object size of" + Twine(MaxRawDataSize
) +
121 "exceeded when writing section data");
125 // Assign indices for sections.
126 if (InitSections
[I
].SectionName
.size() &&
127 !SectionIndexMap
[InitSections
[I
].SectionName
]) {
128 // The section index starts from 1.
129 SectionIndexMap
[InitSections
[I
].SectionName
] = I
+ 1;
130 if ((I
+ 1) > MaxSectionIndex
) {
131 ErrHandler("exceeded the maximum permitted section index of " +
132 Twine(MaxSectionIndex
));
137 // Calculate the physical/virtual address. This field should contain 0 for
138 // all sections except the text, data and bss sections.
139 if (InitSections
[I
].Flags
!= XCOFF::STYP_TEXT
&&
140 InitSections
[I
].Flags
!= XCOFF::STYP_DATA
&&
141 InitSections
[I
].Flags
!= XCOFF::STYP_BSS
)
142 InitSections
[I
].Address
= 0;
144 InitSections
[I
].Address
= CurrentSecAddr
;
146 // Calculate the FileOffsetToData and data size for sections.
147 if (InitSections
[I
].SectionData
.binary_size()) {
148 InitSections
[I
].FileOffsetToData
= CurrentOffset
;
149 CurrentOffset
+= InitSections
[I
].SectionData
.binary_size();
150 // Ensure the offset is aligned to DefaultSectionAlign.
151 CurrentOffset
= alignTo(CurrentOffset
, DefaultSectionAlign
);
152 InitSections
[I
].Size
= CurrentOffset
- InitSections
[I
].FileOffsetToData
;
153 CurrentSecAddr
+= InitSections
[I
].Size
;
156 return initRelocations(CurrentOffset
);
159 bool XCOFFWriter::initStringTable() {
160 if (Obj
.StrTbl
.RawContent
) {
161 size_t RawSize
= Obj
.StrTbl
.RawContent
->binary_size();
162 if (Obj
.StrTbl
.Strings
|| Obj
.StrTbl
.Length
) {
164 "can't specify Strings or Length when RawContent is specified");
167 if (Obj
.StrTbl
.ContentSize
&& *Obj
.StrTbl
.ContentSize
< RawSize
) {
168 ErrHandler("specified ContentSize (" + Twine(*Obj
.StrTbl
.ContentSize
) +
169 ") is less than the RawContent data size (" + Twine(RawSize
) +
175 if (Obj
.StrTbl
.ContentSize
&& *Obj
.StrTbl
.ContentSize
<= 3) {
176 ErrHandler("ContentSize shouldn't be less than 4 without RawContent");
180 // Build the string table.
181 StrTblBuilder
.clear();
183 if (Obj
.StrTbl
.Strings
) {
184 // All specified strings should be added to the string table.
185 for (StringRef StringEnt
: *Obj
.StrTbl
.Strings
)
186 StrTblBuilder
.add(StringEnt
);
188 size_t StrTblIdx
= 0;
189 size_t NumOfStrings
= Obj
.StrTbl
.Strings
->size();
190 for (XCOFFYAML::Symbol
&YamlSym
: Obj
.Symbols
) {
191 if (nameShouldBeInStringTable(YamlSym
.SymbolName
)) {
192 if (StrTblIdx
< NumOfStrings
) {
193 // Overwrite the symbol name with the specified string.
194 YamlSym
.SymbolName
= (*Obj
.StrTbl
.Strings
)[StrTblIdx
];
197 // Names that are not overwritten are still stored in the string
199 StrTblBuilder
.add(YamlSym
.SymbolName
);
203 for (const XCOFFYAML::Symbol
&YamlSym
: Obj
.Symbols
) {
204 if (nameShouldBeInStringTable(YamlSym
.SymbolName
))
205 StrTblBuilder
.add(YamlSym
.SymbolName
);
209 // Check if the file name in the File Auxiliary Entry should be added to the
211 for (const XCOFFYAML::Symbol
&YamlSym
: Obj
.Symbols
) {
212 for (const std::unique_ptr
<XCOFFYAML::AuxSymbolEnt
> &AuxSym
:
213 YamlSym
.AuxEntries
) {
214 if (auto AS
= dyn_cast
<XCOFFYAML::FileAuxEnt
>(AuxSym
.get()))
215 if (nameShouldBeInStringTable(AS
->FileNameOrString
.value_or("")))
216 StrTblBuilder
.add(AS
->FileNameOrString
.value_or(""));
220 StrTblBuilder
.finalize();
222 size_t StrTblSize
= StrTblBuilder
.getSize();
223 if (Obj
.StrTbl
.ContentSize
&& *Obj
.StrTbl
.ContentSize
< StrTblSize
) {
224 ErrHandler("specified ContentSize (" + Twine(*Obj
.StrTbl
.ContentSize
) +
225 ") is less than the size of the data that would otherwise be "
227 Twine(StrTblSize
) + ")");
234 bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset
) {
235 // The default format of the object file is XCOFF32.
236 InitFileHdr
.Magic
= XCOFF::XCOFF32
;
237 InitFileHdr
.NumberOfSections
= Obj
.Sections
.size();
238 InitFileHdr
.NumberOfSymTableEntries
= Obj
.Symbols
.size();
240 for (XCOFFYAML::Symbol
&YamlSym
: Obj
.Symbols
) {
241 uint32_t AuxCount
= YamlSym
.AuxEntries
.size();
242 if (YamlSym
.NumberOfAuxEntries
&& *YamlSym
.NumberOfAuxEntries
< AuxCount
) {
243 ErrHandler("specified NumberOfAuxEntries " +
244 Twine(static_cast<uint32_t>(*YamlSym
.NumberOfAuxEntries
)) +
245 " is less than the actual number "
246 "of auxiliary entries " +
250 YamlSym
.NumberOfAuxEntries
= YamlSym
.NumberOfAuxEntries
.value_or(AuxCount
);
251 // Add the number of auxiliary symbols to the total number.
252 InitFileHdr
.NumberOfSymTableEntries
+= *YamlSym
.NumberOfAuxEntries
;
255 // Calculate SymbolTableOffset for the file header.
256 if (InitFileHdr
.NumberOfSymTableEntries
) {
257 InitFileHdr
.SymbolTableOffset
= CurrentOffset
;
259 InitFileHdr
.NumberOfSymTableEntries
* XCOFF::SymbolTableEntrySize
;
260 if (CurrentOffset
> MaxRawDataSize
) {
261 ErrHandler("maximum object size of" + Twine(MaxRawDataSize
) +
262 "exceeded when writing symbols");
266 // TODO: Calculate FileOffsetToLineNumbers when line number supported.
270 void XCOFFWriter::initAuxFileHeader() {
271 InitAuxFileHdr
= *Obj
.AuxHeader
;
272 // In general, an object file might contain multiple sections of a given type,
273 // but in a loadable module, there must be exactly one .text, .data, .bss, and
274 // .loader section. A loadable object might also have one .tdata section and
275 // one .tbss section.
276 // Set these section-related values if not set explicitly. We assume that the
277 // input YAML matches the format of the loadable object, but if multiple input
278 // sections still have the same type, the first section with that type
280 for (uint16_t I
= 0, E
= InitSections
.size(); I
< E
; ++I
) {
281 switch (InitSections
[I
].Flags
) {
282 case XCOFF::STYP_TEXT
:
283 if (!InitAuxFileHdr
.TextSize
)
284 InitAuxFileHdr
.TextSize
= InitSections
[I
].Size
;
285 if (!InitAuxFileHdr
.TextStartAddr
)
286 InitAuxFileHdr
.TextStartAddr
= InitSections
[I
].Address
;
287 if (!InitAuxFileHdr
.SecNumOfText
)
288 InitAuxFileHdr
.SecNumOfText
= I
+ 1;
290 case XCOFF::STYP_DATA
:
291 if (!InitAuxFileHdr
.InitDataSize
)
292 InitAuxFileHdr
.InitDataSize
= InitSections
[I
].Size
;
293 if (!InitAuxFileHdr
.DataStartAddr
)
294 InitAuxFileHdr
.DataStartAddr
= InitSections
[I
].Address
;
295 if (!InitAuxFileHdr
.SecNumOfData
)
296 InitAuxFileHdr
.SecNumOfData
= I
+ 1;
298 case XCOFF::STYP_BSS
:
299 if (!InitAuxFileHdr
.BssDataSize
)
300 InitAuxFileHdr
.BssDataSize
= InitSections
[I
].Size
;
301 if (!InitAuxFileHdr
.SecNumOfBSS
)
302 InitAuxFileHdr
.SecNumOfBSS
= I
+ 1;
304 case XCOFF::STYP_TDATA
:
305 if (!InitAuxFileHdr
.SecNumOfTData
)
306 InitAuxFileHdr
.SecNumOfTData
= I
+ 1;
308 case XCOFF::STYP_TBSS
:
309 if (!InitAuxFileHdr
.SecNumOfTBSS
)
310 InitAuxFileHdr
.SecNumOfTBSS
= I
+ 1;
312 case XCOFF::STYP_LOADER
:
313 if (!InitAuxFileHdr
.SecNumOfLoader
)
314 InitAuxFileHdr
.SecNumOfLoader
= I
+ 1;
322 bool XCOFFWriter::assignAddressesAndIndices() {
323 uint64_t FileHdrSize
=
324 Is64Bit
? XCOFF::FileHeaderSize64
: XCOFF::FileHeaderSize32
;
325 uint64_t AuxFileHdrSize
= 0;
327 AuxFileHdrSize
= Obj
.Header
.AuxHeaderSize
328 ? Obj
.Header
.AuxHeaderSize
329 : (Is64Bit
? XCOFF::AuxFileHeaderSize64
330 : XCOFF::AuxFileHeaderSize32
);
331 uint64_t SecHdrSize
=
332 Is64Bit
? XCOFF::SectionHeaderSize64
: XCOFF::SectionHeaderSize32
;
333 uint64_t CurrentOffset
=
334 FileHdrSize
+ AuxFileHdrSize
+ InitSections
.size() * SecHdrSize
;
336 // Calculate section header info.
337 if (!initSectionHeader(CurrentOffset
))
339 InitFileHdr
.AuxHeaderSize
= AuxFileHdrSize
;
341 // Calculate file header info.
342 if (!initFileHeader(CurrentOffset
))
345 // Initialize the auxiliary file header.
349 // Initialize the string table.
350 return initStringTable();
353 void XCOFFWriter::writeFileHeader() {
354 W
.write
<uint16_t>(Obj
.Header
.Magic
? Obj
.Header
.Magic
: InitFileHdr
.Magic
);
355 W
.write
<uint16_t>(Obj
.Header
.NumberOfSections
? Obj
.Header
.NumberOfSections
356 : InitFileHdr
.NumberOfSections
);
357 W
.write
<int32_t>(Obj
.Header
.TimeStamp
);
359 W
.write
<uint64_t>(Obj
.Header
.SymbolTableOffset
360 ? Obj
.Header
.SymbolTableOffset
361 : InitFileHdr
.SymbolTableOffset
);
362 W
.write
<uint16_t>(InitFileHdr
.AuxHeaderSize
);
363 W
.write
<uint16_t>(Obj
.Header
.Flags
);
364 W
.write
<int32_t>(Obj
.Header
.NumberOfSymTableEntries
365 ? Obj
.Header
.NumberOfSymTableEntries
366 : InitFileHdr
.NumberOfSymTableEntries
);
368 W
.write
<uint32_t>(Obj
.Header
.SymbolTableOffset
369 ? Obj
.Header
.SymbolTableOffset
370 : InitFileHdr
.SymbolTableOffset
);
371 W
.write
<int32_t>(Obj
.Header
.NumberOfSymTableEntries
372 ? Obj
.Header
.NumberOfSymTableEntries
373 : InitFileHdr
.NumberOfSymTableEntries
);
374 W
.write
<uint16_t>(InitFileHdr
.AuxHeaderSize
);
375 W
.write
<uint16_t>(Obj
.Header
.Flags
);
379 void XCOFFWriter::writeAuxFileHeader() {
380 W
.write
<uint16_t>(InitAuxFileHdr
.Magic
.value_or(yaml::Hex16(1)));
381 W
.write
<uint16_t>(InitAuxFileHdr
.Version
.value_or(yaml::Hex16(1)));
383 W
.OS
.write_zeros(4); // Reserved for debugger.
384 W
.write
<uint64_t>(InitAuxFileHdr
.TextStartAddr
.value_or(yaml::Hex64(0)));
385 W
.write
<uint64_t>(InitAuxFileHdr
.DataStartAddr
.value_or(yaml::Hex64(0)));
386 W
.write
<uint64_t>(InitAuxFileHdr
.TOCAnchorAddr
.value_or(yaml::Hex64(0)));
388 W
.write
<uint32_t>(InitAuxFileHdr
.TextSize
.value_or(yaml::Hex64(0)));
389 W
.write
<uint32_t>(InitAuxFileHdr
.InitDataSize
.value_or(yaml::Hex64(0)));
390 W
.write
<uint32_t>(InitAuxFileHdr
.BssDataSize
.value_or(yaml::Hex64(0)));
391 W
.write
<uint32_t>(InitAuxFileHdr
.EntryPointAddr
.value_or(yaml::Hex64(0)));
392 W
.write
<uint32_t>(InitAuxFileHdr
.TextStartAddr
.value_or(yaml::Hex64(0)));
393 W
.write
<uint32_t>(InitAuxFileHdr
.DataStartAddr
.value_or(yaml::Hex64(0)));
394 W
.write
<uint32_t>(InitAuxFileHdr
.TOCAnchorAddr
.value_or(yaml::Hex64(0)));
396 W
.write
<uint16_t>(InitAuxFileHdr
.SecNumOfEntryPoint
.value_or(0));
397 W
.write
<uint16_t>(InitAuxFileHdr
.SecNumOfText
.value_or(0));
398 W
.write
<uint16_t>(InitAuxFileHdr
.SecNumOfData
.value_or(0));
399 W
.write
<uint16_t>(InitAuxFileHdr
.SecNumOfTOC
.value_or(0));
400 W
.write
<uint16_t>(InitAuxFileHdr
.SecNumOfLoader
.value_or(0));
401 W
.write
<uint16_t>(InitAuxFileHdr
.SecNumOfBSS
.value_or(0));
402 W
.write
<uint16_t>(InitAuxFileHdr
.MaxAlignOfText
.value_or(yaml::Hex16(0)));
403 W
.write
<uint16_t>(InitAuxFileHdr
.MaxAlignOfData
.value_or(yaml::Hex16(0)));
404 W
.write
<uint16_t>(InitAuxFileHdr
.ModuleType
.value_or(yaml::Hex16(0)));
405 W
.write
<uint8_t>(InitAuxFileHdr
.CpuFlag
.value_or(yaml::Hex8(0)));
406 W
.write
<uint8_t>(0); // Reserved for CPU type.
408 W
.write
<uint8_t>(InitAuxFileHdr
.TextPageSize
.value_or(yaml::Hex8(0)));
409 W
.write
<uint8_t>(InitAuxFileHdr
.DataPageSize
.value_or(yaml::Hex8(0)));
410 W
.write
<uint8_t>(InitAuxFileHdr
.StackPageSize
.value_or(yaml::Hex8(0)));
412 InitAuxFileHdr
.FlagAndTDataAlignment
.value_or(yaml::Hex8(0x80)));
413 W
.write
<uint64_t>(InitAuxFileHdr
.TextSize
.value_or(yaml::Hex64(0)));
414 W
.write
<uint64_t>(InitAuxFileHdr
.InitDataSize
.value_or(yaml::Hex64(0)));
415 W
.write
<uint64_t>(InitAuxFileHdr
.BssDataSize
.value_or(yaml::Hex64(0)));
416 W
.write
<uint64_t>(InitAuxFileHdr
.EntryPointAddr
.value_or(yaml::Hex64(0)));
417 W
.write
<uint64_t>(InitAuxFileHdr
.MaxStackSize
.value_or(yaml::Hex64(0)));
418 W
.write
<uint64_t>(InitAuxFileHdr
.MaxDataSize
.value_or(yaml::Hex64(0)));
420 W
.write
<uint32_t>(InitAuxFileHdr
.MaxStackSize
.value_or(yaml::Hex64(0)));
421 W
.write
<uint32_t>(InitAuxFileHdr
.MaxDataSize
.value_or(yaml::Hex64(0)));
422 W
.OS
.write_zeros(4); // Reserved for debugger.
423 W
.write
<uint8_t>(InitAuxFileHdr
.TextPageSize
.value_or(yaml::Hex8(0)));
424 W
.write
<uint8_t>(InitAuxFileHdr
.DataPageSize
.value_or(yaml::Hex8(0)));
425 W
.write
<uint8_t>(InitAuxFileHdr
.StackPageSize
.value_or(yaml::Hex8(0)));
427 InitAuxFileHdr
.FlagAndTDataAlignment
.value_or(yaml::Hex8(0)));
429 W
.write
<uint16_t>(InitAuxFileHdr
.SecNumOfTData
.value_or(0));
430 W
.write
<uint16_t>(InitAuxFileHdr
.SecNumOfTBSS
.value_or(0));
433 InitAuxFileHdr
.Flag
.value_or(yaml::Hex16(XCOFF::SHR_SYMTAB
)));
434 if (InitFileHdr
.AuxHeaderSize
> XCOFF::AuxFileHeaderSize64
)
435 W
.OS
.write_zeros(InitFileHdr
.AuxHeaderSize
- XCOFF::AuxFileHeaderSize64
);
436 } else if (InitFileHdr
.AuxHeaderSize
> XCOFF::AuxFileHeaderSize32
) {
437 W
.OS
.write_zeros(InitFileHdr
.AuxHeaderSize
- XCOFF::AuxFileHeaderSize32
);
441 void XCOFFWriter::writeSectionHeader() {
442 for (uint16_t I
= 0, E
= Obj
.Sections
.size(); I
< E
; ++I
) {
443 XCOFFYAML::Section YamlSec
= Obj
.Sections
[I
];
444 XCOFFYAML::Section DerivedSec
= InitSections
[I
];
445 writeName(YamlSec
.SectionName
, W
);
446 // Virtual address is the same as physical address.
447 uint64_t SectionAddress
=
448 YamlSec
.Address
? YamlSec
.Address
: DerivedSec
.Address
;
450 W
.write
<uint64_t>(SectionAddress
); // Physical address
451 W
.write
<uint64_t>(SectionAddress
); // Virtual address
452 W
.write
<uint64_t>(YamlSec
.Size
? YamlSec
.Size
: DerivedSec
.Size
);
453 W
.write
<uint64_t>(YamlSec
.FileOffsetToData
? YamlSec
.FileOffsetToData
454 : DerivedSec
.FileOffsetToData
);
455 W
.write
<uint64_t>(YamlSec
.FileOffsetToRelocations
456 ? YamlSec
.FileOffsetToRelocations
457 : DerivedSec
.FileOffsetToRelocations
);
458 W
.write
<uint64_t>(YamlSec
.FileOffsetToLineNumbers
);
459 W
.write
<uint32_t>(YamlSec
.NumberOfRelocations
460 ? YamlSec
.NumberOfRelocations
461 : DerivedSec
.NumberOfRelocations
);
462 W
.write
<uint32_t>(YamlSec
.NumberOfLineNumbers
);
463 W
.write
<int32_t>(YamlSec
.Flags
);
466 W
.write
<uint32_t>(SectionAddress
); // Physical address
467 W
.write
<uint32_t>(SectionAddress
); // Virtual address
468 W
.write
<uint32_t>(YamlSec
.Size
? YamlSec
.Size
: DerivedSec
.Size
);
469 W
.write
<uint32_t>(YamlSec
.FileOffsetToData
? YamlSec
.FileOffsetToData
470 : DerivedSec
.FileOffsetToData
);
471 W
.write
<uint32_t>(YamlSec
.FileOffsetToRelocations
472 ? YamlSec
.FileOffsetToRelocations
473 : DerivedSec
.FileOffsetToRelocations
);
474 W
.write
<uint32_t>(YamlSec
.FileOffsetToLineNumbers
);
475 W
.write
<uint16_t>(YamlSec
.NumberOfRelocations
476 ? YamlSec
.NumberOfRelocations
477 : DerivedSec
.NumberOfRelocations
);
478 W
.write
<uint16_t>(YamlSec
.NumberOfLineNumbers
);
479 W
.write
<int32_t>(YamlSec
.Flags
);
484 bool XCOFFWriter::writeSectionData() {
485 for (uint16_t I
= 0, E
= Obj
.Sections
.size(); I
< E
; ++I
) {
486 XCOFFYAML::Section YamlSec
= Obj
.Sections
[I
];
487 if (YamlSec
.SectionData
.binary_size()) {
488 // Fill the padding size with zeros.
489 int64_t PaddingSize
=
490 InitSections
[I
].FileOffsetToData
- (W
.OS
.tell() - StartOffset
);
491 if (PaddingSize
< 0) {
492 ErrHandler("redundant data was written before section data");
495 W
.OS
.write_zeros(PaddingSize
);
496 YamlSec
.SectionData
.writeAsBinary(W
.OS
);
502 bool XCOFFWriter::writeRelocations() {
503 for (uint16_t I
= 0, E
= Obj
.Sections
.size(); I
< E
; ++I
) {
504 XCOFFYAML::Section YamlSec
= Obj
.Sections
[I
];
505 if (!YamlSec
.Relocations
.empty()) {
506 int64_t PaddingSize
=
507 InitSections
[I
].FileOffsetToRelocations
- (W
.OS
.tell() - StartOffset
);
508 if (PaddingSize
< 0) {
509 ErrHandler("redundant data was written before relocations");
512 W
.OS
.write_zeros(PaddingSize
);
513 for (const XCOFFYAML::Relocation
&YamlRel
: YamlSec
.Relocations
) {
515 W
.write
<uint64_t>(YamlRel
.VirtualAddress
);
517 W
.write
<uint32_t>(YamlRel
.VirtualAddress
);
518 W
.write
<uint32_t>(YamlRel
.SymbolIndex
);
519 W
.write
<uint8_t>(YamlRel
.Info
);
520 W
.write
<uint8_t>(YamlRel
.Type
);
527 void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::CsectAuxEnt
&AuxSym
) {
529 W
.write
<uint32_t>(AuxSym
.SectionOrLengthLo
.value_or(0));
530 W
.write
<uint32_t>(AuxSym
.ParameterHashIndex
.value_or(0));
531 W
.write
<uint16_t>(AuxSym
.TypeChkSectNum
.value_or(0));
532 W
.write
<uint8_t>(AuxSym
.SymbolAlignmentAndType
.value_or(0));
533 W
.write
<uint8_t>(AuxSym
.StorageMappingClass
.value_or(XCOFF::XMC_PR
));
534 W
.write
<uint32_t>(AuxSym
.SectionOrLengthHi
.value_or(0));
536 W
.write
<uint8_t>(XCOFF::AUX_CSECT
);
538 W
.write
<uint32_t>(AuxSym
.SectionOrLength
.value_or(0));
539 W
.write
<uint32_t>(AuxSym
.ParameterHashIndex
.value_or(0));
540 W
.write
<uint16_t>(AuxSym
.TypeChkSectNum
.value_or(0));
541 W
.write
<uint8_t>(AuxSym
.SymbolAlignmentAndType
.value_or(0));
542 W
.write
<uint8_t>(AuxSym
.StorageMappingClass
.value_or(XCOFF::XMC_PR
));
543 W
.write
<uint32_t>(AuxSym
.StabInfoIndex
.value_or(0));
544 W
.write
<uint16_t>(AuxSym
.StabSectNum
.value_or(0));
548 void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::ExcpetionAuxEnt
&AuxSym
) {
549 assert(Is64Bit
&& "can't write the exception auxiliary symbol for XCOFF32");
550 W
.write
<uint64_t>(AuxSym
.OffsetToExceptionTbl
.value_or(0));
551 W
.write
<uint32_t>(AuxSym
.SizeOfFunction
.value_or(0));
552 W
.write
<uint32_t>(AuxSym
.SymIdxOfNextBeyond
.value_or(0));
554 W
.write
<uint8_t>(XCOFF::AUX_EXCEPT
);
557 void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt
&AuxSym
) {
559 W
.write
<uint64_t>(AuxSym
.PtrToLineNum
.value_or(0));
560 W
.write
<uint32_t>(AuxSym
.SizeOfFunction
.value_or(0));
561 W
.write
<uint32_t>(AuxSym
.SymIdxOfNextBeyond
.value_or(0));
563 W
.write
<uint8_t>(XCOFF::AUX_FCN
);
565 W
.write
<uint32_t>(AuxSym
.OffsetToExceptionTbl
.value_or(0));
566 W
.write
<uint32_t>(AuxSym
.SizeOfFunction
.value_or(0));
567 W
.write
<uint32_t>(AuxSym
.PtrToLineNum
.value_or(0));
568 W
.write
<uint32_t>(AuxSym
.SymIdxOfNextBeyond
.value_or(0));
573 void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FileAuxEnt
&AuxSym
) {
574 StringRef FileName
= AuxSym
.FileNameOrString
.value_or("");
575 if (nameShouldBeInStringTable(FileName
)) {
577 W
.write
<uint32_t>(StrTblBuilder
.getOffset(FileName
));
579 writeName(FileName
, W
);
581 W
.OS
.write_zeros(XCOFF::FileNamePadSize
);
582 W
.write
<uint8_t>(AuxSym
.FileStringType
.value_or(XCOFF::XFT_FN
));
585 W
.write
<uint8_t>(XCOFF::AUX_FILE
);
591 void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::BlockAuxEnt
&AuxSym
) {
593 W
.write
<uint32_t>(AuxSym
.LineNum
.value_or(0));
594 W
.OS
.write_zeros(13);
595 W
.write
<uint8_t>(XCOFF::AUX_SYM
);
598 W
.write
<uint16_t>(AuxSym
.LineNumHi
.value_or(0));
599 W
.write
<uint16_t>(AuxSym
.LineNumLo
.value_or(0));
600 W
.OS
.write_zeros(12);
604 void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF
&AuxSym
) {
606 W
.write
<uint64_t>(AuxSym
.LengthOfSectionPortion
.value_or(0));
607 W
.write
<uint64_t>(AuxSym
.NumberOfRelocEnt
.value_or(0));
609 W
.write
<uint8_t>(XCOFF::AUX_SECT
);
611 W
.write
<uint32_t>(AuxSym
.LengthOfSectionPortion
.value_or(0));
613 W
.write
<uint32_t>(AuxSym
.NumberOfRelocEnt
.value_or(0));
618 void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForStat
&AuxSym
) {
619 assert(!Is64Bit
&& "can't write the stat auxiliary symbol for XCOFF64");
620 W
.write
<uint32_t>(AuxSym
.SectionLength
.value_or(0));
621 W
.write
<uint16_t>(AuxSym
.NumberOfRelocEnt
.value_or(0));
622 W
.write
<uint16_t>(AuxSym
.NumberOfLineNum
.value_or(0));
623 W
.OS
.write_zeros(10);
626 void XCOFFWriter::writeAuxSymbol(
627 const std::unique_ptr
<XCOFFYAML::AuxSymbolEnt
> &AuxSym
) {
628 if (auto AS
= dyn_cast
<XCOFFYAML::CsectAuxEnt
>(AuxSym
.get()))
630 else if (auto AS
= dyn_cast
<XCOFFYAML::FunctionAuxEnt
>(AuxSym
.get()))
632 else if (auto AS
= dyn_cast
<XCOFFYAML::ExcpetionAuxEnt
>(AuxSym
.get()))
634 else if (auto AS
= dyn_cast
<XCOFFYAML::FileAuxEnt
>(AuxSym
.get()))
636 else if (auto AS
= dyn_cast
<XCOFFYAML::BlockAuxEnt
>(AuxSym
.get()))
638 else if (auto AS
= dyn_cast
<XCOFFYAML::SectAuxEntForDWARF
>(AuxSym
.get()))
640 else if (auto AS
= dyn_cast
<XCOFFYAML::SectAuxEntForStat
>(AuxSym
.get()))
643 llvm_unreachable("unknown auxiliary symbol type");
646 bool XCOFFWriter::writeSymbols() {
647 int64_t PaddingSize
=
648 (uint64_t)InitFileHdr
.SymbolTableOffset
- (W
.OS
.tell() - StartOffset
);
649 if (PaddingSize
< 0) {
650 ErrHandler("redundant data was written before symbols");
653 W
.OS
.write_zeros(PaddingSize
);
654 for (const XCOFFYAML::Symbol
&YamlSym
: Obj
.Symbols
) {
656 W
.write
<uint64_t>(YamlSym
.Value
);
657 W
.write
<uint32_t>(StrTblBuilder
.getOffset(YamlSym
.SymbolName
));
659 if (nameShouldBeInStringTable(YamlSym
.SymbolName
)) {
660 // For XCOFF32: A value of 0 indicates that the symbol name is in the
663 W
.write
<uint32_t>(StrTblBuilder
.getOffset(YamlSym
.SymbolName
));
665 writeName(YamlSym
.SymbolName
, W
);
667 W
.write
<uint32_t>(YamlSym
.Value
);
669 if (YamlSym
.SectionName
) {
670 if (!SectionIndexMap
.count(*YamlSym
.SectionName
)) {
671 ErrHandler("the SectionName " + *YamlSym
.SectionName
+
672 " specified in the symbol does not exist");
675 if (YamlSym
.SectionIndex
&&
676 SectionIndexMap
[*YamlSym
.SectionName
] != *YamlSym
.SectionIndex
) {
677 ErrHandler("the SectionName " + *YamlSym
.SectionName
+
678 " and the SectionIndex (" + Twine(*YamlSym
.SectionIndex
) +
679 ") refer to different sections");
682 W
.write
<int16_t>(SectionIndexMap
[*YamlSym
.SectionName
]);
684 W
.write
<int16_t>(YamlSym
.SectionIndex
? *YamlSym
.SectionIndex
: 0);
686 W
.write
<uint16_t>(YamlSym
.Type
);
687 W
.write
<uint8_t>(YamlSym
.StorageClass
);
689 uint8_t NumOfAuxSym
= YamlSym
.NumberOfAuxEntries
.value_or(0);
690 W
.write
<uint8_t>(NumOfAuxSym
);
692 if (!NumOfAuxSym
&& !YamlSym
.AuxEntries
.size())
695 // Now write auxiliary entries.
696 if (!YamlSym
.AuxEntries
.size()) {
697 W
.OS
.write_zeros(XCOFF::SymbolTableEntrySize
* NumOfAuxSym
);
699 for (const std::unique_ptr
<XCOFFYAML::AuxSymbolEnt
> &AuxSym
:
700 YamlSym
.AuxEntries
) {
701 writeAuxSymbol(AuxSym
);
704 if (NumOfAuxSym
> YamlSym
.AuxEntries
.size())
705 W
.OS
.write_zeros(XCOFF::SymbolTableEntrySize
*
706 (NumOfAuxSym
- YamlSym
.AuxEntries
.size()));
712 void XCOFFWriter::writeStringTable() {
713 if (Obj
.StrTbl
.RawContent
) {
714 Obj
.StrTbl
.RawContent
->writeAsBinary(W
.OS
);
715 if (Obj
.StrTbl
.ContentSize
) {
716 assert(*Obj
.StrTbl
.ContentSize
>= Obj
.StrTbl
.RawContent
->binary_size() &&
717 "Specified ContentSize is less than the RawContent size.");
718 W
.OS
.write_zeros(*Obj
.StrTbl
.ContentSize
-
719 Obj
.StrTbl
.RawContent
->binary_size());
724 size_t StrTblBuilderSize
= StrTblBuilder
.getSize();
725 // If neither Length nor ContentSize is specified, write the StrTblBuilder
726 // directly, which contains the auto-generated Length value.
727 if (!Obj
.StrTbl
.Length
&& !Obj
.StrTbl
.ContentSize
) {
728 if (StrTblBuilderSize
<= 4)
730 StrTblBuilder
.write(W
.OS
);
734 // Serialize the string table's content to a temporary buffer.
735 std::unique_ptr
<WritableMemoryBuffer
> Buf
=
736 WritableMemoryBuffer::getNewMemBuffer(StrTblBuilderSize
);
737 uint8_t *Ptr
= reinterpret_cast<uint8_t *>(Buf
->getBufferStart());
738 StrTblBuilder
.write(Ptr
);
739 // Replace the first 4 bytes, which contain the auto-generated Length value,
740 // with the specified value.
742 support::endian::write32be(Ptr
, Obj
.StrTbl
.Length
? *Obj
.StrTbl
.Length
743 : *Obj
.StrTbl
.ContentSize
);
744 // Copy the buffer content to the actual output stream.
745 W
.OS
.write(Buf
->getBufferStart(), Buf
->getBufferSize());
746 // Add zeros as padding after strings.
747 if (Obj
.StrTbl
.ContentSize
) {
748 assert(*Obj
.StrTbl
.ContentSize
>= StrTblBuilderSize
&&
749 "Specified ContentSize is less than the StringTableBuilder size.");
750 W
.OS
.write_zeros(*Obj
.StrTbl
.ContentSize
- StrTblBuilderSize
);
754 bool XCOFFWriter::writeXCOFF() {
755 if (!assignAddressesAndIndices())
757 StartOffset
= W
.OS
.tell();
760 writeAuxFileHeader();
761 if (!Obj
.Sections
.empty()) {
762 writeSectionHeader();
763 if (!writeSectionData())
765 if (!writeRelocations())
768 if (!Obj
.Symbols
.empty() && !writeSymbols())
774 } // end anonymous namespace
779 bool yaml2xcoff(XCOFFYAML::Object
&Doc
, raw_ostream
&Out
, ErrorHandler EH
) {
780 XCOFFWriter
Writer(Doc
, Out
, EH
);
781 return Writer
.writeXCOFF();