From f5d5db71dfffc045eb107d2d3072cb633bd32314 Mon Sep 17 00:00:00 2001 From: Kevin Enderby Date: Mon, 20 Jun 2016 22:16:18 +0000 Subject: [PATCH] =?utf8?q?Add=20support=20for=20Darwin=E2=80=99s=2064-bit?= =?utf8?q?=20universal=20files=20with=2064-bit=20offsets=20and=20sizes=20f?= =?utf8?q?or=20the=20objects.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 | 51 ++++++++++++--- include/llvm/Support/MachO.h | 13 +++- lib/Object/MachOUniversal.cpp | 58 ++++++++++++++---- lib/Support/Path.cpp | 2 +- .../Inputs/macho-universal64.x86_64.i386 | Bin 0 -> 16624 bytes test/Object/nm-universal-binary.test | 19 ++++++ 6 files changed, 122 insertions(+), 21 deletions(-) create mode 100755 test/Object/Inputs/macho-universal64.x86_64.i386 diff --git a/include/llvm/Object/MachOUniversal.h b/include/llvm/Object/MachOUniversal.h index bbc33383f4c..8e6b204e728 100644 --- a/include/llvm/Object/MachOUniversal.h +++ b/include/llvm/Object/MachOUniversal.h @@ -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> 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. diff --git a/include/llvm/Support/MachO.h b/include/llvm/Support/MachO.h index 3dd161b4a7c..7881f730380 100644 --- a/include/llvm/Support/MachO.h +++ b/include/llvm/Support/MachO.h @@ -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 struct relocation_info { int32_t r_address; diff --git a/lib/Object/MachOUniversal.cpp b/lib/Object/MachOUniversal.cpp index 2d0ddd93f0b..8ccf4de50e0 100644 --- a/lib/Object/MachOUniversal.cpp +++ b/lib/Object/MachOUniversal.cpp @@ -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 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(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(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(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(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; } diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp index 406a37b2cc0..f6355d1df80 100644 --- a/lib/Support/Path.cpp +++ b/lib/Support/Path.cpp @@ -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 index 0000000000000000000000000000000000000000..add12e44a354dc9d71cfb5dec5622955998c14fd GIT binary patch literal 16624 zcmeHN&r4KM7`;y|B`v3@D2g&EDHU~*Aw-bnkW!S`4*?KH`A=-7ybmu&9cd(=} zP75Y#eI|PTOzw2E-d#DkA?x$fVHJwKc)ChTfG zlDr&G#&kT{H;94!{Dy5jVnCx`$h7wRb>DDz!VhNU$D6kC4%;B~-Psn4o5lY`$I0W- zwho6K@X5i=;#FokahZc)wrRpvjSa-$)3%{7kLu=gcWRzCf4Td(cINiY_|@I$LrO}O ztudw6`Rs%3#d*1o?>}tZrv-&$%sKE%vwLIzR65pMSJ!Z$0eQrG%p{Xv&bs3J81Qn| zogPc2{Y1l&@VXkzVxCQS@G@C`i<4a8M379Y{J4d*$COne$*@}%Uswd1FHbrh-5jIC0iRYLi4V4DQ`65 zMJh_mZefi4h|x1Y0&{#=wXTcYC_1`!H5bu54Srpu6aCsB^?OIszV7$CWB#z(mFSKq z)gGo*tUl~8lhu4%dI%4JVdSFs^S9k9F;Qj_+Wra zFCb0aWV7)D#OU*^s9i3q3QT_CnY1|*>7`DkM|yM*m_LpxCI|=uf`A|(2nYg#fFK|U z2m*qDARq|*=LozG^nY{1K=Mq6{R$1}{~mcYHP1!0f2&_&c!6=v?YK&=ZKq8=h&@O{o8b#?Jc@-pb@_>`q_re*U$8;?Tj&gPM=;CI??uE>~aYy9gWi z;Eff}6}(q|L52181#6a}tvg-49+>f4aJo8mcAC@G=??^5@)QIF0YN|z5CjAPK|l}? z1Ox#=U_~Qvc6_$;Av3i94_tdzQur4F5;77nmIs!cvAxJI1n6C^{!i+y`1qT;Kl!84 S{K4Uz-p?GuTK})={67JbC=g5l literal 0 HcmV?d00001 diff --git a/test/Object/nm-universal-binary.test b/test/Object/nm-universal-binary.test index 0cced1829c3..1fce0eea645 100644 --- a/test/Object/nm-universal-binary.test +++ b/test/Object/nm-universal-binary.test @@ -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 -- 2.50.1