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(s: Name, c: 0, n: XCOFF::NameSize); |
90 | char SrcName[] = "" ; |
91 | memcpy(dest: Name, src: StrName.size() ? StrName.data() : SrcName, n: StrName.size()); |
92 | ArrayRef<char> NameRef(Name, XCOFF::NameSize); |
93 | W.write(Val: 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, specifiedOffset: InitSection.FileOffsetToRelocations, |
125 | fieldName: "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::(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, specifiedOffset: InitSections[I].FileOffsetToData, |
196 | fieldName: "FileOffsetToData for the " + |
197 | InitSections[I].SectionName + " section" ); |
198 | return false; |
199 | } |
200 | CurrentOffset = InitSections[I].FileOffsetToData; |
201 | } else { |
202 | CurrentOffset = alignTo(Value: CurrentOffset, Align: 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(S: 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(SymbolName: 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(S: YamlSym.SymbolName); |
273 | } |
274 | } |
275 | } else { |
276 | for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { |
277 | if (nameShouldBeInStringTable(SymbolName: YamlSym.SymbolName)) |
278 | StrTblBuilder.add(S: 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>(Val: AuxSym.get())) |
288 | if (nameShouldBeInStringTable(SymbolName: AS->FileNameOrString.value_or(u: "" ))) |
289 | StrTblBuilder.add(S: AS->FileNameOrString.value_or(u: "" )); |
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::(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(u&: 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, specifiedOffset: Obj.Header.SymbolTableOffset, |
333 | fieldName: "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::() { |
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::() { |
440 | W.write<uint16_t>(Val: Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic); |
441 | W.write<uint16_t>(Val: Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections |
442 | : InitFileHdr.NumberOfSections); |
443 | W.write<int32_t>(Val: Obj.Header.TimeStamp); |
444 | if (Is64Bit) { |
445 | W.write<uint64_t>(Val: InitFileHdr.SymbolTableOffset); |
446 | W.write<uint16_t>(Val: InitFileHdr.AuxHeaderSize); |
447 | W.write<uint16_t>(Val: Obj.Header.Flags); |
448 | W.write<int32_t>(Val: Obj.Header.NumberOfSymTableEntries |
449 | ? Obj.Header.NumberOfSymTableEntries |
450 | : InitFileHdr.NumberOfSymTableEntries); |
451 | } else { |
452 | W.write<uint32_t>(Val: InitFileHdr.SymbolTableOffset); |
453 | W.write<int32_t>(Val: Obj.Header.NumberOfSymTableEntries |
454 | ? Obj.Header.NumberOfSymTableEntries |
455 | : InitFileHdr.NumberOfSymTableEntries); |
456 | W.write<uint16_t>(Val: InitFileHdr.AuxHeaderSize); |
457 | W.write<uint16_t>(Val: Obj.Header.Flags); |
458 | } |
459 | } |
460 | |
461 | void XCOFFWriter::() { |
462 | W.write<uint16_t>(Val: InitAuxFileHdr.Magic.value_or(u: yaml::Hex16(1))); |
463 | W.write<uint16_t>(Val: InitAuxFileHdr.Version.value_or(u: yaml::Hex16(1))); |
464 | if (Is64Bit) { |
465 | W.OS.write_zeros(NumZeros: 4); // Reserved for debugger. |
466 | W.write<uint64_t>(Val: InitAuxFileHdr.TextStartAddr.value_or(u: yaml::Hex64(0))); |
467 | W.write<uint64_t>(Val: InitAuxFileHdr.DataStartAddr.value_or(u: yaml::Hex64(0))); |
468 | W.write<uint64_t>(Val: InitAuxFileHdr.TOCAnchorAddr.value_or(u: yaml::Hex64(0))); |
469 | } else { |
470 | W.write<uint32_t>(Val: InitAuxFileHdr.TextSize.value_or(u: yaml::Hex64(0))); |
471 | W.write<uint32_t>(Val: InitAuxFileHdr.InitDataSize.value_or(u: yaml::Hex64(0))); |
472 | W.write<uint32_t>(Val: InitAuxFileHdr.BssDataSize.value_or(u: yaml::Hex64(0))); |
473 | W.write<uint32_t>(Val: InitAuxFileHdr.EntryPointAddr.value_or(u: yaml::Hex64(0))); |
474 | W.write<uint32_t>(Val: InitAuxFileHdr.TextStartAddr.value_or(u: yaml::Hex64(0))); |
475 | W.write<uint32_t>(Val: InitAuxFileHdr.DataStartAddr.value_or(u: 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>(Val: InitAuxFileHdr.TOCAnchorAddr.value_or(u: yaml::Hex64(0))); |
480 | } |
481 | W.write<uint16_t>(Val: InitAuxFileHdr.SecNumOfEntryPoint.value_or(u: 0)); |
482 | W.write<uint16_t>(Val: InitAuxFileHdr.SecNumOfText.value_or(u: 0)); |
483 | W.write<uint16_t>(Val: InitAuxFileHdr.SecNumOfData.value_or(u: 0)); |
484 | W.write<uint16_t>(Val: InitAuxFileHdr.SecNumOfTOC.value_or(u: 0)); |
485 | W.write<uint16_t>(Val: InitAuxFileHdr.SecNumOfLoader.value_or(u: 0)); |
486 | W.write<uint16_t>(Val: InitAuxFileHdr.SecNumOfBSS.value_or(u: 0)); |
487 | W.write<uint16_t>(Val: InitAuxFileHdr.MaxAlignOfText.value_or(u: yaml::Hex16(0))); |
488 | W.write<uint16_t>(Val: InitAuxFileHdr.MaxAlignOfData.value_or(u: yaml::Hex16(0))); |
489 | W.write<uint16_t>(Val: InitAuxFileHdr.ModuleType.value_or(u: yaml::Hex16(0))); |
490 | W.write<uint8_t>(Val: InitAuxFileHdr.CpuFlag.value_or(u: yaml::Hex8(0))); |
491 | W.write<uint8_t>(Val: 0); // Reserved for CPU type. |
492 | if (Is64Bit) { |
493 | W.write<uint8_t>(Val: InitAuxFileHdr.TextPageSize.value_or(u: yaml::Hex8(0))); |
494 | W.write<uint8_t>(Val: InitAuxFileHdr.DataPageSize.value_or(u: yaml::Hex8(0))); |
495 | W.write<uint8_t>(Val: InitAuxFileHdr.StackPageSize.value_or(u: yaml::Hex8(0))); |
496 | W.write<uint8_t>( |
497 | Val: InitAuxFileHdr.FlagAndTDataAlignment.value_or(u: yaml::Hex8(0x80))); |
498 | W.write<uint64_t>(Val: InitAuxFileHdr.TextSize.value_or(u: yaml::Hex64(0))); |
499 | W.write<uint64_t>(Val: InitAuxFileHdr.InitDataSize.value_or(u: yaml::Hex64(0))); |
500 | W.write<uint64_t>(Val: InitAuxFileHdr.BssDataSize.value_or(u: yaml::Hex64(0))); |
501 | W.write<uint64_t>(Val: InitAuxFileHdr.EntryPointAddr.value_or(u: yaml::Hex64(0))); |
502 | W.write<uint64_t>(Val: InitAuxFileHdr.MaxStackSize.value_or(u: yaml::Hex64(0))); |
503 | W.write<uint64_t>(Val: InitAuxFileHdr.MaxDataSize.value_or(u: yaml::Hex64(0))); |
504 | } else { |
505 | W.write<uint32_t>(Val: InitAuxFileHdr.MaxStackSize.value_or(u: yaml::Hex64(0))); |
506 | W.write<uint32_t>(Val: InitAuxFileHdr.MaxDataSize.value_or(u: yaml::Hex64(0))); |
507 | W.OS.write_zeros(NumZeros: 4); // Reserved for debugger. |
508 | W.write<uint8_t>(Val: InitAuxFileHdr.TextPageSize.value_or(u: yaml::Hex8(0))); |
509 | W.write<uint8_t>(Val: InitAuxFileHdr.DataPageSize.value_or(u: yaml::Hex8(0))); |
510 | W.write<uint8_t>(Val: InitAuxFileHdr.StackPageSize.value_or(u: yaml::Hex8(0))); |
511 | W.write<uint8_t>( |
512 | Val: InitAuxFileHdr.FlagAndTDataAlignment.value_or(u: yaml::Hex8(0))); |
513 | } |
514 | W.write<uint16_t>(Val: InitAuxFileHdr.SecNumOfTData.value_or(u: 0)); |
515 | W.write<uint16_t>(Val: InitAuxFileHdr.SecNumOfTBSS.value_or(u: 0)); |
516 | if (Is64Bit) { |
517 | W.write<uint16_t>( |
518 | Val: InitAuxFileHdr.Flag.value_or(u: yaml::Hex16(XCOFF::SHR_SYMTAB))); |
519 | if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize64) |
520 | W.OS.write_zeros(NumZeros: InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize64); |
521 | } else { |
522 | if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize32) |
523 | W.OS.write_zeros(NumZeros: InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize32); |
524 | } |
525 | } |
526 | |
527 | void XCOFFWriter::() { |
528 | for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { |
529 | XCOFFYAML::Section DerivedSec = InitSections[I]; |
530 | writeName(StrName: DerivedSec.SectionName, W); |
531 | if (Is64Bit) { |
532 | // Virtual address is the same as physical address. |
533 | W.write<uint64_t>(Val: DerivedSec.Address); // Physical address |
534 | W.write<uint64_t>(Val: DerivedSec.Address); // Virtual address |
535 | W.write<uint64_t>(Val: DerivedSec.Size); |
536 | W.write<uint64_t>(Val: DerivedSec.FileOffsetToData); |
537 | W.write<uint64_t>(Val: DerivedSec.FileOffsetToRelocations); |
538 | W.write<uint64_t>(Val: DerivedSec.FileOffsetToLineNumbers); |
539 | W.write<uint32_t>(Val: DerivedSec.NumberOfRelocations); |
540 | W.write<uint32_t>(Val: DerivedSec.NumberOfLineNumbers); |
541 | W.write<int32_t>(Val: DerivedSec.Flags); |
542 | W.OS.write_zeros(NumZeros: 4); |
543 | } else { |
544 | // Virtual address is the same as physical address. |
545 | W.write<uint32_t>(Val: DerivedSec.Address); // Physical address |
546 | W.write<uint32_t>(Val: DerivedSec.Address); // Virtual address |
547 | W.write<uint32_t>(Val: DerivedSec.Size); |
548 | W.write<uint32_t>(Val: DerivedSec.FileOffsetToData); |
549 | W.write<uint32_t>(Val: DerivedSec.FileOffsetToRelocations); |
550 | W.write<uint32_t>(Val: DerivedSec.FileOffsetToLineNumbers); |
551 | W.write<uint16_t>(Val: DerivedSec.NumberOfRelocations); |
552 | W.write<uint16_t>(Val: DerivedSec.NumberOfLineNumbers); |
553 | W.write<int32_t>(Val: 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(NumZeros: PaddingSize); |
570 | YamlSec.SectionData.writeAsBinary(OS&: 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(NumZeros: PaddingSize); |
587 | for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) { |
588 | if (Is64Bit) |
589 | W.write<uint64_t>(Val: YamlRel.VirtualAddress); |
590 | else |
591 | W.write<uint32_t>(Val: YamlRel.VirtualAddress); |
592 | W.write<uint32_t>(Val: YamlRel.SymbolIndex); |
593 | W.write<uint8_t>(Val: YamlRel.Info); |
594 | W.write<uint8_t>(Val: 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>(Val: AuxSym.SectionOrLengthLo.value_or(u: 0)); |
636 | W.write<uint32_t>(Val: AuxSym.ParameterHashIndex.value_or(u: 0)); |
637 | W.write<uint16_t>(Val: AuxSym.TypeChkSectNum.value_or(u: 0)); |
638 | W.write<uint8_t>(Val: SymAlignAndType); |
639 | W.write<uint8_t>(Val: AuxSym.StorageMappingClass.value_or(u: XCOFF::XMC_PR)); |
640 | W.write<uint32_t>(Val: AuxSym.SectionOrLengthHi.value_or(u: 0)); |
641 | W.write<uint8_t>(Val: 0); |
642 | W.write<uint8_t>(Val: XCOFF::AUX_CSECT); |
643 | } else { |
644 | W.write<uint32_t>(Val: AuxSym.SectionOrLength.value_or(u: 0)); |
645 | W.write<uint32_t>(Val: AuxSym.ParameterHashIndex.value_or(u: 0)); |
646 | W.write<uint16_t>(Val: AuxSym.TypeChkSectNum.value_or(u: 0)); |
647 | W.write<uint8_t>(Val: SymAlignAndType); |
648 | W.write<uint8_t>(Val: AuxSym.StorageMappingClass.value_or(u: XCOFF::XMC_PR)); |
649 | W.write<uint32_t>(Val: AuxSym.StabInfoIndex.value_or(u: 0)); |
650 | W.write<uint16_t>(Val: AuxSym.StabSectNum.value_or(u: 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>(Val: AuxSym.OffsetToExceptionTbl.value_or(u: 0)); |
658 | W.write<uint32_t>(Val: AuxSym.SizeOfFunction.value_or(u: 0)); |
659 | W.write<uint32_t>(Val: AuxSym.SymIdxOfNextBeyond.value_or(u: 0)); |
660 | W.write<uint8_t>(Val: 0); |
661 | W.write<uint8_t>(Val: XCOFF::AUX_EXCEPT); |
662 | return true; |
663 | } |
664 | |
665 | bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FunctionAuxEnt &AuxSym) { |
666 | if (Is64Bit) { |
667 | W.write<uint64_t>(Val: AuxSym.PtrToLineNum.value_or(u: 0)); |
668 | W.write<uint32_t>(Val: AuxSym.SizeOfFunction.value_or(u: 0)); |
669 | W.write<uint32_t>(Val: AuxSym.SymIdxOfNextBeyond.value_or(u: 0)); |
670 | W.write<uint8_t>(Val: 0); |
671 | W.write<uint8_t>(Val: XCOFF::AUX_FCN); |
672 | } else { |
673 | W.write<uint32_t>(Val: AuxSym.OffsetToExceptionTbl.value_or(u: 0)); |
674 | W.write<uint32_t>(Val: AuxSym.SizeOfFunction.value_or(u: 0)); |
675 | W.write<uint32_t>(Val: AuxSym.PtrToLineNum.value_or(u: 0)); |
676 | W.write<uint32_t>(Val: AuxSym.SymIdxOfNextBeyond.value_or(u: 0)); |
677 | W.OS.write_zeros(NumZeros: 2); |
678 | } |
679 | return true; |
680 | } |
681 | |
682 | bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::FileAuxEnt &AuxSym) { |
683 | StringRef FileName = AuxSym.FileNameOrString.value_or(u: "" ); |
684 | if (nameShouldBeInStringTable(SymbolName: FileName)) { |
685 | W.write<int32_t>(Val: 0); |
686 | W.write<uint32_t>(Val: StrTblBuilder.getOffset(S: FileName)); |
687 | } else { |
688 | writeName(StrName: FileName, W); |
689 | } |
690 | W.OS.write_zeros(NumZeros: XCOFF::FileNamePadSize); |
691 | W.write<uint8_t>(Val: AuxSym.FileStringType.value_or(u: XCOFF::XFT_FN)); |
692 | if (Is64Bit) { |
693 | W.OS.write_zeros(NumZeros: 2); |
694 | W.write<uint8_t>(Val: XCOFF::AUX_FILE); |
695 | } else { |
696 | W.OS.write_zeros(NumZeros: 3); |
697 | } |
698 | return true; |
699 | } |
700 | |
701 | bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::BlockAuxEnt &AuxSym) { |
702 | if (Is64Bit) { |
703 | W.write<uint32_t>(Val: AuxSym.LineNum.value_or(u: 0)); |
704 | W.OS.write_zeros(NumZeros: 13); |
705 | W.write<uint8_t>(Val: XCOFF::AUX_SYM); |
706 | } else { |
707 | W.OS.write_zeros(NumZeros: 2); |
708 | W.write<uint16_t>(Val: AuxSym.LineNumHi.value_or(u: 0)); |
709 | W.write<uint16_t>(Val: AuxSym.LineNumLo.value_or(u: 0)); |
710 | W.OS.write_zeros(NumZeros: 12); |
711 | } |
712 | return true; |
713 | } |
714 | |
715 | bool XCOFFWriter::writeAuxSymbol(const XCOFFYAML::SectAuxEntForDWARF &AuxSym) { |
716 | if (Is64Bit) { |
717 | W.write<uint64_t>(Val: AuxSym.LengthOfSectionPortion.value_or(u: 0)); |
718 | W.write<uint64_t>(Val: AuxSym.NumberOfRelocEnt.value_or(u: 0)); |
719 | W.write<uint8_t>(Val: 0); |
720 | W.write<uint8_t>(Val: XCOFF::AUX_SECT); |
721 | } else { |
722 | W.write<uint32_t>(Val: AuxSym.LengthOfSectionPortion.value_or(u: 0)); |
723 | W.OS.write_zeros(NumZeros: 4); |
724 | W.write<uint32_t>(Val: AuxSym.NumberOfRelocEnt.value_or(u: 0)); |
725 | W.OS.write_zeros(NumZeros: 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>(Val: AuxSym.SectionLength.value_or(u: 0)); |
733 | W.write<uint16_t>(Val: AuxSym.NumberOfRelocEnt.value_or(u: 0)); |
734 | W.write<uint16_t>(Val: AuxSym.NumberOfLineNum.value_or(u: 0)); |
735 | W.OS.write_zeros(NumZeros: 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>(Val: AuxSym.get())) |
742 | return writeAuxSymbol(AuxSym: *AS); |
743 | else if (auto AS = dyn_cast<XCOFFYAML::FunctionAuxEnt>(Val: AuxSym.get())) |
744 | return writeAuxSymbol(AuxSym: *AS); |
745 | else if (auto AS = dyn_cast<XCOFFYAML::ExcpetionAuxEnt>(Val: AuxSym.get())) |
746 | return writeAuxSymbol(AuxSym: *AS); |
747 | else if (auto AS = dyn_cast<XCOFFYAML::FileAuxEnt>(Val: AuxSym.get())) |
748 | return writeAuxSymbol(AuxSym: *AS); |
749 | else if (auto AS = dyn_cast<XCOFFYAML::BlockAuxEnt>(Val: AuxSym.get())) |
750 | return writeAuxSymbol(AuxSym: *AS); |
751 | else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForDWARF>(Val: AuxSym.get())) |
752 | return writeAuxSymbol(AuxSym: *AS); |
753 | else if (auto AS = dyn_cast<XCOFFYAML::SectAuxEntForStat>(Val: AuxSym.get())) |
754 | return writeAuxSymbol(AuxSym: *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(NumZeros: PaddingSize); |
767 | for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { |
768 | if (Is64Bit) { |
769 | W.write<uint64_t>(Val: YamlSym.Value); |
770 | W.write<uint32_t>(Val: StrTblBuilder.getOffset(S: YamlSym.SymbolName)); |
771 | } else { |
772 | if (nameShouldBeInStringTable(SymbolName: 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>(Val: 0); |
776 | W.write<uint32_t>(Val: StrTblBuilder.getOffset(S: YamlSym.SymbolName)); |
777 | } else { |
778 | writeName(StrName: YamlSym.SymbolName, W); |
779 | } |
780 | W.write<uint32_t>(Val: YamlSym.Value); |
781 | } |
782 | if (YamlSym.SectionName) { |
783 | if (!SectionIndexMap.count(Val: *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>(Val: SectionIndexMap[*YamlSym.SectionName]); |
796 | } else { |
797 | W.write<int16_t>(Val: YamlSym.SectionIndex ? *YamlSym.SectionIndex : 0); |
798 | } |
799 | W.write<uint16_t>(Val: YamlSym.Type); |
800 | W.write<uint8_t>(Val: YamlSym.StorageClass); |
801 | |
802 | uint8_t NumOfAuxSym = YamlSym.NumberOfAuxEntries.value_or(u: 0); |
803 | W.write<uint8_t>(Val: 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(NumZeros: 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(NumZeros: 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(OS&: 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(NumZeros: *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(OS&: 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(Size: StrTblBuilderSize); |
851 | uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()); |
852 | StrTblBuilder.write(Buf: Ptr); |
853 | // Replace the first 4 bytes, which contain the auto-generated Length value, |
854 | // with the specified value. |
855 | memset(s: Ptr, c: 0, n: 4); |
856 | support::endian::write32be(P: Ptr, V: Obj.StrTbl.Length ? *Obj.StrTbl.Length |
857 | : *Obj.StrTbl.ContentSize); |
858 | // Copy the buffer content to the actual output stream. |
859 | W.OS.write(Ptr: Buf->getBufferStart(), Size: 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(NumZeros: *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 | |