llvm-mc/Mach-O: Add section padding where needed (to align the next section).
authorDaniel Dunbar <daniel@zuster.org>
Wed, 26 Aug 2009 04:13:32 +0000 (04:13 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Wed, 26 Aug 2009 04:13:32 +0000 (04:13 +0000)
Also, simplify some of Mach-O writer code which can now use section addresses.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@80067 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/MC/MCAssembler.h
lib/MC/MCAssembler.cpp
test/MC/MachO/section-align-1.s [new file with mode: 0644]
test/MC/MachO/section-align-2.s [new file with mode: 0644]

index ce9dca1ae12593bf4289209325759f3798e6a27a..0da729b3eebb5150803866dd8760556f603cae51 100644 (file)
@@ -82,7 +82,7 @@ public:
 
   uint64_t getAddress() const;
 
-  unsigned getFileSize() const { 
+  uint64_t getFileSize() const { 
     assert(FileSize != ~UINT64_C(0) && "File size not set!");
     return FileSize;
   }
@@ -267,6 +267,9 @@ private:
   /// initialized.
   uint64_t Address;
 
+  /// Size - The content size of this section. This is ~0 until initialized.
+  uint64_t Size;
+
   /// FileSize - The size of this section in the object file. This is ~0 until
   /// initialized.
   uint64_t FileSize;
@@ -305,13 +308,19 @@ public:
   //
   // FIXME: This could all be kept private to the assembler implementation.
 
-  unsigned getAddress() const { 
+  uint64_t getAddress() const { 
     assert(Address != ~UINT64_C(0) && "Address not set!");
     return Address;
   }
   void setAddress(uint64_t Value) { Address = Value; }
 
-  unsigned getFileSize() const { 
+  uint64_t getSize() const { 
+    assert(Size != ~UINT64_C(0) && "File size not set!");
+    return Size;
+  }
+  void setSize(uint64_t Value) { Size = Value; }
+
+  uint64_t getFileSize() const { 
     assert(FileSize != ~UINT64_C(0) && "File size not set!");
     return FileSize;
   }
@@ -414,7 +423,11 @@ private:
   /// LayoutSection - Assign offsets and sizes to the fragments in the section
   /// \arg SD, and update the section size. The section file offset should
   /// already have been computed.
-  void LayoutSection(MCSectionData &SD);
+  ///
+  /// \param NextAlign - The alignment for the section end address, which may
+  /// add padding bytes to the section (these are included in the section "file"
+  /// size, but not its regular size).
+  void LayoutSection(MCSectionData &SD, unsigned NextAlign);
 
 public:
   /// Construct a new assembler instance.
index 13c193275cb8aaa80df59ce5931996724cf57107..26f6d5c9c7d23a9d68bb891f30ea262eb8561ed0 100644 (file)
@@ -217,7 +217,7 @@ public:
     WriteString(Section.getSectionName(), 16);
     WriteString(Section.getSegmentName(), 16);
     Write32(SD.getAddress()); // address
-    Write32(SD.getFileSize()); // size
+    Write32(SD.getSize()); // size
     Write32(FileOffset);
 
     assert(isPowerOf2_32(SD.getAlignment()) && "Invalid alignment!");
@@ -507,11 +507,6 @@ public:
     if (NumSymbols)
       ComputeSymbolTable(Asm, StringTable, LocalSymbolData, ExternalSymbolData,
                          UndefinedSymbolData);
-
-    // Compute the file offsets for all the sections in advance, so that we can
-    // write things out in order.
-    SmallVector<uint64_t, 16> SectionFileOffsets;
-    SectionFileOffsets.resize(NumSections);
   
     // The section data starts after the header, the segment load command (and
     // section headers) and the symbol table.
@@ -525,27 +520,22 @@ public:
       LoadCommandsSize += SymtabLoadCommandSize + DysymtabLoadCommandSize;
     }
 
-    uint64_t FileOffset = Header32Size + LoadCommandsSize;
-    uint64_t SectionDataStartOffset = FileOffset;
+    uint64_t SectionDataStart = Header32Size + LoadCommandsSize;
+    uint64_t SectionDataEnd = SectionDataStart;
     uint64_t SectionDataSize = 0;
-    unsigned Index = 0;
-    for (MCAssembler::iterator it = Asm.begin(),
-           ie = Asm.end(); it != ie; ++it, ++Index) {
-      SectionFileOffsets[Index] = FileOffset;
-      FileOffset += it->getFileSize();
-      SectionDataSize += it->getFileSize();
+    if (!Asm.getSectionList().empty()) {
+      MCSectionData &SD = Asm.getSectionList().back();
+      SectionDataSize = SD.getAddress() + SD.getSize();
+      SectionDataEnd = SectionDataStart + SD.getAddress() + SD.getFileSize();
     }
 
     // Write the prolog, starting with the header and load command...
     WriteHeader32(NumLoadCommands, LoadCommandsSize);
-    WriteSegmentLoadCommand32(NumSections, SectionDataStartOffset,
-                              SectionDataSize);
+    WriteSegmentLoadCommand32(NumSections, SectionDataStart, SectionDataSize);
   
     // ... and then the section headers.
-    Index = 0;
-    for (MCAssembler::iterator it = Asm.begin(),
-           ie = Asm.end(); it != ie; ++it, ++Index)
-      WriteSection32(*it, SectionFileOffsets[Index]);
+    for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it)
+      WriteSection32(*it, SectionDataStart + it->getAddress());
 
     // Write the symbol table load command, if used.
     if (NumSymbols) {
@@ -563,11 +553,10 @@ public:
 
       // If used, the indirect symbols are written after the section data.
       if (NumIndirectSymbols)
-        IndirectSymbolOffset = SectionDataStartOffset + SectionDataSize;
+        IndirectSymbolOffset = SectionDataEnd;
 
       // The symbol table is written after the indirect symbol data.
-      uint64_t SymbolTableOffset =
-        SectionDataStartOffset + SectionDataSize + IndirectSymbolSize;
+      uint64_t SymbolTableOffset = SectionDataEnd + IndirectSymbolSize;
 
       // The string table is written after symbol table.
       uint64_t StringTableOffset =
@@ -675,6 +664,7 @@ MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A)
   : Section(_Section),
     Alignment(1),
     Address(~UINT64_C(0)),
+    Size(~UINT64_C(0)),
     FileSize(~UINT64_C(0))
 {
   if (A)
@@ -701,26 +691,24 @@ MCAssembler::MCAssembler(raw_ostream &_OS) : OS(_OS) {}
 MCAssembler::~MCAssembler() {
 }
 
-void MCAssembler::LayoutSection(MCSectionData &SD) {
-  uint64_t Offset = 0;
+void MCAssembler::LayoutSection(MCSectionData &SD, unsigned NextAlign) {
+  uint64_t Address = SD.getAddress();
 
   for (MCSectionData::iterator it = SD.begin(), ie = SD.end(); it != ie; ++it) {
     MCFragment &F = *it;
 
-    F.setOffset(Offset);
+    F.setOffset(Address - SD.getAddress());
 
     // Evaluate fragment size.
     switch (F.getKind()) {
     case MCFragment::FT_Align: {
       MCAlignFragment &AF = cast<MCAlignFragment>(F);
       
-      uint64_t AlignedOffset = RoundUpToAlignment(Offset, AF.getAlignment());
-      uint64_t PaddingBytes = AlignedOffset - Offset;
-
-      if (PaddingBytes > AF.getMaxBytesToEmit())
+      uint64_t Size = RoundUpToAlignment(Address, AF.getAlignment()) - Address;
+      if (Size > AF.getMaxBytesToEmit())
         AF.setFileSize(0);
       else
-        AF.setFileSize(PaddingBytes);
+        AF.setFileSize(Size);
       break;
     }
 
@@ -735,22 +723,24 @@ void MCAssembler::LayoutSection(MCSectionData &SD) {
       if (!OF.getOffset().isAbsolute())
         llvm_unreachable("FIXME: Not yet implemented!");
       uint64_t OrgOffset = OF.getOffset().getConstant();
+      uint64_t Offset = Address - SD.getAddress();
 
       // FIXME: We need a way to communicate this error.
       if (OrgOffset < Offset)
         llvm_report_error("invalid .org offset '" + Twine(OrgOffset) + 
-                          "' (section offset '" + Twine(Offset) + "'");
+                          "' (at offset '" + Twine(Offset) + "'");
         
       F.setFileSize(OrgOffset - Offset);
       break;
     }      
     }
 
-    Offset += F.getFileSize();
+    Address += F.getFileSize();
   }
 
-  // FIXME: Pad section?
-  SD.setFileSize(Offset);
+  // Set the section sizes.
+  SD.setSize(Address - SD.getAddress());
+  SD.setFileSize(RoundUpToAlignment(Address, NextAlign) - SD.getAddress());
 }
 
 /// WriteFileData - Write the \arg F data to the output file.
@@ -836,16 +826,32 @@ static void WriteFileData(raw_ostream &OS, const MCSectionData &SD,
          ie = SD.end(); it != ie; ++it)
     WriteFileData(OS, *it, MOW);
 
+  // Add section padding.
+  assert(SD.getFileSize() >= SD.getSize() && "Invalid section sizes!");
+  MOW.WriteZeros(SD.getFileSize() - SD.getSize());
+
   assert(OS.tell() - Start == SD.getFileSize());
 }
 
 void MCAssembler::Finish() {
   // Layout the sections and fragments.
   uint64_t Address = 0;
-  for (iterator it = begin(), ie = end(); it != ie; ++it) {
-    it->setAddress(Address);
-    LayoutSection(*it);
-    Address += it->getFileSize();
+  for (iterator it = begin(), ie = end(); it != ie;) {
+    MCSectionData &SD = *it;
+
+    // Select the amount of padding alignment we need, based on either the next
+    // sections alignment or the default alignment.
+    //
+    // FIXME: This should probably match the native word size.
+    unsigned NextAlign = 4;
+    ++it;
+    if (it != ie)
+      NextAlign = it->getAlignment();
+
+    // Layout the section fragments and its size.
+    SD.setAddress(Address);
+    LayoutSection(SD, NextAlign);
+    Address += SD.getFileSize();
   }
 
   // Write the object file.
diff --git a/test/MC/MachO/section-align-1.s b/test/MC/MachO/section-align-1.s
new file mode 100644 (file)
index 0000000..6a5e247
--- /dev/null
@@ -0,0 +1,87 @@
+// RUN: llvm-mc -triple i386-apple-darwin9 %s -filetype=obj -o - | macho-dump | FileCheck %s
+
+name:
+        .byte 0
+
+        // Check that symbol table is aligned to 4 bytes.
+        
+        
+// CHECK: ('cputype', 7)
+// CHECK: ('cpusubtype', 3)
+// CHECK: ('filetype', 1)
+// CHECK: ('num_load_commands', 1)
+// CHECK: ('load_commands_size', 228)
+// CHECK: ('flag', 0)
+// CHECK: ('load_commands', [
+// CHECK:   # Load Command 0
+// CHECK:  (('command', 1)
+// CHECK:   ('size', 124)
+// CHECK:   ('segment_name', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+// CHECK:   ('vm_addr', 0)
+// CHECK:   ('vm_size', 1)
+// CHECK:   ('file_offset', 256)
+// CHECK:   ('file_size', 1)
+// CHECK:   ('maxprot', 7)
+// CHECK:   ('initprot', 7)
+// CHECK:   ('num_sections', 1)
+// CHECK:   ('flags', 0)
+// CHECK:   ('sections', [
+// CHECK:     # Section 0
+// CHECK:    (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+// CHECK:     ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+// CHECK:     ('address', 0)
+// CHECK:     ('size', 1)
+// CHECK:     ('offset', 256)
+// CHECK:     ('alignment', 0)
+// CHECK:     ('reloc_offset', 0)
+// CHECK:     ('num_reloc', 0)
+// CHECK:     ('flags', 0x80000000)
+// CHECK:     ('reserved1', 0)
+// CHECK:     ('reserved2', 0)
+// CHECK:    ),
+// CHECK:   ])
+// CHECK:  ),
+// CHECK:   # Load Command 1
+// CHECK:  (('command', 2)
+// CHECK:   ('size', 24)
+// CHECK:   ('symoff', 260)
+// CHECK:   ('nsyms', 1)
+// CHECK:   ('stroff', 272)
+// CHECK:   ('strsize', 8)
+// CHECK:   ('_string_data', '\x00name\x00\x00\x00')
+// CHECK:   ('_symbols', [
+// CHECK:     # Symbol 0
+// CHECK:    (('n_strx', 1)
+// CHECK:     ('n_type', 0xe)
+// CHECK:     ('n_sect', 1)
+// CHECK:     ('n_desc', 0)
+// CHECK:     ('n_value', 0)
+// CHECK:     ('_string', 'name')
+// CHECK:    ),
+// CHECK:   ])
+// CHECK:  ),
+// CHECK:   # Load Command 2
+// CHECK:  (('command', 11)
+// CHECK:   ('size', 80)
+// CHECK:   ('ilocalsym', 0)
+// CHECK:   ('nlocalsym', 1)
+// CHECK:   ('iextdefsym', 1)
+// CHECK:   ('nextdefsym', 0)
+// CHECK:   ('iundefsym', 1)
+// CHECK:   ('nundefsym', 0)
+// CHECK:   ('tocoff', 0)
+// CHECK:   ('ntoc', 0)
+// CHECK:   ('modtaboff', 0)
+// CHECK:   ('nmodtab', 0)
+// CHECK:   ('extrefsymoff', 0)
+// CHECK:   ('nextrefsyms', 0)
+// CHECK:   ('indirectsymoff', 0)
+// CHECK:   ('nindirectsyms', 0)
+// CHECK:   ('extreloff', 0)
+// CHECK:   ('nextrel', 0)
+// CHECK:   ('locreloff', 0)
+// CHECK:   ('nlocrel', 0)
+// CHECK:   ('_indirect_symbols', [
+// CHECK:   ])
+// CHECK:  ),
+// CHECK: ])
diff --git a/test/MC/MachO/section-align-2.s b/test/MC/MachO/section-align-2.s
new file mode 100644 (file)
index 0000000..e070473
--- /dev/null
@@ -0,0 +1,137 @@
+// RUN: llvm-mc -triple i386-apple-darwin9 %s -filetype=obj -o - | macho-dump | FileCheck %s
+
+        .byte 0
+
+        // There should be 3 padding bytes here.
+        
+        .data
+        .align 2
+foo:
+        .org 8
+bar:
+        .byte 0
+
+        .const
+baz:
+        
+// CHECK: ('cputype', 7)
+// CHECK: ('cpusubtype', 3)
+// CHECK: ('filetype', 1)
+// CHECK: ('num_load_commands', 1)
+// CHECK: ('load_commands_size', 364)
+// CHECK: ('flag', 0)
+// CHECK: ('load_commands', [
+// CHECK:   # Load Command 0
+// CHECK:  (('command', 1)
+// CHECK:   ('size', 260)
+// CHECK:   ('segment_name', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+// CHECK:   ('vm_addr', 0)
+// CHECK:   ('vm_size', 13)
+// CHECK:   ('file_offset', 392)
+// CHECK:   ('file_size', 13)
+// CHECK:   ('maxprot', 7)
+// CHECK:   ('initprot', 7)
+// CHECK:   ('num_sections', 3)
+// CHECK:   ('flags', 0)
+// CHECK:   ('sections', [
+// CHECK:     # Section 0
+// CHECK:    (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+// CHECK:     ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+// CHECK:     ('address', 0)
+// CHECK:     ('size', 1)
+// CHECK:     ('offset', 392)
+// CHECK:     ('alignment', 0)
+// CHECK:     ('reloc_offset', 0)
+// CHECK:     ('num_reloc', 0)
+// CHECK:     ('flags', 0x80000000)
+// CHECK:     ('reserved1', 0)
+// CHECK:     ('reserved2', 0)
+// CHECK:    ),
+// CHECK:     # Section 1
+// CHECK:    (('section_name', '__data\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+// CHECK:     ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+// CHECK:     ('address', 4)
+// CHECK:     ('size', 9)
+// CHECK:     ('offset', 396)
+// CHECK:     ('alignment', 2)
+// CHECK:     ('reloc_offset', 0)
+// CHECK:     ('num_reloc', 0)
+// CHECK:     ('flags', 0x0)
+// CHECK:     ('reserved1', 0)
+// CHECK:     ('reserved2', 0)
+// CHECK:    ),
+// CHECK:     # Section 2
+// CHECK:    (('section_name', '__const\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+// CHECK:     ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+// CHECK:     ('address', 13)
+// CHECK:     ('size', 0)
+// CHECK:     ('offset', 405)
+// CHECK:     ('alignment', 0)
+// CHECK:     ('reloc_offset', 0)
+// CHECK:     ('num_reloc', 0)
+// CHECK:     ('flags', 0x0)
+// CHECK:     ('reserved1', 0)
+// CHECK:     ('reserved2', 0)
+// CHECK:    ),
+// CHECK:   ])
+// CHECK:  ),
+// CHECK:   # Load Command 1
+// CHECK:  (('command', 2)
+// CHECK:   ('size', 24)
+// CHECK:   ('symoff', 408)
+// CHECK:   ('nsyms', 3)
+// CHECK:   ('stroff', 444)
+// CHECK:   ('strsize', 16)
+// CHECK:   ('_string_data', '\x00foo\x00bar\x00baz\x00\x00\x00\x00')
+// CHECK:   ('_symbols', [
+// CHECK:     # Symbol 0
+// CHECK:    (('n_strx', 1)
+// CHECK:     ('n_type', 0xe)
+// CHECK:     ('n_sect', 2)
+// CHECK:     ('n_desc', 0)
+// CHECK:     ('n_value', 4)
+// CHECK:     ('_string', 'foo')
+// CHECK:    ),
+// CHECK:     # Symbol 1
+// CHECK:    (('n_strx', 5)
+// CHECK:     ('n_type', 0xe)
+// CHECK:     ('n_sect', 2)
+// CHECK:     ('n_desc', 0)
+// CHECK:     ('n_value', 12)
+// CHECK:     ('_string', 'bar')
+// CHECK:    ),
+// CHECK:     # Symbol 2
+// CHECK:    (('n_strx', 9)
+// CHECK:     ('n_type', 0xe)
+// CHECK:     ('n_sect', 3)
+// CHECK:     ('n_desc', 0)
+// CHECK:     ('n_value', 13)
+// CHECK:     ('_string', 'baz')
+// CHECK:    ),
+// CHECK:   ])
+// CHECK:  ),
+// CHECK:   # Load Command 2
+// CHECK:  (('command', 11)
+// CHECK:   ('size', 80)
+// CHECK:   ('ilocalsym', 0)
+// CHECK:   ('nlocalsym', 3)
+// CHECK:   ('iextdefsym', 3)
+// CHECK:   ('nextdefsym', 0)
+// CHECK:   ('iundefsym', 3)
+// CHECK:   ('nundefsym', 0)
+// CHECK:   ('tocoff', 0)
+// CHECK:   ('ntoc', 0)
+// CHECK:   ('modtaboff', 0)
+// CHECK:   ('nmodtab', 0)
+// CHECK:   ('extrefsymoff', 0)
+// CHECK:   ('nextrefsyms', 0)
+// CHECK:   ('indirectsymoff', 0)
+// CHECK:   ('nindirectsyms', 0)
+// CHECK:   ('extreloff', 0)
+// CHECK:   ('nextrel', 0)
+// CHECK:   ('locreloff', 0)
+// CHECK:   ('nlocrel', 0)
+// CHECK:   ('_indirect_symbols', [
+// CHECK:   ])
+// CHECK:  ),
+// CHECK: ])