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,6 @@ uint32_t SymbolTableEntryCount = 0; uint64_t SymbolTableOffset = 0; uint16_t SectionCount = 0; - uint64_t RelocationEntryOffset = 0; std::vector> FileNames; bool HasVisibility = false; @@ -250,6 +249,7 @@ {&Text, &Data, &BSS, &TData, &TBSS}}; std::vector DwarfSections; + std::vector OvrfloSections; CsectGroup &getCsectGroup(const MCSectionXCOFF *MCSec); @@ -308,6 +308,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 +351,13 @@ 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; Strings.clear(); MCObjectWriter::reset(); @@ -795,7 +797,9 @@ } 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) return false; @@ -805,10 +809,14 @@ W.write(NameRef); // Write the Physical Address and Virtual Address. In an object file these - // are the same. + // are the same, except for 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); - writeWord(IsDwarf ? 0 : Sec->Address); + // Since line number is not supported, we set it to 0 for overflow section. + writeWord((IsDwarf || IsOvrflo) ? 0 : Sec->Address); writeWord(Sec->Size); writeWord(Sec->FileOffsetToData); @@ -821,8 +829,15 @@ 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(0); // NumberOfLineNumbers. Not supported yet. + W.write( + (IsOvrflo || Sec->RelocationCount == XCOFF::RelocOverflow) + ? Sec->RelocationCount + : 0); // NumberOfLineNumbers. Not supported yet. W.write(Sec->Flags); } @@ -830,9 +845,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 +931,120 @@ } void XCOFFObjectWriter::finalizeSectionInfo() { + // Calculate the RawPointer value for all headers. + uint64_t RawPointer = + (is64Bit() ? (XCOFF::FileHeaderSize64 + + SectionCount * XCOFF::SectionHeaderSize64) + : (XCOFF::FileHeaderSize32 + + SectionCount * XCOFF::SectionHeaderSize32)) + + auxiliaryHeaderSize(); + + 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; + + // This field specifies the number of relocation entries actually + // required. + SecEntry.Address = RelCount; + + SectionCount++; + SecEntry.Index = SectionCount; + + // Add the overflow section header size to RawPointer. + RawPointer += XCOFF::SectionHeaderSize32; + OvrfloSections.push_back(SecEntry); + + // The field in the primary section header is always 65535 + // (XCOFF::RelocOverflow). + Sec->RelocationCount = XCOFF::RelocOverflow; + } 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 +1052,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 +1087,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 +1146,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) { @@ -1111,40 +1192,6 @@ } 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."); - } - - RelocationEntryOffset = RawPointer; } void XCOFFObjectWriter::writeSectionForControlSectionEntry( diff --git a/llvm/test/CodeGen/PowerPC/aix-xcoff-funcsect.ll b/llvm/test/CodeGen/PowerPC/aix-xcoff-funcsect.ll --- a/llvm/test/CodeGen/PowerPC/aix-xcoff-funcsect.ll +++ b/llvm/test/CodeGen/PowerPC/aix-xcoff-funcsect.ll @@ -1,95 +1,79 @@ -; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr4 \ -; RUN: -mattr=-altivec -function-sections < %s | \ -; RUN: FileCheck --check-prefix=ASM %s -; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff -mcpu=pwr4 \ -; RUN: -mattr=-altivec -function-sections < %s | \ -; RUN: FileCheck --check-prefix=ASM %s +;; This test takes a very long time +; REQUIRES: expensive_checks -@alias_foo = alias void (...), bitcast (void ()* @foo to void (...)*) +;; This test generates 65535 relocation entries in a single section, +;; which would trigger an overflow section to be generated in 32-bit mode. +; 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: 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 -define void @foo() { -entry: - ret void -} +;; This test generates 65534 relocation entries, an overflow section should +;; not be generated. +; RUN: grep -v RUN: %s | \ +; RUN: sed >%t.ll 's/SIZE/65534/;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.o %t.ll +; RUN: llvm-readobj --section-headers %t.o | FileCheck --check-prefix=XCOFF32 %s -define hidden void @hidden_foo() { -entry: - ret void -} +;; An XCOFF64 file may not contain an overflow section header. +; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff \ +; RUN: -mcpu=pwr4 -mattr=-altivec -filetype=obj -o %t64.o %t.overflow.ll +; RUN: llvm-readobj --section-headers %t64.o | FileCheck --check-prefix=XCOFF64 %s -define void @bar() { -entry: - call void @foo() - call void @static_overalign_foo() - call void bitcast (void (...)* @alias_foo to void ()*)() - call void bitcast (void (...)* @extern_foo to void ()*)() - call void @hidden_foo() - ret void -} +@c = external global i8, align 1 +@arr = global [SIZE x ptr] [MACRO], align 8 -declare void @extern_foo(...) +; 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: } -define internal void @static_overalign_foo() align 64 { -entry: - ret void -} +; XCOFF32: Section { +; XCOFF32: Name: .data +; XCOFF32-NEXT: PhysicalAddress: 0x0 +; XCOFF32-NEXT: VirtualAddress: 0x0 +; XCOFF32-NEXT: Size: 0x3FFF8 +; XCOFF32-NEXT: RawDataOffset: 0x64 +; XCOFF32-NEXT: RelocationPointer: 0x4005C +; XCOFF32-NEXT: LineNumberPointer: 0x0 +; XCOFF32-NEXT: NumberOfRelocations: 65534 +; XCOFF32-NEXT: NumberOfLineNumbers: 0 +; XCOFF32-NEXT: Type: STYP_DATA (0x40) +; XCOFF32-NEXT: } -; ASM: .csect .foo[PR],5 -; ASM-NEXT: .globl foo[DS] # -- Begin function foo -; ASM-NEXT: .globl .foo[PR] -; ASM-NEXT: .align 4 -; ASM-NEXT: .csect foo[DS] -; ASM-NEXT: alias_foo: # @foo -; ASM-NEXT: .vbyte {{[0-9]+}}, .foo[PR] -; ASM-NEXT: .vbyte {{[0-9]+}}, TOC[TC0] -; ASM-NEXT: .vbyte {{[0-9]+}}, 0 -; ASM-NEXT: .csect .foo[PR],5 -; ASM-NEXT: .alias_foo: -; ASM-NEXT: # %bb.0: # %entry -; ASM-NEXT: blr -; ASM: .csect .hidden_foo[PR],5 -; ASM-NEXT: .globl hidden_foo[DS],hidden # -- Begin function hidden_foo -; ASM-NEXT: .globl .hidden_foo[PR],hidden -; ASM-NEXT: .align 4 -; ASM-NEXT: .csect hidden_foo[DS] -; ASM-NEXT: .vbyte {{[0-9]+}}, .hidden_foo[PR] # @hidden_foo -; ASM-NEXT: .vbyte {{[0-9]+}}, TOC[TC0] -; ASM-NEXT: .vbyte {{[0-9]+}}, 0 -; ASM-NEXT: .csect .hidden_foo[PR] -; ASM-NEXT: # %bb.0: # %entry -; ASM-NEXT: blr -; ASM: .csect .bar[PR],5 -; ASM-NEXT: .globl bar[DS] # -- Begin function bar -; ASM-NEXT: .globl .bar[PR] -; ASM-NEXT: .align 4 -; ASM-NEXT: .csect bar[DS] -; ASM-NEXT: .vbyte {{[0-9]+}}, .bar[PR] # @bar -; ASM-NEXT: .vbyte {{[0-9]+}}, TOC[TC0] -; ASM-NEXT: .vbyte {{[0-9]+}}, 0 -; ASM-NEXT: .csect .bar[PR],5 -; ASM-NEXT: # %bb.0: # %entry -; ASM: bl .foo[PR] -; ASM-NEXT: nop -; ASM-NEXT: bl .static_overalign_foo[PR] -; ASM-NEXT: nop -; ASM-NEXT: bl .alias_foo -; ASM-NEXT: nop -; ASM-NEXT: bl .extern_foo -; ASM-NEXT: nop -; ASM-NEXT: bl .hidden_foo[PR] -; ASM-NEXT: nop -; ASM: .csect .static_overalign_foo[PR],6 -; ASM-NEXT: .lglobl static_overalign_foo[DS] # -- Begin function static_overalign_foo -; ASM-NEXT: .lglobl .static_overalign_foo[PR] -; ASM-NEXT: .align 6 -; ASM-NEXT: .csect static_overalign_foo[DS] -; ASM-NEXT: .vbyte {{[0-9]+}}, .static_overalign_foo[PR] # @static_overalign_foo -; ASM-NEXT: .vbyte {{[0-9]+}}, TOC[TC0] -; ASM-NEXT: .vbyte {{[0-9]+}}, 0 -; ASM-NEXT: .csect .static_overalign_foo[PR],6 -; ASM-NEXT: # %bb.0: # %entry -; ASM-NEXT: blr -; ASM: .extern .extern_foo -; ASM-NEXT: .extern extern_foo[DS] -; ASM-NEXT: .globl alias_foo -; ASM-NEXT: .globl .alias_foo +; XCOFF64: Section { +; XCOFF64: Name: .data +; XCOFF64-NEXT: PhysicalAddress: 0x0 +; XCOFF64-NEXT: VirtualAddress: 0x0 +; XCOFF64-NEXT: Size: 0x7FFF8 +; XCOFF64-NEXT: RawDataOffset: 0xA8 +; XCOFF64-NEXT: RelocationPointer: 0x800A0 +; XCOFF64-NEXT: LineNumberPointer: 0x0 +; XCOFF64-NEXT: NumberOfRelocations: 65535 +; XCOFF64-NEXT: NumberOfLineNumbers: 0 +; XCOFF64-NEXT: Type: STYP_DATA (0x40) +; XCOFF64-NEXT: }