LLVM 17.0.0git
XCOFFEmitter.cpp
Go to the documentation of this file.
1//===- yaml2xcoff - Convert YAML to a xcoff object file -------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// The xcoff component of yaml2obj.
11///
12//===----------------------------------------------------------------------===//
13
14#include "llvm/ADT/DenseMap.h"
21#include "llvm/Support/LEB128.h"
24
25using namespace llvm;
26
27namespace {
28
29constexpr unsigned DefaultSectionAlign = 4;
30constexpr int16_t MaxSectionIndex = INT16_MAX;
31constexpr uint32_t MaxRawDataSize = UINT32_MAX;
32
33class XCOFFWriter {
34public:
35 XCOFFWriter(XCOFFYAML::Object &Obj, raw_ostream &OS, yaml::ErrorHandler EH)
36 : Obj(Obj), W(OS, support::big), ErrHandler(EH),
37 StrTblBuilder(StringTableBuilder::XCOFF) {
38 Is64Bit = Obj.Header.Magic == (llvm::yaml::Hex16)XCOFF::XCOFF64;
39 }
40 bool writeXCOFF();
41
42private:
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();
50
51 void writeFileHeader();
52 void writeAuxFileHeader();
53 void writeSectionHeader();
54 bool writeSectionData();
55 bool writeRelocations();
56 bool writeSymbols();
57 void writeStringTable();
58
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);
67
69 bool Is64Bit = false;
71 yaml::ErrorHandler ErrHandler;
72 StringTableBuilder StrTblBuilder;
73 uint64_t StartOffset;
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;
82};
83
84static void writeName(StringRef StrName, support::endian::Writer W) {
86 memset(Name, 0, XCOFF::NameSize);
87 char SrcName[] = "";
88 memcpy(Name, StrName.size() ? StrName.data() : SrcName, StrName.size());
90 W.write(NameRef);
91}
92
93bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) {
94 // For XCOFF64: The symbol name is always in the string table.
95 return (SymbolName.size() > XCOFF::NameSize) || Is64Bit;
96}
97
98bool 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;
105 CurrentOffset += InitSection.NumberOfRelocations * RelSize;
106 if (CurrentOffset > MaxRawDataSize) {
107 ErrHandler("maximum object size of" + Twine(MaxRawDataSize) +
108 "exceeded when writing relocation data");
109 return false;
110 }
111 }
112 }
113 return true;
114}
115
116bool 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");
122 return false;
123 }
124
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));
133 return false;
134 }
135 }
136
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;
143 else
144 InitSections[I].Address = CurrentSecAddr;
145
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;
154 }
155 }
156 return initRelocations(CurrentOffset);
157}
158
159bool XCOFFWriter::initStringTable() {
160 if (Obj.StrTbl.RawContent) {
161 size_t RawSize = Obj.StrTbl.RawContent->binary_size();
162 if (Obj.StrTbl.Strings || Obj.StrTbl.Length) {
163 ErrHandler(
164 "can't specify Strings or Length when RawContent is specified");
165 return false;
166 }
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) +
170 ")");
171 return false;
172 }
173 return true;
174 }
175 if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize <= 3) {
176 ErrHandler("ContentSize shouldn't be less than 4 without RawContent");
177 return false;
178 }
179
180 // Build the string table.
181 StrTblBuilder.clear();
182
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);
187
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];
195 ++StrTblIdx;
196 } else
197 // Names that are not overwritten are still stored in the string
198 // table.
199 StrTblBuilder.add(YamlSym.SymbolName);
200 }
201 }
202 } else {
203 for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
204 if (nameShouldBeInStringTable(YamlSym.SymbolName))
205 StrTblBuilder.add(YamlSym.SymbolName);
206 }
207 }
208
209 // Check if the file name in the File Auxiliary Entry should be added to the
210 // string table.
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(""));
217 }
218 }
219
220 StrTblBuilder.finalize();
221
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 "
226 "written (" +
227 Twine(StrTblSize) + ")");
228 return false;
229 }
230
231 return true;
232}
233
234bool 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();
239
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 " +
247 Twine(AuxCount));
248 return false;
249 }
250 YamlSym.NumberOfAuxEntries = YamlSym.NumberOfAuxEntries.value_or(AuxCount);
251 // Add the number of auxiliary symbols to the total number.
252 InitFileHdr.NumberOfSymTableEntries += *YamlSym.NumberOfAuxEntries;
253 }
254
255 // Calculate SymbolTableOffset for the file header.
256 if (InitFileHdr.NumberOfSymTableEntries) {
257 InitFileHdr.SymbolTableOffset = CurrentOffset;
258 CurrentOffset +=
259 InitFileHdr.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize;
260 if (CurrentOffset > MaxRawDataSize) {
261 ErrHandler("maximum object size of" + Twine(MaxRawDataSize) +
262 "exceeded when writing symbols");
263 return false;
264 }
265 }
266 // TODO: Calculate FileOffsetToLineNumbers when line number supported.
267 return true;
268}
269
270void 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
279 // prevails.
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;
289 break;
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;
297 break;
298 case XCOFF::STYP_BSS:
299 if (!InitAuxFileHdr.BssDataSize)
300 InitAuxFileHdr.BssDataSize = InitSections[I].Size;
301 if (!InitAuxFileHdr.SecNumOfBSS)
302 InitAuxFileHdr.SecNumOfBSS = I + 1;
303 break;
305 if (!InitAuxFileHdr.SecNumOfTData)
306 InitAuxFileHdr.SecNumOfTData = I + 1;
307 break;
308 case XCOFF::STYP_TBSS:
309 if (!InitAuxFileHdr.SecNumOfTBSS)
310 InitAuxFileHdr.SecNumOfTBSS = I + 1;
311 break;
313 if (!InitAuxFileHdr.SecNumOfLoader)
314 InitAuxFileHdr.SecNumOfLoader = I + 1;
315 break;
316 default:
317 break;
318 }
319 }
320}
321
322bool XCOFFWriter::assignAddressesAndIndices() {
323 uint64_t FileHdrSize =
325 uint64_t AuxFileHdrSize = 0;
326 if (Obj.AuxHeader)
327 AuxFileHdrSize = Obj.Header.AuxHeaderSize
328 ? Obj.Header.AuxHeaderSize
329 : (Is64Bit ? XCOFF::AuxFileHeaderSize64
331 uint64_t SecHdrSize =
333 uint64_t CurrentOffset =
334 FileHdrSize + AuxFileHdrSize + InitSections.size() * SecHdrSize;
335
336 // Calculate section header info.
337 if (!initSectionHeader(CurrentOffset))
338 return false;
339 InitFileHdr.AuxHeaderSize = AuxFileHdrSize;
340
341 // Calculate file header info.
342 if (!initFileHeader(CurrentOffset))
343 return false;
344
345 // Initialize the auxiliary file header.
346 if (Obj.AuxHeader)
347 initAuxFileHeader();
348
349 // Initialize the string table.
350 return initStringTable();
351}
352
353void 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);
358 if (Is64Bit) {
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);
367 } else {
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);
376 }
377}
378
379void 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)));
382 if (Is64Bit) {
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)));
387 } else {
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)));
395 }
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.
407 if (Is64Bit) {
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)));
411 W.write<uint8_t>(
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)));
419 } else {
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)));
426 W.write<uint8_t>(
427 InitAuxFileHdr.FlagAndTDataAlignment.value_or(yaml::Hex8(0)));
428 }
429 W.write<uint16_t>(InitAuxFileHdr.SecNumOfTData.value_or(0));
430 W.write<uint16_t>(InitAuxFileHdr.SecNumOfTBSS.value_or(0));
431 if (Is64Bit) {
432 W.write<uint16_t>(
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);
438 }
439}
440
441void 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;
449 if (Is64Bit) {
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
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);
464 W.OS.write_zeros(4);
465 } else {
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
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);
480 }
481 }
482}
483
484bool 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");
493 return false;
494 }
495 W.OS.write_zeros(PaddingSize);
496 YamlSec.SectionData.writeAsBinary(W.OS);
497 }
498 }
499 return true;
500}
501
502bool 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");
510 return false;
511 }
512 W.OS.write_zeros(PaddingSize);
513 for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) {
514 if (Is64Bit)
515 W.write<uint64_t>(YamlRel.VirtualAddress);
516 else
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);
521 }
522 }
523 }
524 return true;
525}
526
527void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::CsectAuxEnt &AuxSym) {
528 if (Is64Bit) {
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));
535 W.write<uint8_t>(0);
536 W.write<uint8_t>(XCOFF::AUX_CSECT);
537 } else {
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));
545 }
546}
547
548void 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));
553 W.write<uint8_t>(0);
554 W.write<uint8_t>(XCOFF::AUX_EXCEPT);
555}
556
557void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym) {
558 if (Is64Bit) {
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));
562 W.write<uint8_t>(0);
563 W.write<uint8_t>(XCOFF::AUX_FCN);
564 } else {
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));
569 W.OS.write_zeros(2);
570 }
571}
572
573void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym) {
574 StringRef FileName = AuxSym.FileNameOrString.value_or("");
575 if (nameShouldBeInStringTable(FileName)) {
576 W.write<int32_t>(0);
577 W.write<uint32_t>(StrTblBuilder.getOffset(FileName));
578 } else {
579 writeName(FileName, W);
580 }
581 W.OS.write_zeros(XCOFF::FileNamePadSize);
582 W.write<uint8_t>(AuxSym.FileStringType.value_or(XCOFF::XFT_FN));
583 if (Is64Bit) {
584 W.OS.write_zeros(2);
585 W.write<uint8_t>(XCOFF::AUX_FILE);
586 } else {
587 W.OS.write_zeros(3);
588 }
589}
590
591void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym) {
592 if (Is64Bit) {
593 W.write<uint32_t>(AuxSym.LineNum.value_or(0));
594 W.OS.write_zeros(13);
595 W.write<uint8_t>(XCOFF::AUX_SYM);
596 } else {
597 W.OS.write_zeros(2);
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);
601 }
602}
603
604void XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym) {
605 if (Is64Bit) {
606 W.write<uint64_t>(AuxSym.LengthOfSectionPortion.value_or(0));
607 W.write<uint64_t>(AuxSym.NumberOfRelocEnt.value_or(0));
608 W.write<uint8_t>(0);
609 W.write<uint8_t>(XCOFF::AUX_SECT);
610 } else {
611 W.write<uint32_t>(AuxSym.LengthOfSectionPortion.value_or(0));
612 W.OS.write_zeros(4);
613 W.write<uint32_t>(AuxSym.NumberOfRelocEnt.value_or(0));
614 W.OS.write_zeros(6);
615 }
616}
617
618void 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);
624}
625
626void XCOFFWriter::writeAuxSymbol(
627 const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym) {
628 if (auto AS = dyn_cast<XCOFFYAML::CsectAuxEnt>(AuxSym.get()))
629 writeAuxSymbol(*AS);
630 else if (auto AS = dyn_cast<XCOFFYAML::FunctionAuxEnt>(AuxSym.get()))
631 writeAuxSymbol(*AS);
632 else if (auto AS = dyn_cast<XCOFFYAML::ExcpetionAuxEnt>(AuxSym.get()))
633 writeAuxSymbol(*AS);
634 else if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(AuxSym.get()))
635 writeAuxSymbol(*AS);
636 else if (auto AS = dyn_cast<XCOFFYAML::BlockAuxEnt>(AuxSym.get()))
637 writeAuxSymbol(*AS);
638 else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForDWARF>(AuxSym.get()))
639 writeAuxSymbol(*AS);
640 else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForStat>(AuxSym.get()))
641 writeAuxSymbol(*AS);
642 else
643 llvm_unreachable("unknown auxiliary symbol type");
644}
645
646bool 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");
651 return false;
652 }
653 W.OS.write_zeros(PaddingSize);
654 for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
655 if (Is64Bit) {
656 W.write<uint64_t>(YamlSym.Value);
657 W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName));
658 } else {
659 if (nameShouldBeInStringTable(YamlSym.SymbolName)) {
660 // For XCOFF32: A value of 0 indicates that the symbol name is in the
661 // string table.
662 W.write<int32_t>(0);
663 W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName));
664 } else {
665 writeName(YamlSym.SymbolName, W);
666 }
667 W.write<uint32_t>(YamlSym.Value);
668 }
669 if (YamlSym.SectionName) {
670 if (!SectionIndexMap.count(*YamlSym.SectionName)) {
671 ErrHandler("the SectionName " + *YamlSym.SectionName +
672 " specified in the symbol does not exist");
673 return false;
674 }
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");
680 return false;
681 }
682 W.write<int16_t>(SectionIndexMap[*YamlSym.SectionName]);
683 } else {
684 W.write<int16_t>(YamlSym.SectionIndex ? *YamlSym.SectionIndex : 0);
685 }
686 W.write<uint16_t>(YamlSym.Type);
687 W.write<uint8_t>(YamlSym.StorageClass);
688
689 uint8_t NumOfAuxSym = YamlSym.NumberOfAuxEntries.value_or(0);
690 W.write<uint8_t>(NumOfAuxSym);
691
692 if (!NumOfAuxSym && !YamlSym.AuxEntries.size())
693 continue;
694
695 // Now write auxiliary entries.
696 if (!YamlSym.AuxEntries.size()) {
697 W.OS.write_zeros(XCOFF::SymbolTableEntrySize * NumOfAuxSym);
698 } else {
699 for (const std::unique_ptr<XCOFFYAML::AuxSymbolEnt> &AuxSym :
700 YamlSym.AuxEntries) {
701 writeAuxSymbol(AuxSym);
702 }
703 // Pad with zeros.
704 if (NumOfAuxSym > YamlSym.AuxEntries.size())
705 W.OS.write_zeros(XCOFF::SymbolTableEntrySize *
706 (NumOfAuxSym - YamlSym.AuxEntries.size()));
707 }
708 }
709 return true;
710}
711
712void 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());
720 }
721 return;
722 }
723
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)
729 return;
730 StrTblBuilder.write(W.OS);
731 return;
732 }
733
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.
741 memset(Ptr, 0, 4);
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);
751 }
752}
753
754bool XCOFFWriter::writeXCOFF() {
755 if (!assignAddressesAndIndices())
756 return false;
757 StartOffset = W.OS.tell();
758 writeFileHeader();
759 if (Obj.AuxHeader)
760 writeAuxFileHeader();
761 if (!Obj.Sections.empty()) {
762 writeSectionHeader();
763 if (!writeSectionData())
764 return false;
765 if (!writeRelocations())
766 return false;
767 }
768 if (!Obj.Symbols.empty() && !writeSymbols())
769 return false;
770 writeStringTable();
771 return true;
772}
773
774} // end anonymous namespace
775
776namespace llvm {
777namespace yaml {
778
780 XCOFFWriter Writer(Doc, Out, EH);
781 return Writer.writeXCOFF();
782}
783
784} // namespace yaml
785} // namespace llvm
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file defines the DenseMap class.
std::string Name
static Error initRelocations(RelocationSection *Relocs, T RelRange)
Definition: ELFObject.cpp:1612
#define I(x, y, z)
Definition: MD5.cpp:58
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:137
const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:131
Utility for building string tables with deduplicated suffixes.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
static std::unique_ptr< WritableMemoryBuffer > getNewMemBuffer(size_t Size, const Twine &BufferName="")
Allocate a new zero-initialized MemoryBuffer of the specified size.
An efficient, type-erasing, non-owning reference to a callable.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
ArrayRef< uint8_t >::size_type binary_size() const
The number of bytes that are represented by this BinaryRef.
Definition: YAML.h:80
void writeAsBinary(raw_ostream &OS, uint64_t N=UINT64_MAX) const
Write the contents (regardless of whether it is binary or a hex string) as binary to the given raw_os...
Definition: YAML.cpp:39
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char SymbolName[]
Key for Kernel::Metadata::mSymbolName.
@ SHR_SYMTAB
At exec time, create shared symbol table for program (main program only).
Definition: XCOFF.h:63
constexpr size_t RelocationSerializationSize32
Definition: XCOFF.h:38
constexpr size_t RelocationSerializationSize64
Definition: XCOFF.h:39
constexpr size_t FileHeaderSize64
Definition: XCOFF.h:31
constexpr size_t AuxFileHeaderSize64
Definition: XCOFF.h:33
constexpr size_t SectionHeaderSize64
Definition: XCOFF.h:36
@ AUX_SECT
Identifies a SECT auxiliary entry.
Definition: XCOFF.h:346
@ AUX_FILE
Identifies a file auxiliary entry.
Definition: XCOFF.h:344
@ AUX_EXCEPT
Identifies an exception auxiliary entry.
Definition: XCOFF.h:341
@ AUX_FCN
Identifies a function auxiliary entry.
Definition: XCOFF.h:342
@ AUX_SYM
Identifies a symbol auxiliary entry.
Definition: XCOFF.h:343
@ AUX_CSECT
Identifies a csect auxiliary entry.
Definition: XCOFF.h:345
constexpr size_t NameSize
Definition: XCOFF.h:29
constexpr size_t AuxFileHeaderSize32
Definition: XCOFF.h:32
@ N_DEBUG
Definition: XCOFF.h:45
@ N_UNDEF
Definition: XCOFF.h:45
@ N_ABS
Definition: XCOFF.h:45
@ XFT_FN
Specifies the source-file name.
Definition: XCOFF.h:323
constexpr size_t FileHeaderSize32
Definition: XCOFF.h:30
@ XMC_PR
Program Code.
Definition: XCOFF.h:104
constexpr size_t SectionHeaderSize32
Definition: XCOFF.h:35
constexpr size_t SymbolTableEntrySize
Definition: XCOFF.h:37
constexpr size_t FileNamePadSize
Definition: XCOFF.h:28
@ XCOFF32
Definition: XCOFF.h:47
@ XCOFF64
Definition: XCOFF.h:47
@ STYP_LOADER
Definition: XCOFF.h:143
@ STYP_DATA
Definition: XCOFF.h:137
@ STYP_TDATA
Definition: XCOFF.h:141
@ STYP_TEXT
Definition: XCOFF.h:136
@ STYP_BSS
Definition: XCOFF.h:138
@ STYP_TBSS
Definition: XCOFF.h:142
void write32be(void *P, uint32_t V)
Definition: Endian.h:419
bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH)
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition: Alignment.h:155
std::optional< uint32_t > LineNum
Definition: XCOFFYAML.h:161
std::optional< uint16_t > LineNumHi
Definition: XCOFFYAML.h:158
std::optional< uint16_t > LineNumLo
Definition: XCOFFYAML.h:159
std::optional< uint16_t > TypeChkSectNum
Definition: XCOFFYAML.h:123
std::optional< uint32_t > ParameterHashIndex
Definition: XCOFFYAML.h:122
std::optional< uint32_t > SectionOrLength
Definition: XCOFFYAML.h:115
std::optional< uint32_t > SectionOrLengthHi
Definition: XCOFFYAML.h:120
std::optional< uint8_t > SymbolAlignmentAndType
Definition: XCOFFYAML.h:124
std::optional< uint32_t > SectionOrLengthLo
Definition: XCOFFYAML.h:119
std::optional< uint16_t > StabSectNum
Definition: XCOFFYAML.h:117
std::optional< XCOFF::StorageMappingClass > StorageMappingClass
Definition: XCOFFYAML.h:125
std::optional< uint32_t > StabInfoIndex
Definition: XCOFFYAML.h:116
std::optional< int32_t > SymIdxOfNextBeyond
Definition: XCOFFYAML.h:148
std::optional< uint32_t > SizeOfFunction
Definition: XCOFFYAML.h:147
std::optional< uint64_t > OffsetToExceptionTbl
Definition: XCOFFYAML.h:146
std::optional< XCOFF::CFileStringType > FileStringType
Definition: XCOFFYAML.h:105
std::optional< StringRef > FileNameOrString
Definition: XCOFFYAML.h:104
llvm::yaml::Hex16 Magic
Definition: XCOFFYAML.h:24
std::optional< int32_t > SymIdxOfNextBeyond
Definition: XCOFFYAML.h:137
std::optional< uint32_t > OffsetToExceptionTbl
Definition: XCOFFYAML.h:134
std::optional< uint64_t > PtrToLineNum
Definition: XCOFFYAML.h:135
std::optional< uint32_t > SizeOfFunction
Definition: XCOFFYAML.h:136
std::vector< Section > Sections
Definition: XCOFFYAML.h:212
llvm::yaml::Hex8 Type
Definition: XCOFFYAML.h:69
llvm::yaml::Hex64 SymbolIndex
Definition: XCOFFYAML.h:67
llvm::yaml::Hex8 Info
Definition: XCOFFYAML.h:68
llvm::yaml::Hex64 VirtualAddress
Definition: XCOFFYAML.h:66
std::optional< uint32_t > NumberOfRelocEnt
Definition: XCOFFYAML.h:171
std::optional< uint32_t > LengthOfSectionPortion
Definition: XCOFFYAML.h:170
std::optional< uint16_t > NumberOfRelocEnt
Definition: XCOFFYAML.h:181
std::optional< uint16_t > NumberOfLineNum
Definition: XCOFFYAML.h:182
std::optional< uint32_t > SectionLength
Definition: XCOFFYAML.h:180
llvm::yaml::Hex64 FileOffsetToRelocations
Definition: XCOFFYAML.h:77
llvm::yaml::Hex64 Address
Definition: XCOFFYAML.h:74
llvm::yaml::Hex64 Size
Definition: XCOFFYAML.h:75
llvm::yaml::Hex64 FileOffsetToData
Definition: XCOFFYAML.h:76
yaml::BinaryRef SectionData
Definition: XCOFFYAML.h:82
std::vector< Relocation > Relocations
Definition: XCOFFYAML.h:83
llvm::yaml::Hex16 NumberOfLineNumbers
Definition: XCOFFYAML.h:80
llvm::yaml::Hex16 NumberOfRelocations
Definition: XCOFFYAML.h:79
llvm::yaml::Hex64 FileOffsetToLineNumbers
Definition: XCOFFYAML.h:78
std::vector< std::unique_ptr< AuxSymbolEnt > > AuxEntries
Definition: XCOFFYAML.h:198
std::optional< uint16_t > SectionIndex
Definition: XCOFFYAML.h:194
std::optional< uint8_t > NumberOfAuxEntries
Definition: XCOFFYAML.h:197
llvm::yaml::Hex64 Value
Definition: XCOFFYAML.h:192
llvm::yaml::Hex16 Type
Definition: XCOFFYAML.h:195
XCOFF::StorageClass StorageClass
Definition: XCOFFYAML.h:196
std::optional< StringRef > SectionName
Definition: XCOFFYAML.h:193
Adapter to write values to a stream in a particular byte order.
Definition: EndianStream.h:52
Common declarations for yaml2obj.