]> granicus.if.org Git - llvm/commitdiff
Add support for Darwin’s 64-bit universal files with 64-bit offsets and sizes for...
authorKevin Enderby <enderby@apple.com>
Mon, 20 Jun 2016 22:16:18 +0000 (22:16 +0000)
committerKevin Enderby <enderby@apple.com>
Mon, 20 Jun 2016 22:16:18 +0000 (22:16 +0000)
Darwin added support in its Xcode 8.0 tools (released in the beta) for universal
files where offsets and sizes for the objects are 64-bits to allow support for
objects contained in universal files to be larger then 4gb.  The change is very
straight forward.  There is a new magic number that differs by one bit, much
like the 64-bit Mach-O files.  Then there is a new structure that follow the
fat_header that has the same layout but with the offset and size fields using
64-bit values instead of 32-bit values.

rdar://26899493

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@273207 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Object/MachOUniversal.h
include/llvm/Support/MachO.h
lib/Object/MachOUniversal.cpp
lib/Support/Path.cpp
test/Object/Inputs/macho-universal64.x86_64.i386 [new file with mode: 0755]
test/Object/nm-universal-binary.test

index bbc33383f4c31fb7ac476fe0d51ccb8967b89257..8e6b204e728fd501e8d23727fe0cda0a8d12ffe9 100644 (file)
@@ -30,6 +30,7 @@ namespace object {
 class MachOUniversalBinary : public Binary {
   virtual void anchor();
 
+  uint32_t Magic;
   uint32_t NumberOfObjects;
 public:
   class ObjectForArch {
@@ -38,6 +39,7 @@ public:
     uint32_t Index;
     /// \brief Descriptor of the object.
     MachO::fat_arch Header;
+    MachO::fat_arch_64 Header64;
 
   public:
     ObjectForArch(const MachOUniversalBinary *Parent, uint32_t Index);
@@ -52,15 +54,47 @@ public:
     }
 
     ObjectForArch getNext() const { return ObjectForArch(Parent, Index + 1); }
-    uint32_t getCPUType() const { return Header.cputype; }
-    uint32_t getCPUSubType() const { return Header.cpusubtype; }
-    uint32_t getOffset() const { return Header.offset; }
-    uint32_t getSize() const { return Header.size; }
-    uint32_t getAlign() const { return Header.align; }
+    uint32_t getCPUType() const {
+      if (Parent->getMagic() == MachO::FAT_MAGIC)
+        return Header.cputype;
+      else // Parent->getMagic() == MachO::FAT_MAGIC_64
+        return Header64.cputype;
+    }
+    uint32_t getCPUSubType() const {
+      if (Parent->getMagic() == MachO::FAT_MAGIC)
+        return Header.cpusubtype;
+      else // Parent->getMagic() == MachO::FAT_MAGIC_64
+        return Header64.cpusubtype;
+    }
+    uint32_t getOffset() const {
+      if (Parent->getMagic() == MachO::FAT_MAGIC)
+        return Header.offset;
+      else // Parent->getMagic() == MachO::FAT_MAGIC_64
+        return Header64.offset;
+    }
+    uint32_t getSize() const {
+      if (Parent->getMagic() == MachO::FAT_MAGIC)
+        return Header.size;
+      else // Parent->getMagic() == MachO::FAT_MAGIC_64
+        return Header64.size;
+    }
+    uint32_t getAlign() const {
+      if (Parent->getMagic() == MachO::FAT_MAGIC)
+        return Header.align;
+      else // Parent->getMagic() == MachO::FAT_MAGIC_64
+        return Header64.align;
+    }
     std::string getArchTypeName() const {
-      Triple T =
-          MachOObjectFile::getArchTriple(Header.cputype, Header.cpusubtype);
-      return T.getArchName();
+      if (Parent->getMagic() == MachO::FAT_MAGIC) {
+        Triple T =
+            MachOObjectFile::getArchTriple(Header.cputype, Header.cpusubtype);
+        return T.getArchName();
+      } else { // Parent->getMagic() == MachO::FAT_MAGIC_64
+        Triple T =
+            MachOObjectFile::getArchTriple(Header64.cputype,
+                                           Header64.cpusubtype);
+        return T.getArchName();
+      }
     }
 
     Expected<std::unique_ptr<MachOObjectFile>> getAsObjectFile() const;
@@ -103,6 +137,7 @@ public:
     return make_range(begin_objects(), end_objects());
   }
 
+  uint32_t getMagic() const { return Magic; }
   uint32_t getNumberOfObjects() const { return NumberOfObjects; }
 
   // Cast methods.
index 3dd161b4a7cafdd9c5bbde04cc1e7cae4f57dd4a..7881f730380179775946703705fbf99789cdf6d7 100644 (file)
@@ -29,7 +29,9 @@ namespace llvm {
       MH_MAGIC_64 = 0xFEEDFACFu,
       MH_CIGAM_64 = 0xCFFAEDFEu,
       FAT_MAGIC   = 0xCAFEBABEu,
-      FAT_CIGAM   = 0xBEBAFECAu
+      FAT_CIGAM   = 0xBEBAFECAu,
+      FAT_MAGIC_64 = 0xCAFEBABFu,
+      FAT_CIGAM_64 = 0xBFBAFECAu
     };
 
     enum HeaderFileType {
@@ -891,6 +893,15 @@ namespace llvm {
       uint32_t align;
     };
 
+    struct fat_arch_64 {
+      uint32_t cputype;
+      uint32_t cpusubtype;
+      uint64_t offset;
+      uint64_t size;
+      uint32_t align;
+      uint32_t reserved;
+    };
+
     // Structs from <mach-o/reloc.h>
     struct relocation_info {
       int32_t r_address;
index 2d0ddd93f0beb7b1d30337a167e75d273c9da937..8ccf4de50e0941229cbb0d1de6f4ce87bcb67222 100644 (file)
@@ -40,6 +40,16 @@ void SwapStruct(MachO::fat_arch &H) {
   sys::swapByteOrder(H.align);
 }
 
+template<>
+void SwapStruct(MachO::fat_arch_64 &H) {
+  sys::swapByteOrder(H.cputype);
+  sys::swapByteOrder(H.cpusubtype);
+  sys::swapByteOrder(H.offset);
+  sys::swapByteOrder(H.size);
+  sys::swapByteOrder(H.align);
+  sys::swapByteOrder(H.reserved);
+}
+
 template<typename T>
 static T getUniversalBinaryStruct(const char *Ptr) {
   T Res;
@@ -58,11 +68,20 @@ MachOUniversalBinary::ObjectForArch::ObjectForArch(
   } else {
     // Parse object header.
     StringRef ParentData = Parent->getData();
-    const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) +
-                            Index * sizeof(MachO::fat_arch);
-    Header = getUniversalBinaryStruct<MachO::fat_arch>(HeaderPos);
-    if (ParentData.size() < Header.offset + Header.size) {
-      clear();
+    if (Parent->getMagic() == MachO::FAT_MAGIC) {
+      const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) +
+                              Index * sizeof(MachO::fat_arch);
+      Header = getUniversalBinaryStruct<MachO::fat_arch>(HeaderPos);
+      if (ParentData.size() < Header.offset + Header.size) {
+        clear();
+      }
+    } else { // Parent->getMagic() == MachO::FAT_MAGIC_64
+      const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) +
+                              Index * sizeof(MachO::fat_arch_64);
+      Header64 = getUniversalBinaryStruct<MachO::fat_arch_64>(HeaderPos);
+      if (ParentData.size() < Header64.offset + Header64.size) {
+        clear();
+      }
     }
   }
 }
@@ -73,7 +92,11 @@ MachOUniversalBinary::ObjectForArch::getAsObjectFile() const {
     return errorCodeToError(object_error::parse_failed);
 
   StringRef ParentData = Parent->getData();
-  StringRef ObjectData = ParentData.substr(Header.offset, Header.size);
+  StringRef ObjectData;
+  if (Parent->getMagic() == MachO::FAT_MAGIC)
+    ObjectData = ParentData.substr(Header.offset, Header.size);
+  else // Parent->getMagic() == MachO::FAT_MAGIC_64
+    ObjectData = ParentData.substr(Header64.offset, Header64.size);
   StringRef ObjectName = Parent->getFileName();
   MemoryBufferRef ObjBuffer(ObjectData, ObjectName);
   return ObjectFile::createMachOObjectFile(ObjBuffer);
@@ -85,7 +108,11 @@ MachOUniversalBinary::ObjectForArch::getAsArchive() const {
     return object_error::parse_failed;
 
   StringRef ParentData = Parent->getData();
-  StringRef ObjectData = ParentData.substr(Header.offset, Header.size);
+  StringRef ObjectData;
+  if (Parent->getMagic() == MachO::FAT_MAGIC)
+    ObjectData = ParentData.substr(Header.offset, Header.size);
+  else // Parent->getMagic() == MachO::FAT_MAGIC_64
+    ObjectData = ParentData.substr(Header64.offset, Header64.size);
   StringRef ObjectName = Parent->getFileName();
   MemoryBufferRef ObjBuffer(ObjectData, ObjectName);
   return Archive::create(ObjBuffer);
@@ -105,7 +132,8 @@ MachOUniversalBinary::create(MemoryBufferRef Source) {
 
 MachOUniversalBinary::MachOUniversalBinary(MemoryBufferRef Source,
                                            std::error_code &ec)
-    : Binary(Binary::ID_MachOUniversalBinary, Source), NumberOfObjects(0) {
+    : Binary(Binary::ID_MachOUniversalBinary, Source), Magic(0),
+      NumberOfObjects(0) {
   if (Data.getBufferSize() < sizeof(MachO::fat_header)) {
     ec = object_error::invalid_file_type;
     return;
@@ -113,10 +141,18 @@ MachOUniversalBinary::MachOUniversalBinary(MemoryBufferRef Source,
   // Check for magic value and sufficient header size.
   StringRef Buf = getData();
   MachO::fat_header H= getUniversalBinaryStruct<MachO::fat_header>(Buf.begin());
+  Magic = H.magic;
   NumberOfObjects = H.nfat_arch;
-  uint32_t MinSize = sizeof(MachO::fat_header) +
-                     sizeof(MachO::fat_arch) * NumberOfObjects;
-  if (H.magic != MachO::FAT_MAGIC || Buf.size() < MinSize) {
+  uint32_t MinSize = sizeof(MachO::fat_header);
+  if (Magic == MachO::FAT_MAGIC)
+    MinSize += sizeof(MachO::fat_arch) * NumberOfObjects;
+  else if (Magic == MachO::FAT_MAGIC_64)
+    MinSize += sizeof(MachO::fat_arch_64) * NumberOfObjects;
+  else {
+    ec = object_error::parse_failed;
+    return;
+  }
+  if (Buf.size() < MinSize) {
     ec = object_error::parse_failed;
     return;
   }
index 406a37b2cc0d88065b3e3e3f1ac42145fe5c6f0b..f6355d1df805fc55320adb14f6bf7b6a1acc8624 100644 (file)
@@ -1049,7 +1049,7 @@ file_magic identify_magic(StringRef Magic) {
 
     case 0xCA:
       if (Magic[1] == char(0xFE) && Magic[2] == char(0xBA) &&
-          Magic[3] == char(0xBE)) {
+          (Magic[3] == char(0xBE) || Magic[3] == char(0xBF))) {
         // This is complicated by an overlap with Java class files.
         // See the Mach-O section in /usr/share/file/magic for details.
         if (Magic.size() >= 8 && Magic[7] < 43)
diff --git a/test/Object/Inputs/macho-universal64.x86_64.i386 b/test/Object/Inputs/macho-universal64.x86_64.i386
new file mode 100755 (executable)
index 0000000..add12e4
Binary files /dev/null and b/test/Object/Inputs/macho-universal64.x86_64.i386 differ
index 0cced1829c3f62d1646344e8e7229c6f9e1fc60e..1fce0eea6452b86d6a6e7ca9b61d2d7302415a4f 100644 (file)
@@ -1,5 +1,7 @@
 RUN: llvm-nm -arch all %p/Inputs/macho-universal.x86_64.i386 \
 RUN:         | FileCheck %s -check-prefix CHECK-OBJ
+RUN: llvm-nm -arch all %p/Inputs/macho-universal64.x86_64.i386 \
+RUN:         | FileCheck %s -check-prefix CHECK-64-OBJ
 RUN: llvm-nm -arch x86_64 %p/Inputs/macho-universal.x86_64.i386 \
 RUN:         | FileCheck %s -check-prefix CHECK-OBJ-x86_64
 RUN: not llvm-nm -arch armv7m %p/Inputs/macho-universal.x86_64.i386 2>&1 \
@@ -8,6 +10,8 @@ RUN: not llvm-nm -arch foobar %p/Inputs/macho-universal.x86_64.i386 2>&1 \
 RUN:         | FileCheck %s -check-prefix CHECK-OBJ-foobar
 RUN: llvm-nm -arch all %p/Inputs/macho-universal-archive.x86_64.i386 \
 RUN:         | FileCheck %s -check-prefix CHECK-AR
+RUN: llvm-nm -arch all %p/Inputs/macho-universal64-archive.x86_64.i386 \
+RUN:         | FileCheck %s -check-prefix CHECK-64-AR
 RUN: llvm-nm -arch i386 %p/Inputs/macho-universal-archive.x86_64.i386 \
 RUN:         | FileCheck %s -check-prefix CHECK-AR-i386
 RUN: llvm-nm -o -arch all %p/Inputs/macho-universal-archive.x86_64.i386 \
@@ -18,6 +22,11 @@ CHECK-OBJ: 0000000100000f60 T _main
 CHECK-OBJ: macho-universal.x86_64.i386 (for architecture i386):
 CHECK-OBJ: 00001fa0 T _main
 
+CHECK-64-OBJ: macho-universal64.x86_64.i386 (for architecture x86_64):
+CHECK-64-OBJ: 0000000100000f60 T _main
+CHECK-64-OBJ: macho-universal64.x86_64.i386 (for architecture i386):
+CHECK-64-OBJ: 00001fa0 T _main
+
 CHECK-OBJ-x86_64: 0000000100000000 T __mh_execute_header
 CHECK-OBJ-x86_64: 0000000100000f60 T _main
 CHECK-OBJ-x86_64:                  U dyld_stub_binder
@@ -38,6 +47,16 @@ CHECK-AR: macho-universal-archive.x86_64.i386(foo.o) (for architecture i386):
 CHECK-AR: 00000008 D _bar
 CHECK-AR: 00000000 T _foo
 
+CHECK-64-AR: macho-universal64-archive.x86_64.i386(foo.o) (for architecture i386):
+CHECK-64-AR: 00000008 D _bar
+CHECK-64-AR: 00000000 T _foo
+CHECK-64-AR: macho-universal64-archive.x86_64.i386(hello.o) (for architecture x86_64):
+CHECK-64-AR: 0000000000000068 s EH_frame0
+CHECK-64-AR: 000000000000003b s L_.str
+CHECK-64-AR: 0000000000000000 T _main
+CHECK-64-AR: 0000000000000080 S _main.eh
+CHECK-64-AR:                  U _printf
+
 CHECK-AR-i386: macho-universal-archive.x86_64.i386(foo.o):
 CHECK-AR-i386: 00000008 D _bar
 CHECK-AR-i386: 00000000 T _foo