LLVM  14.0.0git
XCOFFEmitter.cpp
Go to the documentation of this file.
1 //===- yaml2xcoff - Convert YAML to a xcoff object file -------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// The xcoff component of yaml2obj.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/ADT/DenseMap.h"
21 #include "llvm/Support/LEB128.h"
24 
25 using namespace llvm;
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, support::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  bool nameShouldBeInStringTable(StringRef SymbolName);
44  bool initFileHeader(uint64_t CurrentOffset);
45  void initAuxFileHeader();
46  bool initSectionHeader(uint64_t &CurrentOffset);
47  bool initRelocations(uint64_t &CurrentOffset);
48  bool initStringTable();
49  bool assignAddressesAndIndices();
50  void writeFileHeader();
51  void writeAuxFileHeader();
52  void writeSectionHeader();
53  bool writeSectionData();
54  bool writeRelocations();
55  bool writeSymbols();
56  void writeStringTable();
57 
58  XCOFFYAML::Object &Obj;
59  bool Is64Bit = false;
61  yaml::ErrorHandler ErrHandler;
62  StringTableBuilder StrTblBuilder;
63  uint64_t StartOffset;
64  // Map the section name to its corrresponding section index.
65  DenseMap<StringRef, int16_t> SectionIndexMap = {
66  {StringRef("N_DEBUG"), XCOFF::N_DEBUG},
67  {StringRef("N_ABS"), XCOFF::N_ABS},
68  {StringRef("N_UNDEF"), XCOFF::N_UNDEF}};
69  XCOFFYAML::FileHeader InitFileHdr = Obj.Header;
70  XCOFFYAML::AuxiliaryHeader InitAuxFileHdr;
71  std::vector<XCOFFYAML::Section> InitSections = Obj.Sections;
72 };
73 
74 static void writeName(StringRef StrName, support::endian::Writer W) {
75  char Name[XCOFF::NameSize];
76  memset(Name, 0, XCOFF::NameSize);
77  char SrcName[] = "";
78  memcpy(Name, StrName.size() ? StrName.data() : SrcName, StrName.size());
80  W.write(NameRef);
81 }
82 
83 bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) {
84  // For XCOFF64: The symbol name is always in the string table.
85  return (SymbolName.size() > XCOFF::NameSize) || Is64Bit;
86 }
87 
88 bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) {
89  for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {
90  if (!InitSections[I].Relocations.empty()) {
91  InitSections[I].NumberOfRelocations = InitSections[I].Relocations.size();
92  InitSections[I].FileOffsetToRelocations = CurrentOffset;
95  CurrentOffset += InitSections[I].NumberOfRelocations * RelSize;
96  if (CurrentOffset > MaxRawDataSize) {
97  ErrHandler("maximum object size of" + Twine(MaxRawDataSize) +
98  "exceeded when writing relocation data");
99  return false;
100  }
101  }
102  }
103  return true;
104 }
105 
106 bool XCOFFWriter::initSectionHeader(uint64_t &CurrentOffset) {
107  uint64_t CurrentSecAddr = 0;
108  for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {
109  if (CurrentOffset > MaxRawDataSize) {
110  ErrHandler("maximum object size of" + Twine(MaxRawDataSize) +
111  "exceeded when writing section data");
112  return false;
113  }
114 
115  // Assign indices for sections.
116  if (InitSections[I].SectionName.size() &&
117  !SectionIndexMap[InitSections[I].SectionName]) {
118  // The section index starts from 1.
119  SectionIndexMap[InitSections[I].SectionName] = I + 1;
120  if ((I + 1) > MaxSectionIndex) {
121  ErrHandler("exceeded the maximum permitted section index of " +
122  Twine(MaxSectionIndex));
123  return false;
124  }
125  }
126 
127  // Calculate the physical/virtual address. This field should contain 0 for
128  // all sections except the text, data and bss sections.
129  if (InitSections[I].Flags != XCOFF::STYP_TEXT &&
130  InitSections[I].Flags != XCOFF::STYP_DATA &&
131  InitSections[I].Flags != XCOFF::STYP_BSS)
132  InitSections[I].Address = 0;
133  else
134  InitSections[I].Address = CurrentSecAddr;
135 
136  // Calculate the FileOffsetToData and data size for sections.
137  if (InitSections[I].SectionData.binary_size()) {
138  InitSections[I].FileOffsetToData = CurrentOffset;
139  CurrentOffset += InitSections[I].SectionData.binary_size();
140  // Ensure the offset is aligned to DefaultSectionAlign.
141  CurrentOffset = alignTo(CurrentOffset, DefaultSectionAlign);
142  InitSections[I].Size = CurrentOffset - InitSections[I].FileOffsetToData;
143  CurrentSecAddr += InitSections[I].Size;
144  }
145  }
146  return initRelocations(CurrentOffset);
147 }
148 
149 bool XCOFFWriter::initStringTable() {
150  if (Obj.StrTbl.RawContent) {
151  size_t RawSize = Obj.StrTbl.RawContent->binary_size();
152  if (Obj.StrTbl.Strings || Obj.StrTbl.Length) {
153  ErrHandler(
154  "can't specify Strings or Length when RawContent is specified");
155  return false;
156  }
157  if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < RawSize) {
158  ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) +
159  ") is less than the RawContent data size (" + Twine(RawSize) +
160  ")");
161  return false;
162  }
163  return true;
164  }
165  if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize <= 3) {
166  ErrHandler("ContentSize shouldn't be less than 4 without RawContent");
167  return false;
168  }
169 
170  // Build the string table.
171  StrTblBuilder.clear();
172 
173  if (Obj.StrTbl.Strings) {
174  // All specified strings should be added to the string table.
175  for (StringRef StringEnt : *Obj.StrTbl.Strings)
176  StrTblBuilder.add(StringEnt);
177 
178  size_t StrTblIdx = 0;
179  size_t NumOfStrings = Obj.StrTbl.Strings->size();
180  for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
181  if (nameShouldBeInStringTable(YamlSym.SymbolName)) {
182  if (StrTblIdx < NumOfStrings) {
183  // Overwrite the symbol name with the specified string.
184  YamlSym.SymbolName = (*Obj.StrTbl.Strings)[StrTblIdx];
185  ++StrTblIdx;
186  } else
187  // Names that are not overwritten are still stored in the string
188  // table.
189  StrTblBuilder.add(YamlSym.SymbolName);
190  }
191  }
192  } else {
193  for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
194  if (nameShouldBeInStringTable(YamlSym.SymbolName))
195  StrTblBuilder.add(YamlSym.SymbolName);
196  }
197  }
198 
199  StrTblBuilder.finalize();
200 
201  size_t StrTblSize = StrTblBuilder.getSize();
202  if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < StrTblSize) {
203  ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) +
204  ") is less than the size of the data that would otherwise be "
205  "written (" +
206  Twine(StrTblSize) + ")");
207  return false;
208  }
209 
210  return true;
211 }
212 
213 bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset) {
214  // The default format of the object file is XCOFF32.
215  InitFileHdr.Magic = XCOFF::XCOFF32;
216  InitFileHdr.NumberOfSections = Obj.Sections.size();
217  InitFileHdr.NumberOfSymTableEntries = Obj.Symbols.size();
218 
219  for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols)
220  // Add the number of auxiliary symbols to the total number.
221  InitFileHdr.NumberOfSymTableEntries += YamlSym.NumberOfAuxEntries;
222 
223  // Calculate SymbolTableOffset for the file header.
224  if (InitFileHdr.NumberOfSymTableEntries) {
225  InitFileHdr.SymbolTableOffset = CurrentOffset;
226  CurrentOffset +=
227  InitFileHdr.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize;
228  if (CurrentOffset > MaxRawDataSize) {
229  ErrHandler("maximum object size of" + Twine(MaxRawDataSize) +
230  "exceeded when writing symbols");
231  return false;
232  }
233  }
234  // TODO: Calculate FileOffsetToLineNumbers when line number supported.
235  return true;
236 }
237 
238 void XCOFFWriter::initAuxFileHeader() {
239  InitAuxFileHdr = *Obj.AuxHeader;
240  // In general, an object file might contain multiple sections of a given type,
241  // but in a loadable module, there must be exactly one .text, .data, .bss, and
242  // .loader section. A loadable object might also have one .tdata section and
243  // one .tbss section.
244  // Set these section-related values if not set explicitly. We assume that the
245  // input YAML matches the format of the loadable object, but if multiple input
246  // sections still have the same type, the first section with that type
247  // prevails.
248  for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) {
249  switch (InitSections[I].Flags) {
250  case XCOFF::STYP_TEXT:
251  if (!InitAuxFileHdr.TextSize)
252  InitAuxFileHdr.TextSize = InitSections[I].Size;
253  if (!InitAuxFileHdr.TextStartAddr)
254  InitAuxFileHdr.TextStartAddr = InitSections[I].Address;
255  if (!InitAuxFileHdr.SecNumOfText)
256  InitAuxFileHdr.SecNumOfText = I + 1;
257  break;
258  case XCOFF::STYP_DATA:
259  if (!InitAuxFileHdr.InitDataSize)
260  InitAuxFileHdr.InitDataSize = InitSections[I].Size;
261  if (!InitAuxFileHdr.DataStartAddr)
262  InitAuxFileHdr.DataStartAddr = InitSections[I].Address;
263  if (!InitAuxFileHdr.SecNumOfData)
264  InitAuxFileHdr.SecNumOfData = I + 1;
265  break;
266  case XCOFF::STYP_BSS:
267  if (!InitAuxFileHdr.BssDataSize)
268  InitAuxFileHdr.BssDataSize = InitSections[I].Size;
269  if (!InitAuxFileHdr.SecNumOfBSS)
270  InitAuxFileHdr.SecNumOfBSS = I + 1;
271  break;
272  case XCOFF::STYP_TDATA:
273  if (!InitAuxFileHdr.SecNumOfTData)
274  InitAuxFileHdr.SecNumOfTData = I + 1;
275  break;
276  case XCOFF::STYP_TBSS:
277  if (!InitAuxFileHdr.SecNumOfTBSS)
278  InitAuxFileHdr.SecNumOfTBSS = I + 1;
279  break;
280  case XCOFF::STYP_LOADER:
281  if (!InitAuxFileHdr.SecNumOfLoader)
282  InitAuxFileHdr.SecNumOfLoader = I + 1;
283  break;
284  default:
285  break;
286  }
287  }
288 }
289 
290 bool XCOFFWriter::assignAddressesAndIndices() {
291  uint64_t FileHdrSize =
293  uint64_t AuxFileHdrSize = 0;
294  if (Obj.AuxHeader)
295  AuxFileHdrSize = Obj.Header.AuxHeaderSize
296  ? Obj.Header.AuxHeaderSize
297  : (Is64Bit ? XCOFF::AuxFileHeaderSize64
299  uint64_t SecHdrSize =
301  uint64_t CurrentOffset =
302  FileHdrSize + AuxFileHdrSize + InitSections.size() * SecHdrSize;
303 
304  // Calculate section header info.
305  if (!initSectionHeader(CurrentOffset))
306  return false;
307  InitFileHdr.AuxHeaderSize = AuxFileHdrSize;
308 
309  // Calculate file header info.
310  if (!initFileHeader(CurrentOffset))
311  return false;
312 
313  // Initialize the auxiliary file header.
314  if (Obj.AuxHeader)
315  initAuxFileHeader();
316 
317  // Initialize the string table.
318  return initStringTable();
319 }
320 
321 void XCOFFWriter::writeFileHeader() {
322  W.write<uint16_t>(Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic);
323  W.write<uint16_t>(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections
324  : InitFileHdr.NumberOfSections);
325  W.write<int32_t>(Obj.Header.TimeStamp);
326  if (Is64Bit) {
327  W.write<uint64_t>(Obj.Header.SymbolTableOffset
328  ? Obj.Header.SymbolTableOffset
329  : InitFileHdr.SymbolTableOffset);
330  W.write<uint16_t>(InitFileHdr.AuxHeaderSize);
331  W.write<uint16_t>(Obj.Header.Flags);
332  W.write<int32_t>(Obj.Header.NumberOfSymTableEntries
333  ? Obj.Header.NumberOfSymTableEntries
334  : InitFileHdr.NumberOfSymTableEntries);
335  } else {
336  W.write<uint32_t>(Obj.Header.SymbolTableOffset
337  ? Obj.Header.SymbolTableOffset
338  : InitFileHdr.SymbolTableOffset);
339  W.write<int32_t>(Obj.Header.NumberOfSymTableEntries
340  ? Obj.Header.NumberOfSymTableEntries
341  : InitFileHdr.NumberOfSymTableEntries);
342  W.write<uint16_t>(InitFileHdr.AuxHeaderSize);
343  W.write<uint16_t>(Obj.Header.Flags);
344  }
345 }
346 
347 void XCOFFWriter::writeAuxFileHeader() {
348  W.write<uint16_t>(InitAuxFileHdr.Magic.getValueOr(yaml::Hex16(1)));
349  W.write<uint16_t>(InitAuxFileHdr.Version.getValueOr(yaml::Hex16(1)));
350  if (Is64Bit) {
351  W.OS.write_zeros(4); // Reserved for debugger.
352  W.write<uint64_t>(InitAuxFileHdr.TextStartAddr.getValueOr(yaml::Hex64(0)));
353  W.write<uint64_t>(InitAuxFileHdr.DataStartAddr.getValueOr(yaml::Hex64(0)));
354  W.write<uint64_t>(InitAuxFileHdr.TOCAnchorAddr.getValueOr(yaml::Hex64(0)));
355  } else {
356  W.write<uint32_t>(InitAuxFileHdr.TextSize.getValueOr(yaml::Hex64(0)));
357  W.write<uint32_t>(InitAuxFileHdr.InitDataSize.getValueOr(yaml::Hex64(0)));
358  W.write<uint32_t>(InitAuxFileHdr.BssDataSize.getValueOr(yaml::Hex64(0)));
359  W.write<uint32_t>(InitAuxFileHdr.EntryPointAddr.getValueOr(yaml::Hex64(0)));
360  W.write<uint32_t>(InitAuxFileHdr.TextStartAddr.getValueOr(yaml::Hex64(0)));
361  W.write<uint32_t>(InitAuxFileHdr.DataStartAddr.getValueOr(yaml::Hex64(0)));
362  W.write<uint32_t>(InitAuxFileHdr.TOCAnchorAddr.getValueOr(yaml::Hex64(0)));
363  }
364  W.write<uint16_t>(InitAuxFileHdr.SecNumOfEntryPoint.getValueOr(0));
365  W.write<uint16_t>(InitAuxFileHdr.SecNumOfText.getValueOr(0));
366  W.write<uint16_t>(InitAuxFileHdr.SecNumOfData.getValueOr(0));
367  W.write<uint16_t>(InitAuxFileHdr.SecNumOfTOC.getValueOr(0));
368  W.write<uint16_t>(InitAuxFileHdr.SecNumOfLoader.getValueOr(0));
369  W.write<uint16_t>(InitAuxFileHdr.SecNumOfBSS.getValueOr(0));
370  W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfText.getValueOr(yaml::Hex16(0)));
371  W.write<uint16_t>(InitAuxFileHdr.MaxAlignOfData.getValueOr(yaml::Hex16(0)));
372  W.write<uint16_t>(InitAuxFileHdr.ModuleType.getValueOr(yaml::Hex16(0)));
373  W.write<uint8_t>(InitAuxFileHdr.CpuFlag.getValueOr(yaml::Hex8(0)));
374  W.write<uint8_t>(0); // Reserved for CPU type.
375  if (Is64Bit) {
376  W.write<uint8_t>(InitAuxFileHdr.TextPageSize.getValueOr(yaml::Hex8(0)));
377  W.write<uint8_t>(InitAuxFileHdr.DataPageSize.getValueOr(yaml::Hex8(0)));
378  W.write<uint8_t>(InitAuxFileHdr.StackPageSize.getValueOr(yaml::Hex8(0)));
379  W.write<uint8_t>(
380  InitAuxFileHdr.FlagAndTDataAlignment.getValueOr(yaml::Hex8(0x80)));
381  W.write<uint64_t>(InitAuxFileHdr.TextSize.getValueOr(yaml::Hex64(0)));
382  W.write<uint64_t>(InitAuxFileHdr.InitDataSize.getValueOr(yaml::Hex64(0)));
383  W.write<uint64_t>(InitAuxFileHdr.BssDataSize.getValueOr(yaml::Hex64(0)));
384  W.write<uint64_t>(InitAuxFileHdr.EntryPointAddr.getValueOr(yaml::Hex64(0)));
385  W.write<uint64_t>(InitAuxFileHdr.MaxStackSize.getValueOr(yaml::Hex64(0)));
386  W.write<uint64_t>(InitAuxFileHdr.MaxDataSize.getValueOr(yaml::Hex64(0)));
387  } else {
388  W.write<uint32_t>(InitAuxFileHdr.MaxStackSize.getValueOr(yaml::Hex64(0)));
389  W.write<uint32_t>(InitAuxFileHdr.MaxDataSize.getValueOr(yaml::Hex64(0)));
390  W.OS.write_zeros(4); // Reserved for debugger.
391  W.write<uint8_t>(InitAuxFileHdr.TextPageSize.getValueOr(yaml::Hex8(0)));
392  W.write<uint8_t>(InitAuxFileHdr.DataPageSize.getValueOr(yaml::Hex8(0)));
393  W.write<uint8_t>(InitAuxFileHdr.StackPageSize.getValueOr(yaml::Hex8(0)));
394  W.write<uint8_t>(
395  InitAuxFileHdr.FlagAndTDataAlignment.getValueOr(yaml::Hex8(0)));
396  }
397  W.write<uint16_t>(InitAuxFileHdr.SecNumOfTData.getValueOr(0));
398  W.write<uint16_t>(InitAuxFileHdr.SecNumOfTBSS.getValueOr(0));
399  if (Is64Bit) {
400  W.write<uint16_t>(InitAuxFileHdr.Flag.getValueOr(yaml::Hex16(XCOFF::SHR_SYMTAB)));
401  if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize64)
402  W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize64);
403  } else if (InitFileHdr.AuxHeaderSize > XCOFF::AuxFileHeaderSize32) {
404  W.OS.write_zeros(InitFileHdr.AuxHeaderSize - XCOFF::AuxFileHeaderSize32);
405  }
406 }
407 
408 void XCOFFWriter::writeSectionHeader() {
409  for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {
410  XCOFFYAML::Section YamlSec = Obj.Sections[I];
411  XCOFFYAML::Section DerivedSec = InitSections[I];
412  writeName(YamlSec.SectionName, W);
413  // Virtual address is the same as physical address.
414  uint64_t SectionAddress =
415  YamlSec.Address ? YamlSec.Address : DerivedSec.Address;
416  if (Is64Bit) {
417  W.write<uint64_t>(SectionAddress); // Physical address
418  W.write<uint64_t>(SectionAddress); // Virtual address
419  W.write<uint64_t>(YamlSec.Size ? YamlSec.Size : DerivedSec.Size);
420  W.write<uint64_t>(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData
421  : DerivedSec.FileOffsetToData);
422  W.write<uint64_t>(YamlSec.FileOffsetToRelocations
423  ? YamlSec.FileOffsetToRelocations
424  : DerivedSec.FileOffsetToRelocations);
425  W.write<uint64_t>(YamlSec.FileOffsetToLineNumbers);
426  W.write<uint32_t>(YamlSec.NumberOfRelocations
427  ? YamlSec.NumberOfRelocations
428  : DerivedSec.NumberOfRelocations);
429  W.write<uint32_t>(YamlSec.NumberOfLineNumbers);
430  W.write<int32_t>(YamlSec.Flags);
431  W.OS.write_zeros(4);
432  } else {
433  W.write<uint32_t>(SectionAddress); // Physical address
434  W.write<uint32_t>(SectionAddress); // Virtual address
435  W.write<uint32_t>(YamlSec.Size ? YamlSec.Size : DerivedSec.Size);
436  W.write<uint32_t>(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData
437  : DerivedSec.FileOffsetToData);
438  W.write<uint32_t>(YamlSec.FileOffsetToRelocations
439  ? YamlSec.FileOffsetToRelocations
440  : DerivedSec.FileOffsetToRelocations);
441  W.write<uint32_t>(YamlSec.FileOffsetToLineNumbers);
442  W.write<uint16_t>(YamlSec.NumberOfRelocations
443  ? YamlSec.NumberOfRelocations
444  : DerivedSec.NumberOfRelocations);
445  W.write<uint16_t>(YamlSec.NumberOfLineNumbers);
446  W.write<int32_t>(YamlSec.Flags);
447  }
448  }
449 }
450 
451 bool XCOFFWriter::writeSectionData() {
452  for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {
453  XCOFFYAML::Section YamlSec = Obj.Sections[I];
454  if (YamlSec.SectionData.binary_size()) {
455  // Fill the padding size with zeros.
456  int64_t PaddingSize =
457  InitSections[I].FileOffsetToData - (W.OS.tell() - StartOffset);
458  if (PaddingSize < 0) {
459  ErrHandler("redundant data was written before section data");
460  return false;
461  }
462  W.OS.write_zeros(PaddingSize);
463  YamlSec.SectionData.writeAsBinary(W.OS);
464  }
465  }
466  return true;
467 }
468 
469 bool XCOFFWriter::writeRelocations() {
470  for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) {
471  XCOFFYAML::Section YamlSec = Obj.Sections[I];
472  if (!YamlSec.Relocations.empty()) {
473  int64_t PaddingSize =
474  InitSections[I].FileOffsetToRelocations - (W.OS.tell() - StartOffset);
475  if (PaddingSize < 0) {
476  ErrHandler("redundant data was written before relocations");
477  return false;
478  }
479  W.OS.write_zeros(PaddingSize);
480  for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) {
481  if (Is64Bit)
482  W.write<uint64_t>(YamlRel.VirtualAddress);
483  else
484  W.write<uint32_t>(YamlRel.VirtualAddress);
485  W.write<uint32_t>(YamlRel.SymbolIndex);
486  W.write<uint8_t>(YamlRel.Info);
487  W.write<uint8_t>(YamlRel.Type);
488  }
489  }
490  }
491  return true;
492 }
493 
494 bool XCOFFWriter::writeSymbols() {
495  int64_t PaddingSize =
496  (uint64_t)InitFileHdr.SymbolTableOffset - (W.OS.tell() - StartOffset);
497  if (PaddingSize < 0) {
498  ErrHandler("redundant data was written before symbols");
499  return false;
500  }
501  W.OS.write_zeros(PaddingSize);
502  for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
503  if (Is64Bit) {
504  W.write<uint64_t>(YamlSym.Value);
505  W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName));
506  } else {
507  if (nameShouldBeInStringTable(YamlSym.SymbolName)) {
508  // For XCOFF32: A value of 0 indicates that the symbol name is in the
509  // string table.
510  W.write<int32_t>(0);
511  W.write<uint32_t>(StrTblBuilder.getOffset(YamlSym.SymbolName));
512  } else {
513  writeName(YamlSym.SymbolName, W);
514  }
515  W.write<uint32_t>(YamlSym.Value);
516  }
517  if (YamlSym.SectionName) {
518  if (!SectionIndexMap.count(*YamlSym.SectionName)) {
519  ErrHandler("the SectionName " + *YamlSym.SectionName +
520  " specified in the symbol does not exist");
521  return false;
522  }
523  if (YamlSym.SectionIndex &&
524  SectionIndexMap[*YamlSym.SectionName] != *YamlSym.SectionIndex) {
525  ErrHandler("the SectionName " + *YamlSym.SectionName +
526  " and the SectionIndex (" + Twine(*YamlSym.SectionIndex) +
527  ") refer to different sections");
528  return false;
529  }
530  W.write<int16_t>(SectionIndexMap[*YamlSym.SectionName]);
531  } else {
532  W.write<int16_t>(YamlSym.SectionIndex ? *YamlSym.SectionIndex : 0);
533  }
534  W.write<uint16_t>(YamlSym.Type);
535  W.write<uint8_t>(YamlSym.StorageClass);
536  W.write<uint8_t>(YamlSym.NumberOfAuxEntries);
537 
538  // Now output the auxiliary entry.
539  for (uint8_t I = 0, E = YamlSym.NumberOfAuxEntries; I < E; ++I) {
540  // TODO: Auxiliary entry is not supported yet.
541  // The auxiliary entries for a symbol follow its symbol table entry. The
542  // length of each auxiliary entry is the same as a symbol table entry (18
543  // bytes). The format and quantity of auxiliary entries depend on the
544  // storage class (n_sclass) and type (n_type) of the symbol table entry.
545  W.OS.write_zeros(XCOFF::SymbolTableEntrySize);
546  }
547  }
548  return true;
549 }
550 
552  if (Obj.StrTbl.RawContent) {
553  Obj.StrTbl.RawContent->writeAsBinary(W.OS);
554  if (Obj.StrTbl.ContentSize) {
555  assert(*Obj.StrTbl.ContentSize >= Obj.StrTbl.RawContent->binary_size() &&
556  "Specified ContentSize is less than the RawContent size.");
557  W.OS.write_zeros(*Obj.StrTbl.ContentSize -
558  Obj.StrTbl.RawContent->binary_size());
559  }
560  return;
561  }
562 
563  size_t StrTblBuilderSize = StrTblBuilder.getSize();
564  // If neither Length nor ContentSize is specified, write the StrTblBuilder
565  // directly, which contains the auto-generated Length value.
566  if (!Obj.StrTbl.Length && !Obj.StrTbl.ContentSize) {
567  if (StrTblBuilderSize <= 4)
568  return;
569  StrTblBuilder.write(W.OS);
570  return;
571  }
572 
573  // Serialize the string table's content to a temporary buffer.
574  std::unique_ptr<WritableMemoryBuffer> Buf =
575  WritableMemoryBuffer::getNewMemBuffer(StrTblBuilderSize);
576  uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart());
577  StrTblBuilder.write(Ptr);
578  // Replace the first 4 bytes, which contain the auto-generated Length value,
579  // with the specified value.
580  memset(Ptr, 0, 4);
581  support::endian::write32be(Ptr, Obj.StrTbl.Length ? *Obj.StrTbl.Length
582  : *Obj.StrTbl.ContentSize);
583  // Copy the buffer content to the actual output stream.
584  W.OS.write(Buf->getBufferStart(), Buf->getBufferSize());
585  // Add zeros as padding after strings.
586  if (Obj.StrTbl.ContentSize) {
587  assert(*Obj.StrTbl.ContentSize >= StrTblBuilderSize &&
588  "Specified ContentSize is less than the StringTableBuilder size.");
589  W.OS.write_zeros(*Obj.StrTbl.ContentSize - StrTblBuilderSize);
590  }
591 }
592 
593 bool XCOFFWriter::writeXCOFF() {
594  if (!assignAddressesAndIndices())
595  return false;
596  StartOffset = W.OS.tell();
597  writeFileHeader();
598  if (Obj.AuxHeader)
599  writeAuxFileHeader();
600  if (!Obj.Sections.empty()) {
601  writeSectionHeader();
602  if (!writeSectionData())
603  return false;
604  if (!writeRelocations())
605  return false;
606  }
607  if (!Obj.Symbols.empty() && !writeSymbols())
608  return false;
610  return true;
611 }
612 
613 } // end anonymous namespace
614 
615 namespace llvm {
616 namespace yaml {
617 
619  XCOFFWriter Writer(Doc, Out, EH);
620  return Writer.writeXCOFF();
621 }
622 
623 } // namespace yaml
624 } // namespace llvm
MemoryBuffer.h
llvm::alignTo
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition: Alignment.h:148
llvm::XCOFFYAML::Symbol::SectionIndex
Optional< uint16_t > SectionIndex
Definition: XCOFFYAML.h:89
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AllocatorList.h:23
ObjectYAML.h
llvm::XCOFFYAML::FileHeader
Definition: XCOFFYAML.h:22
llvm::XCOFFYAML::Section::FileOffsetToRelocations
llvm::yaml::Hex64 FileOffsetToRelocations
Definition: XCOFFYAML.h:76
llvm::XCOFF::SectionHeaderSize64
constexpr size_t SectionHeaderSize64
Definition: XCOFF.h:35
llvm::support::endian::write32be
void write32be(void *P, uint32_t V)
Definition: Endian.h:419
llvm::XCOFF::RelocationSerializationSize64
constexpr size_t RelocationSerializationSize64
Definition: XCOFF.h:38
llvm::XCOFF::STYP_BSS
@ STYP_BSS
Definition: XCOFF.h:95
llvm::XCOFFYAML::AuxiliaryHeader
Definition: XCOFFYAML.h:32
llvm::yaml::yaml2xcoff
bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH)
Definition: XCOFFEmitter.cpp:618
llvm::RISCVFenceField::W
@ W
Definition: RISCVBaseInfo.h:208
llvm::XCOFFYAML::Object::Sections
std::vector< Section > Sections
Definition: XCOFFYAML.h:106
llvm::XCOFF::SectionHeaderSize32
constexpr size_t SectionHeaderSize32
Definition: XCOFF.h:34
llvm::XCOFFYAML::FileHeader::Magic
llvm::yaml::Hex16 Magic
Definition: XCOFFYAML.h:23
DenseMap.h
llvm::XCOFFYAML::Section::FileOffsetToData
llvm::yaml::Hex64 FileOffsetToData
Definition: XCOFFYAML.h:75
llvm::XCOFFYAML::Symbol::SectionName
Optional< StringRef > SectionName
Definition: XCOFFYAML.h:88
llvm::XCOFF::STYP_LOADER
@ STYP_LOADER
Definition: XCOFF.h:100
llvm::support::endian::Writer
Adapter to write values to a stream in a particular byte order.
Definition: EndianStream.h:52
llvm::XCOFFYAML::Relocation
Definition: XCOFFYAML.h:64
XCOFF.h
StringTableBuilder.h
llvm::XCOFF::XCOFF32
@ XCOFF32
Definition: XCOFF.h:44
llvm::XCOFF::N_ABS
@ N_ABS
Definition: XCOFF.h:42
E
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
llvm::XCOFF::XCOFF64
@ XCOFF64
Definition: XCOFF.h:44
XCOFFObjectFile.h
llvm::XCOFF::SHR_SYMTAB
@ SHR_SYMTAB
At exec time, create shared symbol table for program (main program only).
Definition: XCOFF.h:48
llvm::XCOFF::SymbolTableEntrySize
constexpr size_t SymbolTableEntrySize
Definition: XCOFF.h:36
llvm::raw_ostream
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
llvm::object::writeStringTable
static void writeStringTable(std::vector< uint8_t > &B, ArrayRef< const std::string > Strings)
Definition: COFFImportFile.cpp:66
llvm::WritableMemoryBuffer::getNewMemBuffer
static std::unique_ptr< WritableMemoryBuffer > getNewMemBuffer(size_t Size, const Twine &BufferName="")
Allocate a new zero-initialized MemoryBuffer of the specified size.
Definition: MemoryBuffer.cpp:315
llvm::XCOFFYAML::Symbol::SymbolName
StringRef SymbolName
Definition: XCOFFYAML.h:86
llvm::XCOFFYAML::Section::Flags
uint32_t Flags
Definition: XCOFFYAML.h:80
llvm::XCOFF::N_DEBUG
@ N_DEBUG
Definition: XCOFF.h:42
llvm::XCOFFYAML::Relocation::VirtualAddress
llvm::yaml::Hex64 VirtualAddress
Definition: XCOFFYAML.h:65
llvm::XCOFF::NameSize
constexpr size_t NameSize
Definition: XCOFF.h:29
llvm::function_ref
An efficient, type-erasing, non-owning reference to a callable.
Definition: STLExtras.h:168
llvm::XCOFFYAML::Symbol::Type
llvm::yaml::Hex16 Type
Definition: XCOFFYAML.h:90
llvm::XCOFF::STYP_TDATA
@ STYP_TDATA
Definition: XCOFF.h:98
uint64_t
llvm::yaml::BinaryRef::writeAsBinary
void writeAsBinary(raw_ostream &OS, uint64_t N=UINT64_MAX) const
Write the contents (regardless of whether it is binary or a hex string) as binary to the given raw_os...
Definition: YAML.cpp:40
LEB128.h
llvm::DenseMap
Definition: DenseMap.h:714
I
#define I(x, y, z)
Definition: MD5.cpp:59
llvm::XCOFFYAML::Section::NumberOfRelocations
llvm::yaml::Hex16 NumberOfRelocations
Definition: XCOFFYAML.h:78
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
memcpy
<%struct.s * > cast struct s *S to sbyte *< sbyte * > sbyte uint cast struct s *agg result to sbyte *< sbyte * > sbyte uint cast struct s *memtmp to sbyte *< sbyte * > sbyte uint ret void llc ends up issuing two memcpy or custom lower memcpy(of small size) to be ldmia/stmia. I think option 2 is better but the current register allocator cannot allocate a chunk of registers at a time. A feasible temporary solution is to use specific physical registers at the lowering time for small(<
llvm::XCOFFYAML::Object
Definition: XCOFFYAML.h:103
llvm::XCOFFYAML::Symbol::Value
llvm::yaml::Hex64 Value
Definition: XCOFFYAML.h:87
llvm::XCOFFYAML::Relocation::Type
llvm::yaml::Hex8 Type
Definition: XCOFFYAML.h:68
llvm::XCOFFYAML::Section
Definition: XCOFFYAML.h:71
yaml2obj.h
llvm::XCOFFYAML::Relocation::Info
llvm::yaml::Hex8 Info
Definition: XCOFFYAML.h:67
llvm::ArrayRef< char >
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:57
uint32_t
llvm::XCOFF::FileHeaderSize64
constexpr size_t FileHeaderSize64
Definition: XCOFF.h:31
llvm::XCOFF::FileHeaderSize32
constexpr size_t FileHeaderSize32
Definition: XCOFF.h:30
llvm::XCOFF::N_UNDEF
@ N_UNDEF
Definition: XCOFF.h:42
llvm::XCOFFYAML::Object::Header
FileHeader Header
Definition: XCOFFYAML.h:104
llvm::AMDGPU::HSAMD::Kernel::Key::SymbolName
constexpr char SymbolName[]
Key for Kernel::Metadata::mSymbolName.
Definition: AMDGPUMetadata.h:381
llvm::Twine
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:83
llvm::GraphProgram::Name
Name
Definition: GraphWriter.h:52
EndianStream.h
llvm::XCOFFYAML::Section::Size
llvm::yaml::Hex64 Size
Definition: XCOFFYAML.h:74
uint16_t
llvm::SectionName
Definition: DWARFSection.h:21
llvm::XCOFFYAML::Section::FileOffsetToLineNumbers
llvm::yaml::Hex64 FileOffsetToLineNumbers
Definition: XCOFFYAML.h:77
llvm::XCOFFYAML::Symbol::NumberOfAuxEntries
uint8_t NumberOfAuxEntries
Definition: XCOFFYAML.h:92
llvm::StringTableBuilder
Utility for building string tables with deduplicated suffixes.
Definition: StringTableBuilder.h:23
llvm::XCOFFYAML::Section::NumberOfLineNumbers
llvm::yaml::Hex16 NumberOfLineNumbers
Definition: XCOFFYAML.h:79
llvm::XCOFF::STYP_DATA
@ STYP_DATA
Definition: XCOFF.h:94
llvm::XCOFF::AuxFileHeaderSize32
constexpr size_t AuxFileHeaderSize32
Definition: XCOFF.h:32
llvm::XCOFFYAML::Section::Address
llvm::yaml::Hex64 Address
Definition: XCOFFYAML.h:73
llvm::XCOFF::STYP_TEXT
@ STYP_TEXT
Definition: XCOFF.h:93
llvm::yaml::BinaryRef::binary_size
ArrayRef< uint8_t >::size_type binary_size() const
The number of bytes that are represented by this BinaryRef.
Definition: YAML.h:80
support
Reimplement select in terms of SEL *We would really like to support but we need to prove that the add doesn t need to overflow between the two bit chunks *Implement pre post increment support(e.g. PR935) *Implement smarter const ant generation for binops with large immediates. A few ARMv6T2 ops should be pattern matched
Definition: README.txt:10
llvm::XCOFFYAML::Section::SectionData
yaml::BinaryRef SectionData
Definition: XCOFFYAML.h:81
llvm::StringRef::data
const LLVM_NODISCARD char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:148
llvm::XCOFFYAML::Relocation::SymbolIndex
llvm::yaml::Hex64 SymbolIndex
Definition: XCOFFYAML.h:66
llvm::XCOFFYAML::Section::Relocations
std::vector< Relocation > Relocations
Definition: XCOFFYAML.h:82
llvm::XCOFF::RelocationSerializationSize32
constexpr size_t RelocationSerializationSize32
Definition: XCOFF.h:37
llvm::XCOFF::STYP_TBSS
@ STYP_TBSS
Definition: XCOFF.h:99
llvm::XCOFFYAML::Symbol::StorageClass
XCOFF::StorageClass StorageClass
Definition: XCOFFYAML.h:91
raw_ostream.h
llvm::StringRef::size
LLVM_NODISCARD size_t size() const
size - Get the string size.
Definition: StringRef.h:156
llvm::XCOFFYAML::Symbol
Definition: XCOFFYAML.h:85
llvm::XCOFFYAML::Section::SectionName
StringRef SectionName
Definition: XCOFFYAML.h:72
llvm::support::big
@ big
Definition: Endian.h:27
llvm::XCOFF::AuxFileHeaderSize64
constexpr size_t AuxFileHeaderSize64
Definition: XCOFF.h:33