diff options
author | Alexey Samsonov <samsonov@google.com> | 2013-06-18 15:03:28 +0000 |
---|---|---|
committer | Alexey Samsonov <samsonov@google.com> | 2013-06-18 15:03:28 +0000 |
commit | 9c22f87b1374b06dc6c07f6e8047890e390bbe2d (patch) | |
tree | 4b4111e1ecfdffcfc137e357afdb764d72ea3696 /lib | |
parent | 79ac9c8402d4113d42ff2d713c7acdfa800d2397 (diff) | |
download | external_llvm-9c22f87b1374b06dc6c07f6e8047890e390bbe2d.zip external_llvm-9c22f87b1374b06dc6c07f6e8047890e390bbe2d.tar.gz external_llvm-9c22f87b1374b06dc6c07f6e8047890e390bbe2d.tar.bz2 |
Basic support for parsing Mach-O universal binaries in LLVMObject library
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@184191 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp | 1 | ||||
-rw-r--r-- | lib/Object/Binary.cpp | 7 | ||||
-rw-r--r-- | lib/Object/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Object/Error.cpp | 2 | ||||
-rw-r--r-- | lib/Object/MachOObjectFile.cpp | 8 | ||||
-rw-r--r-- | lib/Object/MachOUniversal.cpp | 139 | ||||
-rw-r--r-- | lib/Object/ObjectFile.cpp | 1 | ||||
-rw-r--r-- | lib/Support/PathV2.cpp | 3 |
8 files changed, 158 insertions, 4 deletions
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index f0bd4e3..ee5d722 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -527,6 +527,7 @@ ObjectImage *RuntimeDyld::loadObject(ObjectBuffer *InputBuffer) { case sys::fs::file_magic::archive: case sys::fs::file_magic::coff_object: case sys::fs::file_magic::pecoff_executable: + case sys::fs::file_magic::macho_universal_binary: report_fatal_error("Incompatible object format!"); } } else { diff --git a/lib/Object/Binary.cpp b/lib/Object/Binary.cpp index a149770..177c86c 100644 --- a/lib/Object/Binary.cpp +++ b/lib/Object/Binary.cpp @@ -20,6 +20,7 @@ // Include headers for createBinary. #include "llvm/Object/Archive.h" #include "llvm/Object/COFF.h" +#include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" using namespace llvm; @@ -82,6 +83,12 @@ error_code object::createBinary(MemoryBuffer *Source, Result.swap(ret); return object_error::success; } + case sys::fs::file_magic::macho_universal_binary: { + OwningPtr<Binary> ret(new MachOUniversalBinary(scopedSource.take(), ec)); + if (ec) return ec; + Result.swap(ret); + return object_error::success; + } case sys::fs::file_magic::coff_object: case sys::fs::file_magic::pecoff_executable: { OwningPtr<Binary> ret( diff --git a/lib/Object/CMakeLists.txt b/lib/Object/CMakeLists.txt index cec0e28..2c2cc8e 100644 --- a/lib/Object/CMakeLists.txt +++ b/lib/Object/CMakeLists.txt @@ -7,6 +7,7 @@ add_llvm_library(LLVMObject ELFYAML.cpp Error.cpp MachOObjectFile.cpp + MachOUniversal.cpp Object.cpp ObjectFile.cpp YAML.cpp diff --git a/lib/Object/Error.cpp b/lib/Object/Error.cpp index 7005a72..47ce38c 100644 --- a/lib/Object/Error.cpp +++ b/lib/Object/Error.cpp @@ -34,6 +34,8 @@ std::string _object_error_category::message(int ev) const { object_error::Impl E = static_cast<object_error::Impl>(ev); switch (E) { case object_error::success: return "Success"; + case object_error::arch_not_found: + return "No object file for requested architecture"; case object_error::invalid_file_type: return "The file was not recognized as a valid object file"; case object_error::parse_failed: diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index e62b5a4..12090d6 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -1297,8 +1297,8 @@ StringRef MachOObjectFile::getFileFormatName() const { } } -unsigned MachOObjectFile::getArch() const { - switch (getCPUType(this)) { +Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType) { + switch (CPUType) { case llvm::MachO::CPUTypeI386: return Triple::x86; case llvm::MachO::CPUTypeX86_64: @@ -1314,6 +1314,10 @@ unsigned MachOObjectFile::getArch() const { } } +unsigned MachOObjectFile::getArch() const { + return getArch(getCPUType(this)); +} + StringRef MachOObjectFile::getLoadName() const { // TODO: Implement report_fatal_error("get_load_name() unimplemented in MachOObjectFile"); diff --git a/lib/Object/MachOUniversal.cpp b/lib/Object/MachOUniversal.cpp new file mode 100644 index 0000000..98f7198 --- /dev/null +++ b/lib/Object/MachOUniversal.cpp @@ -0,0 +1,139 @@ +//===- MachOUniversal.cpp - Mach-O universal binary -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the MachOUniversalBinary class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/MachOUniversal.h" + +#include "llvm/Object/MachO.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/MemoryBuffer.h" + +using namespace llvm; +using namespace object; + +template<typename T> +static void SwapValue(T &Value) { + Value = sys::SwapByteOrder(Value); +} + +template<typename T> +static void SwapStruct(T &Value); + +template<> +void SwapStruct(macho::FatHeader &H) { + SwapValue(H.Magic); + SwapValue(H.NumFatArch); +} + +template<> +void SwapStruct(macho::FatArchHeader &H) { + SwapValue(H.CPUType); + SwapValue(H.CPUSubtype); + SwapValue(H.Offset); + SwapValue(H.Size); + SwapValue(H.Align); +} + +template<typename T> +static T getUniversalBinaryStruct(const char *Ptr) { + T Res; + memcpy(&Res, Ptr, sizeof(T)); + // Universal binary headers have big-endian byte order. + if (sys::IsLittleEndianHost) + SwapStruct(Res); + return Res; +} + +MachOUniversalBinary::ObjectForArch::ObjectForArch( + const MachOUniversalBinary *Parent, uint32_t Index) + : Parent(Parent), Index(Index) { + if (Parent == 0 || Index > Parent->getNumberOfObjects()) { + clear(); + } else { + // Parse object header. + StringRef ParentData = Parent->getData(); + const char *HeaderPos = ParentData.begin() + macho::FatHeaderSize + + Index * macho::FatArchHeaderSize; + Header = getUniversalBinaryStruct<macho::FatArchHeader>(HeaderPos); + if (ParentData.size() < Header.Offset + Header.Size) { + clear(); + } + } +} + +error_code MachOUniversalBinary::ObjectForArch::getAsObjectFile( + OwningPtr<ObjectFile> &Result) const { + if (Parent) { + StringRef ParentData = Parent->getData(); + StringRef ObjectData = ParentData.substr(Header.Offset, Header.Size); + Twine ObjectName = + Twine(Parent->getFileName()) + ":" + + Triple::getArchTypeName(MachOObjectFile::getArch(Header.CPUType)); + MemoryBuffer *ObjBuffer = MemoryBuffer::getMemBuffer( + ObjectData, ObjectName.str(), false); + if (ObjectFile *Obj = ObjectFile::createMachOObjectFile(ObjBuffer)) { + Result.reset(Obj); + return object_error::success; + } + } + return object_error::parse_failed; +} + +void MachOUniversalBinary::anchor() { } + +MachOUniversalBinary::MachOUniversalBinary(MemoryBuffer *Source, + error_code &ec) + : Binary(Binary::ID_MachOUniversalBinary, Source), + NumberOfObjects(0) { + if (Source->getBufferSize() < macho::FatHeaderSize) { + ec = object_error::invalid_file_type; + return; + } + // Check for magic value and sufficient header size. + StringRef Buf = getData(); + macho::FatHeader H = getUniversalBinaryStruct<macho::FatHeader>(Buf.begin()); + NumberOfObjects = H.NumFatArch; + uint32_t MinSize = macho::FatHeaderSize + + macho::FatArchHeaderSize * NumberOfObjects; + if (H.Magic != macho::HM_Universal || Buf.size() < MinSize) { + ec = object_error::parse_failed; + return; + } + ec = object_error::success; +} + +static bool getCTMForArch(Triple::ArchType Arch, mach::CPUTypeMachine &CTM) { + switch (Arch) { + case Triple::x86: CTM = mach::CTM_i386; return true; + case Triple::x86_64: CTM = mach::CTM_x86_64; return true; + case Triple::arm: CTM = mach::CTM_ARM; return true; + case Triple::sparc: CTM = mach::CTM_SPARC; return true; + case Triple::ppc: CTM = mach::CTM_PowerPC; return true; + case Triple::ppc64: CTM = mach::CTM_PowerPC64; return true; + default: return false; + } +} + +error_code +MachOUniversalBinary::getObjectForArch(Triple::ArchType Arch, + OwningPtr<ObjectFile> &Result) const { + mach::CPUTypeMachine CTM; + if (!getCTMForArch(Arch, CTM)) + return object_error::arch_not_found; + for (object_iterator I = begin_objects(), E = end_objects(); I != E; ++I) { + if (I->getCPUType() == static_cast<uint32_t>(CTM)) + return I->getAsObjectFile(Result); + } + return object_error::arch_not_found; +} diff --git a/lib/Object/ObjectFile.cpp b/lib/Object/ObjectFile.cpp index 3ec29bf..8dfc265 100644 --- a/lib/Object/ObjectFile.cpp +++ b/lib/Object/ObjectFile.cpp @@ -46,6 +46,7 @@ ObjectFile *ObjectFile::createObjectFile(MemoryBuffer *Object) { case sys::fs::file_magic::unknown: case sys::fs::file_magic::bitcode: case sys::fs::file_magic::archive: + case sys::fs::file_magic::macho_universal_binary: return 0; case sys::fs::file_magic::elf_relocatable: case sys::fs::file_magic::elf_executable: diff --git a/lib/Support/PathV2.cpp b/lib/Support/PathV2.cpp index 24eac47..0536620 100644 --- a/lib/Support/PathV2.cpp +++ b/lib/Support/PathV2.cpp @@ -810,8 +810,7 @@ error_code has_magic(const Twine &path, const Twine &magic, bool &result) { // 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) - // FIXME: Universal Binary of any type. - return file_magic::macho_dynamically_linked_shared_lib; + return file_magic::macho_universal_binary; } break; |