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