From eb6d110c1d0d0089c4da4b4ca9cd64460aa142f3 Mon Sep 17 00:00:00 2001 From: Kevin Enderby Date: Mon, 20 Jun 2016 22:16:18 +0000 Subject: Add support for Darwin’s 64-bit universal files with 64-bit offsets and sizes for the objects. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 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 llvm-svn: 273207 --- llvm/lib/Object/MachOUniversal.cpp | 58 ++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 11 deletions(-) (limited to 'llvm/lib/Object/MachOUniversal.cpp') diff --git a/llvm/lib/Object/MachOUniversal.cpp b/llvm/lib/Object/MachOUniversal.cpp index 2d0ddd93f0b..8ccf4de50e0 100644 --- a/llvm/lib/Object/MachOUniversal.cpp +++ b/llvm/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; } -- cgit v1.2.3