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/Casting.h" |
26 | #include "llvm/Support/EndianStream.h" |
27 | #include "llvm/Support/ErrorHandling.h" |
28 | #include "llvm/Support/MathExtras.h" |
29 | |
30 | #include <deque> |
31 | #include <map> |
32 | |
33 | using namespace llvm; |
34 | |
35 | // An XCOFF object file has a limited set of predefined sections. The most |
36 | // important ones for us (right now) are: |
37 | // .text --> contains program code and read-only data. |
38 | // .data --> contains initialized data, function descriptors, and the TOC. |
39 | // .bss --> contains uninitialized data. |
40 | // Each of these sections is composed of 'Control Sections'. A Control Section |
41 | // is more commonly referred to as a csect. A csect is an indivisible unit of |
42 | // code or data, and acts as a container for symbols. A csect is mapped |
43 | // into a section based on its storage-mapping class, with the exception of |
44 | // XMC_RW which gets mapped to either .data or .bss based on whether it's |
45 | // explicitly initialized or not. |
46 | // |
47 | // We don't represent the sections in the MC layer as there is nothing |
48 | // interesting about them at at that level: they carry information that is |
49 | // only relevant to the ObjectWriter, so we materialize them in this class. |
50 | namespace { |
51 | |
52 | constexpr unsigned DefaultSectionAlign = 4; |
53 | constexpr int16_t MaxSectionIndex = INT16_MAX; |
54 | |
55 | // Packs the csect's alignment and type into a byte. |
56 | uint8_t getEncodedType(const MCSectionXCOFF *); |
57 | |
58 | struct XCOFFRelocation { |
59 | uint32_t SymbolTableIndex; |
60 | uint32_t FixupOffsetInCsect; |
61 | uint8_t SignAndSize; |
62 | uint8_t Type; |
63 | }; |
64 | |
65 | // Wrapper around an MCSymbolXCOFF. |
66 | struct Symbol { |
67 | const MCSymbolXCOFF *const MCSym; |
68 | uint32_t SymbolTableIndex; |
69 | |
70 | XCOFF::VisibilityType getVisibilityType() const { |
71 | return MCSym->getVisibilityType(); |
72 | } |
73 | |
74 | XCOFF::StorageClass getStorageClass() const { |
75 | return MCSym->getStorageClass(); |
76 | } |
77 | StringRef getSymbolTableName() const { return MCSym->getSymbolTableName(); } |
78 | Symbol(const MCSymbolXCOFF *MCSym) : MCSym(MCSym), SymbolTableIndex(-1) {} |
79 | }; |
80 | |
81 | // Wrapper for an MCSectionXCOFF. |
82 | // It can be a Csect or debug section or DWARF section and so on. |
83 | struct XCOFFSection { |
84 | const MCSectionXCOFF *const MCSec; |
85 | uint32_t SymbolTableIndex; |
86 | uint64_t Address; |
87 | uint64_t Size; |
88 | |
89 | SmallVector<Symbol, 1> Syms; |
90 | SmallVector<XCOFFRelocation, 1> Relocations; |
91 | StringRef getSymbolTableName() const { return MCSec->getSymbolTableName(); } |
92 | XCOFF::VisibilityType getVisibilityType() const { |
93 | return MCSec->getVisibilityType(); |
94 | } |
95 | XCOFFSection(const MCSectionXCOFF *MCSec) |
96 | : MCSec(MCSec), SymbolTableIndex(-1), Address(-1), Size(0) {} |
97 | }; |
98 | |
99 | // Type to be used for a container representing a set of csects with |
100 | // (approximately) the same storage mapping class. For example all the csects |
101 | // with a storage mapping class of `xmc_pr` will get placed into the same |
102 | // container. |
103 | using CsectGroup = std::deque<XCOFFSection>; |
104 | using CsectGroups = std::deque<CsectGroup *>; |
105 | |
106 | // The basic section entry defination. This Section represents a section entry |
107 | // in XCOFF section header table. |
108 | struct SectionEntry { |
109 | char Name[XCOFF::NameSize]; |
110 | // The physical/virtual address of the section. For an object file these |
111 | // values are equivalent, except for in the overflow section header, where |
112 | // the physical address specifies the number of relocation entries and the |
113 | // virtual address specifies the number of line number entries. |
114 | // TODO: Divide Address into PhysicalAddress and VirtualAddress when line |
115 | // number entries are supported. |
116 | uint64_t Address; |
117 | uint64_t Size; |
118 | uint64_t FileOffsetToData; |
119 | uint64_t FileOffsetToRelocations; |
120 | uint32_t RelocationCount; |
121 | int32_t Flags; |
122 | |
123 | int16_t Index; |
124 | |
125 | virtual uint64_t advanceFileOffset(const uint64_t MaxRawDataSize, |
126 | const uint64_t RawPointer) { |
127 | FileOffsetToData = RawPointer; |
128 | uint64_t NewPointer = RawPointer + Size; |
129 | if (NewPointer > MaxRawDataSize) |
130 | report_fatal_error(reason: "Section raw data overflowed this object file." ); |
131 | return NewPointer; |
132 | } |
133 | |
134 | // XCOFF has special section numbers for symbols: |
135 | // -2 Specifies N_DEBUG, a special symbolic debugging symbol. |
136 | // -1 Specifies N_ABS, an absolute symbol. The symbol has a value but is not |
137 | // relocatable. |
138 | // 0 Specifies N_UNDEF, an undefined external symbol. |
139 | // Therefore, we choose -3 (N_DEBUG - 1) to represent a section index that |
140 | // hasn't been initialized. |
141 | static constexpr int16_t UninitializedIndex = |
142 | XCOFF::ReservedSectionNum::N_DEBUG - 1; |
143 | |
144 | SectionEntry(StringRef N, int32_t Flags) |
145 | : Name(), Address(0), Size(0), FileOffsetToData(0), |
146 | FileOffsetToRelocations(0), RelocationCount(0), Flags(Flags), |
147 | Index(UninitializedIndex) { |
148 | assert(N.size() <= XCOFF::NameSize && "section name too long" ); |
149 | memcpy(dest: Name, src: N.data(), n: N.size()); |
150 | } |
151 | |
152 | virtual void reset() { |
153 | Address = 0; |
154 | Size = 0; |
155 | FileOffsetToData = 0; |
156 | FileOffsetToRelocations = 0; |
157 | RelocationCount = 0; |
158 | Index = UninitializedIndex; |
159 | } |
160 | |
161 | virtual ~SectionEntry() = default; |
162 | }; |
163 | |
164 | // Represents the data related to a section excluding the csects that make up |
165 | // the raw data of the section. The csects are stored separately as not all |
166 | // sections contain csects, and some sections contain csects which are better |
167 | // stored separately, e.g. the .data section containing read-write, descriptor, |
168 | // TOCBase and TOC-entry csects. |
169 | struct CsectSectionEntry : public SectionEntry { |
170 | // Virtual sections do not need storage allocated in the object file. |
171 | const bool IsVirtual; |
172 | |
173 | // This is a section containing csect groups. |
174 | CsectGroups Groups; |
175 | |
176 | CsectSectionEntry(StringRef N, XCOFF::SectionTypeFlags Flags, bool IsVirtual, |
177 | CsectGroups Groups) |
178 | : SectionEntry(N, Flags), IsVirtual(IsVirtual), Groups(Groups) { |
179 | assert(N.size() <= XCOFF::NameSize && "section name too long" ); |
180 | memcpy(dest: Name, src: N.data(), n: N.size()); |
181 | } |
182 | |
183 | void reset() override { |
184 | SectionEntry::reset(); |
185 | // Clear any csects we have stored. |
186 | for (auto *Group : Groups) |
187 | Group->clear(); |
188 | } |
189 | |
190 | virtual ~CsectSectionEntry() = default; |
191 | }; |
192 | |
193 | struct DwarfSectionEntry : public SectionEntry { |
194 | // For DWARF section entry. |
195 | std::unique_ptr<XCOFFSection> DwarfSect; |
196 | |
197 | // For DWARF section, we must use real size in the section header. MemorySize |
198 | // is for the size the DWARF section occupies including paddings. |
199 | uint32_t MemorySize; |
200 | |
201 | // TODO: Remove this override. Loadable sections (e.g., .text, .data) may need |
202 | // to be aligned. Other sections generally don't need any alignment, but if |
203 | // they're aligned, the RawPointer should be adjusted before writing the |
204 | // section. Then a dwarf-specific function wouldn't be needed. |
205 | uint64_t advanceFileOffset(const uint64_t MaxRawDataSize, |
206 | const uint64_t RawPointer) override { |
207 | FileOffsetToData = RawPointer; |
208 | uint64_t NewPointer = RawPointer + MemorySize; |
209 | assert(NewPointer <= MaxRawDataSize && |
210 | "Section raw data overflowed this object file." ); |
211 | return NewPointer; |
212 | } |
213 | |
214 | DwarfSectionEntry(StringRef N, int32_t Flags, |
215 | std::unique_ptr<XCOFFSection> Sect) |
216 | : SectionEntry(N, Flags | XCOFF::STYP_DWARF), DwarfSect(std::move(Sect)), |
217 | MemorySize(0) { |
218 | assert(DwarfSect->MCSec->isDwarfSect() && |
219 | "This should be a DWARF section!" ); |
220 | assert(N.size() <= XCOFF::NameSize && "section name too long" ); |
221 | memcpy(dest: Name, src: N.data(), n: N.size()); |
222 | } |
223 | |
224 | DwarfSectionEntry(DwarfSectionEntry &&s) = default; |
225 | |
226 | virtual ~DwarfSectionEntry() = default; |
227 | }; |
228 | |
229 | struct ExceptionTableEntry { |
230 | const MCSymbol *Trap; |
231 | uint64_t TrapAddress = ~0ul; |
232 | unsigned Lang; |
233 | unsigned Reason; |
234 | |
235 | ExceptionTableEntry(const MCSymbol *Trap, unsigned Lang, unsigned Reason) |
236 | : Trap(Trap), Lang(Lang), Reason(Reason) {} |
237 | }; |
238 | |
239 | struct ExceptionInfo { |
240 | const MCSymbol *FunctionSymbol; |
241 | unsigned FunctionSize; |
242 | std::vector<ExceptionTableEntry> Entries; |
243 | }; |
244 | |
245 | struct ExceptionSectionEntry : public SectionEntry { |
246 | std::map<const StringRef, ExceptionInfo> ExceptionTable; |
247 | bool isDebugEnabled = false; |
248 | |
249 | ExceptionSectionEntry(StringRef N, int32_t Flags) |
250 | : SectionEntry(N, Flags | XCOFF::STYP_EXCEPT) { |
251 | assert(N.size() <= XCOFF::NameSize && "Section too long." ); |
252 | memcpy(dest: Name, src: N.data(), n: N.size()); |
253 | } |
254 | |
255 | virtual ~ExceptionSectionEntry() = default; |
256 | }; |
257 | |
258 | struct CInfoSymInfo { |
259 | // Name of the C_INFO symbol associated with the section |
260 | std::string Name; |
261 | std::string Metadata; |
262 | // Offset into the start of the metadata in the section |
263 | uint64_t Offset; |
264 | |
265 | CInfoSymInfo(std::string Name, std::string Metadata) |
266 | : Name(Name), Metadata(Metadata) {} |
267 | // Metadata needs to be padded out to an even word size. |
268 | uint32_t paddingSize() const { |
269 | return alignTo(Value: Metadata.size(), Align: sizeof(uint32_t)) - Metadata.size(); |
270 | }; |
271 | |
272 | // Total size of the entry, including the 4 byte length |
273 | uint32_t size() const { |
274 | return Metadata.size() + paddingSize() + sizeof(uint32_t); |
275 | }; |
276 | }; |
277 | |
278 | struct CInfoSymSectionEntry : public SectionEntry { |
279 | std::unique_ptr<CInfoSymInfo> Entry; |
280 | |
281 | CInfoSymSectionEntry(StringRef N, int32_t Flags) : SectionEntry(N, Flags) {} |
282 | virtual ~CInfoSymSectionEntry() = default; |
283 | void addEntry(std::unique_ptr<CInfoSymInfo> NewEntry) { |
284 | Entry = std::move(NewEntry); |
285 | Entry->Offset = sizeof(uint32_t); |
286 | Size += Entry->size(); |
287 | } |
288 | void reset() override { |
289 | SectionEntry::reset(); |
290 | Entry.reset(); |
291 | } |
292 | }; |
293 | |
294 | class XCOFFObjectWriter : public MCObjectWriter { |
295 | |
296 | uint32_t SymbolTableEntryCount = 0; |
297 | uint64_t SymbolTableOffset = 0; |
298 | uint16_t SectionCount = 0; |
299 | uint32_t PaddingsBeforeDwarf = 0; |
300 | std::vector<std::pair<std::string, size_t>> FileNames; |
301 | bool HasVisibility = false; |
302 | |
303 | support::endian::Writer W; |
304 | std::unique_ptr<MCXCOFFObjectTargetWriter> TargetObjectWriter; |
305 | StringTableBuilder Strings; |
306 | |
307 | const uint64_t MaxRawDataSize = |
308 | TargetObjectWriter->is64Bit() ? UINT64_MAX : UINT32_MAX; |
309 | |
310 | // Maps the MCSection representation to its corresponding XCOFFSection |
311 | // wrapper. Needed for finding the XCOFFSection to insert an MCSymbol into |
312 | // from its containing MCSectionXCOFF. |
313 | DenseMap<const MCSectionXCOFF *, XCOFFSection *> SectionMap; |
314 | |
315 | // Maps the MCSymbol representation to its corrresponding symbol table index. |
316 | // Needed for relocation. |
317 | DenseMap<const MCSymbol *, uint32_t> SymbolIndexMap; |
318 | |
319 | // CsectGroups. These store the csects which make up different parts of |
320 | // the sections. Should have one for each set of csects that get mapped into |
321 | // the same section and get handled in a 'similar' way. |
322 | CsectGroup UndefinedCsects; |
323 | CsectGroup ProgramCodeCsects; |
324 | CsectGroup ReadOnlyCsects; |
325 | CsectGroup DataCsects; |
326 | CsectGroup FuncDSCsects; |
327 | CsectGroup TOCCsects; |
328 | CsectGroup BSSCsects; |
329 | CsectGroup TDataCsects; |
330 | CsectGroup TBSSCsects; |
331 | |
332 | // The Predefined sections. |
333 | CsectSectionEntry Text; |
334 | CsectSectionEntry Data; |
335 | CsectSectionEntry BSS; |
336 | CsectSectionEntry TData; |
337 | CsectSectionEntry TBSS; |
338 | |
339 | // All the XCOFF sections, in the order they will appear in the section header |
340 | // table. |
341 | std::array<CsectSectionEntry *const, 5> Sections{ |
342 | ._M_elems: {&Text, &Data, &BSS, &TData, &TBSS}}; |
343 | |
344 | std::vector<DwarfSectionEntry> DwarfSections; |
345 | std::vector<SectionEntry> OverflowSections; |
346 | |
347 | ExceptionSectionEntry ExceptionSection; |
348 | CInfoSymSectionEntry CInfoSymSection; |
349 | |
350 | CsectGroup &getCsectGroup(const MCSectionXCOFF *MCSec); |
351 | |
352 | void reset() override; |
353 | |
354 | void executePostLayoutBinding(MCAssembler &, const MCAsmLayout &) override; |
355 | |
356 | void recordRelocation(MCAssembler &, const MCAsmLayout &, const MCFragment *, |
357 | const MCFixup &, MCValue, uint64_t &) override; |
358 | |
359 | uint64_t writeObject(MCAssembler &, const MCAsmLayout &) override; |
360 | |
361 | bool is64Bit() const { return TargetObjectWriter->is64Bit(); } |
362 | bool nameShouldBeInStringTable(const StringRef &); |
363 | void writeSymbolName(const StringRef &); |
364 | bool auxFileSymNameShouldBeInStringTable(const StringRef &); |
365 | void writeAuxFileSymName(const StringRef &); |
366 | |
367 | void writeSymbolEntryForCsectMemberLabel(const Symbol &SymbolRef, |
368 | const XCOFFSection &CSectionRef, |
369 | int16_t SectionIndex, |
370 | uint64_t SymbolOffset); |
371 | void writeSymbolEntryForControlSection(const XCOFFSection &CSectionRef, |
372 | int16_t SectionIndex, |
373 | XCOFF::StorageClass StorageClass); |
374 | void writeSymbolEntryForDwarfSection(const XCOFFSection &DwarfSectionRef, |
375 | int16_t SectionIndex); |
376 | void writeFileHeader(); |
377 | void writeAuxFileHeader(); |
378 | void writeSectionHeader(const SectionEntry *Sec); |
379 | void writeSectionHeaderTable(); |
380 | void writeSections(const MCAssembler &Asm, const MCAsmLayout &Layout); |
381 | void writeSectionForControlSectionEntry(const MCAssembler &Asm, |
382 | const MCAsmLayout &Layout, |
383 | const CsectSectionEntry &CsectEntry, |
384 | uint64_t &CurrentAddressLocation); |
385 | void writeSectionForDwarfSectionEntry(const MCAssembler &Asm, |
386 | const MCAsmLayout &Layout, |
387 | const DwarfSectionEntry &DwarfEntry, |
388 | uint64_t &CurrentAddressLocation); |
389 | void writeSectionForExceptionSectionEntry( |
390 | const MCAssembler &Asm, const MCAsmLayout &Layout, |
391 | ExceptionSectionEntry &ExceptionEntry, uint64_t &CurrentAddressLocation); |
392 | void writeSectionForCInfoSymSectionEntry(const MCAssembler &Asm, |
393 | const MCAsmLayout &Layout, |
394 | CInfoSymSectionEntry &CInfoSymEntry, |
395 | uint64_t &CurrentAddressLocation); |
396 | void writeSymbolTable(MCAssembler &Asm, const MCAsmLayout &Layout); |
397 | void writeSymbolAuxFileEntry(StringRef &Name, uint8_t ftype); |
398 | void writeSymbolAuxDwarfEntry(uint64_t LengthOfSectionPortion, |
399 | uint64_t NumberOfRelocEnt = 0); |
400 | void writeSymbolAuxCsectEntry(uint64_t SectionOrLength, |
401 | uint8_t SymbolAlignmentAndType, |
402 | uint8_t StorageMappingClass); |
403 | void writeSymbolAuxFunctionEntry(uint32_t EntryOffset, uint32_t FunctionSize, |
404 | uint64_t LineNumberPointer, |
405 | uint32_t EndIndex); |
406 | void writeSymbolAuxExceptionEntry(uint64_t EntryOffset, uint32_t FunctionSize, |
407 | uint32_t EndIndex); |
408 | void writeSymbolEntry(StringRef SymbolName, uint64_t Value, |
409 | int16_t SectionNumber, uint16_t SymbolType, |
410 | uint8_t StorageClass, uint8_t NumberOfAuxEntries = 1); |
411 | void writeRelocations(); |
412 | void writeRelocation(XCOFFRelocation Reloc, const XCOFFSection &Section); |
413 | |
414 | // Called after all the csects and symbols have been processed by |
415 | // `executePostLayoutBinding`, this function handles building up the majority |
416 | // of the structures in the object file representation. Namely: |
417 | // *) Calculates physical/virtual addresses, raw-pointer offsets, and section |
418 | // sizes. |
419 | // *) Assigns symbol table indices. |
420 | // *) Builds up the section header table by adding any non-empty sections to |
421 | // `Sections`. |
422 | void assignAddressesAndIndices(MCAssembler &Asm, const MCAsmLayout &); |
423 | // Called after relocations are recorded. |
424 | void finalizeSectionInfo(); |
425 | void finalizeRelocationInfo(SectionEntry *Sec, uint64_t RelCount); |
426 | void calcOffsetToRelocations(SectionEntry *Sec, uint64_t &RawPointer); |
427 | |
428 | void addExceptionEntry(const MCSymbol *Symbol, const MCSymbol *Trap, |
429 | unsigned LanguageCode, unsigned ReasonCode, |
430 | unsigned FunctionSize, bool hasDebug) override; |
431 | bool hasExceptionSection() { |
432 | return !ExceptionSection.ExceptionTable.empty(); |
433 | } |
434 | unsigned getExceptionSectionSize(); |
435 | unsigned getExceptionOffset(const MCSymbol *Symbol); |
436 | |
437 | void addCInfoSymEntry(StringRef Name, StringRef Metadata) override; |
438 | size_t () const { |
439 | // 64-bit object files have no auxiliary header. |
440 | return HasVisibility && !is64Bit() ? XCOFF::AuxFileHeaderSizeShort : 0; |
441 | } |
442 | |
443 | public: |
444 | XCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW, |
445 | raw_pwrite_stream &OS); |
446 | |
447 | void writeWord(uint64_t Word) { |
448 | is64Bit() ? W.write<uint64_t>(Val: Word) : W.write<uint32_t>(Val: Word); |
449 | } |
450 | }; |
451 | |
452 | XCOFFObjectWriter::XCOFFObjectWriter( |
453 | std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS) |
454 | : W(OS, llvm::endianness::big), TargetObjectWriter(std::move(MOTW)), |
455 | Strings(StringTableBuilder::XCOFF), |
456 | Text(".text" , XCOFF::STYP_TEXT, /* IsVirtual */ false, |
457 | CsectGroups{&ProgramCodeCsects, &ReadOnlyCsects}), |
458 | Data(".data" , XCOFF::STYP_DATA, /* IsVirtual */ false, |
459 | CsectGroups{&DataCsects, &FuncDSCsects, &TOCCsects}), |
460 | BSS(".bss" , XCOFF::STYP_BSS, /* IsVirtual */ true, |
461 | CsectGroups{&BSSCsects}), |
462 | TData(".tdata" , XCOFF::STYP_TDATA, /* IsVirtual */ false, |
463 | CsectGroups{&TDataCsects}), |
464 | TBSS(".tbss" , XCOFF::STYP_TBSS, /* IsVirtual */ true, |
465 | CsectGroups{&TBSSCsects}), |
466 | ExceptionSection(".except" , XCOFF::STYP_EXCEPT), |
467 | CInfoSymSection(".info" , XCOFF::STYP_INFO) {} |
468 | |
469 | void XCOFFObjectWriter::reset() { |
470 | // Clear the mappings we created. |
471 | SymbolIndexMap.clear(); |
472 | SectionMap.clear(); |
473 | |
474 | UndefinedCsects.clear(); |
475 | // Reset any sections we have written to, and empty the section header table. |
476 | for (auto *Sec : Sections) |
477 | Sec->reset(); |
478 | for (auto &DwarfSec : DwarfSections) |
479 | DwarfSec.reset(); |
480 | for (auto &OverflowSec : OverflowSections) |
481 | OverflowSec.reset(); |
482 | ExceptionSection.reset(); |
483 | CInfoSymSection.reset(); |
484 | |
485 | // Reset states in XCOFFObjectWriter. |
486 | SymbolTableEntryCount = 0; |
487 | SymbolTableOffset = 0; |
488 | SectionCount = 0; |
489 | PaddingsBeforeDwarf = 0; |
490 | Strings.clear(); |
491 | |
492 | MCObjectWriter::reset(); |
493 | } |
494 | |
495 | CsectGroup &XCOFFObjectWriter::getCsectGroup(const MCSectionXCOFF *MCSec) { |
496 | switch (MCSec->getMappingClass()) { |
497 | case XCOFF::XMC_PR: |
498 | assert(XCOFF::XTY_SD == MCSec->getCSectType() && |
499 | "Only an initialized csect can contain program code." ); |
500 | return ProgramCodeCsects; |
501 | case XCOFF::XMC_RO: |
502 | assert(XCOFF::XTY_SD == MCSec->getCSectType() && |
503 | "Only an initialized csect can contain read only data." ); |
504 | return ReadOnlyCsects; |
505 | case XCOFF::XMC_RW: |
506 | if (XCOFF::XTY_CM == MCSec->getCSectType()) |
507 | return BSSCsects; |
508 | |
509 | if (XCOFF::XTY_SD == MCSec->getCSectType()) |
510 | return DataCsects; |
511 | |
512 | report_fatal_error(reason: "Unhandled mapping of read-write csect to section." ); |
513 | case XCOFF::XMC_DS: |
514 | return FuncDSCsects; |
515 | case XCOFF::XMC_BS: |
516 | assert(XCOFF::XTY_CM == MCSec->getCSectType() && |
517 | "Mapping invalid csect. CSECT with bss storage class must be " |
518 | "common type." ); |
519 | return BSSCsects; |
520 | case XCOFF::XMC_TL: |
521 | assert(XCOFF::XTY_SD == MCSec->getCSectType() && |
522 | "Mapping invalid csect. CSECT with tdata storage class must be " |
523 | "an initialized csect." ); |
524 | return TDataCsects; |
525 | case XCOFF::XMC_UL: |
526 | assert(XCOFF::XTY_CM == MCSec->getCSectType() && |
527 | "Mapping invalid csect. CSECT with tbss storage class must be " |
528 | "an uninitialized csect." ); |
529 | return TBSSCsects; |
530 | case XCOFF::XMC_TC0: |
531 | assert(XCOFF::XTY_SD == MCSec->getCSectType() && |
532 | "Only an initialized csect can contain TOC-base." ); |
533 | assert(TOCCsects.empty() && |
534 | "We should have only one TOC-base, and it should be the first csect " |
535 | "in this CsectGroup." ); |
536 | return TOCCsects; |
537 | case XCOFF::XMC_TC: |
538 | case XCOFF::XMC_TE: |
539 | assert(XCOFF::XTY_SD == MCSec->getCSectType() && |
540 | "A TOC symbol must be an initialized csect." ); |
541 | assert(!TOCCsects.empty() && |
542 | "We should at least have a TOC-base in this CsectGroup." ); |
543 | return TOCCsects; |
544 | case XCOFF::XMC_TD: |
545 | assert((XCOFF::XTY_SD == MCSec->getCSectType() || |
546 | XCOFF::XTY_CM == MCSec->getCSectType()) && |
547 | "Symbol type incompatible with toc-data." ); |
548 | assert(!TOCCsects.empty() && |
549 | "We should at least have a TOC-base in this CsectGroup." ); |
550 | return TOCCsects; |
551 | default: |
552 | report_fatal_error(reason: "Unhandled mapping of csect to section." ); |
553 | } |
554 | } |
555 | |
556 | static MCSectionXCOFF *getContainingCsect(const MCSymbolXCOFF *XSym) { |
557 | if (XSym->isDefined()) |
558 | return cast<MCSectionXCOFF>(Val: XSym->getFragment()->getParent()); |
559 | return XSym->getRepresentedCsect(); |
560 | } |
561 | |
562 | void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, |
563 | const MCAsmLayout &Layout) { |
564 | for (const auto &S : Asm) { |
565 | const auto *MCSec = cast<const MCSectionXCOFF>(Val: &S); |
566 | assert(!SectionMap.contains(MCSec) && "Cannot add a section twice." ); |
567 | |
568 | // If the name does not fit in the storage provided in the symbol table |
569 | // entry, add it to the string table. |
570 | if (nameShouldBeInStringTable(MCSec->getSymbolTableName())) |
571 | Strings.add(S: MCSec->getSymbolTableName()); |
572 | if (MCSec->isCsect()) { |
573 | // A new control section. Its CsectSectionEntry should already be staticly |
574 | // generated as Text/Data/BSS/TDATA/TBSS. Add this section to the group of |
575 | // the CsectSectionEntry. |
576 | assert(XCOFF::XTY_ER != MCSec->getCSectType() && |
577 | "An undefined csect should not get registered." ); |
578 | CsectGroup &Group = getCsectGroup(MCSec); |
579 | Group.emplace_back(args&: MCSec); |
580 | SectionMap[MCSec] = &Group.back(); |
581 | } else if (MCSec->isDwarfSect()) { |
582 | // A new DwarfSectionEntry. |
583 | std::unique_ptr<XCOFFSection> DwarfSec = |
584 | std::make_unique<XCOFFSection>(args&: MCSec); |
585 | SectionMap[MCSec] = DwarfSec.get(); |
586 | |
587 | DwarfSectionEntry SecEntry(MCSec->getName(), |
588 | *MCSec->getDwarfSubtypeFlags(), |
589 | std::move(DwarfSec)); |
590 | DwarfSections.push_back(x: std::move(SecEntry)); |
591 | } else |
592 | llvm_unreachable("unsupport section type!" ); |
593 | } |
594 | |
595 | for (const MCSymbol &S : Asm.symbols()) { |
596 | // Nothing to do for temporary symbols. |
597 | if (S.isTemporary()) |
598 | continue; |
599 | |
600 | const MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(Val: &S); |
601 | const MCSectionXCOFF *ContainingCsect = getContainingCsect(XSym); |
602 | |
603 | if (XSym->getVisibilityType() != XCOFF::SYM_V_UNSPECIFIED) |
604 | HasVisibility = true; |
605 | |
606 | if (ContainingCsect->getCSectType() == XCOFF::XTY_ER) { |
607 | // Handle undefined symbol. |
608 | UndefinedCsects.emplace_back(args&: ContainingCsect); |
609 | SectionMap[ContainingCsect] = &UndefinedCsects.back(); |
610 | if (nameShouldBeInStringTable(ContainingCsect->getSymbolTableName())) |
611 | Strings.add(S: ContainingCsect->getSymbolTableName()); |
612 | continue; |
613 | } |
614 | |
615 | // If the symbol is the csect itself, we don't need to put the symbol |
616 | // into csect's Syms. |
617 | if (XSym == ContainingCsect->getQualNameSymbol()) |
618 | continue; |
619 | |
620 | // Only put a label into the symbol table when it is an external label. |
621 | if (!XSym->isExternal()) |
622 | continue; |
623 | |
624 | assert(SectionMap.contains(ContainingCsect) && |
625 | "Expected containing csect to exist in map" ); |
626 | XCOFFSection *Csect = SectionMap[ContainingCsect]; |
627 | // Lookup the containing csect and add the symbol to it. |
628 | assert(Csect->MCSec->isCsect() && "only csect is supported now!" ); |
629 | Csect->Syms.emplace_back(Args&: XSym); |
630 | |
631 | // If the name does not fit in the storage provided in the symbol table |
632 | // entry, add it to the string table. |
633 | if (nameShouldBeInStringTable(XSym->getSymbolTableName())) |
634 | Strings.add(S: XSym->getSymbolTableName()); |
635 | } |
636 | |
637 | std::unique_ptr<CInfoSymInfo> &CISI = CInfoSymSection.Entry; |
638 | if (CISI && nameShouldBeInStringTable(CISI->Name)) |
639 | Strings.add(S: CISI->Name); |
640 | |
641 | FileNames = Asm.getFileNames(); |
642 | // Emit ".file" as the source file name when there is no file name. |
643 | if (FileNames.empty()) |
644 | FileNames.emplace_back(args: ".file" , args: 0); |
645 | for (const std::pair<std::string, size_t> &F : FileNames) { |
646 | if (auxFileSymNameShouldBeInStringTable(F.first)) |
647 | Strings.add(S: F.first); |
648 | } |
649 | |
650 | // Always add ".file" to the symbol table. The actual file name will be in |
651 | // the AUX_FILE auxiliary entry. |
652 | if (nameShouldBeInStringTable(".file" )) |
653 | Strings.add(S: ".file" ); |
654 | StringRef Vers = Asm.getCompilerVersion(); |
655 | if (auxFileSymNameShouldBeInStringTable(Vers)) |
656 | Strings.add(S: Vers); |
657 | |
658 | Strings.finalize(); |
659 | assignAddressesAndIndices(Asm, Layout); |
660 | } |
661 | |
662 | void XCOFFObjectWriter::recordRelocation(MCAssembler &Asm, |
663 | const MCAsmLayout &Layout, |
664 | const MCFragment *Fragment, |
665 | const MCFixup &Fixup, MCValue Target, |
666 | uint64_t &FixedValue) { |
667 | auto getIndex = [this](const MCSymbol *Sym, |
668 | const MCSectionXCOFF *ContainingCsect) { |
669 | // If we could not find the symbol directly in SymbolIndexMap, this symbol |
670 | // could either be a temporary symbol or an undefined symbol. In this case, |
671 | // we would need to have the relocation reference its csect instead. |
672 | return SymbolIndexMap.contains(Val: Sym) |
673 | ? SymbolIndexMap[Sym] |
674 | : SymbolIndexMap[ContainingCsect->getQualNameSymbol()]; |
675 | }; |
676 | |
677 | auto getVirtualAddress = |
678 | [this, &Layout](const MCSymbol *Sym, |
679 | const MCSectionXCOFF *ContainingSect) -> uint64_t { |
680 | // A DWARF section. |
681 | if (ContainingSect->isDwarfSect()) |
682 | return Layout.getSymbolOffset(S: *Sym); |
683 | |
684 | // A csect. |
685 | if (!Sym->isDefined()) |
686 | return SectionMap[ContainingSect]->Address; |
687 | |
688 | // A label. |
689 | assert(Sym->isDefined() && "not a valid object that has address!" ); |
690 | return SectionMap[ContainingSect]->Address + Layout.getSymbolOffset(S: *Sym); |
691 | }; |
692 | |
693 | const MCSymbol *const SymA = &Target.getSymA()->getSymbol(); |
694 | |
695 | MCAsmBackend &Backend = Asm.getBackend(); |
696 | bool IsPCRel = Backend.getFixupKindInfo(Kind: Fixup.getKind()).Flags & |
697 | MCFixupKindInfo::FKF_IsPCRel; |
698 | |
699 | uint8_t Type; |
700 | uint8_t SignAndSize; |
701 | std::tie(args&: Type, args&: SignAndSize) = |
702 | TargetObjectWriter->getRelocTypeAndSignSize(Target, Fixup, IsPCRel); |
703 | |
704 | const MCSectionXCOFF *SymASec = getContainingCsect(XSym: cast<MCSymbolXCOFF>(Val: SymA)); |
705 | assert(SectionMap.contains(SymASec) && |
706 | "Expected containing csect to exist in map." ); |
707 | |
708 | assert((Fixup.getOffset() <= |
709 | MaxRawDataSize - Layout.getFragmentOffset(Fragment)) && |
710 | "Fragment offset + fixup offset is overflowed." ); |
711 | uint32_t FixupOffsetInCsect = |
712 | Layout.getFragmentOffset(F: Fragment) + Fixup.getOffset(); |
713 | |
714 | const uint32_t Index = getIndex(SymA, SymASec); |
715 | if (Type == XCOFF::RelocationType::R_POS || |
716 | Type == XCOFF::RelocationType::R_TLS || |
717 | Type == XCOFF::RelocationType::R_TLS_LE || |
718 | Type == XCOFF::RelocationType::R_TLS_IE || |
719 | Type == XCOFF::RelocationType::R_TLS_LD) |
720 | // The FixedValue should be symbol's virtual address in this object file |
721 | // plus any constant value that we might get. |
722 | FixedValue = getVirtualAddress(SymA, SymASec) + Target.getConstant(); |
723 | else if (Type == XCOFF::RelocationType::R_TLSM) |
724 | // The FixedValue should always be zero since the region handle is only |
725 | // known at load time. |
726 | FixedValue = 0; |
727 | else if (Type == XCOFF::RelocationType::R_TOC || |
728 | Type == XCOFF::RelocationType::R_TOCL) { |
729 | // For non toc-data external symbols, R_TOC type relocation will relocate to |
730 | // data symbols that have XCOFF::XTY_SD type csect. For toc-data external |
731 | // symbols, R_TOC type relocation will relocate to data symbols that have |
732 | // XCOFF_ER type csect. For XCOFF_ER kind symbols, there will be no TOC |
733 | // entry for them, so the FixedValue should always be 0. |
734 | if (SymASec->getCSectType() == XCOFF::XTY_ER) { |
735 | FixedValue = 0; |
736 | } else { |
737 | // The FixedValue should be the TOC entry offset from the TOC-base plus |
738 | // any constant offset value. |
739 | int64_t TOCEntryOffset = SectionMap[SymASec]->Address - |
740 | TOCCsects.front().Address + Target.getConstant(); |
741 | // For small code model, if the TOCEntryOffset overflows the 16-bit value, |
742 | // we truncate it back down to 16 bits. The linker will be able to insert |
743 | // fix-up code when needed. |
744 | // For non toc-data symbols, we already did the truncation in |
745 | // PPCAsmPrinter.cpp through setting Target.getConstant() in the |
746 | // expression above by calling getTOCEntryLoadingExprForXCOFF for the |
747 | // various TOC PseudoOps. |
748 | // For toc-data symbols, we were not able to calculate the offset from |
749 | // the TOC in PPCAsmPrinter.cpp since the TOC has not been finalized at |
750 | // that point, so we are adjusting it here though |
751 | // llvm::SignExtend64<16>(TOCEntryOffset); |
752 | // TODO: Since the time that the handling for offsets over 16-bits was |
753 | // added in PPCAsmPrinter.cpp using getTOCEntryLoadingExprForXCOFF, the |
754 | // system assembler and linker have been updated to be able to handle the |
755 | // overflowing offsets, so we no longer need to keep |
756 | // getTOCEntryLoadingExprForXCOFF. |
757 | if (Type == XCOFF::RelocationType::R_TOC && !isInt<16>(x: TOCEntryOffset)) |
758 | TOCEntryOffset = llvm::SignExtend64<16>(x: TOCEntryOffset); |
759 | |
760 | FixedValue = TOCEntryOffset; |
761 | } |
762 | } else if (Type == XCOFF::RelocationType::R_RBR) { |
763 | MCSectionXCOFF *ParentSec = cast<MCSectionXCOFF>(Val: Fragment->getParent()); |
764 | assert((SymASec->getMappingClass() == XCOFF::XMC_PR && |
765 | ParentSec->getMappingClass() == XCOFF::XMC_PR) && |
766 | "Only XMC_PR csect may have the R_RBR relocation." ); |
767 | |
768 | // The address of the branch instruction should be the sum of section |
769 | // address, fragment offset and Fixup offset. |
770 | uint64_t BRInstrAddress = |
771 | SectionMap[ParentSec]->Address + FixupOffsetInCsect; |
772 | // The FixedValue should be the difference between symbol's virtual address |
773 | // and BR instr address plus any constant value. |
774 | FixedValue = getVirtualAddress(SymA, SymASec) - BRInstrAddress + |
775 | Target.getConstant(); |
776 | } else if (Type == XCOFF::RelocationType::R_REF) { |
777 | // The FixedValue and FixupOffsetInCsect should always be 0 since it |
778 | // specifies a nonrelocating reference. |
779 | FixedValue = 0; |
780 | FixupOffsetInCsect = 0; |
781 | } |
782 | |
783 | XCOFFRelocation Reloc = {.SymbolTableIndex: Index, .FixupOffsetInCsect: FixupOffsetInCsect, .SignAndSize: SignAndSize, .Type: Type}; |
784 | MCSectionXCOFF *RelocationSec = cast<MCSectionXCOFF>(Val: Fragment->getParent()); |
785 | assert(SectionMap.contains(RelocationSec) && |
786 | "Expected containing csect to exist in map." ); |
787 | SectionMap[RelocationSec]->Relocations.push_back(Elt: Reloc); |
788 | |
789 | if (!Target.getSymB()) |
790 | return; |
791 | |
792 | const MCSymbol *const SymB = &Target.getSymB()->getSymbol(); |
793 | if (SymA == SymB) |
794 | report_fatal_error(reason: "relocation for opposite term is not yet supported" ); |
795 | |
796 | const MCSectionXCOFF *SymBSec = getContainingCsect(XSym: cast<MCSymbolXCOFF>(Val: SymB)); |
797 | assert(SectionMap.contains(SymBSec) && |
798 | "Expected containing csect to exist in map." ); |
799 | if (SymASec == SymBSec) |
800 | report_fatal_error( |
801 | reason: "relocation for paired relocatable term is not yet supported" ); |
802 | |
803 | assert(Type == XCOFF::RelocationType::R_POS && |
804 | "SymA must be R_POS here if it's not opposite term or paired " |
805 | "relocatable term." ); |
806 | const uint32_t IndexB = getIndex(SymB, SymBSec); |
807 | // SymB must be R_NEG here, given the general form of Target(MCValue) is |
808 | // "SymbolA - SymbolB + imm64". |
809 | const uint8_t TypeB = XCOFF::RelocationType::R_NEG; |
810 | XCOFFRelocation RelocB = {.SymbolTableIndex: IndexB, .FixupOffsetInCsect: FixupOffsetInCsect, .SignAndSize: SignAndSize, .Type: TypeB}; |
811 | SectionMap[RelocationSec]->Relocations.push_back(Elt: RelocB); |
812 | // We already folded "SymbolA + imm64" above when Type is R_POS for SymbolA, |
813 | // now we just need to fold "- SymbolB" here. |
814 | FixedValue -= getVirtualAddress(SymB, SymBSec); |
815 | } |
816 | |
817 | void XCOFFObjectWriter::writeSections(const MCAssembler &Asm, |
818 | const MCAsmLayout &Layout) { |
819 | uint64_t CurrentAddressLocation = 0; |
820 | for (const auto *Section : Sections) |
821 | writeSectionForControlSectionEntry(Asm, Layout, CsectEntry: *Section, |
822 | CurrentAddressLocation); |
823 | for (const auto &DwarfSection : DwarfSections) |
824 | writeSectionForDwarfSectionEntry(Asm, Layout, DwarfEntry: DwarfSection, |
825 | CurrentAddressLocation); |
826 | writeSectionForExceptionSectionEntry(Asm, Layout, ExceptionEntry&: ExceptionSection, |
827 | CurrentAddressLocation); |
828 | writeSectionForCInfoSymSectionEntry(Asm, Layout, CInfoSymEntry&: CInfoSymSection, |
829 | CurrentAddressLocation); |
830 | } |
831 | |
832 | uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm, |
833 | const MCAsmLayout &Layout) { |
834 | // We always emit a timestamp of 0 for reproducibility, so ensure incremental |
835 | // linking is not enabled, in case, like with Windows COFF, such a timestamp |
836 | // is incompatible with incremental linking of XCOFF. |
837 | if (Asm.isIncrementalLinkerCompatible()) |
838 | report_fatal_error(reason: "Incremental linking not supported for XCOFF." ); |
839 | |
840 | finalizeSectionInfo(); |
841 | uint64_t StartOffset = W.OS.tell(); |
842 | |
843 | writeFileHeader(); |
844 | writeAuxFileHeader(); |
845 | writeSectionHeaderTable(); |
846 | writeSections(Asm, Layout); |
847 | writeRelocations(); |
848 | writeSymbolTable(Asm, Layout); |
849 | // Write the string table. |
850 | Strings.write(OS&: W.OS); |
851 | |
852 | return W.OS.tell() - StartOffset; |
853 | } |
854 | |
855 | bool XCOFFObjectWriter::nameShouldBeInStringTable(const StringRef &SymbolName) { |
856 | return SymbolName.size() > XCOFF::NameSize || is64Bit(); |
857 | } |
858 | |
859 | void XCOFFObjectWriter::writeSymbolName(const StringRef &SymbolName) { |
860 | // Magic, Offset or SymbolName. |
861 | if (nameShouldBeInStringTable(SymbolName)) { |
862 | W.write<int32_t>(Val: 0); |
863 | W.write<uint32_t>(Val: Strings.getOffset(S: SymbolName)); |
864 | } else { |
865 | char Name[XCOFF::NameSize + 1]; |
866 | std::strncpy(dest: Name, src: SymbolName.data(), n: XCOFF::NameSize); |
867 | ArrayRef<char> NameRef(Name, XCOFF::NameSize); |
868 | W.write(Val: NameRef); |
869 | } |
870 | } |
871 | |
872 | void XCOFFObjectWriter::writeSymbolEntry(StringRef SymbolName, uint64_t Value, |
873 | int16_t SectionNumber, |
874 | uint16_t SymbolType, |
875 | uint8_t StorageClass, |
876 | uint8_t NumberOfAuxEntries) { |
877 | if (is64Bit()) { |
878 | W.write<uint64_t>(Val: Value); |
879 | W.write<uint32_t>(Val: Strings.getOffset(S: SymbolName)); |
880 | } else { |
881 | writeSymbolName(SymbolName); |
882 | W.write<uint32_t>(Val: Value); |
883 | } |
884 | W.write<int16_t>(Val: SectionNumber); |
885 | W.write<uint16_t>(Val: SymbolType); |
886 | W.write<uint8_t>(Val: StorageClass); |
887 | W.write<uint8_t>(Val: NumberOfAuxEntries); |
888 | } |
889 | |
890 | void XCOFFObjectWriter::writeSymbolAuxCsectEntry(uint64_t SectionOrLength, |
891 | uint8_t SymbolAlignmentAndType, |
892 | uint8_t StorageMappingClass) { |
893 | W.write<uint32_t>(Val: is64Bit() ? Lo_32(Value: SectionOrLength) : SectionOrLength); |
894 | W.write<uint32_t>(Val: 0); // ParameterHashIndex |
895 | W.write<uint16_t>(Val: 0); // TypeChkSectNum |
896 | W.write<uint8_t>(Val: SymbolAlignmentAndType); |
897 | W.write<uint8_t>(Val: StorageMappingClass); |
898 | if (is64Bit()) { |
899 | W.write<uint32_t>(Val: Hi_32(Value: SectionOrLength)); |
900 | W.OS.write_zeros(NumZeros: 1); // Reserved |
901 | W.write<uint8_t>(Val: XCOFF::AUX_CSECT); |
902 | } else { |
903 | W.write<uint32_t>(Val: 0); // StabInfoIndex |
904 | W.write<uint16_t>(Val: 0); // StabSectNum |
905 | } |
906 | } |
907 | |
908 | bool XCOFFObjectWriter::auxFileSymNameShouldBeInStringTable( |
909 | const StringRef &SymbolName) { |
910 | return SymbolName.size() > XCOFF::AuxFileEntNameSize; |
911 | } |
912 | |
913 | void XCOFFObjectWriter::writeAuxFileSymName(const StringRef &SymbolName) { |
914 | // Magic, Offset or SymbolName. |
915 | if (auxFileSymNameShouldBeInStringTable(SymbolName)) { |
916 | W.write<int32_t>(Val: 0); |
917 | W.write<uint32_t>(Val: Strings.getOffset(S: SymbolName)); |
918 | W.OS.write_zeros(NumZeros: XCOFF::FileNamePadSize); |
919 | } else { |
920 | char Name[XCOFF::AuxFileEntNameSize + 1]; |
921 | std::strncpy(dest: Name, src: SymbolName.data(), n: XCOFF::AuxFileEntNameSize); |
922 | ArrayRef<char> NameRef(Name, XCOFF::AuxFileEntNameSize); |
923 | W.write(Val: NameRef); |
924 | } |
925 | } |
926 | |
927 | void XCOFFObjectWriter::writeSymbolAuxFileEntry(StringRef &Name, |
928 | uint8_t ftype) { |
929 | writeAuxFileSymName(SymbolName: Name); |
930 | W.write<uint8_t>(Val: ftype); |
931 | W.OS.write_zeros(NumZeros: 2); |
932 | if (is64Bit()) |
933 | W.write<uint8_t>(Val: XCOFF::AUX_FILE); |
934 | else |
935 | W.OS.write_zeros(NumZeros: 1); |
936 | } |
937 | |
938 | void XCOFFObjectWriter::writeSymbolAuxDwarfEntry( |
939 | uint64_t LengthOfSectionPortion, uint64_t NumberOfRelocEnt) { |
940 | writeWord(Word: LengthOfSectionPortion); |
941 | if (!is64Bit()) |
942 | W.OS.write_zeros(NumZeros: 4); // Reserved |
943 | writeWord(Word: NumberOfRelocEnt); |
944 | if (is64Bit()) { |
945 | W.OS.write_zeros(NumZeros: 1); // Reserved |
946 | W.write<uint8_t>(Val: XCOFF::AUX_SECT); |
947 | } else { |
948 | W.OS.write_zeros(NumZeros: 6); // Reserved |
949 | } |
950 | } |
951 | |
952 | void XCOFFObjectWriter::writeSymbolEntryForCsectMemberLabel( |
953 | const Symbol &SymbolRef, const XCOFFSection &CSectionRef, |
954 | int16_t SectionIndex, uint64_t SymbolOffset) { |
955 | assert(SymbolOffset <= MaxRawDataSize - CSectionRef.Address && |
956 | "Symbol address overflowed." ); |
957 | |
958 | auto Entry = ExceptionSection.ExceptionTable.find(x: SymbolRef.MCSym->getName()); |
959 | if (Entry != ExceptionSection.ExceptionTable.end()) { |
960 | writeSymbolEntry(SymbolName: SymbolRef.getSymbolTableName(), |
961 | Value: CSectionRef.Address + SymbolOffset, SectionNumber: SectionIndex, |
962 | // In the old version of the 32-bit XCOFF interpretation, |
963 | // symbols may require bit 10 (0x0020) to be set if the |
964 | // symbol is a function, otherwise the bit should be 0. |
965 | SymbolType: is64Bit() ? SymbolRef.getVisibilityType() |
966 | : SymbolRef.getVisibilityType() | 0x0020, |
967 | StorageClass: SymbolRef.getStorageClass(), |
968 | NumberOfAuxEntries: (is64Bit() && ExceptionSection.isDebugEnabled) ? 3 : 2); |
969 | if (is64Bit() && ExceptionSection.isDebugEnabled) { |
970 | // On 64 bit with debugging enabled, we have a csect, exception, and |
971 | // function auxilliary entries, so we must increment symbol index by 4. |
972 | writeSymbolAuxExceptionEntry( |
973 | EntryOffset: ExceptionSection.FileOffsetToData + |
974 | getExceptionOffset(Symbol: Entry->second.FunctionSymbol), |
975 | FunctionSize: Entry->second.FunctionSize, |
976 | EndIndex: SymbolIndexMap[Entry->second.FunctionSymbol] + 4); |
977 | } |
978 | // For exception section entries, csect and function auxilliary entries |
979 | // must exist. On 64-bit there is also an exception auxilliary entry. |
980 | writeSymbolAuxFunctionEntry( |
981 | EntryOffset: ExceptionSection.FileOffsetToData + |
982 | getExceptionOffset(Symbol: Entry->second.FunctionSymbol), |
983 | FunctionSize: Entry->second.FunctionSize, LineNumberPointer: 0, |
984 | EndIndex: (is64Bit() && ExceptionSection.isDebugEnabled) |
985 | ? SymbolIndexMap[Entry->second.FunctionSymbol] + 4 |
986 | : SymbolIndexMap[Entry->second.FunctionSymbol] + 3); |
987 | } else { |
988 | writeSymbolEntry(SymbolName: SymbolRef.getSymbolTableName(), |
989 | Value: CSectionRef.Address + SymbolOffset, SectionNumber: SectionIndex, |
990 | SymbolType: SymbolRef.getVisibilityType(), |
991 | StorageClass: SymbolRef.getStorageClass()); |
992 | } |
993 | writeSymbolAuxCsectEntry(SectionOrLength: CSectionRef.SymbolTableIndex, SymbolAlignmentAndType: XCOFF::XTY_LD, |
994 | StorageMappingClass: CSectionRef.MCSec->getMappingClass()); |
995 | } |
996 | |
997 | void XCOFFObjectWriter::writeSymbolEntryForDwarfSection( |
998 | const XCOFFSection &DwarfSectionRef, int16_t SectionIndex) { |
999 | assert(DwarfSectionRef.MCSec->isDwarfSect() && "Not a DWARF section!" ); |
1000 | |
1001 | writeSymbolEntry(SymbolName: DwarfSectionRef.getSymbolTableName(), /*Value=*/0, |
1002 | SectionNumber: SectionIndex, /*SymbolType=*/0, StorageClass: XCOFF::C_DWARF); |
1003 | |
1004 | writeSymbolAuxDwarfEntry(LengthOfSectionPortion: DwarfSectionRef.Size); |
1005 | } |
1006 | |
1007 | void XCOFFObjectWriter::writeSymbolEntryForControlSection( |
1008 | const XCOFFSection &CSectionRef, int16_t SectionIndex, |
1009 | XCOFF::StorageClass StorageClass) { |
1010 | writeSymbolEntry(SymbolName: CSectionRef.getSymbolTableName(), Value: CSectionRef.Address, |
1011 | SectionNumber: SectionIndex, SymbolType: CSectionRef.getVisibilityType(), StorageClass); |
1012 | |
1013 | writeSymbolAuxCsectEntry(SectionOrLength: CSectionRef.Size, SymbolAlignmentAndType: getEncodedType(CSectionRef.MCSec), |
1014 | StorageMappingClass: CSectionRef.MCSec->getMappingClass()); |
1015 | } |
1016 | |
1017 | void XCOFFObjectWriter::writeSymbolAuxFunctionEntry(uint32_t EntryOffset, |
1018 | uint32_t FunctionSize, |
1019 | uint64_t LineNumberPointer, |
1020 | uint32_t EndIndex) { |
1021 | if (is64Bit()) |
1022 | writeWord(Word: LineNumberPointer); |
1023 | else |
1024 | W.write<uint32_t>(Val: EntryOffset); |
1025 | W.write<uint32_t>(Val: FunctionSize); |
1026 | if (!is64Bit()) |
1027 | writeWord(Word: LineNumberPointer); |
1028 | W.write<uint32_t>(Val: EndIndex); |
1029 | if (is64Bit()) { |
1030 | W.OS.write_zeros(NumZeros: 1); |
1031 | W.write<uint8_t>(Val: XCOFF::AUX_FCN); |
1032 | } else { |
1033 | W.OS.write_zeros(NumZeros: 2); |
1034 | } |
1035 | } |
1036 | |
1037 | void XCOFFObjectWriter::writeSymbolAuxExceptionEntry(uint64_t EntryOffset, |
1038 | uint32_t FunctionSize, |
1039 | uint32_t EndIndex) { |
1040 | assert(is64Bit() && "Exception auxilliary entries are 64-bit only." ); |
1041 | W.write<uint64_t>(Val: EntryOffset); |
1042 | W.write<uint32_t>(Val: FunctionSize); |
1043 | W.write<uint32_t>(Val: EndIndex); |
1044 | W.OS.write_zeros(NumZeros: 1); // Pad (unused) |
1045 | W.write<uint8_t>(Val: XCOFF::AUX_EXCEPT); |
1046 | } |
1047 | |
1048 | void XCOFFObjectWriter::() { |
1049 | W.write<uint16_t>(Val: is64Bit() ? XCOFF::XCOFF64 : XCOFF::XCOFF32); |
1050 | W.write<uint16_t>(Val: SectionCount); |
1051 | W.write<int32_t>(Val: 0); // TimeStamp |
1052 | writeWord(Word: SymbolTableOffset); |
1053 | if (is64Bit()) { |
1054 | W.write<uint16_t>(Val: auxiliaryHeaderSize()); |
1055 | W.write<uint16_t>(Val: 0); // Flags |
1056 | W.write<int32_t>(Val: SymbolTableEntryCount); |
1057 | } else { |
1058 | W.write<int32_t>(Val: SymbolTableEntryCount); |
1059 | W.write<uint16_t>(Val: auxiliaryHeaderSize()); |
1060 | W.write<uint16_t>(Val: 0); // Flags |
1061 | } |
1062 | } |
1063 | |
1064 | void XCOFFObjectWriter::() { |
1065 | if (!auxiliaryHeaderSize()) |
1066 | return; |
1067 | W.write<uint16_t>(Val: 0); // Magic |
1068 | W.write<uint16_t>( |
1069 | Val: XCOFF::NEW_XCOFF_INTERPRET); // Version. The new interpretation of the |
1070 | // n_type field in the symbol table entry is |
1071 | // used in XCOFF32. |
1072 | W.write<uint32_t>(Val: Sections[0]->Size); // TextSize |
1073 | W.write<uint32_t>(Val: Sections[1]->Size); // InitDataSize |
1074 | W.write<uint32_t>(Val: Sections[2]->Size); // BssDataSize |
1075 | W.write<uint32_t>(Val: 0); // EntryPointAddr |
1076 | W.write<uint32_t>(Val: Sections[0]->Address); // TextStartAddr |
1077 | W.write<uint32_t>(Val: Sections[1]->Address); // DataStartAddr |
1078 | } |
1079 | |
1080 | void XCOFFObjectWriter::(const SectionEntry *Sec) { |
1081 | bool IsDwarf = (Sec->Flags & XCOFF::STYP_DWARF) != 0; |
1082 | bool IsOvrflo = (Sec->Flags & XCOFF::STYP_OVRFLO) != 0; |
1083 | // Nothing to write for this Section. |
1084 | if (Sec->Index == SectionEntry::UninitializedIndex) |
1085 | return; |
1086 | |
1087 | // Write Name. |
1088 | ArrayRef<char> NameRef(Sec->Name, XCOFF::NameSize); |
1089 | W.write(Val: NameRef); |
1090 | |
1091 | // Write the Physical Address and Virtual Address. |
1092 | // We use 0 for DWARF sections' Physical and Virtual Addresses. |
1093 | writeWord(Word: IsDwarf ? 0 : Sec->Address); |
1094 | // Since line number is not supported, we set it to 0 for overflow sections. |
1095 | writeWord(Word: (IsDwarf || IsOvrflo) ? 0 : Sec->Address); |
1096 | |
1097 | writeWord(Word: Sec->Size); |
1098 | writeWord(Word: Sec->FileOffsetToData); |
1099 | writeWord(Word: Sec->FileOffsetToRelocations); |
1100 | writeWord(Word: 0); // FileOffsetToLineNumberInfo. Not supported yet. |
1101 | |
1102 | if (is64Bit()) { |
1103 | W.write<uint32_t>(Val: Sec->RelocationCount); |
1104 | W.write<uint32_t>(Val: 0); // NumberOfLineNumbers. Not supported yet. |
1105 | W.write<int32_t>(Val: Sec->Flags); |
1106 | W.OS.write_zeros(NumZeros: 4); |
1107 | } else { |
1108 | // For the overflow section header, s_nreloc provides a reference to the |
1109 | // primary section header and s_nlnno must have the same value. |
1110 | // For common section headers, if either of s_nreloc or s_nlnno are set to |
1111 | // 65535, the other one must also be set to 65535. |
1112 | W.write<uint16_t>(Val: Sec->RelocationCount); |
1113 | W.write<uint16_t>(Val: (IsOvrflo || Sec->RelocationCount == XCOFF::RelocOverflow) |
1114 | ? Sec->RelocationCount |
1115 | : 0); // NumberOfLineNumbers. Not supported yet. |
1116 | W.write<int32_t>(Val: Sec->Flags); |
1117 | } |
1118 | } |
1119 | |
1120 | void XCOFFObjectWriter::() { |
1121 | for (const auto *CsectSec : Sections) |
1122 | writeSectionHeader(Sec: CsectSec); |
1123 | for (const auto &DwarfSec : DwarfSections) |
1124 | writeSectionHeader(Sec: &DwarfSec); |
1125 | for (const auto &OverflowSec : OverflowSections) |
1126 | writeSectionHeader(Sec: &OverflowSec); |
1127 | if (hasExceptionSection()) |
1128 | writeSectionHeader(Sec: &ExceptionSection); |
1129 | if (CInfoSymSection.Entry) |
1130 | writeSectionHeader(Sec: &CInfoSymSection); |
1131 | } |
1132 | |
1133 | void XCOFFObjectWriter::writeRelocation(XCOFFRelocation Reloc, |
1134 | const XCOFFSection &Section) { |
1135 | if (Section.MCSec->isCsect()) |
1136 | writeWord(Word: Section.Address + Reloc.FixupOffsetInCsect); |
1137 | else { |
1138 | // DWARF sections' address is set to 0. |
1139 | assert(Section.MCSec->isDwarfSect() && "unsupport section type!" ); |
1140 | writeWord(Word: Reloc.FixupOffsetInCsect); |
1141 | } |
1142 | W.write<uint32_t>(Val: Reloc.SymbolTableIndex); |
1143 | W.write<uint8_t>(Val: Reloc.SignAndSize); |
1144 | W.write<uint8_t>(Val: Reloc.Type); |
1145 | } |
1146 | |
1147 | void XCOFFObjectWriter::writeRelocations() { |
1148 | for (const auto *Section : Sections) { |
1149 | if (Section->Index == SectionEntry::UninitializedIndex) |
1150 | // Nothing to write for this Section. |
1151 | continue; |
1152 | |
1153 | for (const auto *Group : Section->Groups) { |
1154 | if (Group->empty()) |
1155 | continue; |
1156 | |
1157 | for (const auto &Csect : *Group) { |
1158 | for (const auto Reloc : Csect.Relocations) |
1159 | writeRelocation(Reloc, Section: Csect); |
1160 | } |
1161 | } |
1162 | } |
1163 | |
1164 | for (const auto &DwarfSection : DwarfSections) |
1165 | for (const auto &Reloc : DwarfSection.DwarfSect->Relocations) |
1166 | writeRelocation(Reloc, Section: *DwarfSection.DwarfSect); |
1167 | } |
1168 | |
1169 | void XCOFFObjectWriter::writeSymbolTable(MCAssembler &Asm, |
1170 | const MCAsmLayout &Layout) { |
1171 | // Write C_FILE symbols. |
1172 | StringRef Vers = Asm.getCompilerVersion(); |
1173 | |
1174 | for (const std::pair<std::string, size_t> &F : FileNames) { |
1175 | // The n_name of a C_FILE symbol is the source file's name when no auxiliary |
1176 | // entries are present. |
1177 | StringRef FileName = F.first; |
1178 | |
1179 | // For C_FILE symbols, the Source Language ID overlays the high-order byte |
1180 | // of the SymbolType field, and the CPU Version ID is defined as the |
1181 | // low-order byte. |
1182 | // AIX's system assembler determines the source language ID based on the |
1183 | // source file's name suffix, and the behavior here is consistent with it. |
1184 | uint8_t LangID; |
1185 | if (FileName.ends_with(Suffix: ".c" )) |
1186 | LangID = XCOFF::TB_C; |
1187 | else if (FileName.ends_with_insensitive(Suffix: ".f" ) || |
1188 | FileName.ends_with_insensitive(Suffix: ".f77" ) || |
1189 | FileName.ends_with_insensitive(Suffix: ".f90" ) || |
1190 | FileName.ends_with_insensitive(Suffix: ".f95" ) || |
1191 | FileName.ends_with_insensitive(Suffix: ".f03" ) || |
1192 | FileName.ends_with_insensitive(Suffix: ".f08" )) |
1193 | LangID = XCOFF::TB_Fortran; |
1194 | else |
1195 | LangID = XCOFF::TB_CPLUSPLUS; |
1196 | uint8_t CpuID; |
1197 | if (is64Bit()) |
1198 | CpuID = XCOFF::TCPU_PPC64; |
1199 | else |
1200 | CpuID = XCOFF::TCPU_COM; |
1201 | |
1202 | int NumberOfFileAuxEntries = 1; |
1203 | if (!Vers.empty()) |
1204 | ++NumberOfFileAuxEntries; |
1205 | writeSymbolEntry(SymbolName: ".file" , /*Value=*/0, SectionNumber: XCOFF::ReservedSectionNum::N_DEBUG, |
1206 | /*SymbolType=*/(LangID << 8) | CpuID, StorageClass: XCOFF::C_FILE, |
1207 | NumberOfAuxEntries: NumberOfFileAuxEntries); |
1208 | writeSymbolAuxFileEntry(Name&: FileName, ftype: XCOFF::XFT_FN); |
1209 | if (!Vers.empty()) |
1210 | writeSymbolAuxFileEntry(Name&: Vers, ftype: XCOFF::XFT_CV); |
1211 | } |
1212 | |
1213 | if (CInfoSymSection.Entry) |
1214 | writeSymbolEntry(SymbolName: CInfoSymSection.Entry->Name, Value: CInfoSymSection.Entry->Offset, |
1215 | SectionNumber: CInfoSymSection.Index, |
1216 | /*SymbolType=*/0, StorageClass: XCOFF::C_INFO, |
1217 | /*NumberOfAuxEntries=*/0); |
1218 | |
1219 | for (const auto &Csect : UndefinedCsects) { |
1220 | writeSymbolEntryForControlSection(CSectionRef: Csect, SectionIndex: XCOFF::ReservedSectionNum::N_UNDEF, |
1221 | StorageClass: Csect.MCSec->getStorageClass()); |
1222 | } |
1223 | |
1224 | for (const auto *Section : Sections) { |
1225 | if (Section->Index == SectionEntry::UninitializedIndex) |
1226 | // Nothing to write for this Section. |
1227 | continue; |
1228 | |
1229 | for (const auto *Group : Section->Groups) { |
1230 | if (Group->empty()) |
1231 | continue; |
1232 | |
1233 | const int16_t SectionIndex = Section->Index; |
1234 | for (const auto &Csect : *Group) { |
1235 | // Write out the control section first and then each symbol in it. |
1236 | writeSymbolEntryForControlSection(CSectionRef: Csect, SectionIndex, |
1237 | StorageClass: Csect.MCSec->getStorageClass()); |
1238 | |
1239 | for (const auto &Sym : Csect.Syms) |
1240 | writeSymbolEntryForCsectMemberLabel( |
1241 | SymbolRef: Sym, CSectionRef: Csect, SectionIndex, SymbolOffset: Layout.getSymbolOffset(S: *(Sym.MCSym))); |
1242 | } |
1243 | } |
1244 | } |
1245 | |
1246 | for (const auto &DwarfSection : DwarfSections) |
1247 | writeSymbolEntryForDwarfSection(DwarfSectionRef: *DwarfSection.DwarfSect, |
1248 | SectionIndex: DwarfSection.Index); |
1249 | } |
1250 | |
1251 | void XCOFFObjectWriter::finalizeRelocationInfo(SectionEntry *Sec, |
1252 | uint64_t RelCount) { |
1253 | // Handles relocation field overflows in an XCOFF32 file. An XCOFF64 file |
1254 | // may not contain an overflow section header. |
1255 | if (!is64Bit() && (RelCount >= static_cast<uint32_t>(XCOFF::RelocOverflow))) { |
1256 | // Generate an overflow section header. |
1257 | SectionEntry SecEntry(".ovrflo" , XCOFF::STYP_OVRFLO); |
1258 | |
1259 | // This field specifies the file section number of the section header that |
1260 | // overflowed. |
1261 | SecEntry.RelocationCount = Sec->Index; |
1262 | |
1263 | // This field specifies the number of relocation entries actually |
1264 | // required. |
1265 | SecEntry.Address = RelCount; |
1266 | SecEntry.Index = ++SectionCount; |
1267 | OverflowSections.push_back(x: std::move(SecEntry)); |
1268 | |
1269 | // The field in the primary section header is always 65535 |
1270 | // (XCOFF::RelocOverflow). |
1271 | Sec->RelocationCount = XCOFF::RelocOverflow; |
1272 | } else { |
1273 | Sec->RelocationCount = RelCount; |
1274 | } |
1275 | } |
1276 | |
1277 | void XCOFFObjectWriter::calcOffsetToRelocations(SectionEntry *Sec, |
1278 | uint64_t &RawPointer) { |
1279 | if (!Sec->RelocationCount) |
1280 | return; |
1281 | |
1282 | Sec->FileOffsetToRelocations = RawPointer; |
1283 | uint64_t RelocationSizeInSec = 0; |
1284 | if (!is64Bit() && |
1285 | Sec->RelocationCount == static_cast<uint32_t>(XCOFF::RelocOverflow)) { |
1286 | // Find its corresponding overflow section. |
1287 | for (auto &OverflowSec : OverflowSections) { |
1288 | if (OverflowSec.RelocationCount == static_cast<uint32_t>(Sec->Index)) { |
1289 | RelocationSizeInSec = |
1290 | OverflowSec.Address * XCOFF::RelocationSerializationSize32; |
1291 | |
1292 | // This field must have the same values as in the corresponding |
1293 | // primary section header. |
1294 | OverflowSec.FileOffsetToRelocations = Sec->FileOffsetToRelocations; |
1295 | } |
1296 | } |
1297 | assert(RelocationSizeInSec && "Overflow section header doesn't exist." ); |
1298 | } else { |
1299 | RelocationSizeInSec = Sec->RelocationCount * |
1300 | (is64Bit() ? XCOFF::RelocationSerializationSize64 |
1301 | : XCOFF::RelocationSerializationSize32); |
1302 | } |
1303 | |
1304 | RawPointer += RelocationSizeInSec; |
1305 | if (RawPointer > MaxRawDataSize) |
1306 | report_fatal_error(reason: "Relocation data overflowed this object file." ); |
1307 | } |
1308 | |
1309 | void XCOFFObjectWriter::finalizeSectionInfo() { |
1310 | for (auto *Section : Sections) { |
1311 | if (Section->Index == SectionEntry::UninitializedIndex) |
1312 | // Nothing to record for this Section. |
1313 | continue; |
1314 | |
1315 | uint64_t RelCount = 0; |
1316 | for (const auto *Group : Section->Groups) { |
1317 | if (Group->empty()) |
1318 | continue; |
1319 | |
1320 | for (auto &Csect : *Group) |
1321 | RelCount += Csect.Relocations.size(); |
1322 | } |
1323 | finalizeRelocationInfo(Sec: Section, RelCount); |
1324 | } |
1325 | |
1326 | for (auto &DwarfSection : DwarfSections) |
1327 | finalizeRelocationInfo(Sec: &DwarfSection, |
1328 | RelCount: DwarfSection.DwarfSect->Relocations.size()); |
1329 | |
1330 | // Calculate the RawPointer value for all headers. |
1331 | uint64_t RawPointer = |
1332 | (is64Bit() ? (XCOFF::FileHeaderSize64 + |
1333 | SectionCount * XCOFF::SectionHeaderSize64) |
1334 | : (XCOFF::FileHeaderSize32 + |
1335 | SectionCount * XCOFF::SectionHeaderSize32)) + |
1336 | auxiliaryHeaderSize(); |
1337 | |
1338 | // Calculate the file offset to the section data. |
1339 | for (auto *Sec : Sections) { |
1340 | if (Sec->Index == SectionEntry::UninitializedIndex || Sec->IsVirtual) |
1341 | continue; |
1342 | |
1343 | RawPointer = Sec->advanceFileOffset(MaxRawDataSize, RawPointer); |
1344 | } |
1345 | |
1346 | if (!DwarfSections.empty()) { |
1347 | RawPointer += PaddingsBeforeDwarf; |
1348 | for (auto &DwarfSection : DwarfSections) { |
1349 | RawPointer = DwarfSection.advanceFileOffset(MaxRawDataSize, RawPointer); |
1350 | } |
1351 | } |
1352 | |
1353 | if (hasExceptionSection()) |
1354 | RawPointer = ExceptionSection.advanceFileOffset(MaxRawDataSize, RawPointer); |
1355 | |
1356 | if (CInfoSymSection.Entry) |
1357 | RawPointer = CInfoSymSection.advanceFileOffset(MaxRawDataSize, RawPointer); |
1358 | |
1359 | for (auto *Sec : Sections) { |
1360 | if (Sec->Index != SectionEntry::UninitializedIndex) |
1361 | calcOffsetToRelocations(Sec, RawPointer); |
1362 | } |
1363 | |
1364 | for (auto &DwarfSec : DwarfSections) |
1365 | calcOffsetToRelocations(Sec: &DwarfSec, RawPointer); |
1366 | |
1367 | // TODO Error check that the number of symbol table entries fits in 32-bits |
1368 | // signed ... |
1369 | if (SymbolTableEntryCount) |
1370 | SymbolTableOffset = RawPointer; |
1371 | } |
1372 | |
1373 | void XCOFFObjectWriter::addExceptionEntry( |
1374 | const MCSymbol *Symbol, const MCSymbol *Trap, unsigned LanguageCode, |
1375 | unsigned ReasonCode, unsigned FunctionSize, bool hasDebug) { |
1376 | // If a module had debug info, debugging is enabled and XCOFF emits the |
1377 | // exception auxilliary entry. |
1378 | if (hasDebug) |
1379 | ExceptionSection.isDebugEnabled = true; |
1380 | auto Entry = ExceptionSection.ExceptionTable.find(x: Symbol->getName()); |
1381 | if (Entry != ExceptionSection.ExceptionTable.end()) { |
1382 | Entry->second.Entries.push_back( |
1383 | x: ExceptionTableEntry(Trap, LanguageCode, ReasonCode)); |
1384 | return; |
1385 | } |
1386 | ExceptionInfo NewEntry; |
1387 | NewEntry.FunctionSymbol = Symbol; |
1388 | NewEntry.FunctionSize = FunctionSize; |
1389 | NewEntry.Entries.push_back( |
1390 | x: ExceptionTableEntry(Trap, LanguageCode, ReasonCode)); |
1391 | ExceptionSection.ExceptionTable.insert( |
1392 | x: std::pair<const StringRef, ExceptionInfo>(Symbol->getName(), NewEntry)); |
1393 | } |
1394 | |
1395 | unsigned XCOFFObjectWriter::getExceptionSectionSize() { |
1396 | unsigned EntryNum = 0; |
1397 | |
1398 | for (auto it = ExceptionSection.ExceptionTable.begin(); |
1399 | it != ExceptionSection.ExceptionTable.end(); ++it) |
1400 | // The size() gets +1 to account for the initial entry containing the |
1401 | // symbol table index. |
1402 | EntryNum += it->second.Entries.size() + 1; |
1403 | |
1404 | return EntryNum * (is64Bit() ? XCOFF::ExceptionSectionEntrySize64 |
1405 | : XCOFF::ExceptionSectionEntrySize32); |
1406 | } |
1407 | |
1408 | unsigned XCOFFObjectWriter::getExceptionOffset(const MCSymbol *Symbol) { |
1409 | unsigned EntryNum = 0; |
1410 | for (auto it = ExceptionSection.ExceptionTable.begin(); |
1411 | it != ExceptionSection.ExceptionTable.end(); ++it) { |
1412 | if (Symbol == it->second.FunctionSymbol) |
1413 | break; |
1414 | EntryNum += it->second.Entries.size() + 1; |
1415 | } |
1416 | return EntryNum * (is64Bit() ? XCOFF::ExceptionSectionEntrySize64 |
1417 | : XCOFF::ExceptionSectionEntrySize32); |
1418 | } |
1419 | |
1420 | void XCOFFObjectWriter::addCInfoSymEntry(StringRef Name, StringRef Metadata) { |
1421 | assert(!CInfoSymSection.Entry && "Multiple entries are not supported" ); |
1422 | CInfoSymSection.addEntry( |
1423 | NewEntry: std::make_unique<CInfoSymInfo>(args: Name.str(), args: Metadata.str())); |
1424 | } |
1425 | |
1426 | void XCOFFObjectWriter::assignAddressesAndIndices(MCAssembler &Asm, |
1427 | const MCAsmLayout &Layout) { |
1428 | // The symbol table starts with all the C_FILE symbols. Each C_FILE symbol |
1429 | // requires 1 or 2 auxiliary entries. |
1430 | uint32_t SymbolTableIndex = |
1431 | (2 + (Asm.getCompilerVersion().empty() ? 0 : 1)) * FileNames.size(); |
1432 | |
1433 | if (CInfoSymSection.Entry) |
1434 | SymbolTableIndex++; |
1435 | |
1436 | // Calculate indices for undefined symbols. |
1437 | for (auto &Csect : UndefinedCsects) { |
1438 | Csect.Size = 0; |
1439 | Csect.Address = 0; |
1440 | Csect.SymbolTableIndex = SymbolTableIndex; |
1441 | SymbolIndexMap[Csect.MCSec->getQualNameSymbol()] = Csect.SymbolTableIndex; |
1442 | // 1 main and 1 auxiliary symbol table entry for each contained symbol. |
1443 | SymbolTableIndex += 2; |
1444 | } |
1445 | |
1446 | // The address corrresponds to the address of sections and symbols in the |
1447 | // object file. We place the shared address 0 immediately after the |
1448 | // section header table. |
1449 | uint64_t Address = 0; |
1450 | // Section indices are 1-based in XCOFF. |
1451 | int32_t SectionIndex = 1; |
1452 | bool HasTDataSection = false; |
1453 | |
1454 | for (auto *Section : Sections) { |
1455 | const bool IsEmpty = |
1456 | llvm::all_of(Range&: Section->Groups, |
1457 | P: [](const CsectGroup *Group) { return Group->empty(); }); |
1458 | if (IsEmpty) |
1459 | continue; |
1460 | |
1461 | if (SectionIndex > MaxSectionIndex) |
1462 | report_fatal_error(reason: "Section index overflow!" ); |
1463 | Section->Index = SectionIndex++; |
1464 | SectionCount++; |
1465 | |
1466 | bool SectionAddressSet = false; |
1467 | // Reset the starting address to 0 for TData section. |
1468 | if (Section->Flags == XCOFF::STYP_TDATA) { |
1469 | Address = 0; |
1470 | HasTDataSection = true; |
1471 | } |
1472 | // Reset the starting address to 0 for TBSS section if the object file does |
1473 | // not contain TData Section. |
1474 | if ((Section->Flags == XCOFF::STYP_TBSS) && !HasTDataSection) |
1475 | Address = 0; |
1476 | |
1477 | for (auto *Group : Section->Groups) { |
1478 | if (Group->empty()) |
1479 | continue; |
1480 | |
1481 | for (auto &Csect : *Group) { |
1482 | const MCSectionXCOFF *MCSec = Csect.MCSec; |
1483 | Csect.Address = alignTo(Size: Address, A: MCSec->getAlign()); |
1484 | Csect.Size = Layout.getSectionAddressSize(Sec: MCSec); |
1485 | Address = Csect.Address + Csect.Size; |
1486 | Csect.SymbolTableIndex = SymbolTableIndex; |
1487 | SymbolIndexMap[MCSec->getQualNameSymbol()] = Csect.SymbolTableIndex; |
1488 | // 1 main and 1 auxiliary symbol table entry for the csect. |
1489 | SymbolTableIndex += 2; |
1490 | |
1491 | for (auto &Sym : Csect.Syms) { |
1492 | bool hasExceptEntry = false; |
1493 | auto Entry = |
1494 | ExceptionSection.ExceptionTable.find(x: Sym.MCSym->getName()); |
1495 | if (Entry != ExceptionSection.ExceptionTable.end()) { |
1496 | hasExceptEntry = true; |
1497 | for (auto &TrapEntry : Entry->second.Entries) { |
1498 | TrapEntry.TrapAddress = Layout.getSymbolOffset(S: *(Sym.MCSym)) + |
1499 | TrapEntry.Trap->getOffset(); |
1500 | } |
1501 | } |
1502 | Sym.SymbolTableIndex = SymbolTableIndex; |
1503 | SymbolIndexMap[Sym.MCSym] = Sym.SymbolTableIndex; |
1504 | // 1 main and 1 auxiliary symbol table entry for each contained |
1505 | // symbol. For symbols with exception section entries, a function |
1506 | // auxilliary entry is needed, and on 64-bit XCOFF with debugging |
1507 | // enabled, an additional exception auxilliary entry is needed. |
1508 | SymbolTableIndex += 2; |
1509 | if (hasExceptionSection() && hasExceptEntry) { |
1510 | if (is64Bit() && ExceptionSection.isDebugEnabled) |
1511 | SymbolTableIndex += 2; |
1512 | else |
1513 | SymbolTableIndex += 1; |
1514 | } |
1515 | } |
1516 | } |
1517 | |
1518 | if (!SectionAddressSet) { |
1519 | Section->Address = Group->front().Address; |
1520 | SectionAddressSet = true; |
1521 | } |
1522 | } |
1523 | |
1524 | // Make sure the address of the next section aligned to |
1525 | // DefaultSectionAlign. |
1526 | Address = alignTo(Value: Address, Align: DefaultSectionAlign); |
1527 | Section->Size = Address - Section->Address; |
1528 | } |
1529 | |
1530 | // Start to generate DWARF sections. Sections other than DWARF section use |
1531 | // DefaultSectionAlign as the default alignment, while DWARF sections have |
1532 | // their own alignments. If these two alignments are not the same, we need |
1533 | // some paddings here and record the paddings bytes for FileOffsetToData |
1534 | // calculation. |
1535 | if (!DwarfSections.empty()) |
1536 | PaddingsBeforeDwarf = |
1537 | alignTo(Size: Address, |
1538 | A: (*DwarfSections.begin()).DwarfSect->MCSec->getAlign()) - |
1539 | Address; |
1540 | |
1541 | DwarfSectionEntry *LastDwarfSection = nullptr; |
1542 | for (auto &DwarfSection : DwarfSections) { |
1543 | assert((SectionIndex <= MaxSectionIndex) && "Section index overflow!" ); |
1544 | |
1545 | XCOFFSection &DwarfSect = *DwarfSection.DwarfSect; |
1546 | const MCSectionXCOFF *MCSec = DwarfSect.MCSec; |
1547 | |
1548 | // Section index. |
1549 | DwarfSection.Index = SectionIndex++; |
1550 | SectionCount++; |
1551 | |
1552 | // Symbol index. |
1553 | DwarfSect.SymbolTableIndex = SymbolTableIndex; |
1554 | SymbolIndexMap[MCSec->getQualNameSymbol()] = DwarfSect.SymbolTableIndex; |
1555 | // 1 main and 1 auxiliary symbol table entry for the csect. |
1556 | SymbolTableIndex += 2; |
1557 | |
1558 | // Section address. Make it align to section alignment. |
1559 | // We use address 0 for DWARF sections' Physical and Virtual Addresses. |
1560 | // This address is used to tell where is the section in the final object. |
1561 | // See writeSectionForDwarfSectionEntry(). |
1562 | DwarfSection.Address = DwarfSect.Address = |
1563 | alignTo(Size: Address, A: MCSec->getAlign()); |
1564 | |
1565 | // Section size. |
1566 | // For DWARF section, we must use the real size which may be not aligned. |
1567 | DwarfSection.Size = DwarfSect.Size = Layout.getSectionAddressSize(Sec: MCSec); |
1568 | |
1569 | Address = DwarfSection.Address + DwarfSection.Size; |
1570 | |
1571 | if (LastDwarfSection) |
1572 | LastDwarfSection->MemorySize = |
1573 | DwarfSection.Address - LastDwarfSection->Address; |
1574 | LastDwarfSection = &DwarfSection; |
1575 | } |
1576 | if (LastDwarfSection) { |
1577 | // Make the final DWARF section address align to the default section |
1578 | // alignment for follow contents. |
1579 | Address = alignTo(Value: LastDwarfSection->Address + LastDwarfSection->Size, |
1580 | Align: DefaultSectionAlign); |
1581 | LastDwarfSection->MemorySize = Address - LastDwarfSection->Address; |
1582 | } |
1583 | if (hasExceptionSection()) { |
1584 | ExceptionSection.Index = SectionIndex++; |
1585 | SectionCount++; |
1586 | ExceptionSection.Address = 0; |
1587 | ExceptionSection.Size = getExceptionSectionSize(); |
1588 | Address += ExceptionSection.Size; |
1589 | Address = alignTo(Value: Address, Align: DefaultSectionAlign); |
1590 | } |
1591 | |
1592 | if (CInfoSymSection.Entry) { |
1593 | CInfoSymSection.Index = SectionIndex++; |
1594 | SectionCount++; |
1595 | CInfoSymSection.Address = 0; |
1596 | Address += CInfoSymSection.Size; |
1597 | Address = alignTo(Value: Address, Align: DefaultSectionAlign); |
1598 | } |
1599 | |
1600 | SymbolTableEntryCount = SymbolTableIndex; |
1601 | } |
1602 | |
1603 | void XCOFFObjectWriter::writeSectionForControlSectionEntry( |
1604 | const MCAssembler &Asm, const MCAsmLayout &Layout, |
1605 | const CsectSectionEntry &CsectEntry, uint64_t &CurrentAddressLocation) { |
1606 | // Nothing to write for this Section. |
1607 | if (CsectEntry.Index == SectionEntry::UninitializedIndex) |
1608 | return; |
1609 | |
1610 | // There could be a gap (without corresponding zero padding) between |
1611 | // sections. |
1612 | // There could be a gap (without corresponding zero padding) between |
1613 | // sections. |
1614 | assert(((CurrentAddressLocation <= CsectEntry.Address) || |
1615 | (CsectEntry.Flags == XCOFF::STYP_TDATA) || |
1616 | (CsectEntry.Flags == XCOFF::STYP_TBSS)) && |
1617 | "CurrentAddressLocation should be less than or equal to section " |
1618 | "address if the section is not TData or TBSS." ); |
1619 | |
1620 | CurrentAddressLocation = CsectEntry.Address; |
1621 | |
1622 | // For virtual sections, nothing to write. But need to increase |
1623 | // CurrentAddressLocation for later sections like DWARF section has a correct |
1624 | // writing location. |
1625 | if (CsectEntry.IsVirtual) { |
1626 | CurrentAddressLocation += CsectEntry.Size; |
1627 | return; |
1628 | } |
1629 | |
1630 | for (const auto &Group : CsectEntry.Groups) { |
1631 | for (const auto &Csect : *Group) { |
1632 | if (uint32_t PaddingSize = Csect.Address - CurrentAddressLocation) |
1633 | W.OS.write_zeros(NumZeros: PaddingSize); |
1634 | if (Csect.Size) |
1635 | Asm.writeSectionData(OS&: W.OS, Section: Csect.MCSec, Layout); |
1636 | CurrentAddressLocation = Csect.Address + Csect.Size; |
1637 | } |
1638 | } |
1639 | |
1640 | // The size of the tail padding in a section is the end virtual address of |
1641 | // the current section minus the end virtual address of the last csect |
1642 | // in that section. |
1643 | if (uint64_t PaddingSize = |
1644 | CsectEntry.Address + CsectEntry.Size - CurrentAddressLocation) { |
1645 | W.OS.write_zeros(NumZeros: PaddingSize); |
1646 | CurrentAddressLocation += PaddingSize; |
1647 | } |
1648 | } |
1649 | |
1650 | void XCOFFObjectWriter::writeSectionForDwarfSectionEntry( |
1651 | const MCAssembler &Asm, const MCAsmLayout &Layout, |
1652 | const DwarfSectionEntry &DwarfEntry, uint64_t &CurrentAddressLocation) { |
1653 | // There could be a gap (without corresponding zero padding) between |
1654 | // sections. For example DWARF section alignment is bigger than |
1655 | // DefaultSectionAlign. |
1656 | assert(CurrentAddressLocation <= DwarfEntry.Address && |
1657 | "CurrentAddressLocation should be less than or equal to section " |
1658 | "address." ); |
1659 | |
1660 | if (uint64_t PaddingSize = DwarfEntry.Address - CurrentAddressLocation) |
1661 | W.OS.write_zeros(NumZeros: PaddingSize); |
1662 | |
1663 | if (DwarfEntry.Size) |
1664 | Asm.writeSectionData(OS&: W.OS, Section: DwarfEntry.DwarfSect->MCSec, Layout); |
1665 | |
1666 | CurrentAddressLocation = DwarfEntry.Address + DwarfEntry.Size; |
1667 | |
1668 | // DWARF section size is not aligned to DefaultSectionAlign. |
1669 | // Make sure CurrentAddressLocation is aligned to DefaultSectionAlign. |
1670 | uint32_t Mod = CurrentAddressLocation % DefaultSectionAlign; |
1671 | uint32_t TailPaddingSize = Mod ? DefaultSectionAlign - Mod : 0; |
1672 | if (TailPaddingSize) |
1673 | W.OS.write_zeros(NumZeros: TailPaddingSize); |
1674 | |
1675 | CurrentAddressLocation += TailPaddingSize; |
1676 | } |
1677 | |
1678 | void XCOFFObjectWriter::writeSectionForExceptionSectionEntry( |
1679 | const MCAssembler &Asm, const MCAsmLayout &Layout, |
1680 | ExceptionSectionEntry &ExceptionEntry, uint64_t &CurrentAddressLocation) { |
1681 | for (auto it = ExceptionEntry.ExceptionTable.begin(); |
1682 | it != ExceptionEntry.ExceptionTable.end(); it++) { |
1683 | // For every symbol that has exception entries, you must start the entries |
1684 | // with an initial symbol table index entry |
1685 | W.write<uint32_t>(Val: SymbolIndexMap[it->second.FunctionSymbol]); |
1686 | if (is64Bit()) { |
1687 | // 4-byte padding on 64-bit. |
1688 | W.OS.write_zeros(NumZeros: 4); |
1689 | } |
1690 | W.OS.write_zeros(NumZeros: 2); |
1691 | for (auto &TrapEntry : it->second.Entries) { |
1692 | writeWord(Word: TrapEntry.TrapAddress); |
1693 | W.write<uint8_t>(Val: TrapEntry.Lang); |
1694 | W.write<uint8_t>(Val: TrapEntry.Reason); |
1695 | } |
1696 | } |
1697 | |
1698 | CurrentAddressLocation += getExceptionSectionSize(); |
1699 | } |
1700 | |
1701 | void XCOFFObjectWriter::writeSectionForCInfoSymSectionEntry( |
1702 | const MCAssembler &Asm, const MCAsmLayout &Layout, |
1703 | CInfoSymSectionEntry &CInfoSymEntry, uint64_t &CurrentAddressLocation) { |
1704 | if (!CInfoSymSection.Entry) |
1705 | return; |
1706 | |
1707 | constexpr int WordSize = sizeof(uint32_t); |
1708 | std::unique_ptr<CInfoSymInfo> &CISI = CInfoSymEntry.Entry; |
1709 | const std::string &Metadata = CISI->Metadata; |
1710 | |
1711 | // Emit the 4-byte length of the metadata. |
1712 | W.write<uint32_t>(Val: Metadata.size()); |
1713 | |
1714 | if (Metadata.size() == 0) |
1715 | return; |
1716 | |
1717 | // Write out the payload one word at a time. |
1718 | size_t Index = 0; |
1719 | while (Index + WordSize <= Metadata.size()) { |
1720 | uint32_t NextWord = |
1721 | llvm::support::endian::read32be(P: Metadata.data() + Index); |
1722 | W.write<uint32_t>(Val: NextWord); |
1723 | Index += WordSize; |
1724 | } |
1725 | |
1726 | // If there is padding, we have at least one byte of payload left to emit. |
1727 | if (CISI->paddingSize()) { |
1728 | std::array<uint8_t, WordSize> LastWord = {0}; |
1729 | ::memcpy(dest: LastWord.data(), src: Metadata.data() + Index, n: Metadata.size() - Index); |
1730 | W.write<uint32_t>(Val: llvm::support::endian::read32be(P: LastWord.data())); |
1731 | } |
1732 | |
1733 | CurrentAddressLocation += CISI->size(); |
1734 | } |
1735 | |
1736 | // Takes the log base 2 of the alignment and shifts the result into the 5 most |
1737 | // significant bits of a byte, then or's in the csect type into the least |
1738 | // significant 3 bits. |
1739 | uint8_t getEncodedType(const MCSectionXCOFF *Sec) { |
1740 | unsigned Log2Align = Log2(A: Sec->getAlign()); |
1741 | // Result is a number in the range [0, 31] which fits in the 5 least |
1742 | // significant bits. Shift this value into the 5 most significant bits, and |
1743 | // bitwise-or in the csect type. |
1744 | uint8_t EncodedAlign = Log2Align << 3; |
1745 | return EncodedAlign | Sec->getCSectType(); |
1746 | } |
1747 | |
1748 | } // end anonymous namespace |
1749 | |
1750 | std::unique_ptr<MCObjectWriter> |
1751 | llvm::createXCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW, |
1752 | raw_pwrite_stream &OS) { |
1753 | return std::make_unique<XCOFFObjectWriter>(args: std::move(MOTW), args&: OS); |
1754 | } |
1755 | |