diff options
Diffstat (limited to 'llvm/lib/MC/XCOFFObjectWriter.cpp')
| -rw-r--r-- | llvm/lib/MC/XCOFFObjectWriter.cpp | 474 |
1 files changed, 253 insertions, 221 deletions
diff --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp index 177253d7a9d7..977e77bf67fd 100644 --- a/llvm/lib/MC/XCOFFObjectWriter.cpp +++ b/llvm/lib/MC/XCOFFObjectWriter.cpp @@ -22,8 +22,9 @@ #include "llvm/MC/MCValue.h" #include "llvm/MC/MCXCOFFObjectWriter.h" #include "llvm/MC/StringTableBuilder.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/EndianStream.h" -#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include <deque> @@ -65,6 +66,10 @@ struct Symbol { const MCSymbolXCOFF *const MCSym; uint32_t SymbolTableIndex; + XCOFF::VisibilityType getVisibilityType() const { + return MCSym->getVisibilityType(); + } + XCOFF::StorageClass getStorageClass() const { return MCSym->getStorageClass(); } @@ -77,12 +82,15 @@ struct Symbol { struct XCOFFSection { const MCSectionXCOFF *const MCSec; uint32_t SymbolTableIndex; - uint32_t Address; - uint32_t Size; + uint64_t Address; + uint64_t Size; SmallVector<Symbol, 1> Syms; SmallVector<XCOFFRelocation, 1> Relocations; StringRef getSymbolTableName() const { return MCSec->getSymbolTableName(); } + XCOFF::VisibilityType getVisibilityType() const { + return MCSec->getVisibilityType(); + } XCOFFSection(const MCSectionXCOFF *MCSec) : MCSec(MCSec), SymbolTableIndex(-1), Address(-1), Size(0) {} }; @@ -100,10 +108,10 @@ struct SectionEntry { char Name[XCOFF::NameSize]; // The physical/virtual address of the section. For an object file // these values are equivalent. - uint32_t Address; - uint32_t Size; - uint32_t FileOffsetToData; - uint32_t FileOffsetToRelocations; + uint64_t Address; + uint64_t Size; + uint64_t FileOffsetToData; + uint64_t FileOffsetToRelocations; uint32_t RelocationCount; int32_t Flags; @@ -136,7 +144,7 @@ struct SectionEntry { Index = UninitializedIndex; } - virtual ~SectionEntry() {} + virtual ~SectionEntry() = default; }; // Represents the data related to a section excluding the csects that make up @@ -165,16 +173,21 @@ struct CsectSectionEntry : public SectionEntry { Group->clear(); } - virtual ~CsectSectionEntry() {} + virtual ~CsectSectionEntry() = default; }; struct DwarfSectionEntry : public SectionEntry { // For DWARF section entry. std::unique_ptr<XCOFFSection> DwarfSect; + // For DWARF section, we must use real size in the section header. MemorySize + // is for the size the DWARF section occupies including paddings. + uint32_t MemorySize; + DwarfSectionEntry(StringRef N, int32_t Flags, std::unique_ptr<XCOFFSection> Sect) - : SectionEntry(N, Flags | XCOFF::STYP_DWARF), DwarfSect(std::move(Sect)) { + : SectionEntry(N, Flags | XCOFF::STYP_DWARF), DwarfSect(std::move(Sect)), + MemorySize(0) { assert(DwarfSect->MCSec->isDwarfSect() && "This should be a DWARF section!"); assert(N.size() <= XCOFF::NameSize && "section name too long"); @@ -183,20 +196,24 @@ struct DwarfSectionEntry : public SectionEntry { DwarfSectionEntry(DwarfSectionEntry &&s) = default; - virtual ~DwarfSectionEntry() {} + virtual ~DwarfSectionEntry() = default; }; class XCOFFObjectWriter : public MCObjectWriter { uint32_t SymbolTableEntryCount = 0; - uint32_t SymbolTableOffset = 0; + uint64_t SymbolTableOffset = 0; uint16_t SectionCount = 0; - uint32_t RelocationEntryOffset = 0; + uint64_t RelocationEntryOffset = 0; + std::vector<std::pair<std::string, size_t>> FileNames; support::endian::Writer W; std::unique_ptr<MCXCOFFObjectTargetWriter> TargetObjectWriter; StringTableBuilder Strings; + const uint64_t MaxRawDataSize = + TargetObjectWriter->is64Bit() ? UINT64_MAX : UINT32_MAX; + // Maps the MCSection representation to its corresponding XCOFFSection // wrapper. Needed for finding the XCOFFSection to insert an MCSymbol into // from its containing MCSectionXCOFF. @@ -244,26 +261,39 @@ class XCOFFObjectWriter : public MCObjectWriter { uint64_t writeObject(MCAssembler &, const MCAsmLayout &) override; - static bool nameShouldBeInStringTable(const StringRef &); + bool is64Bit() const { return TargetObjectWriter->is64Bit(); } + bool nameShouldBeInStringTable(const StringRef &); void writeSymbolName(const StringRef &); - void writeSymbolTableEntryForCsectMemberLabel(const Symbol &, - const XCOFFSection &, int16_t, - uint64_t); - void writeSymbolTableEntryForControlSection(const XCOFFSection &, int16_t, - XCOFF::StorageClass); - void writeSymbolTableEntryForDwarfSection(const XCOFFSection &, int16_t); + + void writeSymbolEntryForCsectMemberLabel(const Symbol &SymbolRef, + const XCOFFSection &CSectionRef, + int16_t SectionIndex, + uint64_t SymbolOffset); + void writeSymbolEntryForControlSection(const XCOFFSection &CSectionRef, + int16_t SectionIndex, + XCOFF::StorageClass StorageClass); + void writeSymbolEntryForDwarfSection(const XCOFFSection &DwarfSectionRef, + int16_t SectionIndex); void writeFileHeader(); void writeSectionHeaderTable(); void writeSections(const MCAssembler &Asm, const MCAsmLayout &Layout); void writeSectionForControlSectionEntry(const MCAssembler &Asm, const MCAsmLayout &Layout, const CsectSectionEntry &CsectEntry, - uint32_t &CurrentAddressLocation); + uint64_t &CurrentAddressLocation); void writeSectionForDwarfSectionEntry(const MCAssembler &Asm, const MCAsmLayout &Layout, const DwarfSectionEntry &DwarfEntry, - uint32_t &CurrentAddressLocation); + uint64_t &CurrentAddressLocation); void writeSymbolTable(const MCAsmLayout &Layout); + void writeSymbolAuxDwarfEntry(uint64_t LengthOfSectionPortion, + uint64_t NumberOfRelocEnt = 0); + void writeSymbolAuxCsectEntry(uint64_t SectionOrLength, + uint8_t SymbolAlignmentAndType, + uint8_t StorageMappingClass); + void writeSymbolEntry(StringRef SymbolName, uint64_t Value, + int16_t SectionNumber, uint16_t SymbolType, + uint8_t StorageClass, uint8_t NumberOfAuxEntries = 1); void writeRelocations(); void writeRelocation(XCOFFRelocation Reloc, const XCOFFSection &Section); @@ -278,10 +308,8 @@ class XCOFFObjectWriter : public MCObjectWriter { void assignAddressesAndIndices(const MCAsmLayout &); void finalizeSectionInfo(); - bool - needsAuxiliaryHeader() const { /* TODO aux header support not implemented. */ - return false; - } + // TODO aux header support not implemented. + bool needsAuxiliaryHeader() const { return false; } // Returns the size of the auxiliary header to be written to the object file. size_t auxiliaryHeaderSize() const { @@ -293,6 +321,10 @@ class XCOFFObjectWriter : public MCObjectWriter { public: XCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS); + + void writeWord(uint64_t Word) { + is64Bit() ? W.write<uint64_t>(Word) : W.write<uint32_t>(Word); + } }; XCOFFObjectWriter::XCOFFObjectWriter( @@ -396,9 +428,6 @@ static MCSectionXCOFF *getContainingCsect(const MCSymbolXCOFF *XSym) { void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) { - if (TargetObjectWriter->is64Bit()) - report_fatal_error("64-bit XCOFF object files are not supported yet."); - for (const auto &S : Asm) { const auto *MCSec = cast<const MCSectionXCOFF>(&S); assert(SectionMap.find(MCSec) == SectionMap.end() && @@ -424,7 +453,7 @@ void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, SectionMap[MCSec] = DwarfSec.get(); DwarfSectionEntry SecEntry(MCSec->getName(), - MCSec->getDwarfSubtypeFlags().getValue(), + *MCSec->getDwarfSubtypeFlags(), std::move(DwarfSec)); DwarfSections.push_back(std::move(SecEntry)); } else @@ -470,6 +499,15 @@ void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, Strings.add(XSym->getSymbolTableName()); } + FileNames = Asm.getFileNames(); + // Emit ".file" as the source file name when there is no file name. + if (FileNames.empty()) + FileNames.emplace_back(".file", 0); + for (const std::pair<std::string, size_t> &F : FileNames) { + if (nameShouldBeInStringTable(F.first)) + Strings.add(F.first); + } + Strings.finalize(); assignAddressesAndIndices(Layout); } @@ -547,10 +585,9 @@ void XCOFFObjectWriter::recordRelocation(MCAssembler &Asm, FixedValue = TOCEntryOffset; } - assert( - (TargetObjectWriter->is64Bit() || - Fixup.getOffset() <= UINT32_MAX - Layout.getFragmentOffset(Fragment)) && - "Fragment offset + fixup offset is overflowed in 32-bit mode."); + assert((Fixup.getOffset() <= + MaxRawDataSize - Layout.getFragmentOffset(Fragment)) && + "Fragment offset + fixup offset is overflowed."); uint32_t FixupOffsetInCsect = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); @@ -590,7 +627,7 @@ void XCOFFObjectWriter::recordRelocation(MCAssembler &Asm, void XCOFFObjectWriter::writeSections(const MCAssembler &Asm, const MCAsmLayout &Layout) { - uint32_t CurrentAddressLocation = 0; + uint64_t CurrentAddressLocation = 0; for (const auto *Section : Sections) writeSectionForControlSectionEntry(Asm, Layout, *Section, CurrentAddressLocation); @@ -607,9 +644,6 @@ uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm, if (Asm.isIncrementalLinkerCompatible()) report_fatal_error("Incremental linking not supported for XCOFF."); - if (TargetObjectWriter->is64Bit()) - report_fatal_error("64-bit XCOFF object files are not supported yet."); - finalizeSectionInfo(); uint64_t StartOffset = W.OS.tell(); @@ -617,7 +651,6 @@ uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm, writeSectionHeaderTable(); writeSections(Asm, Layout); writeRelocations(); - writeSymbolTable(Layout); // Write the string table. Strings.write(W.OS); @@ -626,142 +659,130 @@ uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm, } bool XCOFFObjectWriter::nameShouldBeInStringTable(const StringRef &SymbolName) { - return SymbolName.size() > XCOFF::NameSize; + return SymbolName.size() > XCOFF::NameSize || is64Bit(); } void XCOFFObjectWriter::writeSymbolName(const StringRef &SymbolName) { + // Magic, Offset or SymbolName. if (nameShouldBeInStringTable(SymbolName)) { W.write<int32_t>(0); W.write<uint32_t>(Strings.getOffset(SymbolName)); } else { - char Name[XCOFF::NameSize+1]; + char Name[XCOFF::NameSize + 1]; std::strncpy(Name, SymbolName.data(), XCOFF::NameSize); ArrayRef<char> NameRef(Name, XCOFF::NameSize); W.write(NameRef); } } -void XCOFFObjectWriter::writeSymbolTableEntryForCsectMemberLabel( - const Symbol &SymbolRef, const XCOFFSection &CSectionRef, - int16_t SectionIndex, uint64_t SymbolOffset) { - // Name or Zeros and string table offset - writeSymbolName(SymbolRef.getSymbolTableName()); - assert(SymbolOffset <= UINT32_MAX - CSectionRef.Address && - "Symbol address overflows."); - W.write<uint32_t>(CSectionRef.Address + SymbolOffset); - W.write<int16_t>(SectionIndex); +void XCOFFObjectWriter::writeSymbolEntry(StringRef SymbolName, uint64_t Value, + int16_t SectionNumber, + uint16_t SymbolType, + uint8_t StorageClass, + uint8_t NumberOfAuxEntries) { + if (is64Bit()) { + W.write<uint64_t>(Value); + W.write<uint32_t>(Strings.getOffset(SymbolName)); + } else { + writeSymbolName(SymbolName); + W.write<uint32_t>(Value); + } + W.write<int16_t>(SectionNumber); // Basic/Derived type. See the description of the n_type field for symbol // table entries for a detailed description. Since we don't yet support // visibility, and all other bits are either optionally set or reserved, this // is always zero. - // TODO FIXME How to assert a symbol's visibilty is default? + if (SymbolType != 0) + report_fatal_error("Emitting non-zero visibilities is not supported yet."); // TODO Set the function indicator (bit 10, 0x0020) for functions // when debugging is enabled. - W.write<uint16_t>(0); - W.write<uint8_t>(SymbolRef.getStorageClass()); - // Always 1 aux entry for now. - W.write<uint8_t>(1); + W.write<uint16_t>(SymbolType); + W.write<uint8_t>(StorageClass); + W.write<uint8_t>(NumberOfAuxEntries); +} + +void XCOFFObjectWriter::writeSymbolAuxCsectEntry(uint64_t SectionOrLength, + uint8_t SymbolAlignmentAndType, + uint8_t StorageMappingClass) { + W.write<uint32_t>(is64Bit() ? Lo_32(SectionOrLength) : SectionOrLength); + W.write<uint32_t>(0); // ParameterHashIndex + W.write<uint16_t>(0); // TypeChkSectNum + W.write<uint8_t>(SymbolAlignmentAndType); + W.write<uint8_t>(StorageMappingClass); + if (is64Bit()) { + W.write<uint32_t>(Hi_32(SectionOrLength)); + W.OS.write_zeros(1); // Reserved + W.write<uint8_t>(XCOFF::AUX_CSECT); + } else { + W.write<uint32_t>(0); // StabInfoIndex + W.write<uint16_t>(0); // StabSectNum + } +} + +void XCOFFObjectWriter::writeSymbolAuxDwarfEntry( + uint64_t LengthOfSectionPortion, uint64_t NumberOfRelocEnt) { + writeWord(LengthOfSectionPortion); + if (!is64Bit()) + W.OS.write_zeros(4); // Reserved + writeWord(NumberOfRelocEnt); + if (is64Bit()) { + W.OS.write_zeros(1); // Reserved + W.write<uint8_t>(XCOFF::AUX_SECT); + } else { + W.OS.write_zeros(6); // Reserved + } +} - // Now output the auxiliary entry. - W.write<uint32_t>(CSectionRef.SymbolTableIndex); - // Parameter typecheck hash. Not supported. - W.write<uint32_t>(0); - // Typecheck section number. Not supported. - W.write<uint16_t>(0); - // Symbol type: Label - W.write<uint8_t>(XCOFF::XTY_LD); - // Storage mapping class. - W.write<uint8_t>(CSectionRef.MCSec->getMappingClass()); - // Reserved (x_stab). - W.write<uint32_t>(0); - // Reserved (x_snstab). - W.write<uint16_t>(0); +void XCOFFObjectWriter::writeSymbolEntryForCsectMemberLabel( + const Symbol &SymbolRef, const XCOFFSection &CSectionRef, + int16_t SectionIndex, uint64_t SymbolOffset) { + assert(SymbolOffset <= MaxRawDataSize - CSectionRef.Address && + "Symbol address overflowed."); + + writeSymbolEntry(SymbolRef.getSymbolTableName(), + CSectionRef.Address + SymbolOffset, SectionIndex, + SymbolRef.getVisibilityType(), SymbolRef.getStorageClass()); + + writeSymbolAuxCsectEntry(CSectionRef.SymbolTableIndex, XCOFF::XTY_LD, + CSectionRef.MCSec->getMappingClass()); } -void XCOFFObjectWriter::writeSymbolTableEntryForDwarfSection( +void XCOFFObjectWriter::writeSymbolEntryForDwarfSection( const XCOFFSection &DwarfSectionRef, int16_t SectionIndex) { assert(DwarfSectionRef.MCSec->isDwarfSect() && "Not a DWARF section!"); - // n_name, n_zeros, n_offset - writeSymbolName(DwarfSectionRef.getSymbolTableName()); - // n_value - W.write<uint32_t>(0); - // n_scnum - W.write<int16_t>(SectionIndex); - // n_type - W.write<uint16_t>(0); - // n_sclass - W.write<uint8_t>(XCOFF::C_DWARF); - // Always 1 aux entry for now. - W.write<uint8_t>(1); + writeSymbolEntry(DwarfSectionRef.getSymbolTableName(), /*Value=*/0, + SectionIndex, /*SymbolType=*/0, XCOFF::C_DWARF); - // Now output the auxiliary entry. - // x_scnlen - W.write<uint32_t>(DwarfSectionRef.Size); - // Reserved - W.write<uint32_t>(0); - // x_nreloc. Set to 0 for now. - W.write<uint32_t>(0); - // Reserved - W.write<uint32_t>(0); - // Reserved - W.write<uint16_t>(0); + writeSymbolAuxDwarfEntry(DwarfSectionRef.Size); } -void XCOFFObjectWriter::writeSymbolTableEntryForControlSection( +void XCOFFObjectWriter::writeSymbolEntryForControlSection( const XCOFFSection &CSectionRef, int16_t SectionIndex, XCOFF::StorageClass StorageClass) { - // n_name, n_zeros, n_offset - writeSymbolName(CSectionRef.getSymbolTableName()); - // n_value - W.write<uint32_t>(CSectionRef.Address); - // n_scnum - W.write<int16_t>(SectionIndex); - // Basic/Derived type. See the description of the n_type field for symbol - // table entries for a detailed description. Since we don't yet support - // visibility, and all other bits are either optionally set or reserved, this - // is always zero. - // TODO FIXME How to assert a symbol's visibilty is default? - // TODO Set the function indicator (bit 10, 0x0020) for functions - // when debugging is enabled. - W.write<uint16_t>(0); - // n_sclass - W.write<uint8_t>(StorageClass); - // Always 1 aux entry for now. - W.write<uint8_t>(1); + writeSymbolEntry(CSectionRef.getSymbolTableName(), CSectionRef.Address, + SectionIndex, CSectionRef.getVisibilityType(), StorageClass); - // Now output the auxiliary entry. - W.write<uint32_t>(CSectionRef.Size); - // Parameter typecheck hash. Not supported. - W.write<uint32_t>(0); - // Typecheck section number. Not supported. - W.write<uint16_t>(0); - // Symbol type. - W.write<uint8_t>(getEncodedType(CSectionRef.MCSec)); - // Storage mapping class. - W.write<uint8_t>(CSectionRef.MCSec->getMappingClass()); - // Reserved (x_stab). - W.write<uint32_t>(0); - // Reserved (x_snstab). - W.write<uint16_t>(0); + writeSymbolAuxCsectEntry(CSectionRef.Size, getEncodedType(CSectionRef.MCSec), + CSectionRef.MCSec->getMappingClass()); } void XCOFFObjectWriter::writeFileHeader() { - // Magic. - W.write<uint16_t>(0x01df); - // Number of sections. + W.write<uint16_t>(is64Bit() ? XCOFF::XCOFF64 : XCOFF::XCOFF32); W.write<uint16_t>(SectionCount); - // Timestamp field. For reproducible output we write a 0, which represents no - // timestamp. - W.write<int32_t>(0); - // Byte Offset to the start of the symbol table. - W.write<uint32_t>(SymbolTableOffset); - // Number of entries in the symbol table. - W.write<int32_t>(SymbolTableEntryCount); - // Size of the optional header. - W.write<uint16_t>(0); - // Flags. - W.write<uint16_t>(0); + W.write<int32_t>(0); // TimeStamp + writeWord(SymbolTableOffset); + if (is64Bit()) { + W.write<uint16_t>(0); // AuxHeaderSize. No optional header for an object + // file that is not to be loaded. + W.write<uint16_t>(0); // Flags + W.write<int32_t>(SymbolTableEntryCount); + } else { + W.write<int32_t>(SymbolTableEntryCount); + W.write<uint16_t>(0); // AuxHeaderSize. No optional header for an object + // file that is not to be loaded. + W.write<uint16_t>(0); // Flags + } } void XCOFFObjectWriter::writeSectionHeaderTable() { @@ -777,27 +798,24 @@ void XCOFFObjectWriter::writeSectionHeaderTable() { // Write the Physical Address and Virtual Address. In an object file these // are the same. // We use 0 for DWARF sections' Physical and Virtual Addresses. - if (!IsDwarf) { - W.write<uint32_t>(Sec->Address); - W.write<uint32_t>(Sec->Address); - } else { - W.write<uint32_t>(0); - W.write<uint32_t>(0); - } + writeWord(IsDwarf ? 0 : Sec->Address); + writeWord(IsDwarf ? 0 : Sec->Address); - W.write<uint32_t>(Sec->Size); - W.write<uint32_t>(Sec->FileOffsetToData); - W.write<uint32_t>(Sec->FileOffsetToRelocations); + writeWord(Sec->Size); + writeWord(Sec->FileOffsetToData); + writeWord(Sec->FileOffsetToRelocations); + writeWord(0); // FileOffsetToLineNumberInfo. Not supported yet. - // Line number pointer. Not supported yet. - W.write<uint32_t>(0); - - W.write<uint16_t>(Sec->RelocationCount); - - // Line number counts. Not supported yet. - W.write<uint16_t>(0); - - W.write<int32_t>(Sec->Flags); + if (is64Bit()) { + W.write<uint32_t>(Sec->RelocationCount); + W.write<uint32_t>(0); // NumberOfLineNumbers. Not supported yet. + W.write<int32_t>(Sec->Flags); + W.OS.write_zeros(4); + } else { + W.write<uint16_t>(Sec->RelocationCount); + W.write<uint16_t>(0); // NumberOfLineNumbers. Not supported yet. + W.write<int32_t>(Sec->Flags); + } return true; }; @@ -811,11 +829,11 @@ void XCOFFObjectWriter::writeSectionHeaderTable() { void XCOFFObjectWriter::writeRelocation(XCOFFRelocation Reloc, const XCOFFSection &Section) { if (Section.MCSec->isCsect()) - W.write<uint32_t>(Section.Address + Reloc.FixupOffsetInCsect); + writeWord(Section.Address + Reloc.FixupOffsetInCsect); else { // DWARF sections' address is set to 0. assert(Section.MCSec->isDwarfSect() && "unsupport section type!"); - W.write<uint32_t>(Reloc.FixupOffsetInCsect); + writeWord(Reloc.FixupOffsetInCsect); } W.write<uint32_t>(Reloc.SymbolTableIndex); W.write<uint8_t>(Reloc.SignAndSize); @@ -845,34 +863,18 @@ void XCOFFObjectWriter::writeRelocations() { } void XCOFFObjectWriter::writeSymbolTable(const MCAsmLayout &Layout) { - // Write symbol 0 as C_FILE. - // FIXME: support 64-bit C_FILE symbol. - // - // n_name. The n_name of a C_FILE symbol is the source filename when no - // auxiliary entries are present. The source filename is alternatively - // provided by an auxiliary entry, in which case the n_name of the C_FILE - // symbol is `.file`. - // FIXME: add the real source filename. - writeSymbolName(".file"); - // n_value. The n_value of a C_FILE symbol is its symbol table index. - W.write<uint32_t>(0); - // n_scnum. N_DEBUG is a reserved section number for indicating a special - // symbolic debugging symbol. - W.write<int16_t>(XCOFF::ReservedSectionNum::N_DEBUG); - // n_type. The n_type field of a C_FILE symbol encodes the source language and - // CPU version info; zero indicates no info. - W.write<uint16_t>(0); - // n_sclass. The C_FILE symbol provides source file-name information, - // source-language ID and CPU-version ID information and some other optional - // infos. - W.write<uint8_t>(XCOFF::C_FILE); - // n_numaux. No aux entry for now. - W.write<uint8_t>(0); + // Write C_FILE symbols. + // The n_name of a C_FILE symbol is the source file's name when no auxiliary + // entries are present. + for (const std::pair<std::string, size_t> &F : FileNames) { + writeSymbolEntry(F.first, /*Value=*/0, XCOFF::ReservedSectionNum::N_DEBUG, + /*SymbolType=*/0, XCOFF::C_FILE, + /*NumberOfAuxEntries=*/0); + } for (const auto &Csect : UndefinedCsects) { - writeSymbolTableEntryForControlSection(Csect, - XCOFF::ReservedSectionNum::N_UNDEF, - Csect.MCSec->getStorageClass()); + writeSymbolEntryForControlSection(Csect, XCOFF::ReservedSectionNum::N_UNDEF, + Csect.MCSec->getStorageClass()); } for (const auto *Section : Sections) { @@ -887,19 +889,19 @@ void XCOFFObjectWriter::writeSymbolTable(const MCAsmLayout &Layout) { const int16_t SectionIndex = Section->Index; for (const auto &Csect : *Group) { // Write out the control section first and then each symbol in it. - writeSymbolTableEntryForControlSection(Csect, SectionIndex, - Csect.MCSec->getStorageClass()); + writeSymbolEntryForControlSection(Csect, SectionIndex, + Csect.MCSec->getStorageClass()); for (const auto &Sym : Csect.Syms) - writeSymbolTableEntryForCsectMemberLabel( + writeSymbolEntryForCsectMemberLabel( Sym, Csect, SectionIndex, Layout.getSymbolOffset(*(Sym.MCSym))); } } } for (const auto &DwarfSection : DwarfSections) - writeSymbolTableEntryForDwarfSection(*DwarfSection.DwarfSect, - DwarfSection.Index); + writeSymbolEntryForDwarfSection(*DwarfSection.DwarfSect, + DwarfSection.Index); } void XCOFFObjectWriter::finalizeSectionInfo() { @@ -914,8 +916,10 @@ void XCOFFObjectWriter::finalizeSectionInfo() { for (auto &Csect : *Group) { const size_t CsectRelocCount = Csect.Relocations.size(); - if (CsectRelocCount >= XCOFF::RelocOverflow || - Section->RelocationCount >= XCOFF::RelocOverflow - CsectRelocCount) + // An XCOFF64 file may not contain an overflow section header. + if (!is64Bit() && (CsectRelocCount >= XCOFF::RelocOverflow || + Section->RelocationCount >= + XCOFF::RelocOverflow - CsectRelocCount)) report_fatal_error( "relocation entries overflowed; overflow section is " "not implemented yet"); @@ -938,10 +942,12 @@ void XCOFFObjectWriter::finalizeSectionInfo() { return false; Sec->FileOffsetToRelocations = RawPointer; - const uint32_t RelocationSizeInSec = - Sec->RelocationCount * XCOFF::RelocationSerializationSize32; + const uint64_t RelocationSizeInSec = + Sec->RelocationCount * (is64Bit() + ? XCOFF::RelocationSerializationSize64 + : XCOFF::RelocationSerializationSize32); RawPointer += RelocationSizeInSec; - if (RawPointer > UINT32_MAX) + if (RawPointer > MaxRawDataSize) report_fatal_error("Relocation data overflowed this object file."); return true; @@ -960,8 +966,8 @@ void XCOFFObjectWriter::finalizeSectionInfo() { } void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) { - // The first symbol table entry (at index 0) is for the file name. - uint32_t SymbolTableIndex = 1; + // The symbol table starts with all the C_FILE symbols. + uint32_t SymbolTableIndex = FileNames.size(); // Calculate indices for undefined symbols. for (auto &Csect : UndefinedCsects) { @@ -976,10 +982,11 @@ void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) { // The address corrresponds to the address of sections and symbols in the // object file. We place the shared address 0 immediately after the // section header table. - uint32_t Address = 0; + uint64_t Address = 0; // Section indices are 1-based in XCOFF. int32_t SectionIndex = 1; bool HasTDataSection = false; + uint32_t PaddingsBeforeDwarf = 0; for (auto *Section : Sections) { const bool IsEmpty = @@ -1039,6 +1046,19 @@ void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) { Section->Size = Address - Section->Address; } + // Start to generate DWARF sections. Sections other than DWARF section use + // DefaultSectionAlign as the default alignment, while DWARF sections have + // their own alignments. If these two alignments are not the same, we need + // some paddings here and record the paddings bytes for FileOffsetToData + // calculation. + if (!DwarfSections.empty()) + PaddingsBeforeDwarf = + alignTo(Address, + (*DwarfSections.begin()).DwarfSect->MCSec->getAlignment()) - + Address; + + DwarfSectionEntry *LastDwarfSection = nullptr; + for (auto &DwarfSection : DwarfSections) { assert((SectionIndex <= MaxSectionIndex) && "Section index overflow!"); @@ -1066,40 +1086,52 @@ void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) { // For DWARF section, we must use the real size which may be not aligned. DwarfSection.Size = DwarfSect.Size = Layout.getSectionAddressSize(MCSec); - // Make the Address align to default alignment for follow section. - Address = alignTo(DwarfSect.Address + DwarfSect.Size, DefaultSectionAlign); + Address = DwarfSection.Address + DwarfSection.Size; + + if (LastDwarfSection) + LastDwarfSection->MemorySize = + DwarfSection.Address - LastDwarfSection->Address; + LastDwarfSection = &DwarfSection; + } + if (LastDwarfSection) { + // Make the final DWARF section address align to the default section + // alignment for follow contents. + Address = alignTo(LastDwarfSection->Address + LastDwarfSection->Size, + DefaultSectionAlign); + LastDwarfSection->MemorySize = Address - LastDwarfSection->Address; } SymbolTableEntryCount = SymbolTableIndex; // Calculate the RawPointer value for each section. - uint64_t RawPointer = XCOFF::FileHeaderSize32 + auxiliaryHeaderSize() + - SectionCount * XCOFF::SectionHeaderSize32; + uint64_t RawPointer = + (is64Bit() ? (XCOFF::FileHeaderSize64 + + SectionCount * XCOFF::SectionHeaderSize64) + : (XCOFF::FileHeaderSize32 + + SectionCount * XCOFF::SectionHeaderSize32)) + + auxiliaryHeaderSize(); + for (auto *Sec : Sections) { if (Sec->Index == SectionEntry::UninitializedIndex || Sec->IsVirtual) continue; Sec->FileOffsetToData = RawPointer; RawPointer += Sec->Size; - if (RawPointer > UINT32_MAX) + if (RawPointer > MaxRawDataSize) report_fatal_error("Section raw data overflowed this object file."); } - for (auto &DwarfSection : DwarfSections) { - // Address of csect sections are always aligned to DefaultSectionAlign, but - // address of DWARF section are aligned to Section alignment which may be - // bigger than DefaultSectionAlign, need to execlude the padding bits. - RawPointer = - alignTo(RawPointer, DwarfSection.DwarfSect->MCSec->getAlignment()); + // Increase the raw pointer for the padding bytes between csect sections and + // DWARF sections. + if (!DwarfSections.empty()) + RawPointer += PaddingsBeforeDwarf; + for (auto &DwarfSection : DwarfSections) { DwarfSection.FileOffsetToData = RawPointer; - // Some section entries, like DWARF section size is not aligned, so - // RawPointer may be not aligned. - RawPointer += DwarfSection.Size; - // Make sure RawPointer is aligned. - RawPointer = alignTo(RawPointer, DefaultSectionAlign); - assert(RawPointer <= UINT32_MAX && + RawPointer += DwarfSection.MemorySize; + + assert(RawPointer <= MaxRawDataSize && "Section raw data overflowed this object file."); } @@ -1108,7 +1140,7 @@ void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) { void XCOFFObjectWriter::writeSectionForControlSectionEntry( const MCAssembler &Asm, const MCAsmLayout &Layout, - const CsectSectionEntry &CsectEntry, uint32_t &CurrentAddressLocation) { + const CsectSectionEntry &CsectEntry, uint64_t &CurrentAddressLocation) { // Nothing to write for this Section. if (CsectEntry.Index == SectionEntry::UninitializedIndex) return; @@ -1146,7 +1178,7 @@ void XCOFFObjectWriter::writeSectionForControlSectionEntry( // The size of the tail padding in a section is the end virtual address of // the current section minus the the end virtual address of the last csect // in that section. - if (uint32_t PaddingSize = + if (uint64_t PaddingSize = CsectEntry.Address + CsectEntry.Size - CurrentAddressLocation) { W.OS.write_zeros(PaddingSize); CurrentAddressLocation += PaddingSize; @@ -1155,7 +1187,7 @@ void XCOFFObjectWriter::writeSectionForControlSectionEntry( void XCOFFObjectWriter::writeSectionForDwarfSectionEntry( const MCAssembler &Asm, const MCAsmLayout &Layout, - const DwarfSectionEntry &DwarfEntry, uint32_t &CurrentAddressLocation) { + const DwarfSectionEntry &DwarfEntry, uint64_t &CurrentAddressLocation) { // There could be a gap (without corresponding zero padding) between // sections. For example DWARF section alignment is bigger than // DefaultSectionAlign. @@ -1163,7 +1195,7 @@ void XCOFFObjectWriter::writeSectionForDwarfSectionEntry( "CurrentAddressLocation should be less than or equal to section " "address."); - if (uint32_t PaddingSize = DwarfEntry.Address - CurrentAddressLocation) + if (uint64_t PaddingSize = DwarfEntry.Address - CurrentAddressLocation) W.OS.write_zeros(PaddingSize); if (DwarfEntry.Size) |
