[yaml2obj] Enable support for parsing 64-bit XCOFF.
authorEsme-Yi <esme.yi@ibm.com>
Fri, 30 Jul 2021 02:06:04 +0000 (02:06 +0000)
committerEsme-Yi <esme.yi@ibm.com>
Fri, 30 Jul 2021 02:06:04 +0000 (02:06 +0000)
Summary: Add support for yaml2obj to parse 64-bit XCOFF.

Reviewed By: shchenz

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

llvm/include/llvm/BinaryFormat/XCOFF.h
llvm/lib/ObjectYAML/XCOFFEmitter.cpp
llvm/test/tools/yaml2obj/XCOFF/basic-doc64.yaml [new file with mode: 0644]

index 8a42d26..6705cdd 100644 (file)
@@ -28,9 +28,12 @@ namespace XCOFF {
 constexpr size_t FileNamePadSize = 6;
 constexpr size_t NameSize = 8;
 constexpr size_t FileHeaderSize32 = 20;
+constexpr size_t FileHeaderSize64 = 24;
 constexpr size_t SectionHeaderSize32 = 40;
+constexpr size_t SectionHeaderSize64 = 72;
 constexpr size_t SymbolTableEntrySize = 18;
 constexpr size_t RelocationSerializationSize32 = 10;
+constexpr size_t RelocationSerializationSize64 = 14;
 constexpr uint16_t RelocOverflow = 65535;
 constexpr uint8_t AllocRegNo = 31;
 
index 14fea54..8b132eb 100644 (file)
@@ -75,7 +75,8 @@ static void writeName(StringRef StrName, support::endian::Writer W) {
 }
 
 bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) {
-  return SymbolName.size() > XCOFF::NameSize;
+  // For XCOFF64: The symbol name is always in the string table.
+  return (SymbolName.size() > XCOFF::NameSize) || Is64Bit;
 }
 
 bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) {
@@ -83,8 +84,9 @@ bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) {
     if (!InitSections[I].Relocations.empty()) {
       InitSections[I].NumberOfRelocations = InitSections[I].Relocations.size();
       InitSections[I].FileOffsetToRelocations = CurrentOffset;
-      CurrentOffset += InitSections[I].NumberOfRelocations *
-                       XCOFF::RelocationSerializationSize32;
+      uint64_t RelSize = Is64Bit ? XCOFF::RelocationSerializationSize64
+                                 : XCOFF::RelocationSerializationSize32;
+      CurrentOffset += InitSections[I].NumberOfRelocations * RelSize;
       if (CurrentOffset > MaxRawDataSize) {
         ErrHandler("maximum object size of" + Twine(MaxRawDataSize) +
                    "exceeded when writing relocation data");
@@ -170,9 +172,12 @@ bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset) {
 
 bool XCOFFWriter::assignAddressesAndIndices() {
   Strings.clear();
-  uint64_t CurrentOffset =
-      XCOFF::FileHeaderSize32 /* TODO: + auxiliaryHeaderSize() */ +
-      InitSections.size() * XCOFF::SectionHeaderSize32;
+  uint64_t FileHdrSize =
+      Is64Bit ? XCOFF::FileHeaderSize64 : XCOFF::FileHeaderSize32;
+  uint64_t SecHdrSize =
+      Is64Bit ? XCOFF::SectionHeaderSize64 : XCOFF::SectionHeaderSize32;
+  uint64_t CurrentOffset = FileHdrSize /* TODO: + auxiliaryHeaderSize() */ +
+                           InitSections.size() * SecHdrSize;
 
   // Calculate section header info.
   if (!initSectionHeader(CurrentOffset))
@@ -186,14 +191,25 @@ void XCOFFWriter::writeFileHeader() {
   W.write<uint16_t>(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections
                                                 : InitFileHdr.NumberOfSections);
   W.write<int32_t>(Obj.Header.TimeStamp);
-  W.write<uint32_t>(Obj.Header.SymbolTableOffset
-                        ? Obj.Header.SymbolTableOffset
-                        : InitFileHdr.SymbolTableOffset);
-  W.write<int32_t>(Obj.Header.NumberOfSymTableEntries
-                       ? Obj.Header.NumberOfSymTableEntries
-                       : InitFileHdr.NumberOfSymTableEntries);
-  W.write<uint16_t>(Obj.Header.AuxHeaderSize);
-  W.write<uint16_t>(Obj.Header.Flags);
+  if (Is64Bit) {
+    W.write<uint64_t>(Obj.Header.SymbolTableOffset
+                          ? Obj.Header.SymbolTableOffset
+                          : InitFileHdr.SymbolTableOffset);
+    W.write<uint16_t>(Obj.Header.AuxHeaderSize);
+    W.write<uint16_t>(Obj.Header.Flags);
+    W.write<int32_t>(Obj.Header.NumberOfSymTableEntries
+                         ? Obj.Header.NumberOfSymTableEntries
+                         : InitFileHdr.NumberOfSymTableEntries);
+  } else {
+    W.write<uint32_t>(Obj.Header.SymbolTableOffset
+                          ? Obj.Header.SymbolTableOffset
+                          : InitFileHdr.SymbolTableOffset);
+    W.write<int32_t>(Obj.Header.NumberOfSymTableEntries
+                         ? Obj.Header.NumberOfSymTableEntries
+                         : InitFileHdr.NumberOfSymTableEntries);
+    W.write<uint16_t>(Obj.Header.AuxHeaderSize);
+    W.write<uint16_t>(Obj.Header.Flags);
+  }
 }
 
 void XCOFFWriter::writeSectionHeader() {
@@ -202,22 +218,40 @@ void XCOFFWriter::writeSectionHeader() {
     XCOFFYAML::Section DerivedSec = InitSections[I];
     writeName(YamlSec.SectionName, W);
     // Virtual address is the same as physical address.
-    uint32_t SectionAddress =
+    uint64_t SectionAddress =
         YamlSec.Address ? YamlSec.Address : DerivedSec.Address;
-    W.write<uint32_t>(SectionAddress); // Physical address
-    W.write<uint32_t>(SectionAddress); // Virtual address
-    W.write<uint32_t>(YamlSec.Size ? YamlSec.Size : DerivedSec.Size);
-    W.write<uint32_t>(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData
-                                               : DerivedSec.FileOffsetToData);
-    W.write<uint32_t>(YamlSec.FileOffsetToRelocations
-                          ? YamlSec.FileOffsetToRelocations
-                          : DerivedSec.FileOffsetToRelocations);
-    W.write<uint32_t>(YamlSec.FileOffsetToLineNumbers);
-    W.write<uint16_t>(YamlSec.NumberOfRelocations
-                          ? YamlSec.NumberOfRelocations
-                          : DerivedSec.NumberOfRelocations);
-    W.write<uint16_t>(YamlSec.NumberOfLineNumbers);
-    W.write<int32_t>(YamlSec.Flags);
+    if (Is64Bit) {
+      W.write<uint64_t>(SectionAddress); // Physical address
+      W.write<uint64_t>(SectionAddress); // Virtual address
+      W.write<uint64_t>(YamlSec.Size ? YamlSec.Size : DerivedSec.Size);
+      W.write<uint64_t>(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData
+                                                 : DerivedSec.FileOffsetToData);
+      W.write<uint64_t>(YamlSec.FileOffsetToRelocations
+                            ? YamlSec.FileOffsetToRelocations
+                            : DerivedSec.FileOffsetToRelocations);
+      W.write<uint64_t>(YamlSec.FileOffsetToLineNumbers);
+      W.write<uint32_t>(YamlSec.NumberOfRelocations
+                            ? YamlSec.NumberOfRelocations
+                            : DerivedSec.NumberOfRelocations);
+      W.write<uint32_t>(YamlSec.NumberOfLineNumbers);
+      W.write<int32_t>(YamlSec.Flags);
+      W.OS.write_zeros(4);
+    } else {
+      W.write<uint32_t>(SectionAddress); // Physical address
+      W.write<uint32_t>(SectionAddress); // Virtual address
+      W.write<uint32_t>(YamlSec.Size ? YamlSec.Size : DerivedSec.Size);
+      W.write<uint32_t>(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData
+                                                 : DerivedSec.FileOffsetToData);
+      W.write<uint32_t>(YamlSec.FileOffsetToRelocations
+                            ? YamlSec.FileOffsetToRelocations
+                            : DerivedSec.FileOffsetToRelocations);
+      W.write<uint32_t>(YamlSec.FileOffsetToLineNumbers);
+      W.write<uint16_t>(YamlSec.NumberOfRelocations
+                            ? YamlSec.NumberOfRelocations
+                            : DerivedSec.NumberOfRelocations);
+      W.write<uint16_t>(YamlSec.NumberOfLineNumbers);
+      W.write<int32_t>(YamlSec.Flags);
+    }
   }
 }
 
@@ -232,8 +266,7 @@ bool XCOFFWriter::writeSectionData() {
         ErrHandler("redundant data was written before section data");
         return false;
       }
-      if (PaddingSize > 0)
-        W.OS.write_zeros(PaddingSize);
+      W.OS.write_zeros(PaddingSize);
       YamlSec.SectionData.writeAsBinary(W.OS);
     }
   }
@@ -250,10 +283,12 @@ bool XCOFFWriter::writeRelocations() {
         ErrHandler("redundant data was written before relocations");
         return false;
       }
-      if (PaddingSize > 0)
-        W.OS.write_zeros(PaddingSize);
+      W.OS.write_zeros(PaddingSize);
       for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) {
-        W.write<uint32_t>(YamlRel.VirtualAddress);
+        if (Is64Bit)
+          W.write<uint64_t>(YamlRel.VirtualAddress);
+        else
+          W.write<uint32_t>(YamlRel.VirtualAddress);
         W.write<uint32_t>(YamlRel.SymbolIndex);
         W.write<uint8_t>(YamlRel.Info);
         W.write<uint8_t>(YamlRel.Type);
@@ -270,18 +305,22 @@ bool XCOFFWriter::writeSymbols() {
     ErrHandler("redundant data was written before symbols");
     return false;
   }
-  if (PaddingSize > 0)
-    W.OS.write_zeros(PaddingSize);
+  W.OS.write_zeros(PaddingSize);
   for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) {
-    if (nameShouldBeInStringTable(YamlSym.SymbolName)) {
-      // For XCOFF32: A value of 0 indicates that the symbol name is in the
-      // string table.
-      W.write<int32_t>(0);
+    if (Is64Bit) {
+      W.write<uint64_t>(YamlSym.Value);
       W.write<uint32_t>(Strings.getOffset(YamlSym.SymbolName));
     } else {
-      writeName(YamlSym.SymbolName, W);
+      if (nameShouldBeInStringTable(YamlSym.SymbolName)) {
+        // For XCOFF32: A value of 0 indicates that the symbol name is in the
+        // string table.
+        W.write<int32_t>(0);
+        W.write<uint32_t>(Strings.getOffset(YamlSym.SymbolName));
+      } else {
+        writeName(YamlSym.SymbolName, W);
+      }
+      W.write<uint32_t>(YamlSym.Value);
     }
-    W.write<uint32_t>(YamlSym.Value);
     W.write<int16_t>(
         YamlSym.SectionName.size() ? SectionIndexMap[YamlSym.SectionName] : 0);
     W.write<uint16_t>(YamlSym.Type);
@@ -295,17 +334,13 @@ bool XCOFFWriter::writeSymbols() {
       // length of each auxiliary entry is the same as a symbol table entry (18
       // bytes). The format and quantity of auxiliary entries depend on the
       // storage class (n_sclass) and type (n_type) of the symbol table entry.
-      W.OS.write_zeros(18);
+      W.OS.write_zeros(XCOFF::SymbolTableEntrySize);
     }
   }
   return true;
 }
 
 bool XCOFFWriter::writeXCOFF() {
-  if (Is64Bit) {
-    ErrHandler("only XCOFF32 is currently supported");
-    return false;
-  }
   if (!assignAddressesAndIndices())
     return false;
   StartOffset = W.OS.tell();
diff --git a/llvm/test/tools/yaml2obj/XCOFF/basic-doc64.yaml b/llvm/test/tools/yaml2obj/XCOFF/basic-doc64.yaml
new file mode 100644 (file)
index 0000000..4933468
--- /dev/null
@@ -0,0 +1,136 @@
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-readobj --headers --symbols %t | \
+# RUN:   FileCheck %s --check-prefix=CHECK64
+
+--- !XCOFF
+FileHeader:
+  MagicNumber:     0x01F7
+Sections:
+  - Name:            .text
+    Flags:           [ STYP_TEXT ]
+  - Name:            .data
+    Flags:           [ STYP_DATA ]
+    SectionData:     "0000000000000FC0"
+  - Name:            .bss
+    Flags:           [ STYP_BSS ]
+    Relocations:
+      - Type:        0x02
+  - Name:            .debug
+    Address:         0x0
+    Size:            0x60
+    Flags:           [ STYP_DEBUG, STYP_DATA ]
+    SectionData:     01110103
+Symbols:
+  - Name:            .file
+    Section:         N_DEBUG
+  - Name:            .undef
+  - Name:            .abs
+    Section:         N_ABS
+  - Name:            .text
+    Value:           0x0
+    Section:         .text
+    Type:            0x0
+    StorageClass:    C_HIDEXT
+
+# CHECK64:      AddressSize: 64bit
+# CHECK64-NEXT: FileHeader {
+# CHECK64-NEXT:   Magic: 0x1F7
+# CHECK64-NEXT:   NumberOfSections: 4
+# CHECK64-NEXT:   TimeStamp: None (0x0)
+# CHECK64-NEXT:   SymbolTableOffset: 0x152
+# CHECK64-NEXT:   SymbolTableEntries: 4
+# CHECK64-NEXT:   OptionalHeaderSize: 0x0
+# CHECK64-NEXT:   Flags: 0x0
+# CHECK64-NEXT: }
+# CHECK64-NEXT: Sections [
+# CHECK64-NEXT:   Section {
+# CHECK64-NEXT:     Index: 1
+# CHECK64-NEXT:     Name: .text
+# CHECK64-NEXT:     PhysicalAddress: 0x0
+# CHECK64-NEXT:     VirtualAddress: 0x0
+# CHECK64-NEXT:     Size: 0x0
+# CHECK64-NEXT:     RawDataOffset: 0x0
+# CHECK64-NEXT:     RelocationPointer: 0x0
+# CHECK64-NEXT:     LineNumberPointer: 0x0
+# CHECK64-NEXT:     NumberOfRelocations: 0
+# CHECK64-NEXT:     NumberOfLineNumbers: 0
+# CHECK64-NEXT:     Type: STYP_TEXT (0x20)
+# CHECK64-NEXT:   }
+# CHECK64-NEXT:   Section {
+# CHECK64-NEXT:     Index: 2
+# CHECK64-NEXT:     Name: .data
+# CHECK64-NEXT:     PhysicalAddress: 0x0
+# CHECK64-NEXT:     VirtualAddress: 0x0
+# CHECK64-NEXT:     Size: 0x8
+# CHECK64-NEXT:     RawDataOffset: 0x138
+# CHECK64-NEXT:     RelocationPointer: 0x0
+# CHECK64-NEXT:     LineNumberPointer: 0x0
+# CHECK64-NEXT:     NumberOfRelocations: 0
+# CHECK64-NEXT:     NumberOfLineNumbers: 0
+# CHECK64-NEXT:     Type: STYP_DATA (0x40)
+# CHECK64-NEXT:   }
+# CHECK64-NEXT:   Section {
+# CHECK64-NEXT:     Index: 3
+# CHECK64-NEXT:     Name: .bss
+# CHECK64-NEXT:     PhysicalAddress: 0x8
+# CHECK64-NEXT:     VirtualAddress: 0x8
+# CHECK64-NEXT:     Size: 0x0
+# CHECK64-NEXT:     RawDataOffset: 0x0
+# CHECK64-NEXT:     RelocationPointer: 0x144
+# CHECK64-NEXT:     LineNumberPointer: 0x0
+# CHECK64-NEXT:     NumberOfRelocations: 1
+# CHECK64-NEXT:     NumberOfLineNumbers: 0
+# CHECK64-NEXT:     Type: STYP_BSS (0x80)
+# CHECK64-NEXT:   }
+# CHECK64-NEXT:   Section {
+# CHECK64-NEXT:     Index: 4
+# CHECK64-NEXT:     Name: .debug
+# CHECK64-NEXT:     PhysicalAddress: 0x0
+# CHECK64-NEXT:     VirtualAddress: 0x0
+# CHECK64-NEXT:     Size: 0x60
+# CHECK64-NEXT:     RawDataOffset: 0x140
+# CHECK64-NEXT:     RelocationPointer: 0x0
+# CHECK64-NEXT:     LineNumberPointer: 0x0
+# CHECK64-NEXT:     NumberOfRelocations: 0
+# CHECK64-NEXT:     NumberOfLineNumbers: 0
+# CHECK64-NEXT:     Type: 0x2040
+# CHECK64-NEXT:   }
+# CHECK64-NEXT: ]
+# CHECK64-NEXT: Symbols [
+# CHECK64-NEXT:   Symbol {
+# CHECK64-NEXT:     Index: 0
+# CHECK64-NEXT:     Name: .file
+# CHECK64-NEXT:     Value: 0x0
+# CHECK64-NEXT:     Section: N_DEBUG
+# CHECK64-NEXT:     Type: 0x0
+# CHECK64-NEXT:     StorageClass: C_NULL (0x0)
+# CHECK64-NEXT:     NumberOfAuxEntries: 0
+# CHECK64-NEXT:   }
+# CHECK64-NEXT:   Symbol {
+# CHECK64-NEXT:     Index: 1
+# CHECK64-NEXT:     Name: .undef
+# CHECK64-NEXT:     Value: 0x0
+# CHECK64-NEXT:     Section: N_UNDEF
+# CHECK64-NEXT:     Type: 0x0
+# CHECK64-NEXT:     StorageClass: C_NULL (0x0)
+# CHECK64-NEXT:     NumberOfAuxEntries: 0
+# CHECK64-NEXT:   }
+# CHECK64-NEXT:   Symbol {
+# CHECK64-NEXT:     Index: 2
+# CHECK64-NEXT:     Name: .abs
+# CHECK64-NEXT:     Value: 0x0
+# CHECK64-NEXT:     Section: N_ABS
+# CHECK64-NEXT:     Type: 0x0
+# CHECK64-NEXT:     StorageClass: C_NULL (0x0)
+# CHECK64-NEXT:     NumberOfAuxEntries: 0
+# CHECK64-NEXT:   }
+# CHECK64-NEXT:   Symbol {
+# CHECK64-NEXT:     Index: 3
+# CHECK64-NEXT:     Name: .text
+# CHECK64-NEXT:     Value (RelocatableAddress): 0x0
+# CHECK64-NEXT:     Section: .text
+# CHECK64-NEXT:     Type: 0x0
+# CHECK64-NEXT:     StorageClass: C_HIDEXT (0x6B)
+# CHECK64-NEXT:     NumberOfAuxEntries: 0
+# CHECK64-NEXT:   }
+# CHECK64-NEXT: ]