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
13 #include "llvm/BinaryFormat/XCOFF.h"
14 #include "llvm/MC/MCAsmBackend.h"
15 #include "llvm/MC/MCAsmLayout.h"
16 #include "llvm/MC/MCAssembler.h"
17 #include "llvm/MC/MCFixup.h"
18 #include "llvm/MC/MCFixupKindInfo.h"
19 #include "llvm/MC/MCObjectWriter.h"
20 #include "llvm/MC/MCSectionXCOFF.h"
21 #include "llvm/MC/MCSymbolXCOFF.h"
22 #include "llvm/MC/MCValue.h"
23 #include "llvm/MC/MCXCOFFObjectWriter.h"
24 #include "llvm/MC/StringTableBuilder.h"
25 #include "llvm/Support/EndianStream.h"
26 #include "llvm/Support/Error.h"
27 #include "llvm/Support/MathExtras.h"
28
29 #include <deque>
30
31 using namespace llvm;
32
33 // An XCOFF object file has a limited set of predefined sections. The most
34 // important ones for us (right now) are:
35 // .text --> contains program code and read-only data.
36 // .data --> contains initialized data, function descriptors, and the TOC.
37 // .bss --> contains uninitialized data.
38 // Each of these sections is composed of 'Control Sections'. A Control Section
39 // is more commonly referred to as a csect. A csect is an indivisible unit of
40 // code or data, and acts as a container for symbols. A csect is mapped
41 // into a section based on its storage-mapping class, with the exception of
42 // XMC_RW which gets mapped to either .data or .bss based on whether it's
43 // explicitly initialized or not.
44 //
45 // We don't represent the sections in the MC layer as there is nothing
46 // interesting about them at at that level: they carry information that is
47 // only relevant to the ObjectWriter, so we materialize them in this class.
48 namespace {
49
50 constexpr unsigned DefaultSectionAlign = 4;
51 constexpr int16_t MaxSectionIndex = INT16_MAX;
52
53 // Packs the csect's alignment and type into a byte.
54 uint8_t getEncodedType(const MCSectionXCOFF *);
55
56 struct XCOFFRelocation {
57 uint32_t SymbolTableIndex;
58 uint32_t FixupOffsetInCsect;
59 uint8_t SignAndSize;
60 uint8_t Type;
61 };
62
63 // Wrapper around an MCSymbolXCOFF.
64 struct Symbol {
65 const MCSymbolXCOFF *const MCSym;
66 uint32_t SymbolTableIndex;
67
getStorageClass__anondc5f94440111::Symbol68 XCOFF::StorageClass getStorageClass() const {
69 return MCSym->getStorageClass();
70 }
getSymbolTableName__anondc5f94440111::Symbol71 StringRef getSymbolTableName() const { return MCSym->getSymbolTableName(); }
Symbol__anondc5f94440111::Symbol72 Symbol(const MCSymbolXCOFF *MCSym) : MCSym(MCSym), SymbolTableIndex(-1) {}
73 };
74
75 // Wrapper for an MCSectionXCOFF.
76 struct ControlSection {
77 const MCSectionXCOFF *const MCCsect;
78 uint32_t SymbolTableIndex;
79 uint32_t Address;
80 uint32_t Size;
81
82 SmallVector<Symbol, 1> Syms;
83 SmallVector<XCOFFRelocation, 1> Relocations;
getSymbolTableName__anondc5f94440111::ControlSection84 StringRef getSymbolTableName() const { return MCCsect->getSymbolTableName(); }
ControlSection__anondc5f94440111::ControlSection85 ControlSection(const MCSectionXCOFF *MCSec)
86 : MCCsect(MCSec), SymbolTableIndex(-1), Address(-1), Size(0) {}
87 };
88
89 // Type to be used for a container representing a set of csects with
90 // (approximately) the same storage mapping class. For example all the csects
91 // with a storage mapping class of `xmc_pr` will get placed into the same
92 // container.
93 using CsectGroup = std::deque<ControlSection>;
94 using CsectGroups = std::deque<CsectGroup *>;
95
96 // Represents the data related to a section excluding the csects that make up
97 // the raw data of the section. The csects are stored separately as not all
98 // sections contain csects, and some sections contain csects which are better
99 // stored separately, e.g. the .data section containing read-write, descriptor,
100 // TOCBase and TOC-entry csects.
101 struct Section {
102 char Name[XCOFF::NameSize];
103 // The physical/virtual address of the section. For an object file
104 // these values are equivalent.
105 uint32_t Address;
106 uint32_t Size;
107 uint32_t FileOffsetToData;
108 uint32_t FileOffsetToRelocations;
109 uint32_t RelocationCount;
110 int32_t Flags;
111
112 int16_t Index;
113
114 // Virtual sections do not need storage allocated in the object file.
115 const bool IsVirtual;
116
117 // XCOFF has special section numbers for symbols:
118 // -2 Specifies N_DEBUG, a special symbolic debugging symbol.
119 // -1 Specifies N_ABS, an absolute symbol. The symbol has a value but is not
120 // relocatable.
121 // 0 Specifies N_UNDEF, an undefined external symbol.
122 // Therefore, we choose -3 (N_DEBUG - 1) to represent a section index that
123 // hasn't been initialized.
124 static constexpr int16_t UninitializedIndex =
125 XCOFF::ReservedSectionNum::N_DEBUG - 1;
126
127 CsectGroups Groups;
128
reset__anondc5f94440111::Section129 void reset() {
130 Address = 0;
131 Size = 0;
132 FileOffsetToData = 0;
133 FileOffsetToRelocations = 0;
134 RelocationCount = 0;
135 Index = UninitializedIndex;
136 // Clear any csects we have stored.
137 for (auto *Group : Groups)
138 Group->clear();
139 }
140
Section__anondc5f94440111::Section141 Section(StringRef N, XCOFF::SectionTypeFlags Flags, bool IsVirtual,
142 CsectGroups Groups)
143 : Name(), Address(0), Size(0), FileOffsetToData(0),
144 FileOffsetToRelocations(0), RelocationCount(0), Flags(Flags),
145 Index(UninitializedIndex), IsVirtual(IsVirtual), Groups(Groups) {
146 assert(N.size() <= XCOFF::NameSize && "section name too long");
147 memcpy(Name, N.data(), N.size());
148 }
149 };
150
151 class XCOFFObjectWriter : public MCObjectWriter {
152
153 uint32_t SymbolTableEntryCount = 0;
154 uint32_t SymbolTableOffset = 0;
155 uint16_t SectionCount = 0;
156 uint32_t RelocationEntryOffset = 0;
157
158 support::endian::Writer W;
159 std::unique_ptr<MCXCOFFObjectTargetWriter> TargetObjectWriter;
160 StringTableBuilder Strings;
161
162 // Maps the MCSection representation to its corresponding ControlSection
163 // wrapper. Needed for finding the ControlSection to insert an MCSymbol into
164 // from its containing MCSectionXCOFF.
165 DenseMap<const MCSectionXCOFF *, ControlSection *> SectionMap;
166
167 // Maps the MCSymbol representation to its corrresponding symbol table index.
168 // Needed for relocation.
169 DenseMap<const MCSymbol *, uint32_t> SymbolIndexMap;
170
171 // CsectGroups. These store the csects which make up different parts of
172 // the sections. Should have one for each set of csects that get mapped into
173 // the same section and get handled in a 'similar' way.
174 CsectGroup UndefinedCsects;
175 CsectGroup ProgramCodeCsects;
176 CsectGroup ReadOnlyCsects;
177 CsectGroup DataCsects;
178 CsectGroup FuncDSCsects;
179 CsectGroup TOCCsects;
180 CsectGroup BSSCsects;
181 CsectGroup TDataCsects;
182 CsectGroup TBSSCsects;
183
184 // The Predefined sections.
185 Section Text;
186 Section Data;
187 Section BSS;
188 Section TData;
189 Section TBSS;
190
191 // All the XCOFF sections, in the order they will appear in the section header
192 // table.
193 std::array<Section *const, 5> Sections{{&Text, &Data, &BSS, &TData, &TBSS}};
194
195 CsectGroup &getCsectGroup(const MCSectionXCOFF *MCSec);
196
197 virtual void reset() override;
198
199 void executePostLayoutBinding(MCAssembler &, const MCAsmLayout &) override;
200
201 void recordRelocation(MCAssembler &, const MCAsmLayout &, const MCFragment *,
202 const MCFixup &, MCValue, uint64_t &) override;
203
204 uint64_t writeObject(MCAssembler &, const MCAsmLayout &) override;
205
206 static bool nameShouldBeInStringTable(const StringRef &);
207 void writeSymbolName(const StringRef &);
208 void writeSymbolTableEntryForCsectMemberLabel(const Symbol &,
209 const ControlSection &, int16_t,
210 uint64_t);
211 void writeSymbolTableEntryForControlSection(const ControlSection &, int16_t,
212 XCOFF::StorageClass);
213 void writeFileHeader();
214 void writeSectionHeaderTable();
215 void writeSections(const MCAssembler &Asm, const MCAsmLayout &Layout);
216 void writeSymbolTable(const MCAsmLayout &Layout);
217 void writeRelocations();
218 void writeRelocation(XCOFFRelocation Reloc, const ControlSection &CSection);
219
220 // Called after all the csects and symbols have been processed by
221 // `executePostLayoutBinding`, this function handles building up the majority
222 // of the structures in the object file representation. Namely:
223 // *) Calculates physical/virtual addresses, raw-pointer offsets, and section
224 // sizes.
225 // *) Assigns symbol table indices.
226 // *) Builds up the section header table by adding any non-empty sections to
227 // `Sections`.
228 void assignAddressesAndIndices(const MCAsmLayout &);
229 void finalizeSectionInfo();
230
231 bool
needsAuxiliaryHeader() const232 needsAuxiliaryHeader() const { /* TODO aux header support not implemented. */
233 return false;
234 }
235
236 // Returns the size of the auxiliary header to be written to the object file.
auxiliaryHeaderSize() const237 size_t auxiliaryHeaderSize() const {
238 assert(!needsAuxiliaryHeader() &&
239 "Auxiliary header support not implemented.");
240 return 0;
241 }
242
243 public:
244 XCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW,
245 raw_pwrite_stream &OS);
246 };
247
XCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW,raw_pwrite_stream & OS)248 XCOFFObjectWriter::XCOFFObjectWriter(
249 std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS)
250 : W(OS, support::big), TargetObjectWriter(std::move(MOTW)),
251 Strings(StringTableBuilder::XCOFF),
252 Text(".text", XCOFF::STYP_TEXT, /* IsVirtual */ false,
253 CsectGroups{&ProgramCodeCsects, &ReadOnlyCsects}),
254 Data(".data", XCOFF::STYP_DATA, /* IsVirtual */ false,
255 CsectGroups{&DataCsects, &FuncDSCsects, &TOCCsects}),
256 BSS(".bss", XCOFF::STYP_BSS, /* IsVirtual */ true,
257 CsectGroups{&BSSCsects}),
258 TData(".tdata", XCOFF::STYP_TDATA, /* IsVirtual */ false,
259 CsectGroups{&TDataCsects}),
260 TBSS(".tbss", XCOFF::STYP_TBSS, /* IsVirtual */ true,
261 CsectGroups{&TBSSCsects}) {}
262
reset()263 void XCOFFObjectWriter::reset() {
264 // Clear the mappings we created.
265 SymbolIndexMap.clear();
266 SectionMap.clear();
267
268 UndefinedCsects.clear();
269 // Reset any sections we have written to, and empty the section header table.
270 for (auto *Sec : Sections)
271 Sec->reset();
272
273 // Reset states in XCOFFObjectWriter.
274 SymbolTableEntryCount = 0;
275 SymbolTableOffset = 0;
276 SectionCount = 0;
277 RelocationEntryOffset = 0;
278 Strings.clear();
279
280 MCObjectWriter::reset();
281 }
282
getCsectGroup(const MCSectionXCOFF * MCSec)283 CsectGroup &XCOFFObjectWriter::getCsectGroup(const MCSectionXCOFF *MCSec) {
284 switch (MCSec->getMappingClass()) {
285 case XCOFF::XMC_PR:
286 assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
287 "Only an initialized csect can contain program code.");
288 return ProgramCodeCsects;
289 case XCOFF::XMC_RO:
290 assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
291 "Only an initialized csect can contain read only data.");
292 return ReadOnlyCsects;
293 case XCOFF::XMC_RW:
294 if (XCOFF::XTY_CM == MCSec->getCSectType())
295 return BSSCsects;
296
297 if (XCOFF::XTY_SD == MCSec->getCSectType())
298 return DataCsects;
299
300 report_fatal_error("Unhandled mapping of read-write csect to section.");
301 case XCOFF::XMC_DS:
302 return FuncDSCsects;
303 case XCOFF::XMC_BS:
304 assert(XCOFF::XTY_CM == MCSec->getCSectType() &&
305 "Mapping invalid csect. CSECT with bss storage class must be "
306 "common type.");
307 return BSSCsects;
308 case XCOFF::XMC_TL:
309 assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
310 "Mapping invalid csect. CSECT with tdata storage class must be "
311 "an initialized csect.");
312 return TDataCsects;
313 case XCOFF::XMC_UL:
314 assert(XCOFF::XTY_CM == MCSec->getCSectType() &&
315 "Mapping invalid csect. CSECT with tbss storage class must be "
316 "an uninitialized csect.");
317 return TBSSCsects;
318 case XCOFF::XMC_TC0:
319 assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
320 "Only an initialized csect can contain TOC-base.");
321 assert(TOCCsects.empty() &&
322 "We should have only one TOC-base, and it should be the first csect "
323 "in this CsectGroup.");
324 return TOCCsects;
325 case XCOFF::XMC_TC:
326 case XCOFF::XMC_TE:
327 assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
328 "Only an initialized csect can contain TC entry.");
329 assert(!TOCCsects.empty() &&
330 "We should at least have a TOC-base in this CsectGroup.");
331 return TOCCsects;
332 case XCOFF::XMC_TD:
333 report_fatal_error("toc-data not yet supported when writing object files.");
334 default:
335 report_fatal_error("Unhandled mapping of csect to section.");
336 }
337 }
338
getContainingCsect(const MCSymbolXCOFF * XSym)339 static MCSectionXCOFF *getContainingCsect(const MCSymbolXCOFF *XSym) {
340 if (XSym->isDefined())
341 return cast<MCSectionXCOFF>(XSym->getFragment()->getParent());
342 return XSym->getRepresentedCsect();
343 }
344
executePostLayoutBinding(MCAssembler & Asm,const MCAsmLayout & Layout)345 void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
346 const MCAsmLayout &Layout) {
347 if (TargetObjectWriter->is64Bit())
348 report_fatal_error("64-bit XCOFF object files are not supported yet.");
349
350 for (const auto &S : Asm) {
351 const auto *MCSec = cast<const MCSectionXCOFF>(&S);
352 assert(SectionMap.find(MCSec) == SectionMap.end() &&
353 "Cannot add a csect twice.");
354 assert(XCOFF::XTY_ER != MCSec->getCSectType() &&
355 "An undefined csect should not get registered.");
356
357 // If the name does not fit in the storage provided in the symbol table
358 // entry, add it to the string table.
359 if (nameShouldBeInStringTable(MCSec->getSymbolTableName()))
360 Strings.add(MCSec->getSymbolTableName());
361
362 CsectGroup &Group = getCsectGroup(MCSec);
363 Group.emplace_back(MCSec);
364 SectionMap[MCSec] = &Group.back();
365 }
366
367 for (const MCSymbol &S : Asm.symbols()) {
368 // Nothing to do for temporary symbols.
369 if (S.isTemporary())
370 continue;
371
372 const MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(&S);
373 const MCSectionXCOFF *ContainingCsect = getContainingCsect(XSym);
374
375 if (ContainingCsect->getCSectType() == XCOFF::XTY_ER) {
376 // Handle undefined symbol.
377 UndefinedCsects.emplace_back(ContainingCsect);
378 SectionMap[ContainingCsect] = &UndefinedCsects.back();
379 if (nameShouldBeInStringTable(ContainingCsect->getSymbolTableName()))
380 Strings.add(ContainingCsect->getSymbolTableName());
381 continue;
382 }
383
384 // If the symbol is the csect itself, we don't need to put the symbol
385 // into csect's Syms.
386 if (XSym == ContainingCsect->getQualNameSymbol())
387 continue;
388
389 // Only put a label into the symbol table when it is an external label.
390 if (!XSym->isExternal())
391 continue;
392
393 assert(SectionMap.find(ContainingCsect) != SectionMap.end() &&
394 "Expected containing csect to exist in map");
395 // Lookup the containing csect and add the symbol to it.
396 SectionMap[ContainingCsect]->Syms.emplace_back(XSym);
397
398 // If the name does not fit in the storage provided in the symbol table
399 // entry, add it to the string table.
400 if (nameShouldBeInStringTable(XSym->getSymbolTableName()))
401 Strings.add(XSym->getSymbolTableName());
402 }
403
404 Strings.finalize();
405 assignAddressesAndIndices(Layout);
406 }
407
recordRelocation(MCAssembler & Asm,const MCAsmLayout & Layout,const MCFragment * Fragment,const MCFixup & Fixup,MCValue Target,uint64_t & FixedValue)408 void XCOFFObjectWriter::recordRelocation(MCAssembler &Asm,
409 const MCAsmLayout &Layout,
410 const MCFragment *Fragment,
411 const MCFixup &Fixup, MCValue Target,
412 uint64_t &FixedValue) {
413 auto getIndex = [this](const MCSymbol *Sym,
414 const MCSectionXCOFF *ContainingCsect) {
415 // If we could not find the symbol directly in SymbolIndexMap, this symbol
416 // could either be a temporary symbol or an undefined symbol. In this case,
417 // we would need to have the relocation reference its csect instead.
418 return SymbolIndexMap.find(Sym) != SymbolIndexMap.end()
419 ? SymbolIndexMap[Sym]
420 : SymbolIndexMap[ContainingCsect->getQualNameSymbol()];
421 };
422
423 auto getVirtualAddress = [this,
424 &Layout](const MCSymbol *Sym,
425 const MCSectionXCOFF *ContainingCsect) {
426 // If Sym is a csect, return csect's address.
427 // If Sym is a label, return csect's address + label's offset from the csect.
428 return SectionMap[ContainingCsect]->Address +
429 (Sym->isDefined() ? Layout.getSymbolOffset(*Sym) : 0);
430 };
431
432 const MCSymbol *const SymA = &Target.getSymA()->getSymbol();
433
434 MCAsmBackend &Backend = Asm.getBackend();
435 bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags &
436 MCFixupKindInfo::FKF_IsPCRel;
437
438 uint8_t Type;
439 uint8_t SignAndSize;
440 std::tie(Type, SignAndSize) =
441 TargetObjectWriter->getRelocTypeAndSignSize(Target, Fixup, IsPCRel);
442
443 const MCSectionXCOFF *SymASec = getContainingCsect(cast<MCSymbolXCOFF>(SymA));
444
445 if (SymASec->isCsect() && SymASec->getMappingClass() == XCOFF::XMC_TD)
446 report_fatal_error("toc-data not yet supported when writing object files.");
447
448 assert(SectionMap.find(SymASec) != SectionMap.end() &&
449 "Expected containing csect to exist in map.");
450
451 const uint32_t Index = getIndex(SymA, SymASec);
452 if (Type == XCOFF::RelocationType::R_POS ||
453 Type == XCOFF::RelocationType::R_TLS)
454 // The FixedValue should be symbol's virtual address in this object file
455 // plus any constant value that we might get.
456 FixedValue = getVirtualAddress(SymA, SymASec) + Target.getConstant();
457 else if (Type == XCOFF::RelocationType::R_TLSM)
458 // The FixedValue should always be zero since the region handle is only
459 // known at load time.
460 FixedValue = 0;
461 else if (Type == XCOFF::RelocationType::R_TOC ||
462 Type == XCOFF::RelocationType::R_TOCL) {
463 // The FixedValue should be the TOC entry offset from the TOC-base plus any
464 // constant offset value.
465 const int64_t TOCEntryOffset = SectionMap[SymASec]->Address -
466 TOCCsects.front().Address +
467 Target.getConstant();
468 if (Type == XCOFF::RelocationType::R_TOC && !isInt<16>(TOCEntryOffset))
469 report_fatal_error("TOCEntryOffset overflows in small code model mode");
470
471 FixedValue = TOCEntryOffset;
472 }
473
474 assert(
475 (TargetObjectWriter->is64Bit() ||
476 Fixup.getOffset() <= UINT32_MAX - Layout.getFragmentOffset(Fragment)) &&
477 "Fragment offset + fixup offset is overflowed in 32-bit mode.");
478 uint32_t FixupOffsetInCsect =
479 Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
480
481 XCOFFRelocation Reloc = {Index, FixupOffsetInCsect, SignAndSize, Type};
482 MCSectionXCOFF *RelocationSec = cast<MCSectionXCOFF>(Fragment->getParent());
483 assert(SectionMap.find(RelocationSec) != SectionMap.end() &&
484 "Expected containing csect to exist in map.");
485 SectionMap[RelocationSec]->Relocations.push_back(Reloc);
486
487 if (!Target.getSymB())
488 return;
489
490 const MCSymbol *const SymB = &Target.getSymB()->getSymbol();
491 if (SymA == SymB)
492 report_fatal_error("relocation for opposite term is not yet supported");
493
494 const MCSectionXCOFF *SymBSec = getContainingCsect(cast<MCSymbolXCOFF>(SymB));
495 assert(SectionMap.find(SymBSec) != SectionMap.end() &&
496 "Expected containing csect to exist in map.");
497 if (SymASec == SymBSec)
498 report_fatal_error(
499 "relocation for paired relocatable term is not yet supported");
500
501 assert(Type == XCOFF::RelocationType::R_POS &&
502 "SymA must be R_POS here if it's not opposite term or paired "
503 "relocatable term.");
504 const uint32_t IndexB = getIndex(SymB, SymBSec);
505 // SymB must be R_NEG here, given the general form of Target(MCValue) is
506 // "SymbolA - SymbolB + imm64".
507 const uint8_t TypeB = XCOFF::RelocationType::R_NEG;
508 XCOFFRelocation RelocB = {IndexB, FixupOffsetInCsect, SignAndSize, TypeB};
509 SectionMap[RelocationSec]->Relocations.push_back(RelocB);
510 // We already folded "SymbolA + imm64" above when Type is R_POS for SymbolA,
511 // now we just need to fold "- SymbolB" here.
512 FixedValue -= getVirtualAddress(SymB, SymBSec);
513 }
514
writeSections(const MCAssembler & Asm,const MCAsmLayout & Layout)515 void XCOFFObjectWriter::writeSections(const MCAssembler &Asm,
516 const MCAsmLayout &Layout) {
517 uint32_t CurrentAddressLocation = 0;
518 for (const auto *Section : Sections) {
519 // Nothing to write for this Section.
520 if (Section->Index == Section::UninitializedIndex || Section->IsVirtual)
521 continue;
522
523 // There could be a gap (without corresponding zero padding) between
524 // sections.
525 assert(((CurrentAddressLocation <= Section->Address) ||
526 (Section->Flags == XCOFF::STYP_TDATA) ||
527 (Section->Flags == XCOFF::STYP_TBSS)) &&
528 "CurrentAddressLocation should be less than or equal to section "
529 "address if the section is not TData or TBSS.");
530
531 CurrentAddressLocation = Section->Address;
532
533 for (const auto *Group : Section->Groups) {
534 for (const auto &Csect : *Group) {
535 if (uint32_t PaddingSize = Csect.Address - CurrentAddressLocation)
536 W.OS.write_zeros(PaddingSize);
537 if (Csect.Size)
538 Asm.writeSectionData(W.OS, Csect.MCCsect, Layout);
539 CurrentAddressLocation = Csect.Address + Csect.Size;
540 }
541 }
542
543 // The size of the tail padding in a section is the end virtual address of
544 // the current section minus the the end virtual address of the last csect
545 // in that section.
546 if (uint32_t PaddingSize =
547 Section->Address + Section->Size - CurrentAddressLocation) {
548 W.OS.write_zeros(PaddingSize);
549 CurrentAddressLocation += PaddingSize;
550 }
551 }
552 }
553
writeObject(MCAssembler & Asm,const MCAsmLayout & Layout)554 uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm,
555 const MCAsmLayout &Layout) {
556 // We always emit a timestamp of 0 for reproducibility, so ensure incremental
557 // linking is not enabled, in case, like with Windows COFF, such a timestamp
558 // is incompatible with incremental linking of XCOFF.
559 if (Asm.isIncrementalLinkerCompatible())
560 report_fatal_error("Incremental linking not supported for XCOFF.");
561
562 if (TargetObjectWriter->is64Bit())
563 report_fatal_error("64-bit XCOFF object files are not supported yet.");
564
565 finalizeSectionInfo();
566 uint64_t StartOffset = W.OS.tell();
567
568 writeFileHeader();
569 writeSectionHeaderTable();
570 writeSections(Asm, Layout);
571 writeRelocations();
572
573 writeSymbolTable(Layout);
574 // Write the string table.
575 Strings.write(W.OS);
576
577 return W.OS.tell() - StartOffset;
578 }
579
nameShouldBeInStringTable(const StringRef & SymbolName)580 bool XCOFFObjectWriter::nameShouldBeInStringTable(const StringRef &SymbolName) {
581 return SymbolName.size() > XCOFF::NameSize;
582 }
583
writeSymbolName(const StringRef & SymbolName)584 void XCOFFObjectWriter::writeSymbolName(const StringRef &SymbolName) {
585 if (nameShouldBeInStringTable(SymbolName)) {
586 W.write<int32_t>(0);
587 W.write<uint32_t>(Strings.getOffset(SymbolName));
588 } else {
589 char Name[XCOFF::NameSize+1];
590 std::strncpy(Name, SymbolName.data(), XCOFF::NameSize);
591 ArrayRef<char> NameRef(Name, XCOFF::NameSize);
592 W.write(NameRef);
593 }
594 }
595
writeSymbolTableEntryForCsectMemberLabel(const Symbol & SymbolRef,const ControlSection & CSectionRef,int16_t SectionIndex,uint64_t SymbolOffset)596 void XCOFFObjectWriter::writeSymbolTableEntryForCsectMemberLabel(
597 const Symbol &SymbolRef, const ControlSection &CSectionRef,
598 int16_t SectionIndex, uint64_t SymbolOffset) {
599 // Name or Zeros and string table offset
600 writeSymbolName(SymbolRef.getSymbolTableName());
601 assert(SymbolOffset <= UINT32_MAX - CSectionRef.Address &&
602 "Symbol address overflows.");
603 W.write<uint32_t>(CSectionRef.Address + SymbolOffset);
604 W.write<int16_t>(SectionIndex);
605 // Basic/Derived type. See the description of the n_type field for symbol
606 // table entries for a detailed description. Since we don't yet support
607 // visibility, and all other bits are either optionally set or reserved, this
608 // is always zero.
609 // TODO FIXME How to assert a symbol's visibilty is default?
610 // TODO Set the function indicator (bit 10, 0x0020) for functions
611 // when debugging is enabled.
612 W.write<uint16_t>(0);
613 W.write<uint8_t>(SymbolRef.getStorageClass());
614 // Always 1 aux entry for now.
615 W.write<uint8_t>(1);
616
617 // Now output the auxiliary entry.
618 W.write<uint32_t>(CSectionRef.SymbolTableIndex);
619 // Parameter typecheck hash. Not supported.
620 W.write<uint32_t>(0);
621 // Typecheck section number. Not supported.
622 W.write<uint16_t>(0);
623 // Symbol type: Label
624 W.write<uint8_t>(XCOFF::XTY_LD);
625 // Storage mapping class.
626 W.write<uint8_t>(CSectionRef.MCCsect->getMappingClass());
627 // Reserved (x_stab).
628 W.write<uint32_t>(0);
629 // Reserved (x_snstab).
630 W.write<uint16_t>(0);
631 }
632
writeSymbolTableEntryForControlSection(const ControlSection & CSectionRef,int16_t SectionIndex,XCOFF::StorageClass StorageClass)633 void XCOFFObjectWriter::writeSymbolTableEntryForControlSection(
634 const ControlSection &CSectionRef, int16_t SectionIndex,
635 XCOFF::StorageClass StorageClass) {
636 // n_name, n_zeros, n_offset
637 writeSymbolName(CSectionRef.getSymbolTableName());
638 // n_value
639 W.write<uint32_t>(CSectionRef.Address);
640 // n_scnum
641 W.write<int16_t>(SectionIndex);
642 // Basic/Derived type. See the description of the n_type field for symbol
643 // table entries for a detailed description. Since we don't yet support
644 // visibility, and all other bits are either optionally set or reserved, this
645 // is always zero.
646 // TODO FIXME How to assert a symbol's visibilty is default?
647 // TODO Set the function indicator (bit 10, 0x0020) for functions
648 // when debugging is enabled.
649 W.write<uint16_t>(0);
650 // n_sclass
651 W.write<uint8_t>(StorageClass);
652 // Always 1 aux entry for now.
653 W.write<uint8_t>(1);
654
655 // Now output the auxiliary entry.
656 W.write<uint32_t>(CSectionRef.Size);
657 // Parameter typecheck hash. Not supported.
658 W.write<uint32_t>(0);
659 // Typecheck section number. Not supported.
660 W.write<uint16_t>(0);
661 // Symbol type.
662 W.write<uint8_t>(getEncodedType(CSectionRef.MCCsect));
663 // Storage mapping class.
664 W.write<uint8_t>(CSectionRef.MCCsect->getMappingClass());
665 // Reserved (x_stab).
666 W.write<uint32_t>(0);
667 // Reserved (x_snstab).
668 W.write<uint16_t>(0);
669 }
670
writeFileHeader()671 void XCOFFObjectWriter::writeFileHeader() {
672 // Magic.
673 W.write<uint16_t>(0x01df);
674 // Number of sections.
675 W.write<uint16_t>(SectionCount);
676 // Timestamp field. For reproducible output we write a 0, which represents no
677 // timestamp.
678 W.write<int32_t>(0);
679 // Byte Offset to the start of the symbol table.
680 W.write<uint32_t>(SymbolTableOffset);
681 // Number of entries in the symbol table.
682 W.write<int32_t>(SymbolTableEntryCount);
683 // Size of the optional header.
684 W.write<uint16_t>(0);
685 // Flags.
686 W.write<uint16_t>(0);
687 }
688
writeSectionHeaderTable()689 void XCOFFObjectWriter::writeSectionHeaderTable() {
690 for (const auto *Sec : Sections) {
691 // Nothing to write for this Section.
692 if (Sec->Index == Section::UninitializedIndex)
693 continue;
694
695 // Write Name.
696 ArrayRef<char> NameRef(Sec->Name, XCOFF::NameSize);
697 W.write(NameRef);
698
699 // Write the Physical Address and Virtual Address. In an object file these
700 // are the same.
701 W.write<uint32_t>(Sec->Address);
702 W.write<uint32_t>(Sec->Address);
703
704 W.write<uint32_t>(Sec->Size);
705 W.write<uint32_t>(Sec->FileOffsetToData);
706 W.write<uint32_t>(Sec->FileOffsetToRelocations);
707
708 // Line number pointer. Not supported yet.
709 W.write<uint32_t>(0);
710
711 W.write<uint16_t>(Sec->RelocationCount);
712
713 // Line number counts. Not supported yet.
714 W.write<uint16_t>(0);
715
716 W.write<int32_t>(Sec->Flags);
717 }
718 }
719
writeRelocation(XCOFFRelocation Reloc,const ControlSection & CSection)720 void XCOFFObjectWriter::writeRelocation(XCOFFRelocation Reloc,
721 const ControlSection &CSection) {
722 W.write<uint32_t>(CSection.Address + Reloc.FixupOffsetInCsect);
723 W.write<uint32_t>(Reloc.SymbolTableIndex);
724 W.write<uint8_t>(Reloc.SignAndSize);
725 W.write<uint8_t>(Reloc.Type);
726 }
727
writeRelocations()728 void XCOFFObjectWriter::writeRelocations() {
729 for (const auto *Section : Sections) {
730 if (Section->Index == Section::UninitializedIndex)
731 // Nothing to write for this Section.
732 continue;
733
734 for (const auto *Group : Section->Groups) {
735 if (Group->empty())
736 continue;
737
738 for (const auto &Csect : *Group) {
739 for (const auto Reloc : Csect.Relocations)
740 writeRelocation(Reloc, Csect);
741 }
742 }
743 }
744 }
745
writeSymbolTable(const MCAsmLayout & Layout)746 void XCOFFObjectWriter::writeSymbolTable(const MCAsmLayout &Layout) {
747 // Write symbol 0 as C_FILE.
748 // FIXME: support 64-bit C_FILE symbol.
749 //
750 // n_name. The n_name of a C_FILE symbol is the source filename when no
751 // auxiliary entries are present. The source filename is alternatively
752 // provided by an auxiliary entry, in which case the n_name of the C_FILE
753 // symbol is `.file`.
754 // FIXME: add the real source filename.
755 writeSymbolName(".file");
756 // n_value. The n_value of a C_FILE symbol is its symbol table index.
757 W.write<uint32_t>(0);
758 // n_scnum. N_DEBUG is a reserved section number for indicating a special
759 // symbolic debugging symbol.
760 W.write<int16_t>(XCOFF::ReservedSectionNum::N_DEBUG);
761 // n_type. The n_type field of a C_FILE symbol encodes the source language and
762 // CPU version info; zero indicates no info.
763 W.write<uint16_t>(0);
764 // n_sclass. The C_FILE symbol provides source file-name information,
765 // source-language ID and CPU-version ID information and some other optional
766 // infos.
767 W.write<uint8_t>(XCOFF::C_FILE);
768 // n_numaux. No aux entry for now.
769 W.write<uint8_t>(0);
770
771 for (const auto &Csect : UndefinedCsects) {
772 writeSymbolTableEntryForControlSection(
773 Csect, XCOFF::ReservedSectionNum::N_UNDEF, Csect.MCCsect->getStorageClass());
774 }
775
776 for (const auto *Section : Sections) {
777 if (Section->Index == Section::UninitializedIndex)
778 // Nothing to write for this Section.
779 continue;
780
781 for (const auto *Group : Section->Groups) {
782 if (Group->empty())
783 continue;
784
785 const int16_t SectionIndex = Section->Index;
786 for (const auto &Csect : *Group) {
787 // Write out the control section first and then each symbol in it.
788 writeSymbolTableEntryForControlSection(
789 Csect, SectionIndex, Csect.MCCsect->getStorageClass());
790
791 for (const auto &Sym : Csect.Syms)
792 writeSymbolTableEntryForCsectMemberLabel(
793 Sym, Csect, SectionIndex, Layout.getSymbolOffset(*(Sym.MCSym)));
794 }
795 }
796 }
797 }
798
finalizeSectionInfo()799 void XCOFFObjectWriter::finalizeSectionInfo() {
800 for (auto *Section : Sections) {
801 if (Section->Index == Section::UninitializedIndex)
802 // Nothing to record for this Section.
803 continue;
804
805 for (const auto *Group : Section->Groups) {
806 if (Group->empty())
807 continue;
808
809 for (auto &Csect : *Group) {
810 const size_t CsectRelocCount = Csect.Relocations.size();
811 if (CsectRelocCount >= XCOFF::RelocOverflow ||
812 Section->RelocationCount >= XCOFF::RelocOverflow - CsectRelocCount)
813 report_fatal_error(
814 "relocation entries overflowed; overflow section is "
815 "not implemented yet");
816
817 Section->RelocationCount += CsectRelocCount;
818 }
819 }
820 }
821
822 // Calculate the file offset to the relocation entries.
823 uint64_t RawPointer = RelocationEntryOffset;
824 for (auto Sec : Sections) {
825 if (Sec->Index == Section::UninitializedIndex || !Sec->RelocationCount)
826 continue;
827
828 Sec->FileOffsetToRelocations = RawPointer;
829 const uint32_t RelocationSizeInSec =
830 Sec->RelocationCount * XCOFF::RelocationSerializationSize32;
831 RawPointer += RelocationSizeInSec;
832 if (RawPointer > UINT32_MAX)
833 report_fatal_error("Relocation data overflowed this object file.");
834 }
835
836 // TODO Error check that the number of symbol table entries fits in 32-bits
837 // signed ...
838 if (SymbolTableEntryCount)
839 SymbolTableOffset = RawPointer;
840 }
841
assignAddressesAndIndices(const MCAsmLayout & Layout)842 void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) {
843 // The first symbol table entry (at index 0) is for the file name.
844 uint32_t SymbolTableIndex = 1;
845
846 // Calculate indices for undefined symbols.
847 for (auto &Csect : UndefinedCsects) {
848 Csect.Size = 0;
849 Csect.Address = 0;
850 Csect.SymbolTableIndex = SymbolTableIndex;
851 SymbolIndexMap[Csect.MCCsect->getQualNameSymbol()] = Csect.SymbolTableIndex;
852 // 1 main and 1 auxiliary symbol table entry for each contained symbol.
853 SymbolTableIndex += 2;
854 }
855
856 // The address corrresponds to the address of sections and symbols in the
857 // object file. We place the shared address 0 immediately after the
858 // section header table.
859 uint32_t Address = 0;
860 // Section indices are 1-based in XCOFF.
861 int32_t SectionIndex = 1;
862 bool HasTDataSection = false;
863
864 for (auto *Section : Sections) {
865 const bool IsEmpty =
866 llvm::all_of(Section->Groups,
867 [](const CsectGroup *Group) { return Group->empty(); });
868 if (IsEmpty)
869 continue;
870
871 if (SectionIndex > MaxSectionIndex)
872 report_fatal_error("Section index overflow!");
873 Section->Index = SectionIndex++;
874 SectionCount++;
875
876 bool SectionAddressSet = false;
877 // Reset the starting address to 0 for TData section.
878 if (Section->Flags == XCOFF::STYP_TDATA) {
879 Address = 0;
880 HasTDataSection = true;
881 }
882 // Reset the starting address to 0 for TBSS section if the object file does
883 // not contain TData Section.
884 if ((Section->Flags == XCOFF::STYP_TBSS) && !HasTDataSection)
885 Address = 0;
886
887 for (auto *Group : Section->Groups) {
888 if (Group->empty())
889 continue;
890
891 for (auto &Csect : *Group) {
892 const MCSectionXCOFF *MCSec = Csect.MCCsect;
893 Csect.Address = alignTo(Address, MCSec->getAlignment());
894 Csect.Size = Layout.getSectionAddressSize(MCSec);
895 Address = Csect.Address + Csect.Size;
896 Csect.SymbolTableIndex = SymbolTableIndex;
897 SymbolIndexMap[MCSec->getQualNameSymbol()] = Csect.SymbolTableIndex;
898 // 1 main and 1 auxiliary symbol table entry for the csect.
899 SymbolTableIndex += 2;
900
901 for (auto &Sym : Csect.Syms) {
902 Sym.SymbolTableIndex = SymbolTableIndex;
903 SymbolIndexMap[Sym.MCSym] = Sym.SymbolTableIndex;
904 // 1 main and 1 auxiliary symbol table entry for each contained
905 // symbol.
906 SymbolTableIndex += 2;
907 }
908 }
909
910 if (!SectionAddressSet) {
911 Section->Address = Group->front().Address;
912 SectionAddressSet = true;
913 }
914 }
915
916 // Make sure the address of the next section aligned to
917 // DefaultSectionAlign.
918 Address = alignTo(Address, DefaultSectionAlign);
919 Section->Size = Address - Section->Address;
920 }
921
922 SymbolTableEntryCount = SymbolTableIndex;
923
924 // Calculate the RawPointer value for each section.
925 uint64_t RawPointer = sizeof(XCOFF::FileHeader32) + auxiliaryHeaderSize() +
926 SectionCount * sizeof(XCOFF::SectionHeader32);
927 for (auto *Sec : Sections) {
928 if (Sec->Index == Section::UninitializedIndex || Sec->IsVirtual)
929 continue;
930
931 Sec->FileOffsetToData = RawPointer;
932 RawPointer += Sec->Size;
933 if (RawPointer > UINT32_MAX)
934 report_fatal_error("Section raw data overflowed this object file.");
935 }
936
937 RelocationEntryOffset = RawPointer;
938 }
939
940 // Takes the log base 2 of the alignment and shifts the result into the 5 most
941 // significant bits of a byte, then or's in the csect type into the least
942 // significant 3 bits.
getEncodedType(const MCSectionXCOFF * Sec)943 uint8_t getEncodedType(const MCSectionXCOFF *Sec) {
944 unsigned Align = Sec->getAlignment();
945 assert(isPowerOf2_32(Align) && "Alignment must be a power of 2.");
946 unsigned Log2Align = Log2_32(Align);
947 // Result is a number in the range [0, 31] which fits in the 5 least
948 // significant bits. Shift this value into the 5 most significant bits, and
949 // bitwise-or in the csect type.
950 uint8_t EncodedAlign = Log2Align << 3;
951 return EncodedAlign | Sec->getCSectType();
952 }
953
954 } // end anonymous namespace
955
956 std::unique_ptr<MCObjectWriter>
createXCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW,raw_pwrite_stream & OS)957 llvm::createXCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW,
958 raw_pwrite_stream &OS) {
959 return std::make_unique<XCOFFObjectWriter>(std::move(MOTW), OS);
960 }
961