diff --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp --- a/llvm/lib/MC/XCOFFObjectWriter.cpp +++ b/llvm/lib/MC/XCOFFObjectWriter.cpp @@ -234,7 +234,6 @@ uint32_t SymbolTableEntryCount = 0; uint64_t SymbolTableOffset = 0; uint16_t SectionCount = 0; - uint64_t RelocationEntryOffset = 0; std::vector> FileNames; bool HasVisibility = false; @@ -280,6 +279,7 @@ {&Text, &Data, &BSS, &TData, &TBSS}}; std::vector DwarfSections; + std::vector OverflowSections; ExceptionSectionEntry ExceptionSection; @@ -309,6 +309,7 @@ int16_t SectionIndex); void writeFileHeader(); void writeAuxFileHeader(); + void writeSectionHeader(const SectionEntry *Sec); void writeSectionHeaderTable(); void writeSections(const MCAssembler &Asm, const MCAsmLayout &Layout); void writeSectionForControlSectionEntry(const MCAssembler &Asm, @@ -348,7 +349,11 @@ // *) Builds up the section header table by adding any non-empty sections to // `Sections`. void assignAddressesAndIndices(const MCAsmLayout &); + // Called after relocations are recorded. void finalizeSectionInfo(); + void finalizeRelocationInfo(SectionEntry *Sec, uint64_t RelCount); + void calcOffsetToRelocations(SectionEntry *Sec, uint64_t &RawPointer); + void addExceptionEntry(const MCSymbol *Symbol, const MCSymbol *Trap, unsigned LanguageCode, unsigned ReasonCode, unsigned FunctionSize, bool hasDebug) override; @@ -399,13 +404,14 @@ Sec->reset(); for (auto &DwarfSec : DwarfSections) DwarfSec.reset(); + for (auto &OvrfloSec : OverflowSections) + OvrfloSec.reset(); ExceptionSection.reset(); // Reset states in XCOFFObjectWriter. SymbolTableEntryCount = 0; SymbolTableOffset = 0; SectionCount = 0; - RelocationEntryOffset = 0; Strings.clear(); MCObjectWriter::reset(); @@ -906,47 +912,59 @@ W.write(Sections[1]->Address); // DataStartAddr } -void XCOFFObjectWriter::writeSectionHeaderTable() { - auto writeSectionHeader = [&](const SectionEntry *Sec, bool IsDwarf) { - // Nothing to write for this Section. - if (Sec->Index == SectionEntry::UninitializedIndex) - return false; - - // Write Name. - ArrayRef NameRef(Sec->Name, XCOFF::NameSize); - W.write(NameRef); - - // 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. - writeWord(IsDwarf ? 0 : Sec->Address); - writeWord(IsDwarf ? 0 : Sec->Address); - - writeWord(Sec->Size); - writeWord(Sec->FileOffsetToData); - writeWord(Sec->FileOffsetToRelocations); - writeWord(0); // FileOffsetToLineNumberInfo. Not supported yet. +void XCOFFObjectWriter::writeSectionHeader(const SectionEntry *Sec) { + bool IsDwarf = (Sec->Flags & XCOFF::STYP_DWARF) != 0; + bool IsOvrflo = (Sec->Flags & XCOFF::STYP_OVRFLO) != 0; + // Nothing to write for this Section. + if (Sec->Index == SectionEntry::UninitializedIndex) + return; - if (is64Bit()) { - W.write(Sec->RelocationCount); - W.write(0); // NumberOfLineNumbers. Not supported yet. - W.write(Sec->Flags); - W.OS.write_zeros(4); - } else { - W.write(Sec->RelocationCount); - W.write(0); // NumberOfLineNumbers. Not supported yet. - W.write(Sec->Flags); - } + // Write Name. + ArrayRef NameRef(Sec->Name, XCOFF::NameSize); + W.write(NameRef); + + // Write the Physical Address and Virtual Address. In an object file these + // are the same, except in the the overflow section header. + // In the overflow section header the Physical Address specifies the number + // of relocation entries actually required and the Virtual Address specifies + // the number of line number entries actually required. + // We use 0 for DWARF sections' Physical and Virtual Addresses. + writeWord(IsDwarf ? 0 : Sec->Address); + // Since line number is not supported, we set it to 0 for overflow sections. + writeWord((IsDwarf || IsOvrflo) ? 0 : Sec->Address); + + writeWord(Sec->Size); + writeWord(Sec->FileOffsetToData); + writeWord(Sec->FileOffsetToRelocations); + writeWord(0); // FileOffsetToLineNumberInfo. Not supported yet. - return true; - }; + if (is64Bit()) { + W.write(Sec->RelocationCount); + W.write(0); // NumberOfLineNumbers. Not supported yet. + W.write(Sec->Flags); + W.OS.write_zeros(4); + } else { + // For the overflow section header, s_nreloc provides a reference to the + // primary section header and s_nlnno must have the same value. + // For common section header, either of s_nreloc or s_nlnno is set to + // 65535, the other one must also be set to 65535. + W.write(Sec->RelocationCount); + W.write((IsOvrflo || Sec->RelocationCount == XCOFF::RelocOverflow) + ? Sec->RelocationCount + : 0); // NumberOfLineNumbers. Not supported yet. + W.write(Sec->Flags); + } +} +void XCOFFObjectWriter::writeSectionHeaderTable() { for (const auto *CsectSec : Sections) - writeSectionHeader(CsectSec, /* IsDwarf */ false); + writeSectionHeader(CsectSec); for (const auto &DwarfSec : DwarfSections) - writeSectionHeader(&DwarfSec, /* IsDwarf */ true); + writeSectionHeader(&DwarfSec); + for (const auto &OvrfloSec : OverflowSections) + writeSectionHeader(&OvrfloSec); if (hasExceptionSection()) - writeSectionHeader(&ExceptionSection, false); + writeSectionHeader(&ExceptionSection); } void XCOFFObjectWriter::writeRelocation(XCOFFRelocation Reloc, @@ -1027,60 +1045,139 @@ DwarfSection.Index); } +void XCOFFObjectWriter::finalizeRelocationInfo(SectionEntry *Sec, + uint64_t RelCount) { + // Handles relocation field overflows in an XCOFF32 file. An XCOFF64 file + // may not contain an overflow section header. + if (!is64Bit() && (RelCount >= static_cast(XCOFF::RelocOverflow))) { + // Generate an overflow section header. + SectionEntry SecEntry(".ovrflo", XCOFF::STYP_OVRFLO); + + // This field specifies the file section number of the section header that + // overflowed. + SecEntry.RelocationCount = Sec->Index; + + // This field specifies the number of relocation entries actually + // required. + SecEntry.Address = RelCount; + SecEntry.Index = ++SectionCount; + OverflowSections.push_back(SecEntry); + + // The field in the primary section header is always 65535 + // (XCOFF::RelocOverflow). + Sec->RelocationCount = XCOFF::RelocOverflow; + } else { + Sec->RelocationCount = RelCount; + } +} + +void XCOFFObjectWriter::calcOffsetToRelocations(SectionEntry *Sec, + uint64_t &RawPointer) { + if (!Sec->RelocationCount) + return; + + Sec->FileOffsetToRelocations = RawPointer; + uint64_t RelocationSizeInSec = 0; + if (!is64Bit() && + Sec->RelocationCount == static_cast(XCOFF::RelocOverflow)) { + // Find its corresponding overflow section. + for (auto &OvrfloSec : OverflowSections) { + if (OvrfloSec.RelocationCount == static_cast(Sec->Index)) { + RelocationSizeInSec = + OvrfloSec.Address * XCOFF::RelocationSerializationSize32; + + // This field must have the same values as in the corresponding + // primary section header. + OvrfloSec.FileOffsetToRelocations = Sec->FileOffsetToRelocations; + } + } + assert(RelocationSizeInSec && "Overflow section header doesn't exist."); + } else { + RelocationSizeInSec = Sec->RelocationCount * + (is64Bit() ? XCOFF::RelocationSerializationSize64 + : XCOFF::RelocationSerializationSize32); + } + + RawPointer += RelocationSizeInSec; + if (RawPointer > MaxRawDataSize) + report_fatal_error("Relocation data overflowed this object file."); +} + void XCOFFObjectWriter::finalizeSectionInfo() { for (auto *Section : Sections) { if (Section->Index == SectionEntry::UninitializedIndex) // Nothing to record for this Section. continue; + uint64_t RelCount = 0; for (const auto *Group : Section->Groups) { if (Group->empty()) continue; - for (auto &Csect : *Group) { - const size_t CsectRelocCount = Csect.Relocations.size(); - // 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"); - - Section->RelocationCount += CsectRelocCount; - } + for (auto &Csect : *Group) + RelCount += Csect.Relocations.size(); } + finalizeRelocationInfo(Section, RelCount); } for (auto &DwarfSection : DwarfSections) - DwarfSection.RelocationCount = DwarfSection.DwarfSect->Relocations.size(); - - // Calculate the file offset to the relocation entries. - uint64_t RawPointer = RelocationEntryOffset; - auto calcOffsetToRelocations = [&](SectionEntry *Sec, bool IsDwarf) { - if (!IsDwarf && Sec->Index == SectionEntry::UninitializedIndex) - return false; - - if (!Sec->RelocationCount) - return false; - - Sec->FileOffsetToRelocations = RawPointer; - const uint64_t RelocationSizeInSec = - Sec->RelocationCount * (is64Bit() - ? XCOFF::RelocationSerializationSize64 - : XCOFF::RelocationSerializationSize32); - RawPointer += RelocationSizeInSec; + finalizeRelocationInfo(&DwarfSection, + DwarfSection.DwarfSect->Relocations.size()); + + // Calculate the RawPointer value for all headers. + uint64_t RawPointer = + (is64Bit() ? (XCOFF::FileHeaderSize64 + + SectionCount * XCOFF::SectionHeaderSize64) + : (XCOFF::FileHeaderSize32 + + SectionCount * XCOFF::SectionHeaderSize32)) + + auxiliaryHeaderSize(); + + // Calculate the file offset to the section data. + uint64_t CurrAddress = 0; + for (auto *Sec : Sections) { + if (Sec->Index == SectionEntry::UninitializedIndex || Sec->IsVirtual) + continue; + + Sec->FileOffsetToData = RawPointer; + RawPointer += Sec->Size; if (RawPointer > MaxRawDataSize) - report_fatal_error("Relocation data overflowed this object file."); + report_fatal_error("Section raw data overflowed this object file."); - return true; - }; + CurrAddress = Sec->Address + Sec->Size; + } - for (auto *Sec : Sections) - calcOffsetToRelocations(Sec, /* IsDwarf */ false); + // 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 padding here and to use this + // padding in FileOffsetToData calculation. + if (!DwarfSections.empty()) { + RawPointer += + alignTo(CurrAddress, + (*DwarfSections.begin()).DwarfSect->MCSec->getAlign()) - + CurrAddress; + for (auto &DwarfSection : DwarfSections) { + DwarfSection.FileOffsetToData = RawPointer; + RawPointer += DwarfSection.MemorySize; + if (RawPointer > MaxRawDataSize) + report_fatal_error("Section raw data overflowed this object file."); + } + } + + if (hasExceptionSection()) { + ExceptionSection.FileOffsetToData = RawPointer; + RawPointer += ExceptionSection.Size; + + assert(RawPointer <= MaxRawDataSize && + "Section raw data overflowed this object file."); + } + + for (auto *Sec : Sections) { + if (Sec->Index != SectionEntry::UninitializedIndex) + calcOffsetToRelocations(Sec, RawPointer); + } for (auto &DwarfSec : DwarfSections) - calcOffsetToRelocations(&DwarfSec, /* IsDwarf */ true); + calcOffsetToRelocations(&DwarfSec, RawPointer); // TODO Error check that the number of symbol table entries fits in 32-bits // signed ... @@ -1156,7 +1253,6 @@ // 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 = @@ -1234,19 +1330,8 @@ 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->getAlign()) - - Address; - + // Start to generate DWARF sections. DwarfSectionEntry *LastDwarfSection = nullptr; - for (auto &DwarfSection : DwarfSections) { assert((SectionIndex <= MaxSectionIndex) && "Section index overflow!"); @@ -1296,49 +1381,8 @@ Address += ExceptionSection.Size; Address = alignTo(Address, DefaultSectionAlign); } - SymbolTableEntryCount = SymbolTableIndex; - // Calculate the RawPointer value for each section. - 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 > MaxRawDataSize) - report_fatal_error("Section raw data overflowed this object file."); - } - - // 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; - - RawPointer += DwarfSection.MemorySize; - - assert(RawPointer <= MaxRawDataSize && - "Section raw data overflowed this object file."); - } - - if (hasExceptionSection()) { - ExceptionSection.FileOffsetToData = RawPointer; - RawPointer += ExceptionSection.Size; - - assert(RawPointer <= MaxRawDataSize && - "Section raw data overflowed this object file."); - } - - RelocationEntryOffset = RawPointer; + SymbolTableEntryCount = SymbolTableIndex; } void XCOFFObjectWriter::writeSectionForControlSectionEntry( diff --git a/llvm/test/CodeGen/PowerPC/aix-xcoff-huge-relocs.ll b/llvm/test/CodeGen/PowerPC/aix-xcoff-huge-relocs.ll --- a/llvm/test/CodeGen/PowerPC/aix-xcoff-huge-relocs.ll +++ b/llvm/test/CodeGen/PowerPC/aix-xcoff-huge-relocs.ll @@ -3,14 +3,11 @@ ;; This test generates 65535 relocation entries in a single section, ;; which would trigger an overflow section to be generated in 32-bit mode. -;; Since overflow section is not supported yet, we will emit an error instead of -;; generating an invalid binary for now. ; RUN: grep -v RUN: %s | \ -; RUN: sed >%t.overflow.ll 's/SIZE/65535/;s/MACRO/#/;s/#/################/g;s/#/################/g;s/#/################/g;s/#/################/g;s/#/#_/g;s/_#_\([^#]\)/\1/;s/_/, /g;s/#/ptr @c/g;' -; RUN: not --crash llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff \ -; RUN: -mcpu=pwr4 -mattr=-altivec -filetype=obj -o %t.o %t.overflow.ll 2>&1 | \ -; RUN: FileCheck --check-prefix=OVERFLOW %s -; OVERFLOW: LLVM ERROR: relocation entries overflowed; overflow section is not implemented yet +; RUN: sed > %t.overflow.ll 's/SIZE/65535/;s/MACRO/#/;s/#/################/g;s/#/################/g;s/#/################/g;s/#/################/g;s/#/#_/g;s/_#_\([^#]\)/\1/;s/_/, /g;s/#/ptr @c/g;' +; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff \ +; RUN: -mcpu=pwr4 -mattr=-altivec -filetype=obj -o %t.overflow.o %t.overflow.ll +; RUN: llvm-readobj --section-headers %t.overflow.o | FileCheck --check-prefix=OVERFLOW %s ;; This test generates 65534 relocation entries, an overflow section should ;; not be generated. @@ -28,8 +25,33 @@ @c = external global i8, align 1 @arr = global [SIZE x ptr] [MACRO], align 8 -; XCOFF32-NOT: Name: .ovrflo -; XCOFF32-NOT: Type: STYP_OVRFLO +; OVERFLOW: Section { +; OVERFLOW-NEXT: Index: 2 +; OVERFLOW-NEXT: Name: .data +; OVERFLOW-NEXT: PhysicalAddress: 0x0 +; OVERFLOW-NEXT: VirtualAddress: 0x0 +; OVERFLOW-NEXT: Size: 0x3FFFC +; OVERFLOW-NEXT: RawDataOffset: 0x8C +; OVERFLOW-NEXT: RelocationPointer: 0x40088 +; OVERFLOW-NEXT: LineNumberPointer: 0x0 +; OVERFLOW-NEXT: NumberOfRelocations: 65535 +; OVERFLOW-NEXT: NumberOfLineNumbers: 65535 +; OVERFLOW-NEXT: Type: STYP_DATA (0x40) +; OVERFLOW-NEXT: } +; OVERFLOW-NEXT: Section { +; OVERFLOW-NEXT: Index: 3 +; OVERFLOW-NEXT: Name: .ovrflo +; OVERFLOW-NEXT: NumberOfRelocations: 65535 +; OVERFLOW-NEXT: NumberOfLineNumbers: 0 +; OVERFLOW-NEXT: Size: 0x0 +; OVERFLOW-NEXT: RawDataOffset: 0x0 +; OVERFLOW-NEXT: RelocationPointer: 0x40088 +; OVERFLOW-NEXT: LineNumberPointer: 0x0 +; OVERFLOW-NEXT: IndexOfSectionOverflowed: 2 +; OVERFLOW-NEXT: IndexOfSectionOverflowed: 2 +; OVERFLOW-NEXT: Type: STYP_OVRFLO (0x8000) +; OVERFLOW-NEXT: } + ; XCOFF32: Section { ; XCOFF32: Name: .data ; XCOFF32-NEXT: PhysicalAddress: 0x0 @@ -42,8 +64,6 @@ ; XCOFF32-NEXT: NumberOfLineNumbers: 0 ; XCOFF32-NEXT: Type: STYP_DATA (0x40) ; XCOFF32-NEXT: } -; XCOFF32-NOT: Name: .ovrflo -; XCOFF32-NOT: Type: STYP_OVRFLO ; XCOFF64: Section { ; XCOFF64: Name: .data