MC/Mach-O: Initial x86_64 support.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@98454 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp
index 29ac868..dae2d93 100644
--- a/lib/MC/MCAssembler.cpp
+++ b/lib/MC/MCAssembler.cpp
@@ -24,6 +24,7 @@
 #include "llvm/Support/MachO.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Target/TargetRegistry.h"
 #include "llvm/Target/TargetAsmBackend.h"
 
 // FIXME: Gross.
@@ -86,14 +87,19 @@
     Header_Magic64 = 0xFEEDFACF
   };
 
-  static const unsigned Header32Size = 28;
-  static const unsigned Header64Size = 32;
-  static const unsigned SegmentLoadCommand32Size = 56;
-  static const unsigned Section32Size = 68;
-  static const unsigned SymtabLoadCommandSize = 24;
-  static const unsigned DysymtabLoadCommandSize = 80;
-  static const unsigned Nlist32Size = 12;
-  static const unsigned RelocationInfoSize = 8;
+  enum {
+    Header32Size = 28,
+    Header64Size = 32,
+    SegmentLoadCommand32Size = 56,
+    SegmentLoadCommand64Size = 72,
+    Section32Size = 68,
+    Section64Size = 80,
+    SymtabLoadCommandSize = 24,
+    DysymtabLoadCommandSize = 80,
+    Nlist32Size = 12,
+    Nlist64Size = 16,
+    RelocationInfoSize = 8
+  };
 
   enum HeaderFileType {
     HFT_Object = 0x1
@@ -106,7 +112,8 @@
   enum LoadCommandType {
     LCT_Segment = 0x1,
     LCT_Symtab = 0x2,
-    LCT_Dysymtab = 0xb
+    LCT_Dysymtab = 0xb,
+    LCT_Segment64 = 0x19
   };
 
   // See <mach-o/nlist.h>.
@@ -161,11 +168,12 @@
   };
 
   raw_ostream &OS;
-  bool IsLSB;
+  unsigned Is64Bit : 1;
+  unsigned IsLSB : 1;
 
 public:
-  MachObjectWriter(raw_ostream &_OS, bool _IsLSB = true)
-    : OS(_OS), IsLSB(_IsLSB) {
+  MachObjectWriter(raw_ostream &_OS, bool _Is64Bit, bool _IsLSB = true)
+    : OS(_OS), Is64Bit(_Is64Bit), IsLSB(_IsLSB) {
   }
 
   /// @name Helper Methods
@@ -222,22 +230,23 @@
 
   /// @}
 
-  void WriteHeader32(unsigned NumLoadCommands, unsigned LoadCommandsSize,
-                     bool SubsectionsViaSymbols) {
+  void WriteHeader(unsigned NumLoadCommands, unsigned LoadCommandsSize,
+                   bool SubsectionsViaSymbols) {
     uint32_t Flags = 0;
 
     if (SubsectionsViaSymbols)
       Flags |= HF_SubsectionsViaSymbols;
 
-    // struct mach_header (28 bytes)
+    // struct mach_header (28 bytes) or
+    // struct mach_header_64 (32 bytes)
 
     uint64_t Start = OS.tell();
     (void) Start;
 
-    Write32(Header_Magic32);
+    Write32(Is64Bit ? Header_Magic64 : Header_Magic32);
 
     // FIXME: Support cputype.
-    Write32(MachO::CPUTypeI386);
+    Write32(Is64Bit ? MachO::CPUTypeX86_64 : MachO::CPUTypeI386);
     // FIXME: Support cpusubtype.
     Write32(MachO::CPUSubType_I386_ALL);
     Write32(HFT_Object);
@@ -245,48 +254,62 @@
                                  // segment.
     Write32(LoadCommandsSize);
     Write32(Flags);
+    if (Is64Bit)
+      Write32(0); // reserved
 
-    assert(OS.tell() - Start == Header32Size);
+    assert(OS.tell() - Start == Is64Bit ? Header64Size : Header32Size);
   }
 
-  /// WriteSegmentLoadCommand32 - Write a 32-bit segment load command.
+  /// WriteSegmentLoadCommand - Write a 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 VMSize,
-                                 uint64_t SectionDataStartOffset,
-                                 uint64_t SectionDataSize) {
-    // struct segment_command (56 bytes)
+  void WriteSegmentLoadCommand(unsigned NumSections,
+                               uint64_t VMSize,
+                               uint64_t SectionDataStartOffset,
+                               uint64_t SectionDataSize) {
+    // struct segment_command (56 bytes) or
+    // struct segment_command_64 (72 bytes)
 
     uint64_t Start = OS.tell();
     (void) Start;
 
-    Write32(LCT_Segment);
-    Write32(SegmentLoadCommand32Size + NumSections * Section32Size);
+    unsigned SegmentLoadCommandSize = Is64Bit ? SegmentLoadCommand64Size :
+      SegmentLoadCommand32Size;
+    Write32(Is64Bit ? LCT_Segment64 : LCT_Segment);
+    Write32(SegmentLoadCommandSize +
+            NumSections * (Is64Bit ? Section64Size : Section32Size));
 
     WriteString("", 16);
-    Write32(0); // vmaddr
-    Write32(VMSize); // vmsize
-    Write32(SectionDataStartOffset); // file offset
-    Write32(SectionDataSize); // file size
+    if (Is64Bit) {
+      Write64(0); // vmaddr
+      Write64(VMSize); // vmsize
+      Write64(SectionDataStartOffset); // file offset
+      Write64(SectionDataSize); // file size
+    } else {
+      Write32(0); // vmaddr
+      Write32(VMSize); // vmsize
+      Write32(SectionDataStartOffset); // file offset
+      Write32(SectionDataSize); // file size
+    }
     Write32(0x7); // maxprot
     Write32(0x7); // initprot
     Write32(NumSections);
     Write32(0); // flags
 
-    assert(OS.tell() - Start == SegmentLoadCommand32Size);
+    assert(OS.tell() - Start == SegmentLoadCommandSize);
   }
 
-  void WriteSection32(const MCSectionData &SD, uint64_t FileOffset,
-                      uint64_t RelocationsStart, unsigned NumRelocations) {
+  void WriteSection(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)
+    // struct section (68 bytes) or
+    // struct section_64 (80 bytes)
 
     uint64_t Start = OS.tell();
     (void) Start;
@@ -296,8 +319,13 @@
       static_cast<const MCSectionMachO&>(SD.getSection());
     WriteString(Section.getSectionName(), 16);
     WriteString(Section.getSegmentName(), 16);
-    Write32(SD.getAddress()); // address
-    Write32(SD.getSize()); // size
+    if (Is64Bit) {
+      Write64(SD.getAddress()); // address
+      Write64(SD.getSize()); // size
+    } else {
+      Write32(SD.getAddress()); // address
+      Write32(SD.getSize()); // size
+    }
     Write32(FileOffset);
 
     unsigned Flags = Section.getTypeAndAttributes();
@@ -311,8 +339,10 @@
     Write32(Flags);
     Write32(0); // reserved1
     Write32(Section.getStubSize()); // reserved2
+    if (Is64Bit)
+      Write32(0); // reserved3
 
-    assert(OS.tell() - Start == Section32Size);
+    assert(OS.tell() - Start == Is64Bit ? Section64Size : Section32Size);
   }
 
   void WriteSymtabLoadCommand(uint32_t SymbolOffset, uint32_t NumSymbols,
@@ -748,7 +778,8 @@
     // The section data starts after the header, the segment load command (and
     // section headers) and the symbol table.
     unsigned NumLoadCommands = 1;
-    uint64_t LoadCommandsSize =
+    uint64_t LoadCommandsSize = Is64Bit ?
+      SegmentLoadCommand64Size + NumSections * Section64Size :
       SegmentLoadCommand32Size + NumSections * Section32Size;
 
     // Add the symbol table load command sizes, if used.
@@ -759,7 +790,8 @@
 
     // Compute the total size of the section data, as well as its file size and
     // vm size.
-    uint64_t SectionDataStart = Header32Size + LoadCommandsSize;
+    uint64_t SectionDataStart = (Is64Bit ? Header64Size : Header32Size)
+      + LoadCommandsSize;
     uint64_t SectionDataSize = 0;
     uint64_t SectionDataFileSize = 0;
     uint64_t VMSize = 0;
@@ -785,10 +817,10 @@
     SectionDataFileSize += SectionDataPadding;
 
     // Write the prolog, starting with the header and load command...
-    WriteHeader32(NumLoadCommands, LoadCommandsSize,
-                  Asm.getSubsectionsViaSymbols());
-    WriteSegmentLoadCommand32(NumSections, VMSize,
-                              SectionDataStart, SectionDataSize);
+    WriteHeader(NumLoadCommands, LoadCommandsSize,
+                Asm.getSubsectionsViaSymbols());
+    WriteSegmentLoadCommand(NumSections, VMSize,
+                            SectionDataStart, SectionDataSize);
 
     // ... and then the section headers.
     //
@@ -815,7 +847,7 @@
 
       unsigned NumRelocs = RelocInfos.size() - NumRelocsStart;
       uint64_t SectionStart = SectionDataStart + SD.getAddress();
-      WriteSection32(SD, SectionStart, RelocTableEnd, NumRelocs);
+      WriteSection(SD, SectionStart, RelocTableEnd, NumRelocs);
       RelocTableEnd += NumRelocs * RelocationInfoSize;
     }
 
@@ -1284,7 +1316,10 @@
       dump(); });
 
   // Write the object file.
-  MachObjectWriter MOW(OS);
+  //
+  // FIXME: Factor out MCObjectWriter.
+  bool Is64Bit = StringRef(getBackend().getTarget().getName()) == "x86-64";
+  MachObjectWriter MOW(OS, Is64Bit);
   MOW.WriteObject(*this);
 
   OS.flush();