LLVM  10.0.0svn
XCOFFObjectWriter.cpp
Go to the documentation of this file.
1 //===-- lib/MC/XCOFFObjectWriter.cpp - XCOFF file writer ------------------===//
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 // This file implements XCOFF object file writer information.
10 //
11 //===----------------------------------------------------------------------===//
12 
14 #include "llvm/MC/MCAsmLayout.h"
15 #include "llvm/MC/MCAssembler.h"
16 #include "llvm/MC/MCObjectWriter.h"
17 #include "llvm/MC/MCSectionXCOFF.h"
18 #include "llvm/MC/MCSymbolXCOFF.h"
19 #include "llvm/MC/MCValue.h"
22 #include "llvm/Support/Error.h"
24 
25 #include <deque>
26 
27 using namespace llvm;
28 
29 // An XCOFF object file has a limited set of predefined sections. The most
30 // important ones for us (right now) are:
31 // .text --> contains program code and read-only data.
32 // .data --> contains initialized data, function descriptors, and the TOC.
33 // .bss --> contains uninitialized data.
34 // Each of these sections is composed of 'Control Sections'. A Control Section
35 // is more commonly referred to as a csect. A csect is an indivisible unit of
36 // code or data, and acts as a container for symbols. A csect is mapped
37 // into a section based on its storage-mapping class, with the exception of
38 // XMC_RW which gets mapped to either .data or .bss based on whether it's
39 // explicitly initialized or not.
40 //
41 // We don't represent the sections in the MC layer as there is nothing
42 // interesting about them at at that level: they carry information that is
43 // only relevant to the ObjectWriter, so we materialize them in this class.
44 namespace {
45 
46 constexpr unsigned DefaultSectionAlign = 4;
47 
48 // Packs the csect's alignment and type into a byte.
49 uint8_t getEncodedType(const MCSectionXCOFF *);
50 
51 // Wrapper around an MCSymbolXCOFF.
52 struct Symbol {
53  const MCSymbolXCOFF *const MCSym;
54  uint32_t SymbolTableIndex;
55 
56  XCOFF::StorageClass getStorageClass() const {
57  return MCSym->getStorageClass();
58  }
59  StringRef getName() const { return MCSym->getName(); }
60  bool nameInStringTable() const {
61  return MCSym->getName().size() > XCOFF::NameSize;
62  }
63 
64  Symbol(const MCSymbolXCOFF *MCSym) : MCSym(MCSym), SymbolTableIndex(-1) {}
65 };
66 
67 // Wrapper for an MCSectionXCOFF.
68 struct ControlSection {
69  const MCSectionXCOFF *const MCCsect;
70  uint32_t SymbolTableIndex;
72  uint32_t Size;
73 
75 
76  ControlSection(const MCSectionXCOFF *MCSec)
77  : MCCsect(MCSec), SymbolTableIndex(-1), Address(-1) {}
78 };
79 
80 // Represents the data related to a section excluding the csects that make up
81 // the raw data of the section. The csects are stored separately as not all
82 // sections contain csects, and some sections contain csects which are better
83 // stored separately, e.g. the .data section containing read-write, descriptor,
84 // TOCBase and TOC-entry csects.
85 struct Section {
86  char Name[XCOFF::NameSize];
87  // The physical/virtual address of the section. For an object file
88  // these values are equivalent.
90  uint32_t Size;
91  uint32_t FileOffsetToData;
92  uint32_t FileOffsetToRelocations;
93  uint32_t RelocationCount;
94  int32_t Flags;
95 
96  uint16_t Index;
97 
98  // Virtual sections do not need storage allocated in the object file.
99  const bool IsVirtual;
100 
101  void reset() {
102  Address = 0;
103  Size = 0;
104  FileOffsetToData = 0;
105  FileOffsetToRelocations = 0;
106  RelocationCount = 0;
107  Index = -1;
108  }
109 
110  Section(const char *N, XCOFF::SectionTypeFlags Flags, bool IsVirtual)
111  : Address(0), Size(0), FileOffsetToData(0), FileOffsetToRelocations(0),
112  RelocationCount(0), Flags(Flags), Index(-1), IsVirtual(IsVirtual) {
113  strncpy(Name, N, XCOFF::NameSize);
114  }
115 };
116 
117 class XCOFFObjectWriter : public MCObjectWriter {
118  // Type to be used for a container representing a set of csects with
119  // (approximately) the same storage mapping class. For example all the csects
120  // with a storage mapping class of `xmc_pr` will get placed into the same
121  // container.
122  using ControlSections = std::deque<ControlSection>;
123 
125  std::unique_ptr<MCXCOFFObjectTargetWriter> TargetObjectWriter;
126  StringTableBuilder Strings;
127 
128  // The non-empty sections, in the order they will appear in the section header
129  // table.
130  std::vector<Section *> Sections;
131 
132  // The Predefined sections.
133  Section Text;
134  Section BSS;
135 
136  // ControlSections. These store the csects which make up different parts of
137  // the sections. Should have one for each set of csects that get mapped into
138  // the same section and get handled in a 'similar' way.
139  ControlSections ProgramCodeCsects;
140  ControlSections BSSCsects;
141 
142  uint32_t SymbolTableEntryCount = 0;
143  uint32_t SymbolTableOffset = 0;
144 
145  virtual void reset() override;
146 
147  void executePostLayoutBinding(MCAssembler &, const MCAsmLayout &) override;
148 
149  void recordRelocation(MCAssembler &, const MCAsmLayout &, const MCFragment *,
150  const MCFixup &, MCValue, uint64_t &) override;
151 
152  uint64_t writeObject(MCAssembler &, const MCAsmLayout &) override;
153 
154  void writeFileHeader();
155  void writeSectionHeaderTable();
156  void writeSymbolTable();
157 
158  // Called after all the csects and symbols have been processed by
159  // `executePostLayoutBinding`, this function handles building up the majority
160  // of the structures in the object file representation. Namely:
161  // *) Calculates physical/virtual addresses, raw-pointer offsets, and section
162  // sizes.
163  // *) Assigns symbol table indices.
164  // *) Builds up the section header table by adding any non-empty sections to
165  // `Sections`.
166  void assignAddressesAndIndices(const llvm::MCAsmLayout &);
167 
168  bool
169  needsAuxiliaryHeader() const { /* TODO aux header support not implemented. */
170  return false;
171  }
172 
173  // Returns the size of the auxiliary header to be written to the object file.
174  size_t auxiliaryHeaderSize() const {
175  assert(!needsAuxiliaryHeader() &&
176  "Auxiliary header support not implemented.");
177  return 0;
178  }
179 
180 public:
181  XCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW,
182  raw_pwrite_stream &OS);
183 };
184 
185 XCOFFObjectWriter::XCOFFObjectWriter(
186  std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS)
187  : W(OS, support::big), TargetObjectWriter(std::move(MOTW)),
188  Strings(StringTableBuilder::XCOFF),
189  Text(".text", XCOFF::STYP_TEXT, /* IsVirtual */ false),
190  BSS(".bss", XCOFF::STYP_BSS, /* IsVirtual */ true) {}
191 
192 void XCOFFObjectWriter::reset() {
193  // Reset any sections we have written to, and empty the section header table.
194  for (auto *Sec : Sections)
195  Sec->reset();
196  Sections.clear();
197 
198  // Clear any csects we have stored.
199  ProgramCodeCsects.clear();
200  BSSCsects.clear();
201 
202  // Reset the symbol table and string table.
203  SymbolTableEntryCount = 0;
204  SymbolTableOffset = 0;
205  Strings.clear();
206 
208 }
209 
210 void XCOFFObjectWriter::executePostLayoutBinding(
211  llvm::MCAssembler &Asm, const llvm::MCAsmLayout &Layout) {
212  if (TargetObjectWriter->is64Bit())
213  report_fatal_error("64-bit XCOFF object files are not supported yet.");
214 
215  // Maps the MC Section representation to its corresponding ControlSection
216  // wrapper. Needed for finding the ControlSection to insert an MCSymbol into
217  // from its containing MCSectionXCOFF.
219 
220  for (const auto &S : Asm) {
221  const MCSectionXCOFF *MCSec = dyn_cast<const MCSectionXCOFF>(&S);
222  assert(WrapperMap.find(MCSec) == WrapperMap.end() &&
223  "Cannot add a csect twice.");
224 
225  switch (MCSec->getMappingClass()) {
226  case XCOFF::XMC_PR:
227  assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
228  "Only an initialized csect can contain program code.");
229  // TODO FIXME Handle .text section csects.
230  break;
231  case XCOFF::XMC_RW:
232  if (XCOFF::XTY_CM == MCSec->getCSectType()) {
233  BSSCsects.emplace_back(MCSec);
234  WrapperMap[MCSec] = &BSSCsects.back();
235  break;
236  }
237  report_fatal_error("Unhandled mapping of read-write csect to section.");
238  case XCOFF::XMC_BS:
239  assert(XCOFF::XTY_CM == MCSec->getCSectType() &&
240  "Mapping invalid csect. CSECT with bss storage class must be "
241  "common type.");
242  BSSCsects.emplace_back(MCSec);
243  WrapperMap[MCSec] = &BSSCsects.back();
244  break;
245  default:
246  report_fatal_error("Unhandled mapping of csect to section.");
247  }
248  }
249 
250  for (const MCSymbol &S : Asm.symbols()) {
251  // Nothing to do for temporary symbols.
252  if (S.isTemporary())
253  continue;
254  const MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(&S);
255 
256  // Map the symbol into its containing csect.
257  const MCSectionXCOFF *ContainingCsect = XSym->getContainingCsect();
258  assert(WrapperMap.find(ContainingCsect) != WrapperMap.end() &&
259  "Expected containing csect to exist in map");
260 
261  // Lookup the containing csect and add the symbol to it.
262  WrapperMap[ContainingCsect]->Syms.emplace_back(XSym);
263 
264  // If the name does not fit in the storage provided in the symbol table
265  // entry, add it to the string table.
266  const Symbol &WrapperSym = WrapperMap[ContainingCsect]->Syms.back();
267  if (WrapperSym.nameInStringTable()) {
268  Strings.add(WrapperSym.getName());
269  }
270  }
271 
272  Strings.finalize();
273  assignAddressesAndIndices(Layout);
274 }
275 
276 void XCOFFObjectWriter::recordRelocation(MCAssembler &, const MCAsmLayout &,
277  const MCFragment *, const MCFixup &,
278  MCValue, uint64_t &) {
279  report_fatal_error("XCOFF relocations not supported.");
280 }
281 
282 uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &) {
283  // We always emit a timestamp of 0 for reproducibility, so ensure incremental
284  // linking is not enabled, in case, like with Windows COFF, such a timestamp
285  // is incompatible with incremental linking of XCOFF.
287  report_fatal_error("Incremental linking not supported for XCOFF.");
288 
289  if (TargetObjectWriter->is64Bit())
290  report_fatal_error("64-bit XCOFF object files are not supported yet.");
291 
292  uint64_t StartOffset = W.OS.tell();
293 
294  writeFileHeader();
295  writeSectionHeaderTable();
296  // TODO writeSections();
297  // TODO writeRelocations();
298 
299  // TODO FIXME Finalize symbols.
301  // Write the string table.
302  Strings.write(W.OS);
303 
304  return W.OS.tell() - StartOffset;
305 }
306 
307 void XCOFFObjectWriter::writeFileHeader() {
308  // Magic.
309  W.write<uint16_t>(0x01df);
310  // Number of sections.
311  W.write<uint16_t>(Sections.size());
312  // Timestamp field. For reproducible output we write a 0, which represents no
313  // timestamp.
314  W.write<int32_t>(0);
315  // Byte Offset to the start of the symbol table.
316  W.write<uint32_t>(SymbolTableOffset);
317  // Number of entries in the symbol table.
318  W.write<int32_t>(SymbolTableEntryCount);
319  // Size of the optional header.
320  W.write<uint16_t>(0);
321  // Flags.
322  W.write<uint16_t>(0);
323 }
324 
325 void XCOFFObjectWriter::writeSectionHeaderTable() {
326  for (const auto *Sec : Sections) {
327  // Write Name.
328  ArrayRef<char> NameRef(Sec->Name, XCOFF::NameSize);
329  W.write(NameRef);
330 
331  // Write the Physical Address and Virtual Address. In an object file these
332  // are the same.
333  W.write<uint32_t>(Sec->Address);
334  W.write<uint32_t>(Sec->Address);
335 
336  W.write<uint32_t>(Sec->Size);
337  W.write<uint32_t>(Sec->FileOffsetToData);
338 
339  // Relocation pointer and Lineno pointer. Not supported yet.
340  W.write<uint32_t>(0);
341  W.write<uint32_t>(0);
342 
343  // Relocation and line-number counts. Not supported yet.
344  W.write<uint16_t>(0);
345  W.write<uint16_t>(0);
346 
347  W.write<int32_t>(Sec->Flags);
348  }
349 }
350 
352  assert(ProgramCodeCsects.size() == 0 && ".text csects not handled yet.");
353 
354  // The BSS Section is special in that the csects must contain a single symbol,
355  // and the contained symbol cannot be represented in the symbol table as a
356  // label definition.
357  for (auto &Sec : BSSCsects) {
358  assert(Sec.Syms.size() == 1 &&
359  "Uninitialized csect cannot contain more then 1 symbol.");
360  Symbol &Sym = Sec.Syms.back();
361 
362  // Write the symbol's name.
363  if (Sym.nameInStringTable()) {
364  W.write<int32_t>(0);
365  W.write<uint32_t>(Strings.getOffset(Sym.getName()));
366  } else {
367  char Name[XCOFF::NameSize];
368  std::strncpy(Name, Sym.getName().data(), XCOFF::NameSize);
369  ArrayRef<char> NameRef(Name, XCOFF::NameSize);
370  W.write(NameRef);
371  }
372 
373  W.write<uint32_t>(Sec.Address);
374  W.write<int16_t>(BSS.Index);
375  // Basic/Derived type. See the description of the n_type field for symbol
376  // table entries for a detailed description. Since we don't yet support
377  // visibility, and all other bits are either optionally set or reserved,
378  // this is always zero.
379  // TODO FIXME How to assert a symbols visibility is default?
380  W.write<uint16_t>(0);
381 
382  W.write<uint8_t>(Sym.getStorageClass());
383 
384  // Always 1 aux entry for now.
385  W.write<uint8_t>(1);
386 
387  W.write<uint32_t>(Sec.Size);
388 
389  // Parameter typecheck hash. Not supported.
390  W.write<uint32_t>(0);
391  // Typecheck section number. Not supported.
392  W.write<uint16_t>(0);
393  // Symbol type.
394  W.write<uint8_t>(getEncodedType(Sec.MCCsect));
395  // Storage mapping class.
396  W.write<uint8_t>(Sec.MCCsect->getMappingClass());
397  // Reserved (x_stab).
398  W.write<uint32_t>(0);
399  // Reserved (x_snstab).
400  W.write<uint16_t>(0);
401  }
402 }
403 
404 void XCOFFObjectWriter::assignAddressesAndIndices(
405  const llvm::MCAsmLayout &Layout) {
406  // The address corrresponds to the address of sections and symbols in the
407  // object file. We place the shared address 0 immediately after the
408  // section header table.
409  uint32_t Address = 0;
410  // Section indices are 1-based in XCOFF.
411  uint16_t SectionIndex = 1;
412  // The first symbol table entry is for the file name. We are not emitting it
413  // yet, so start at index 0.
414  uint32_t SymbolTableIndex = 0;
415 
416  // Text section comes first. TODO
417  // Data section Second. TODO
418 
419  // BSS Section third.
420  if (!BSSCsects.empty()) {
421  Sections.push_back(&BSS);
422  BSS.Index = SectionIndex++;
423  assert(alignTo(Address, DefaultSectionAlign) == Address &&
424  "Improperly aligned address for section.");
425  uint32_t StartAddress = Address;
426  for (auto &Csect : BSSCsects) {
427  const MCSectionXCOFF *MCSec = Csect.MCCsect;
428  Address = alignTo(Address, MCSec->getAlignment());
429  Csect.Address = Address;
430  Address += Layout.getSectionAddressSize(MCSec);
431  Csect.SymbolTableIndex = SymbolTableIndex;
432  // 1 main and 1 auxiliary symbol table entry for the csect.
433  SymbolTableIndex += 2;
434  Csect.Size = Layout.getSectionAddressSize(MCSec);
435 
436  assert(Csect.Syms.size() == 1 &&
437  "csect in the BSS can only contain a single symbol.");
438  Csect.Syms[0].SymbolTableIndex = Csect.SymbolTableIndex;
439  }
440  // Pad out Address to the default alignment. This is to match how the system
441  // assembler handles the .bss section. Its size is always a multiple of 4.
442  Address = alignTo(Address, DefaultSectionAlign);
443  BSS.Size = Address - StartAddress;
444  }
445 
446  SymbolTableEntryCount = SymbolTableIndex;
447 
448  // Calculate the RawPointer value for each section.
449  uint64_t RawPointer = sizeof(XCOFF::FileHeader32) + auxiliaryHeaderSize() +
450  Sections.size() * sizeof(XCOFF::SectionHeader32);
451  for (auto *Sec : Sections) {
452  if (!Sec->IsVirtual) {
453  Sec->FileOffsetToData = RawPointer;
454  RawPointer += Sec->Size;
455  }
456  }
457 
458  // TODO Add in Relocation storage to the RawPointer Calculation.
459  // TODO What to align the SymbolTable to?
460  // TODO Error check that the number of symbol table entries fits in 32-bits
461  // signed ...
462  if (SymbolTableEntryCount)
463  SymbolTableOffset = RawPointer;
464 }
465 
466 // Takes the log base 2 of the alignment and shifts the result into the 5 most
467 // significant bits of a byte, then or's in the csect type into the least
468 // significant 3 bits.
469 uint8_t getEncodedType(const MCSectionXCOFF *Sec) {
470  unsigned Align = Sec->getAlignment();
471  assert(isPowerOf2_32(Align) && "Alignment must be a power of 2.");
472  unsigned Log2Align = Log2_32(Align);
473  // Result is a number in the range [0, 31] which fits in the 5 least
474  // significant bits. Shift this value into the 5 most significant bits, and
475  // bitwise-or in the csect type.
476  uint8_t EncodedAlign = Log2Align << 3;
477  return EncodedAlign | Sec->getCSectType();
478 }
479 
480 } // end anonymous namespace
481 
482 std::unique_ptr<MCObjectWriter>
483 llvm::createXCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW,
484  raw_pwrite_stream &OS) {
485  return std::make_unique<XCOFFObjectWriter>(std::move(MOTW), OS);
486 }
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:139
This class represents lattice values for constants.
Definition: AllocatorList.h:23
This represents an "assembler immediate".
Definition: MCValue.h:39
uint64_t getSectionAddressSize(const MCSection *Sec) const
Get the address space size of the given section, as it effects layout.
Definition: MCFragment.cpp:175
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:41
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
block Block Frequency true
Read Write Data.
Definition: XCOFF.h:42
Defines the object file and target independent interfaces used by the assembler backend to write nati...
Encode information on a single operation to perform on a byte sequence (e.g., an encoded instruction)...
Definition: MCFixup.h:77
unsigned getAlignment() const
Definition: MCSection.h:121
Definition: BitVector.h:937
const MCSectionXCOFF * getContainingCsect() const
Definition: MCSymbolXCOFF.h:45
Encapsulates the layout of an assembly file at a particular point in time.
Definition: MCAsmLayout.h:28
static StringRef getName(Value *V)
SectionTypeFlags
Definition: XCOFF.h:58
void write(raw_ostream &OS) const
StorageClass
Definition: XCOFF.h:76
Utility for building string tables with deduplicated suffixes.
size_t add(CachedHashStringRef S)
Add a string to the builder.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
Definition: APInt.h:32
LLVM_NODISCARD size_t size() const
size - Get the string size.
Definition: StringRef.h:144
Common csect definition. For uninitialized storage.
Definition: XCOFF.h:148
Program Code.
Definition: XCOFF.h:30
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition: MathExtras.h:428
virtual void reset()
lifetime management
void finalize()
Analyze the strings and build the final table.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:40
std::unique_ptr< MCObjectWriter > createXCOFFObjectWriter(std::unique_ptr< MCXCOFFObjectTargetWriter > MOTW, raw_pwrite_stream &OS)
XCOFF::SymbolType getCSectType() const
BSS class (uninitialized static internal)
Definition: XCOFF.h:48
size_t getOffset(CachedHashStringRef S) const
Get the offest of a string in the string table.
void write(ArrayRef< value_type > Val)
Definition: EndianStream.h:55
This is a &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:837
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition: MathExtras.h:538
Csect definition for initialized storage.
Definition: XCOFF.h:145
Adapter to write values to a stream in a particular byte order.
Definition: EndianStream.h:51
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition: Alignment.h:126
static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, bool Deterministic, ArrayRef< MemberData > Members, StringRef StringTable)
XCOFF::StorageMappingClass getMappingClass() const
#define N
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
Definition: Casting.h:332
uint32_t Size
Definition: Profile.cpp:46
StringRef getName() const
getName - Get the symbol name.
Definition: MCSymbol.h:204
An abstract base class for streams implementations that also support a pwrite operation.
Definition: raw_ostream.h:359
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
bool isIncrementalLinkerCompatible() const
Definition: MCAssembler.h:313
XCOFF::StorageClass getStorageClass() const
Definition: MCSymbolXCOFF.h:32
uint64_t tell() const
tell - Return the current offset with the file.
Definition: raw_ostream.h:111
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48