[llvm-commits] [llvm] r79652 - in /llvm/trunk: include/llvm/MC/MCAssembler.h lib/MC/MCAssembler.cpp lib/MC/MCMachOStreamer.cpp test/MC/MachO/data.s

Daniel Dunbar daniel at zuster.org
Fri Aug 21 11:29:01 PDT 2009


Author: ddunbar
Date: Fri Aug 21 13:29:01 2009
New Revision: 79652

URL: http://llvm.org/viewvc/llvm-project?rev=79652&view=rev
Log:
llvm-mc/Mach-O: Support byte and fill value emission.

Added:
    llvm/trunk/test/MC/MachO/data.s
Modified:
    llvm/trunk/include/llvm/MC/MCAssembler.h
    llvm/trunk/lib/MC/MCAssembler.cpp
    llvm/trunk/lib/MC/MCMachOStreamer.cpp

Modified: llvm/trunk/include/llvm/MC/MCAssembler.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCAssembler.h?rev=79652&r1=79651&r2=79652&view=diff

==============================================================================
--- llvm/trunk/include/llvm/MC/MCAssembler.h (original)
+++ llvm/trunk/include/llvm/MC/MCAssembler.h Fri Aug 21 13:29:01 2009
@@ -10,8 +10,11 @@
 #ifndef LLVM_MC_MCASSEMBLER_H
 #define LLVM_MC_MCASSEMBLER_H
 
+#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/ilist.h"
 #include "llvm/ADT/ilist_node.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/Support/DataTypes.h"
 
 namespace llvm {
@@ -25,7 +28,211 @@
   void operator=(const MCFragment&); // DO NOT IMPLEMENT
 
 public:
-  MCFragment(MCSectionData *SD = 0);
+  enum FragmentType {
+    FT_Data,
+    FT_Align,
+    FT_Fill,
+    FT_Org
+  };
+
+private:
+  FragmentType Kind;
+
+  /// @name Assembler Backend Data
+  /// @{
+  //
+  // FIXME: This could all be kept private to the assembler implementation.
+
+  /// FileOffset - The offset of this section in the object file. This is ~0
+  /// until initialized.
+  uint64_t FileOffset;
+
+  /// FileSize - The size of this section in the object file. This is ~0 until
+  /// initialized.
+  uint64_t FileSize;
+
+  /// @}
+
+protected:
+  MCFragment(FragmentType _Kind, MCSectionData *SD = 0);
+
+public:
+  // Only for sentinel.
+  MCFragment();
+  virtual ~MCFragment();
+
+  FragmentType getKind() const { return Kind; }
+
+  // FIXME: This should be abstract, fix sentinel.
+  virtual unsigned getMaxFileSize() const {
+    assert(0 && "Invalid getMaxFileSize call !");
+  };
+
+  /// @name Assembler Backend Support
+  /// @{
+  //
+  // FIXME: This could all be kept private to the assembler implementation.
+
+  unsigned getFileSize() const { 
+    assert(FileSize != ~UINT64_C(0) && "File size not set!");
+    return FileSize;
+  }
+  void setFileSize(uint64_t Value) {
+    assert(Value <= getMaxFileSize() && "Invalid file size!");
+    FileSize = Value;
+  }
+
+  uint64_t getFileOffset() const {
+    assert(FileOffset != ~UINT64_C(0) && "File offset not set!");
+    return FileOffset;
+  }
+  void setFileOffset(uint64_t Value) { FileOffset = Value; }
+
+  /// @}
+
+  static bool classof(const MCFragment *O) { return true; }
+};
+
+class MCDataFragment : public MCFragment {
+  SmallString<32> Contents;
+
+public:
+  MCDataFragment(MCSectionData *SD = 0) : MCFragment(FT_Data, SD) {}
+
+  /// @name Accessors
+  /// @{
+
+  unsigned getMaxFileSize() const {
+    return Contents.size();
+  }
+
+  SmallString<32> &getContents() { return Contents; }
+  const SmallString<32> &getContents() const { return Contents; }
+
+  /// @}
+
+  static bool classof(const MCFragment *F) { 
+    return F->getKind() == MCFragment::FT_Data; 
+  }
+  static bool classof(const MCDataFragment *) { return true; }
+};
+
+class MCAlignFragment : public MCFragment {
+  /// Alignment - The alignment to ensure, in bytes.
+  unsigned Alignment;
+
+  /// Value - Value to use for filling padding bytes.
+  int64_t Value;
+
+  /// ValueSize - The size of the integer (in bytes) of \arg Value.
+  unsigned ValueSize;
+
+  /// MaxBytesToEmit - The maximum number of bytes to emit; if the alignment
+  /// cannot be satisfied in this width then this fragment is ignored.
+  unsigned MaxBytesToEmit;
+
+public:
+  MCAlignFragment(unsigned _Alignment, int64_t _Value, unsigned _ValueSize,
+                  unsigned _MaxBytesToEmit, MCSectionData *SD = 0)
+    : MCFragment(FT_Align, SD), Alignment(_Alignment),
+      Value(_Value),ValueSize(_ValueSize),
+      MaxBytesToEmit(_MaxBytesToEmit) {}
+
+  /// @name Accessors
+  /// @{
+
+  unsigned getMaxFileSize() const {
+    return std::max(Alignment - 1, MaxBytesToEmit);
+  }
+
+  unsigned getAlignment() const { return Alignment; }
+  
+  int64_t getValue() const { return Value; }
+
+  unsigned getValueSize() const { return ValueSize; }
+
+  unsigned getMaxBytesToEmit() const { return MaxBytesToEmit; }
+
+  /// @}
+
+  static bool classof(const MCFragment *F) { 
+    return F->getKind() == MCFragment::FT_Align; 
+  }
+  static bool classof(const MCAlignFragment *) { return true; }
+};
+
+class MCFillFragment : public MCFragment {
+  /// Value - Value to use for filling bytes.
+  MCValue Value;
+
+  /// ValueSize - The size (in bytes) of \arg Value to use when filling.
+  unsigned ValueSize;
+
+  /// Count - The number of copies of \arg Value to insert.
+  uint64_t Count;
+
+public:
+  MCFillFragment(MCValue _Value, unsigned _ValueSize, uint64_t _Count,
+                 MCSectionData *SD = 0) 
+    : MCFragment(FT_Fill, SD),
+      Value(_Value), ValueSize(_ValueSize), Count(_Count) {}
+
+  /// @name Accessors
+  /// @{
+
+  unsigned getMaxFileSize() const {
+    return ValueSize * Count;
+  }
+
+  MCValue getValue() const { return Value; }
+  
+  unsigned getValueSize() const { return ValueSize; }
+
+  uint64_t getCount() const { return Count; }
+
+  /// @}
+
+  static bool classof(const MCFragment *F) { 
+    return F->getKind() == MCFragment::FT_Fill; 
+  }
+  static bool classof(const MCFillFragment *) { return true; }
+};
+
+class MCOrgFragment : public MCFragment {
+  /// Offset - The offset this fragment should start at.
+  MCValue Offset;
+
+  /// Value - Value to use for filling bytes.  
+  int64_t Value;
+
+  /// ValueSize - The size (in bytes) of \arg Value to use when filling.
+  unsigned ValueSize;
+
+public:
+  MCOrgFragment(MCValue _Offset, int64_t _Value, unsigned _ValueSize,
+                MCSectionData *SD = 0)
+    : MCFragment(FT_Org, SD),
+      Offset(_Offset), Value(_Value), ValueSize(_ValueSize) {}
+  /// @name Accessors
+  /// @{
+
+  unsigned getMaxFileSize() const {
+    // FIXME
+    return 0;
+  }
+
+  MCValue getOffset() const { return Offset; }
+  
+  int64_t getValue() const { return Value; }
+  
+  unsigned getValueSize() const { return ValueSize; }
+
+  /// @}
+
+  static bool classof(const MCFragment *F) { 
+    return F->getKind() == MCFragment::FT_Org; 
+  }
+  static bool classof(const MCOrgFragment *) { return true; }
 };
 
 // FIXME: Should this be a separate class, or just merged into MCSection? Since
@@ -38,6 +245,9 @@
 public:
   typedef iplist<MCFragment> FragmentListType;
 
+  typedef FragmentListType::const_iterator const_iterator;
+  typedef FragmentListType::iterator iterator;
+
 private:
   iplist<MCFragment> Fragments;
   const MCSection &Section;
@@ -50,10 +260,12 @@
   //
   // FIXME: This could all be kept private to the assembler implementation.
 
-  /// FileOffset - The offset of this section in the object file.
+  /// FileOffset - The offset of this section in the object file. This is ~0
+  /// until initialized.
   uint64_t FileOffset;
 
-  /// FileSize - The size of this section in the object file.
+  /// FileSize - The size of this section in the object file. This is ~0 until
+  /// initialized.
   uint64_t FileSize;
 
   /// @}
@@ -63,26 +275,44 @@
   MCSectionData();
   MCSectionData(const MCSection &Section, MCAssembler *A = 0);
 
-  const FragmentListType &getFragmentList() const { return Fragments; }
-  FragmentListType &getFragmentList() { return Fragments; }
-
   const MCSection &getSection() const { return Section; }
 
   unsigned getAlignment() const { return Alignment; }
   void setAlignment(unsigned Value) { Alignment = Value; }
 
+
+  /// @name Section List Access
+  /// @{
+
+  const FragmentListType &getFragmentList() const { return Fragments; }
+  FragmentListType &getFragmentList() { return Fragments; }
+
+  iterator begin() { return Fragments.begin(); }
+  const_iterator begin() const { return Fragments.begin(); }
+
+  iterator end() { return Fragments.end(); }
+  const_iterator end() const { return Fragments.end(); }
+
+  size_t size() const { return Fragments.size(); }
+
+  /// @}
   /// @name Assembler Backend Support
   /// @{
   //
   // FIXME: This could all be kept private to the assembler implementation.
 
-  unsigned getFileSize() const { return FileSize; }
-
-  uint64_t getFileOffset() const { return FileOffset; }
+  unsigned getFileSize() const { 
+    assert(FileSize != ~UINT64_C(0) && "File size not set!");
+    return FileSize;
+  }
+  void setFileSize(uint64_t Value) { FileSize = Value; }
+
+  uint64_t getFileOffset() const {
+    assert(FileOffset != ~UINT64_C(0) && "File offset not set!");
+    return FileOffset;
+  }
   void setFileOffset(uint64_t Value) { FileOffset = Value; }
 
-  void WriteFileData(raw_ostream &OS) const;
-
   /// @}
 };
 
@@ -101,6 +331,12 @@
   
   iplist<MCSectionData> Sections;
 
+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);
+
 public:
   /// Construct a new assembler instance.
   ///

Modified: llvm/trunk/lib/MC/MCAssembler.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCAssembler.cpp?rev=79652&r1=79651&r2=79652&view=diff

==============================================================================
--- llvm/trunk/lib/MC/MCAssembler.cpp (original)
+++ llvm/trunk/lib/MC/MCAssembler.cpp Fri Aug 21 13:29:01 2009
@@ -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();
 }

Modified: llvm/trunk/lib/MC/MCMachOStreamer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCMachOStreamer.cpp?rev=79652&r1=79651&r2=79652&view=diff

==============================================================================
--- llvm/trunk/lib/MC/MCMachOStreamer.cpp (original)
+++ llvm/trunk/lib/MC/MCMachOStreamer.cpp Fri Aug 21 13:29:01 2009
@@ -139,22 +139,28 @@
 }
 
 void MCMachOStreamer::EmitBytes(const StringRef &Data) {
-  llvm_unreachable("FIXME: Not yet implemented!");
+  MCDataFragment *DF = new MCDataFragment(CurSectionData);
+  DF->getContents().append(Data.begin(), Data.end());
 }
 
 void MCMachOStreamer::EmitValue(const MCValue &Value, unsigned Size) {
-  llvm_unreachable("FIXME: Not yet implemented!");
+  new MCFillFragment(Value, Size, 1, CurSectionData);
 }
 
 void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment,
                                            int64_t Value, unsigned ValueSize,
                                            unsigned MaxBytesToEmit) {
-  llvm_unreachable("FIXME: Not yet implemented!");
+  new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit,
+                      CurSectionData);
+
+  // Update the maximum alignment on the current section if necessary
+  if (ByteAlignment > CurSectionData->getAlignment())
+    CurSectionData->setAlignment(ByteAlignment);
 }
 
 void MCMachOStreamer::EmitValueToOffset(const MCValue &Offset,
                                         unsigned char Value) {
-  llvm_unreachable("FIXME: Not yet implemented!");
+  new MCOrgFragment(Offset, Value, 1, CurSectionData);
 }
 
 void MCMachOStreamer::EmitInstruction(const MCInst &Inst) {

Added: llvm/trunk/test/MC/MachO/data.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/MachO/data.s?rev=79652&view=auto

==============================================================================
--- llvm/trunk/test/MC/MachO/data.s (added)
+++ llvm/trunk/test/MC/MachO/data.s Fri Aug 21 13:29:01 2009
@@ -0,0 +1,60 @@
+// RUN: llvm-mc %s -filetype=obj -o - | macho-dump | FileCheck %s
+
+        .data
+        .ascii "hello"
+        .byte 0xAB
+        .short 0xABCD
+        .long 0xABCDABCD
+        .quad 0xABCDABCDABCDABCD
+
+// CHECK: ('cputype', 7)
+// CHECK: ('cpusubtype', 3)
+// CHECK: ('filetype', 1)
+// CHECK: ('num_load_commands', 1)
+// CHECK: ('load_commands_size', 192)
+// CHECK: ('flag', 0)
+// CHECK: ('load_commands', [
+// CHECK:   # Load Command 0
+// CHECK:  (('command', 1)
+// CHECK:   ('size', 192)
+// 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', 20)
+// CHECK:   ('file_offset', 220)
+// CHECK:   ('file_size', 20)
+// CHECK:   ('maxprot', 7)
+// CHECK:   ('initprot', 7)
+// CHECK:   ('num_sections', 2)
+// 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', 0)
+// CHECK:     ('offset', 220)
+// 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', 0)
+// CHECK:     ('size', 20)
+// CHECK:     ('offset', 220)
+// CHECK:     ('alignment', 0)
+// CHECK:     ('reloc_offset', 0)
+// CHECK:     ('num_reloc', 0)
+// CHECK:     ('flags', 0x0)
+// CHECK:     ('reserved1', 0)
+// CHECK:     ('reserved2', 0)
+// CHECK:    ),
+// CHECK:   ])
+// CHECK:  ),
+// CHECK: ])
+
+// FIXME: Dump contents, so we can check those too.





More information about the llvm-commits mailing list