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