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