llvm-mc/Mach-O: Support byte and fill value emission.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79652 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp
index 7a1e935..883cabe 100644
--- a/lib/MC/MCAssembler.cpp
+++ b/lib/MC/MCAssembler.cpp
@@ -10,6 +10,7 @@
 #include "llvm/MC/MCAssembler.h"
 #include "llvm/MC/MCSectionMachO.h"
 #include "llvm/Support/DataTypes.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Target/TargetMachOWriterInfo.h"
 
@@ -48,17 +49,37 @@
   /// @name Helper Methods
   /// @{
 
+  void Write8(uint8_t Value) {
+    OS << char(Value);
+  }
+
+  void Write16(uint16_t Value) {
+    if (IsLSB) {
+      Write8(uint8_t(Value >> 0));
+      Write8(uint8_t(Value >> 8));
+    } else {
+      Write8(uint8_t(Value >> 8));
+      Write8(uint8_t(Value >> 0));
+    }
+  }
+
   void Write32(uint32_t Value) {
     if (IsLSB) {
-      OS << char(Value >> 0);
-      OS << char(Value >> 8);
-      OS << char(Value >> 16);
-      OS << char(Value >> 24);
+      Write16(uint16_t(Value >> 0));
+      Write16(uint16_t(Value >> 16));
     } else {
-      OS << char(Value >> 24);
-      OS << char(Value >> 16);
-      OS << char(Value >> 8);
-      OS << char(Value >> 0);
+      Write16(uint16_t(Value >> 16));
+      Write16(uint16_t(Value >> 0));
+    }
+  }
+
+  void Write64(uint64_t Value) {
+    if (IsLSB) {
+      Write32(uint32_t(Value >> 0));
+      Write32(uint32_t(Value >> 32));
+    } else {
+      Write32(uint32_t(Value >> 32));
+      Write32(uint32_t(Value >> 0));
     }
   }
 
@@ -115,7 +136,12 @@
     Write32(CmdSize);
   }
 
-  void WriteSegmentLoadCommand32(unsigned NumSections) {
+  /// WriteSegmentLoadCommand32 - Write a 32-bit segment load command.
+  ///
+  /// \arg NumSections - The number of sections in this segment.
+  /// \arg SectionDataSize - The total size of the sections.
+  void WriteSegmentLoadCommand32(unsigned NumSections,
+                                 uint64_t SectionDataSize) {
     // struct segment_command (56 bytes)
 
     uint64_t Start = OS.tell();
@@ -126,10 +152,10 @@
 
     WriteString("", 16);
     Write32(0); // vmaddr
-    Write32(0); // vmsize
+    Write32(SectionDataSize); // vmsize
     Write32(Header32Size + SegmentLoadCommand32Size + 
             NumSections * Section32Size); // file offset
-    Write32(0); // file size
+    Write32(SectionDataSize); // file size
     Write32(0x7); // maxprot
     Write32(0x7); // initprot
     Write32(NumSections);
@@ -169,12 +195,21 @@
 
 /* *** */
 
-MCFragment::MCFragment(MCSectionData *SD)
+MCFragment::MCFragment() : Kind(FragmentType(~0)) {
+}
+
+MCFragment::MCFragment(FragmentType _Kind, MCSectionData *SD)
+  : Kind(_Kind),
+    FileOffset(~UINT64_C(0)),
+    FileSize(~UINT64_C(0))
 {
   if (SD)
     SD->getFragmentList().push_back(this);
 }
 
+MCFragment::~MCFragment() {
+}
+
 /* *** */
 
 MCSectionData::MCSectionData() : Section(*(MCSection*)0) {}
@@ -182,17 +217,13 @@
 MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A)
   : Section(_Section),
     Alignment(1),
-    FileOffset(0),
-    FileSize(0)
+    FileOffset(~UINT64_C(0)),
+    FileSize(~UINT64_C(0))
 {
   if (A)
     A->getSectionList().push_back(this);
 }
 
-void MCSectionData::WriteFileData(raw_ostream &OS) const {
-  
-}
-
 /* *** */
 
 MCAssembler::MCAssembler(raw_ostream &_OS) : OS(_OS) {}
@@ -200,21 +231,97 @@
 MCAssembler::~MCAssembler() {
 }
 
+void MCAssembler::LayoutSection(MCSectionData &SD) {
+  uint64_t Offset = SD.getFileOffset();
+
+  for (MCSectionData::iterator it = SD.begin(), ie = SD.end(); it != ie; ++it) {
+    MCFragment &F = *it;
+    F.setFileOffset(Offset);
+    F.setFileSize(F.getMaxFileSize());
+    Offset += F.getFileSize();
+  }
+
+  // FIXME: Pad section?
+  SD.setFileSize(Offset - SD.getFileOffset());
+}
+
+/// WriteFileData - Write the \arg F data to the output file.
+static void WriteFileData(raw_ostream &OS, const MCFragment &F,
+                          MachObjectWriter &MOW) {
+  uint64_t Start = OS.tell();
+  (void) Start;
+    
+  // FIXME: Embed in fragments instead?
+  switch (F.getKind()) {
+  default:
+    assert(0 && "Invalid section kind!");
+
+  case MCFragment::FT_Data:
+    OS << cast<MCDataFragment>(F).getContents().str();
+    break;
+
+  case MCFragment::FT_Align:
+    llvm_unreachable("FIXME: Not yet implemented!");
+
+  case MCFragment::FT_Fill: {
+    MCFillFragment &FF = cast<MCFillFragment>(F);
+
+    if (!FF.getValue().isAbsolute())
+      llvm_unreachable("FIXME: Not yet implemented!");
+
+    for (uint64_t i = 0, e = FF.getCount(); i != e; ++i) {
+      switch (FF.getValueSize()) {
+      default:
+        assert(0 && "Invalid size!");
+      case 1: MOW.Write8 (uint8_t (FF.getValue().getConstant())); break;
+      case 2: MOW.Write16(uint16_t(FF.getValue().getConstant())); break;
+      case 4: MOW.Write32(uint32_t(FF.getValue().getConstant())); break;
+      case 8: MOW.Write64(uint64_t(FF.getValue().getConstant())); break;
+      }
+    }
+    break;
+  }
+    
+  case MCFragment::FT_Org:
+    llvm_unreachable("FIXME: Not yet implemented!");
+  }
+
+  assert(OS.tell() - Start == F.getFileSize());
+}
+
+/// WriteFileData - Write the \arg SD data to the output file.
+static void WriteFileData(raw_ostream &OS, const MCSectionData &SD,
+                          MachObjectWriter &MOW) {
+  uint64_t Start = OS.tell();
+  (void) Start;
+      
+  for (MCSectionData::const_iterator it = SD.begin(),
+         ie = SD.end(); it != ie; ++it)
+    WriteFileData(OS, *it, MOW);
+
+  assert(OS.tell() - Start == SD.getFileSize());
+}
+
 void MCAssembler::Finish() {
   unsigned NumSections = Sections.size();
-  
-  // Compute the file offsets so we can write in a single pass.
+
+  // Layout the sections and fragments.
   uint64_t Offset = MachObjectWriter::getPrologSize32(NumSections);
+  uint64_t SectionDataSize = 0;
   for (iterator it = begin(), ie = end(); it != ie; ++it) {
     it->setFileOffset(Offset);
+
+    LayoutSection(*it);
+
     Offset += it->getFileSize();
+    SectionDataSize += it->getFileSize();
   }
 
   MachObjectWriter MOW(OS);
 
   // Write the prolog, starting with the header and load command...
   MOW.WriteHeader32(NumSections);
-  MOW.WriteSegmentLoadCommand32(NumSections);
+  MOW.WriteSegmentLoadCommand32(NumSections, SectionDataSize);
   
   // ... and then the section headers.
   for (iterator it = begin(), ie = end(); it != ie; ++it)
@@ -222,7 +329,7 @@
 
   // Finally, write the section data.
   for (iterator it = begin(), ie = end(); it != ie; ++it)
-    it->WriteFileData(OS);
-  
+    WriteFileData(OS, *it, MOW);
+
   OS.flush();
 }