[ORC] Add std::tuple support to SimplePackedSerialization.
[llvm-project.git] / llvm / lib / ObjectYAML / XCOFFEmitter.cpp
blob8b132ebf5e5de5a706d6a4abdb0111fc5772a842
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 //===----------------------------------------------------------------------===//
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/raw_ostream.h"
22 #include "llvm/Support/LEB128.h"
24 using namespace llvm;
26 namespace {
28 constexpr unsigned DefaultSectionAlign = 4;
29 constexpr int16_t MaxSectionIndex = INT16_MAX;
30 constexpr uint32_t MaxRawDataSize = UINT32_MAX;
32 class XCOFFWriter {
33 public:
34 XCOFFWriter(XCOFFYAML::Object &Obj, raw_ostream &OS, yaml::ErrorHandler EH)
35 : Obj(Obj), W(OS, support::big), ErrHandler(EH),
36 Strings(StringTableBuilder::XCOFF) {
37 Is64Bit = Obj.Header.Magic == (llvm::yaml::Hex16)XCOFF::XCOFF64;
39 bool writeXCOFF();
41 private:
42 bool nameShouldBeInStringTable(StringRef SymbolName);
43 bool initFileHeader(uint64_t CurrentOffset);
44 bool initSectionHeader(uint64_t &CurrentOffset);
45 bool initRelocations(uint64_t &CurrentOffset);
46 bool assignAddressesAndIndices();
47 void writeFileHeader();
48 void writeSectionHeader();
49 bool writeSectionData();
50 bool writeRelocations();
51 bool writeSymbols();
53 XCOFFYAML::Object &Obj;
54 bool Is64Bit = false;
55 support::endian::Writer W;
56 yaml::ErrorHandler ErrHandler;
57 StringTableBuilder Strings;
58 uint64_t StartOffset;
59 // Map the section name to its corrresponding section index.
60 DenseMap<StringRef, int16_t> SectionIndexMap = {
61 {StringRef("N_DEBUG"), XCOFF::N_DEBUG},
62 {StringRef("N_ABS"), XCOFF::N_ABS},
63 {StringRef("N_UNDEF"), XCOFF::N_UNDEF}};
64 XCOFFYAML::FileHeader InitFileHdr = Obj.Header;
65 std::vector<XCOFFYAML::Section> InitSections = Obj.Sections;
68 static void writeName(StringRef StrName, support::endian::Writer W) {
69 char Name[XCOFF::NameSize];
70 memset(Name, 0, XCOFF::NameSize);
71 char SrcName[] = "";
72 memcpy(Name, StrName.size() ? StrName.data() : SrcName, StrName.size());
73 ArrayRef<char> NameRef(Name, XCOFF::NameSize);
74 W.write(NameRef);
77 bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) {
78 // For XCOFF64: The symbol name is always in the string table.
79 return (SymbolName.size() > XCOFF::NameSize) || Is64Bit;
82 bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) {
83 for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {
84 if (!InitSections[I].Relocations.empty()) {
85 InitSections[I].NumberOfRelocations = InitSections[I].Relocations.size();
86 InitSections[I].FileOffsetToRelocations = CurrentOffset;
87 uint64_t RelSize = Is64Bit ? XCOFF::RelocationSerializationSize64
88 : XCOFF::RelocationSerializationSize32;
89 CurrentOffset += InitSections[I].NumberOfRelocations * RelSize;
90 if (CurrentOffset > MaxRawDataSize) {
91 ErrHandler("maximum object size of" + Twine(MaxRawDataSize) +
92 "exceeded when writing relocation data");
93 return false;
97 return true;
100 bool XCOFFWriter::initSectionHeader(uint64_t &CurrentOffset) {
101 uint64_t CurrentSecAddr = 0;
102 for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {
103 if (CurrentOffset > MaxRawDataSize) {
104 ErrHandler("maximum object size of" + Twine(MaxRawDataSize) +
105 "exceeded when writing section data");
106 return false;
109 // Assign indices for sections.
110 if (InitSections[I].SectionName.size() &&
111 !SectionIndexMap[InitSections[I].SectionName]) {
112 // The section index starts from 1.
113 SectionIndexMap[InitSections[I].SectionName] = I + 1;
114 if ((I + 1) > MaxSectionIndex) {
115 ErrHandler("exceeded the maximum permitted section index of " +
116 Twine(MaxSectionIndex));
117 return false;
121 // Calculate the physical/virtual address. This field should contain 0 for
122 // all sections except the text, data and bss sections.
123 if (InitSections[I].Flags != XCOFF::STYP_TEXT &&
124 InitSections[I].Flags != XCOFF::STYP_DATA &&
125 InitSections[I].Flags != XCOFF::STYP_BSS)
126 InitSections[I].Address = 0;
127 else
128 InitSections[I].Address = CurrentSecAddr;
130 // Calculate the FileOffsetToData and data size for sections.
131 if (InitSections[I].SectionData.binary_size()) {
132 InitSections[I].FileOffsetToData = CurrentOffset;
133 CurrentOffset += InitSections[I].SectionData.binary_size();
134 // Ensure the offset is aligned to DefaultSectionAlign.
135 CurrentOffset = alignTo(CurrentOffset, DefaultSectionAlign);
136 InitSections[I].Size = CurrentOffset - InitSections[I].FileOffsetToData;
137 CurrentSecAddr += InitSections[I].Size;
140 return initRelocations(CurrentOffset);
143 bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset) {
144 // The default format of the object file is XCOFF32.
145 InitFileHdr.Magic = XCOFF::XCOFF32;
146 InitFileHdr.NumberOfSections = Obj.Sections.size();
147 InitFileHdr.NumberOfSymTableEntries = Obj.Symbols.size();
149 for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
150 // Add the number of auxiliary symbols to the total number.
151 InitFileHdr.NumberOfSymTableEntries += YamlSym.NumberOfAuxEntries;
152 if (nameShouldBeInStringTable(YamlSym.SymbolName))
153 Strings.add(YamlSym.SymbolName);
155 // Finalize the string table.
156 Strings.finalize();
158 // Calculate SymbolTableOffset for the file header.
159 if (InitFileHdr.NumberOfSymTableEntries) {
160 InitFileHdr.SymbolTableOffset = CurrentOffset;
161 CurrentOffset +=
162 InitFileHdr.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize;
163 if (CurrentOffset > MaxRawDataSize) {
164 ErrHandler("maximum object size of" + Twine(MaxRawDataSize) +
165 "exceeded when writing symbols");
166 return false;
169 // TODO: Calculate FileOffsetToLineNumbers when line number supported.
170 return true;
173 bool XCOFFWriter::assignAddressesAndIndices() {
174 Strings.clear();
175 uint64_t FileHdrSize =
176 Is64Bit ? XCOFF::FileHeaderSize64 : XCOFF::FileHeaderSize32;
177 uint64_t SecHdrSize =
178 Is64Bit ? XCOFF::SectionHeaderSize64 : XCOFF::SectionHeaderSize32;
179 uint64_t CurrentOffset = FileHdrSize /* TODO: + auxiliaryHeaderSize() */ +
180 InitSections.size() * SecHdrSize;
182 // Calculate section header info.
183 if (!initSectionHeader(CurrentOffset))
184 return false;
185 // Calculate file header info.
186 return initFileHeader(CurrentOffset);
189 void XCOFFWriter::writeFileHeader() {
190 W.write<uint16_t>(Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic);
191 W.write<uint16_t>(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections
192 : InitFileHdr.NumberOfSections);
193 W.write<int32_t>(Obj.Header.TimeStamp);
194 if (Is64Bit) {
195 W.write<uint64_t>(Obj.Header.SymbolTableOffset
196 ? Obj.Header.SymbolTableOffset
197 : InitFileHdr.SymbolTableOffset);
198 W.write<uint16_t>(Obj.Header.AuxHeaderSize);
199 W.write<uint16_t>(Obj.Header.Flags);
200 W.write<int32_t>(Obj.Header.NumberOfSymTableEntries
201 ? Obj.Header.NumberOfSymTableEntries
202 : InitFileHdr.NumberOfSymTableEntries);
203 } else {
204 W.write<uint32_t>(Obj.Header.SymbolTableOffset
205 ? Obj.Header.SymbolTableOffset
206 : InitFileHdr.SymbolTableOffset);
207 W.write<int32_t>(Obj.Header.NumberOfSymTableEntries
208 ? Obj.Header.NumberOfSymTableEntries
209 : InitFileHdr.NumberOfSymTableEntries);
210 W.write<uint16_t>(Obj.Header.AuxHeaderSize);
211 W.write<uint16_t>(Obj.Header.Flags);
215 void XCOFFWriter::writeSectionHeader() {
216 for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {
217 XCOFFYAML::Section YamlSec = Obj.Sections[I];
218 XCOFFYAML::Section DerivedSec = InitSections[I];
219 writeName(YamlSec.SectionName, W);
220 // Virtual address is the same as physical address.
221 uint64_t SectionAddress =
222 YamlSec.Address ? YamlSec.Address : DerivedSec.Address;
223 if (Is64Bit) {
224 W.write<uint64_t>(SectionAddress); // Physical address
225 W.write<uint64_t>(SectionAddress); // Virtual address
226 W.write<uint64_t>(YamlSec.Size ? YamlSec.Size : DerivedSec.Size);
227 W.write<uint64_t>(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData
228 : DerivedSec.FileOffsetToData);
229 W.write<uint64_t>(YamlSec.FileOffsetToRelocations
230 ? YamlSec.FileOffsetToRelocations
231 : DerivedSec.FileOffsetToRelocations);
232 W.write<uint64_t>(YamlSec.FileOffsetToLineNumbers);
233 W.write<uint32_t>(YamlSec.NumberOfRelocations
234 ? YamlSec.NumberOfRelocations
235 : DerivedSec.NumberOfRelocations);
236 W.write<uint32_t>(YamlSec.NumberOfLineNumbers);
237 W.write<int32_t>(YamlSec.Flags);
238 W.OS.write_zeros(4);
239 } else {
240 W.write<uint32_t>(SectionAddress); // Physical address
241 W.write<uint32_t>(SectionAddress); // Virtual address
242 W.write<uint32_t>(YamlSec.Size ? YamlSec.Size : DerivedSec.Size);
243 W.write<uint32_t>(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData
244 : DerivedSec.FileOffsetToData);
245 W.write<uint32_t>(YamlSec.FileOffsetToRelocations
246 ? YamlSec.FileOffsetToRelocations
247 : DerivedSec.FileOffsetToRelocations);
248 W.write<uint32_t>(YamlSec.FileOffsetToLineNumbers);
249 W.write<uint16_t>(YamlSec.NumberOfRelocations
250 ? YamlSec.NumberOfRelocations
251 : DerivedSec.NumberOfRelocations);
252 W.write<uint16_t>(YamlSec.NumberOfLineNumbers);
253 W.write<int32_t>(YamlSec.Flags);
258 bool XCOFFWriter::writeSectionData() {
259 for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {
260 XCOFFYAML::Section YamlSec = Obj.Sections[I];
261 if (YamlSec.SectionData.binary_size()) {
262 // Fill the padding size with zeros.
263 int64_t PaddingSize =
264 InitSections[I].FileOffsetToData - (W.OS.tell() - StartOffset);
265 if (PaddingSize < 0) {
266 ErrHandler("redundant data was written before section data");
267 return false;
269 W.OS.write_zeros(PaddingSize);
270 YamlSec.SectionData.writeAsBinary(W.OS);
273 return true;
276 bool XCOFFWriter::writeRelocations() {
277 for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {
278 XCOFFYAML::Section YamlSec = Obj.Sections[I];
279 if (!YamlSec.Relocations.empty()) {
280 int64_t PaddingSize =
281 InitSections[I].FileOffsetToRelocations - (W.OS.tell() - StartOffset);
282 if (PaddingSize < 0) {
283 ErrHandler("redundant data was written before relocations");
284 return false;
286 W.OS.write_zeros(PaddingSize);
287 for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) {
288 if (Is64Bit)
289 W.write<uint64_t>(YamlRel.VirtualAddress);
290 else
291 W.write<uint32_t>(YamlRel.VirtualAddress);
292 W.write<uint32_t>(YamlRel.SymbolIndex);
293 W.write<uint8_t>(YamlRel.Info);
294 W.write<uint8_t>(YamlRel.Type);
298 return true;
301 bool XCOFFWriter::writeSymbols() {
302 int64_t PaddingSize =
303 (uint64_t)InitFileHdr.SymbolTableOffset - (W.OS.tell() - StartOffset);
304 if (PaddingSize < 0) {
305 ErrHandler("redundant data was written before symbols");
306 return false;
308 W.OS.write_zeros(PaddingSize);
309 for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
310 if (Is64Bit) {
311 W.write<uint64_t>(YamlSym.Value);
312 W.write<uint32_t>(Strings.getOffset(YamlSym.SymbolName));
313 } else {
314 if (nameShouldBeInStringTable(YamlSym.SymbolName)) {
315 // For XCOFF32: A value of 0 indicates that the symbol name is in the
316 // string table.
317 W.write<int32_t>(0);
318 W.write<uint32_t>(Strings.getOffset(YamlSym.SymbolName));
319 } else {
320 writeName(YamlSym.SymbolName, W);
322 W.write<uint32_t>(YamlSym.Value);
324 W.write<int16_t>(
325 YamlSym.SectionName.size() ? SectionIndexMap[YamlSym.SectionName] : 0);
326 W.write<uint16_t>(YamlSym.Type);
327 W.write<uint8_t>(YamlSym.StorageClass);
328 W.write<uint8_t>(YamlSym.NumberOfAuxEntries);
330 // Now output the auxiliary entry.
331 for (uint8_t I = 0, E = YamlSym.NumberOfAuxEntries; I < E; ++I) {
332 // TODO: Auxiliary entry is not supported yet.
333 // The auxiliary entries for a symbol follow its symbol table entry. The
334 // length of each auxiliary entry is the same as a symbol table entry (18
335 // bytes). The format and quantity of auxiliary entries depend on the
336 // storage class (n_sclass) and type (n_type) of the symbol table entry.
337 W.OS.write_zeros(XCOFF::SymbolTableEntrySize);
340 return true;
343 bool XCOFFWriter::writeXCOFF() {
344 if (!assignAddressesAndIndices())
345 return false;
346 StartOffset = W.OS.tell();
347 writeFileHeader();
348 if (!Obj.Sections.empty()) {
349 writeSectionHeader();
350 if (!writeSectionData())
351 return false;
352 if (!writeRelocations())
353 return false;
355 if (!Obj.Symbols.empty() && !writeSymbols())
356 return false;
357 // Write the string table.
358 if (Strings.getSize() > 4)
359 Strings.write(W.OS);
360 return true;
363 } // end anonymous namespace
365 namespace llvm {
366 namespace yaml {
368 bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH) {
369 XCOFFWriter Writer(Doc, Out, EH);
370 return Writer.writeXCOFF();
373 } // namespace yaml
374 } // namespace llvm