llvm-mc: Support .zerofill emission.
 - I'm still trying to figure out the cleanest way to implement this and match the assembler, currently there are some substantial differences.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@80347 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp
index 1375b77..8057fcb 100644
--- a/lib/MC/MCAssembler.cpp
+++ b/lib/MC/MCAssembler.cpp
@@ -28,6 +28,15 @@
 static void WriteFileData(raw_ostream &OS, const MCSectionData &SD,
                           MachObjectWriter &MOW);
 
+/// isVirtualSection - Check if this is a section which does not actually exist
+/// in the object file.
+static bool isVirtualSection(const MCSection &Section) {
+  // FIXME: Lame.
+  const MCSectionMachO &SMO = static_cast<const MCSectionMachO&>(Section);
+  unsigned Type = SMO.getTypeAndAttributes() & MCSectionMachO::SECTION_TYPE;
+  return (Type == MCSectionMachO::S_ZEROFILL);
+}
+
 class MachObjectWriter {
   // See <mach-o/loader.h>.
   enum {
@@ -229,6 +238,12 @@
 
   void WriteSection32(const MCSectionData &SD, uint64_t FileOffset,
                       uint64_t RelocationsStart, unsigned NumRelocations) {
+    // The offset is unused for virtual sections.
+    if (isVirtualSection(SD.getSection())) {
+      assert(SD.getFileSize() == 0 && "Invalid file size!");
+      FileOffset = 0;
+    }
+
     // struct section (68 bytes)
 
     uint64_t Start = OS.tell();
@@ -692,6 +707,9 @@
 
       VMSize = std::max(VMSize, SD.getAddress() + SD.getSize());
 
+      if (isVirtualSection(SD.getSection()))
+        continue;
+
       SectionDataSize = std::max(SectionDataSize,
                                  SD.getAddress() + SD.getSize());
       SectionDataFileSize = std::max(SectionDataFileSize, 
@@ -922,7 +940,7 @@
     case MCFragment::FT_Align: {
       MCAlignFragment &AF = cast<MCAlignFragment>(F);
       
-      uint64_t Size = RoundUpToAlignment(Address, AF.getAlignment()) - Address;
+      uint64_t Size = OffsetToAlignment(Address, AF.getAlignment());
       if (Size > AF.getMaxBytesToEmit())
         AF.setFileSize(0);
       else
@@ -968,6 +986,19 @@
       F.setFileSize(OrgOffset - Offset);
       break;
     }      
+
+    case MCFragment::FT_ZeroFill: {
+      MCZeroFillFragment &ZFF = cast<MCZeroFillFragment>(F);
+
+      // Align the fragment offset; it is safe to adjust the offset freely since
+      // this is only in virtual sections.
+      uint64_t Aligned = RoundUpToAlignment(Address, ZFF.getAlignment());
+      F.setOffset(Aligned - SD.getAddress());
+
+      // FIXME: This is misnamed.
+      F.setFileSize(ZFF.getSize());
+      break;
+    }
     }
 
     Address += F.getFileSize();
@@ -975,7 +1006,10 @@
 
   // Set the section sizes.
   SD.setSize(Address - SD.getAddress());
-  SD.setFileSize(Address - SD.getAddress());
+  if (isVirtualSection(SD.getSection()))
+    SD.setFileSize(0);
+  else
+    SD.setFileSize(Address - SD.getAddress());
 }
 
 /// WriteFileData - Write the \arg F data to the output file.
@@ -1055,6 +1089,11 @@
 
     break;
   }
+
+  case MCFragment::FT_ZeroFill: {
+    assert(0 && "Invalid zero fill fragment in concrete section!");
+    break;
+  }
   }
 
   assert(OS.tell() - Start == F.getFileSize());
@@ -1063,6 +1102,12 @@
 /// WriteFileData - Write the \arg SD data to the output file.
 static void WriteFileData(raw_ostream &OS, const MCSectionData &SD,
                           MachObjectWriter &MOW) {
+  // Ignore virtual sections.
+  if (isVirtualSection(SD.getSection())) {
+    assert(SD.getFileSize() == 0);
+    return;
+  }
+
   uint64_t Start = OS.tell();
   (void) Start;
       
@@ -1078,12 +1123,16 @@
 }
 
 void MCAssembler::Finish() {
-  // Layout the sections and fragments.
+  // Layout the concrete sections and fragments.
   uint64_t Address = 0;
   MCSectionData *Prev = 0;
   for (iterator it = begin(), ie = end(); it != ie; ++it) {
     MCSectionData &SD = *it;
 
+    // Skip virtual sections.
+    if (isVirtualSection(SD.getSection()))
+      continue;
+
     // Align this section if necessary by adding padding bytes to the previous
     // section.
     if (uint64_t Pad = OffsetToAlignment(Address, it->getAlignment())) {
@@ -1100,6 +1149,18 @@
     Prev = &SD;
   }
 
+  // Layout the virtual sections.
+  for (iterator it = begin(), ie = end(); it != ie; ++it) {
+    MCSectionData &SD = *it;
+
+    if (!isVirtualSection(SD.getSection()))
+      continue;
+
+    SD.setAddress(Address);
+    LayoutSection(SD);
+    Address += SD.getSize();
+  }
+
   // Write the object file.
   MachObjectWriter MOW(OS);
   MOW.WriteObject(*this);