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 @@ -204,7 +204,7 @@ uint32_t SymbolTableEntryCount = 0; uint64_t SymbolTableOffset = 0; uint16_t SectionCount = 0; - uint64_t RelocationEntryOffset = 0; + uint64_t EndOfAllHeadersOffset = 0; std::vector> FileNames; bool HasVisibility = false; @@ -250,6 +250,7 @@ {&Text, &Data, &BSS, &TData, &TBSS}}; std::vector DwarfSections; + std::vector OvrfloSections; CsectGroup &getCsectGroup(const MCSectionXCOFF *MCSec); @@ -308,6 +309,7 @@ // *) 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(); size_t auxiliaryHeaderSize() const { @@ -350,12 +352,14 @@ Sec->reset(); for (auto &DwarfSec : DwarfSections) DwarfSec.reset(); + for (auto &OvrfloSec : OvrfloSections) + OvrfloSec.reset(); // Reset states in XCOFFObjectWriter. SymbolTableEntryCount = 0; SymbolTableOffset = 0; SectionCount = 0; - RelocationEntryOffset = 0; + EndOfAllHeadersOffset = 0; Strings.clear(); MCObjectWriter::reset(); @@ -795,9 +799,11 @@ } void XCOFFObjectWriter::writeSectionHeaderTable() { - auto writeSectionHeader = [&](const SectionEntry *Sec, bool IsDwarf) { + auto 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) + if (Sec->Index == SectionEntry::UninitializedIndex && !IsOvrflo) return false; // Write Name. @@ -807,8 +813,11 @@ // 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. + // 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. writeWord(IsDwarf ? 0 : Sec->Address); - writeWord(IsDwarf ? 0 : Sec->Address); + writeWord((IsDwarf || IsOvrflo) ? 0 : Sec->Address); writeWord(Sec->Size); writeWord(Sec->FileOffsetToData); @@ -822,7 +831,9 @@ W.OS.write_zeros(4); } else { W.write(Sec->RelocationCount); - W.write(0); // NumberOfLineNumbers. Not supported yet. + W.write(IsOvrflo + ? Sec->RelocationCount + : 0); // NumberOfLineNumbers. Not supported yet. W.write(Sec->Flags); } @@ -830,9 +841,11 @@ }; for (const auto *CsectSec : Sections) - writeSectionHeader(CsectSec, /* IsDwarf */ false); + writeSectionHeader(CsectSec); + for (const auto &OvrfloSec : OvrfloSections) + writeSectionHeader(&OvrfloSec); for (const auto &DwarfSec : DwarfSections) - writeSectionHeader(&DwarfSec, /* IsDwarf */ true); + writeSectionHeader(&DwarfSec); } void XCOFFObjectWriter::writeRelocation(XCOFFRelocation Reloc, @@ -914,47 +927,113 @@ } void XCOFFObjectWriter::finalizeSectionInfo() { + uint64_t RawPointer = EndOfAllHeadersOffset; + auto countRelocations = [&](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 >= (uint32_t)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; + + // The field value will be 65535 (XCOFF::RelocOverflow). + Sec->RelocationCount = XCOFF::RelocOverflow; + + // This field specifies the number of relocation entries actually + // required. + SecEntry.Address = RelCount; + SecEntry.Index = 3; + + // Add the overflow section header size to RawPointer. + RawPointer += XCOFF::SectionHeaderSize32; + OvrfloSections.push_back(SecEntry); + SectionCount++; + } else { + Sec->RelocationCount = RelCount; + } + }; + 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(); } + countRelocations(Section, RelCount); } for (auto &DwarfSection : DwarfSections) - DwarfSection.RelocationCount = DwarfSection.DwarfSect->Relocations.size(); + countRelocations(&DwarfSection, 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; + // 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("Section raw data overflowed this object file."); + + CurrAddress = Sec->Address + Sec->Size; + } + // 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()) + RawPointer += + alignTo(CurrAddress, + (*DwarfSections.begin()).DwarfSect->MCSec->getAlignment()) - + CurrAddress; + + for (auto &DwarfSection : DwarfSections) { + DwarfSection.FileOffsetToData = RawPointer; + RawPointer += DwarfSection.MemorySize; + if (RawPointer > MaxRawDataSize) + report_fatal_error("Section raw data overflowed this object file."); + } + + // Calculate the file offset to the relocation entries. + auto calcOffsetToRelocations = [&](SectionEntry *Sec) { if (!Sec->RelocationCount) return false; Sec->FileOffsetToRelocations = RawPointer; - const uint64_t RelocationSizeInSec = - Sec->RelocationCount * (is64Bit() - ? XCOFF::RelocationSerializationSize64 - : XCOFF::RelocationSerializationSize32); + uint64_t RelocationSizeInSec = 0; + if (!is64Bit() && Sec->RelocationCount == (uint32_t)XCOFF::RelocOverflow) { + + // Find its corresponding overflow section. + for (auto &OvrfloSec : OvrfloSections) { + if (OvrfloSec.RelocationCount == (uint32_t)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."); @@ -962,11 +1041,13 @@ return true; }; - for (auto *Sec : Sections) - calcOffsetToRelocations(Sec, /* IsDwarf */ false); + for (auto *Sec : Sections) { + if (Sec->Index != SectionEntry::UninitializedIndex) + calcOffsetToRelocations(Sec); + } for (auto &DwarfSec : DwarfSections) - calcOffsetToRelocations(&DwarfSec, /* IsDwarf */ true); + calcOffsetToRelocations(&DwarfSec); // TODO Error check that the number of symbol table entries fits in 32-bits // signed ... @@ -995,7 +1076,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 = @@ -1055,17 +1135,7 @@ 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; - + // Start to generate DWARF sections. DwarfSectionEntry *LastDwarfSection = nullptr; for (auto &DwarfSection : DwarfSections) { @@ -1112,7 +1182,7 @@ SymbolTableEntryCount = SymbolTableIndex; - // Calculate the RawPointer value for each section. + // Calculate the RawPointer value for all headers. uint64_t RawPointer = (is64Bit() ? (XCOFF::FileHeaderSize64 + SectionCount * XCOFF::SectionHeaderSize64) @@ -1120,31 +1190,7 @@ 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."); - } - - RelocationEntryOffset = RawPointer; + EndOfAllHeadersOffset = RawPointer; } 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: 0 +; 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: 65535 +; OVERFLOW-NEXT: Size: 0x0 +; OVERFLOW-NEXT: RawDataOffset: 0x0 +; OVERFLOW-NEXT: RelocationPointer: 0x40088 +; OVERFLOW-NEXT: LineNumberPointer: 0x0 +; OVERFLOW-NEXT: IndexOfSectionOverflowed: 2 +; OVERFLOW-NEXT: IndexOfSectionOverflowed: 0 +; 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