[llvm] ea6dec1 - [XCOFF] support the overflow section (only relocation overflow is handled).

via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 9 23:39:28 PST 2023


Author: esmeyi
Date: 2023-01-10T02:39:02-05:00
New Revision: ea6dec1b3a5671d2b7f41300b5c2b29a77520147

URL: https://github.com/llvm/llvm-project/commit/ea6dec1b3a5671d2b7f41300b5c2b29a77520147
DIFF: https://github.com/llvm/llvm-project/commit/ea6dec1b3a5671d2b7f41300b5c2b29a77520147.diff

LOG: [XCOFF] support the overflow section (only relocation overflow is handled).

Summary: This patch handles relocation field overflows in an XCOFF32 file. (XCOFF64 files may not have overflow section headers.) If a section has more than 65,534 relocation entries or line number entries, both of these fields are set to a value of 65535. In this case, an overflow section header with the s_flags field equal to STYP_OVRFLO is used to contain the relocation and line-number count information. Since line number is not supported, this patch only handles the relocation overflow.

Reviewed By: shchenz

Differential Revision: https://reviews.llvm.org/D137819

Added: 
    

Modified: 
    llvm/lib/MC/XCOFFObjectWriter.cpp
    llvm/test/CodeGen/PowerPC/aix-xcoff-huge-relocs.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp
index 30a9de38df27..980b014e832f 100644
--- a/llvm/lib/MC/XCOFFObjectWriter.cpp
+++ b/llvm/lib/MC/XCOFFObjectWriter.cpp
@@ -107,8 +107,12 @@ using CsectGroups = std::deque<CsectGroup *>;
 // in XCOFF section header table.
 struct SectionEntry {
   char Name[XCOFF::NameSize];
-  // The physical/virtual address of the section. For an object file
-  // these values are equivalent.
+  // The physical/virtual address of the section. For an object file these
+  // values are equivalent, except for in the overflow section header, where
+  // the physical address specifies the number of relocation entries and the
+  // virtual address specifies the number of line number entries.
+  // TODO: Divide Address into PhysicalAddress and VirtualAddress when line
+  // number entries are supported.
   uint64_t Address;
   uint64_t Size;
   uint64_t FileOffsetToData;
@@ -234,7 +238,6 @@ class XCOFFObjectWriter : public MCObjectWriter {
   uint32_t SymbolTableEntryCount = 0;
   uint64_t SymbolTableOffset = 0;
   uint16_t SectionCount = 0;
-  uint64_t RelocationEntryOffset = 0;
   std::vector<std::pair<std::string, size_t>> FileNames;
   bool HasVisibility = false;
 
@@ -280,6 +283,7 @@ class XCOFFObjectWriter : public MCObjectWriter {
       {&Text, &Data, &BSS, &TData, &TBSS}};
 
   std::vector<DwarfSectionEntry> DwarfSections;
+  std::vector<SectionEntry> OverflowSections;
 
   ExceptionSectionEntry ExceptionSection;
 
@@ -309,6 +313,7 @@ class XCOFFObjectWriter : public MCObjectWriter {
                                        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 +353,11 @@ class XCOFFObjectWriter : public MCObjectWriter {
   // *) 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 +408,14 @@ void XCOFFObjectWriter::reset() {
     Sec->reset();
   for (auto &DwarfSec : DwarfSections)
     DwarfSec.reset();
+  for (auto &OverflowSec : OverflowSections)
+    OverflowSec.reset();
   ExceptionSection.reset();
 
   // Reset states in XCOFFObjectWriter.
   SymbolTableEntryCount = 0;
   SymbolTableOffset = 0;
   SectionCount = 0;
-  RelocationEntryOffset = 0;
   Strings.clear();
 
   MCObjectWriter::reset();
@@ -921,47 +931,55 @@ void XCOFFObjectWriter::writeAuxFileHeader() {
   W.write<uint32_t>(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;
+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;
 
-    // Write Name.
-    ArrayRef<char> NameRef(Sec->Name, XCOFF::NameSize);
-    W.write(NameRef);
+  // Write Name.
+  ArrayRef<char> 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);
+  // Write the Physical Address and Virtual Address.
+  // 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.
+  writeWord(Sec->Size);
+  writeWord(Sec->FileOffsetToData);
+  writeWord(Sec->FileOffsetToRelocations);
+  writeWord(0); // FileOffsetToLineNumberInfo. Not supported yet.
 
-    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;
-  };
+  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 {
+    // 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 headers, if either of s_nreloc or s_nlnno are set to
+    // 65535, the other one must also be set to 65535.
+    W.write<uint16_t>(Sec->RelocationCount);
+    W.write<uint16_t>((IsOvrflo || Sec->RelocationCount == XCOFF::RelocOverflow)
+                          ? Sec->RelocationCount
+                          : 0); // NumberOfLineNumbers. Not supported yet.
+    W.write<int32_t>(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 &OverflowSec : OverflowSections)
+    writeSectionHeader(&OverflowSec);
   if (hasExceptionSection())
-    writeSectionHeader(&ExceptionSection, false);
+    writeSectionHeader(&ExceptionSection);
 }
 
 void XCOFFObjectWriter::writeRelocation(XCOFFRelocation Reloc,
@@ -1042,60 +1060,139 @@ void XCOFFObjectWriter::writeSymbolTable(const MCAsmLayout &Layout) {
                                     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<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;
+    SecEntry.Index = ++SectionCount;
+    OverflowSections.push_back(std::move(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<uint32_t>(XCOFF::RelocOverflow)) {
+    // Find its corresponding overflow section.
+    for (auto &OverflowSec : OverflowSections) {
+      if (OverflowSec.RelocationCount == static_cast<uint32_t>(Sec->Index)) {
+        RelocationSizeInSec =
+            OverflowSec.Address * XCOFF::RelocationSerializationSize32;
+
+        // This field must have the same values as in the corresponding
+        // primary section header.
+        OverflowSec.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 ...
@@ -1171,7 +1268,6 @@ void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) {
   // 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 =
@@ -1249,19 +1345,8 @@ 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->getAlign()) -
-        Address;
-
+  // Start to generate DWARF sections.
   DwarfSectionEntry *LastDwarfSection = nullptr;
-
   for (auto &DwarfSection : DwarfSections) {
     assert((SectionIndex <= MaxSectionIndex) && "Section index overflow!");
 
@@ -1311,49 +1396,8 @@ void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) {
     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
index 289c0877fabe..6f430e83d8cc 100644
--- 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


        


More information about the llvm-commits mailing list