llvm-mc/Mach-O: Support .o emission for .org and .align.
authorDaniel Dunbar <daniel@zuster.org>
Fri, 21 Aug 2009 23:07:38 +0000 (23:07 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Fri, 21 Aug 2009 23:07:38 +0000 (23:07 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79684 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/MC/MCAssembler.h
lib/MC/MCAssembler.cpp
lib/MC/MCMachOStreamer.cpp
test/MC/MachO/data.s

index a5739f2bc977fe7d7eea55a94d7ca685f6ac7432..17de0b68b445ab2a6d793da31d7a98f448db007b 100644 (file)
@@ -64,7 +64,7 @@ public:
   FragmentType getKind() const { return Kind; }
 
   // FIXME: This should be abstract, fix sentinel.
-  virtual unsigned getMaxFileSize() const {
+  virtual uint64_t getMaxFileSize() const {
     assert(0 && "Invalid getMaxFileSize call !");
   };
 
@@ -102,7 +102,7 @@ public:
   /// @name Accessors
   /// @{
 
-  unsigned getMaxFileSize() const {
+  uint64_t getMaxFileSize() const {
     return Contents.size();
   }
 
@@ -141,7 +141,7 @@ public:
   /// @name Accessors
   /// @{
 
-  unsigned getMaxFileSize() const {
+  uint64_t getMaxFileSize() const {
     return std::max(Alignment - 1, MaxBytesToEmit);
   }
 
@@ -180,7 +180,7 @@ public:
   /// @name Accessors
   /// @{
 
-  unsigned getMaxFileSize() const {
+  uint64_t getMaxFileSize() const {
     return ValueSize * Count;
   }
 
@@ -203,29 +203,23 @@ class MCOrgFragment : public MCFragment {
   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;
+  int8_t Value;
 
 public:
-  MCOrgFragment(MCValue _Offset, int64_t _Value, unsigned _ValueSize,
-                MCSectionData *SD = 0)
+  MCOrgFragment(MCValue _Offset, int8_t _Value, MCSectionData *SD = 0)
     : MCFragment(FT_Org, SD),
-      Offset(_Offset), Value(_Value), ValueSize(_ValueSize) {}
+      Offset(_Offset), Value(_Value) {}
   /// @name Accessors
   /// @{
 
-  unsigned getMaxFileSize() const {
-    // FIXME
-    return 0;
+  uint64_t getMaxFileSize() const {
+    // FIXME: This doesn't make much sense.
+    return ~UINT64_C(0);
   }
 
   MCValue getOffset() const { return Offset; }
   
-  int64_t getValue() const { return Value; }
-  
-  unsigned getValueSize() const { return ValueSize; }
+  uint8_t getValue() const { return Value; }
 
   /// @}
 
index 883cabe45c3762049cb06938f53c8ef8c3aba6e5..9d8c3c5600dde4ce2afeea384be02256855014ac 100644 (file)
@@ -8,6 +8,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/MC/MCAssembler.h"
+
+#include "llvm/ADT/Twine.h"
 #include "llvm/MC/MCSectionMachO.h"
 #include "llvm/Support/DataTypes.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -232,17 +234,58 @@ MCAssembler::~MCAssembler() {
 }
 
 void MCAssembler::LayoutSection(MCSectionData &SD) {
-  uint64_t Offset = SD.getFileOffset();
+  uint64_t FileOffset = SD.getFileOffset();
+  uint64_t SectionOffset = 0;
 
   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();
+
+    F.setFileOffset(FileOffset);
+
+    // Evaluate fragment size.
+    switch (F.getKind()) {
+    case MCFragment::FT_Align: {
+      MCAlignFragment &AF = cast<MCAlignFragment>(F);
+      
+      uint64_t AlignedOffset =
+        RoundUpToAlignment(SectionOffset, AF.getAlignment());
+      uint64_t PaddingBytes = AlignedOffset - SectionOffset;
+
+      if (PaddingBytes > AF.getMaxBytesToEmit())
+        AF.setFileSize(0);
+      else
+        AF.setFileSize(PaddingBytes);
+      break;
+    }
+
+    case MCFragment::FT_Data:
+    case MCFragment::FT_Fill:
+      F.setFileSize(F.getMaxFileSize());
+      break;
+
+    case MCFragment::FT_Org: {
+      MCOrgFragment &OF = cast<MCOrgFragment>(F);
+
+      if (!OF.getOffset().isAbsolute())
+        llvm_unreachable("FIXME: Not yet implemented!");
+      uint64_t OrgOffset = OF.getOffset().getConstant();
+
+      // FIXME: We need a way to communicate this error.
+      if (OrgOffset < SectionOffset)
+        llvm_report_error("invalid .org offset '" + Twine(OrgOffset) + 
+                          "' (section offset '" + Twine(SectionOffset) + "'");
+        
+      F.setFileSize(OrgOffset - SectionOffset);
+      break;
+    }      
+    }
+
+    FileOffset += F.getFileSize();
+    SectionOffset += F.getFileSize();
   }
 
   // FIXME: Pad section?
-  SD.setFileSize(Offset - SD.getFileOffset());
+  SD.setFileSize(FileOffset - SD.getFileOffset());
 }
 
 /// WriteFileData - Write the \arg F data to the output file.
@@ -251,39 +294,68 @@ static void WriteFileData(raw_ostream &OS, const MCFragment &F,
   uint64_t Start = OS.tell();
   (void) Start;
     
+  assert(F.getFileOffset() == Start && "Invalid file offset!");
+
   // FIXME: Embed in fragments instead?
   switch (F.getKind()) {
-  default:
-    assert(0 && "Invalid section kind!");
+  case MCFragment::FT_Align: {
+    MCAlignFragment &AF = cast<MCAlignFragment>(F);
+    uint64_t Count = AF.getFileSize() / AF.getValueSize();
+
+    // FIXME: This error shouldn't actually occur (the front end should emit
+    // multiple .align directives to enforce the semantics it wants), but is
+    // severe enough that we want to report it. How to handle this?
+    if (Count * AF.getValueSize() != AF.getFileSize())
+      llvm_report_error("undefined .align directive, value size '" + 
+                        Twine(AF.getValueSize()) + 
+                        "' is not a divisor of padding size '" +
+                        Twine(AF.getFileSize()) + "'");
+
+    for (uint64_t i = 0; i != Count; ++i) {
+      switch (AF.getValueSize()) {
+      default:
+        assert(0 && "Invalid size!");
+      case 1: MOW.Write8 (uint8_t (AF.getValue())); break;
+      case 2: MOW.Write16(uint16_t(AF.getValue())); break;
+      case 4: MOW.Write32(uint32_t(AF.getValue())); break;
+      case 8: MOW.Write64(uint64_t(AF.getValue())); break;
+      }
+    }
+    break;
+  }
 
   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!");
+    int64_t Value = FF.getValue().getConstant();
 
     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;
+      case 1: MOW.Write8 (uint8_t (Value)); break;
+      case 2: MOW.Write16(uint16_t(Value)); break;
+      case 4: MOW.Write32(uint32_t(Value)); break;
+      case 8: MOW.Write64(uint64_t(Value)); break;
       }
     }
     break;
   }
     
-  case MCFragment::FT_Org:
-    llvm_unreachable("FIXME: Not yet implemented!");
+  case MCFragment::FT_Org: {
+    MCOrgFragment &OF = cast<MCOrgFragment>(F);
+
+    for (uint64_t i = 0, e = OF.getFileSize(); i != e; ++i)
+      MOW.Write8(uint8_t(OF.getValue()));
+
+    break;
+  }
   }
 
   assert(OS.tell() - Start == F.getFileSize());
index 0ad03273cf0aff907b2710a66bb4bbd9c429df57..316051ce01d6a9969064918363d749062238a5b2 100644 (file)
@@ -150,6 +150,8 @@ void MCMachOStreamer::EmitValue(const MCValue &Value, unsigned Size) {
 void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment,
                                            int64_t Value, unsigned ValueSize,
                                            unsigned MaxBytesToEmit) {
+  if (MaxBytesToEmit == 0)
+    MaxBytesToEmit = ByteAlignment;
   new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit,
                       CurSectionData);
 
@@ -160,7 +162,7 @@ void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment,
 
 void MCMachOStreamer::EmitValueToOffset(const MCValue &Offset,
                                         unsigned char Value) {
-  new MCOrgFragment(Offset, Value, 1, CurSectionData);
+  new MCOrgFragment(Offset, Value, CurSectionData);
 }
 
 void MCMachOStreamer::EmitInstruction(const MCInst &Inst) {
index 3d39b53593cb0936891744d1754713ad1cff8278..56979b61f247bd26c6c6d67114e9b8a9a72e9501 100644 (file)
@@ -6,6 +6,13 @@
         .short 0xABCD
         .long 0xABCDABCD
         .quad 0xABCDABCDABCDABCD
+.org 30
+        .long 0xF000            // 34
+        .p2align  3, 0xAB       // 40 (0xAB * 6)
+        .short 0                // 42
+        .p2alignw 3, 0xABCD     // 48 (0xABCD * 2)
+        .short 0                // 50
+        .p2alignw 3, 0xABCD, 5  // 50
 
 // CHECK: ('cputype', 7)
 // CHECK: ('cpusubtype', 3)
@@ -19,9 +26,9 @@
 // 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:   ('vm_size', 50)
 // CHECK:   ('file_offset', 220)
-// CHECK:   ('file_size', 20)
+// CHECK:   ('file_size', 50)
 // CHECK:   ('maxprot', 7)
 // CHECK:   ('initprot', 7)
 // CHECK:   ('num_sections', 2)
@@ -44,9 +51,9 @@
 // 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:     ('size', 50)
 // CHECK:     ('offset', 220)
-// CHECK:     ('alignment', 0)
+// CHECK:     ('alignment', 3)
 // CHECK:     ('reloc_offset', 0)
 // CHECK:     ('num_reloc', 0)
 // CHECK:     ('flags', 0x0)