llvm.org GIT mirror llvm / 9c22f87
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 Alexey Samsonov 7 years ago
17 changed file(s) with 312 addition(s) and 4 deletion(s). Raw diff Collapse all Expand all
3737
3838 enum {
3939 ID_Archive,
40 ID_MachOUniversalBinary,
4041 // Object and children.
4142 ID_StartObjects,
4243 ID_COFF,
8687 return TypeID == ID_Archive;
8788 }
8889
90 bool isMachOUniversalBinary() const {
91 return TypeID == ID_MachOUniversalBinary;
92 }
93
8994 bool isELF() const {
9095 return TypeID >= ID_ELF32L && TypeID <= ID_ELF64B;
9196 }
2323 struct object_error {
2424 enum Impl {
2525 success = 0,
26 arch_not_found,
2627 invalid_file_type,
2728 parse_failed,
2829 unexpected_eof
1616
1717 #include "llvm/ADT/ArrayRef.h"
1818 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/Triple.h"
1920 #include "llvm/Object/MachOFormat.h"
2021 #include "llvm/Object/ObjectFile.h"
2122 #include "llvm/Support/MachO.h"
195196 bool is64Bit() const;
196197 void ReadULEB128s(uint64_t Index, SmallVectorImpl &Out) const;
197198
199 static Triple::ArchType getArch(uint32_t CPUType);
200
198201 static bool classof(const Binary *v) {
199202 return v->isMachO();
200203 }
9494 enum StructureSizes {
9595 Header32Size = 28,
9696 Header64Size = 32,
97 FatHeaderSize = 8,
98 FatArchHeaderSize = 20,
9799 SegmentLoadCommand32Size = 56,
98100 SegmentLoadCommand64Size = 72,
99101 Section32Size = 68,
127129 /// \brief Extended header for 64-bit object files.
128130 struct Header64Ext {
129131 uint32_t Reserved;
132 };
133
134 /// \brief Header for universal object files.
135 struct FatHeader {
136 uint32_t Magic;
137 uint32_t NumFatArch;
138 };
139
140 /// \brief Header for a single-architecture object file in a
141 /// universal binary.
142 struct FatArchHeader {
143 uint32_t CPUType;
144 uint32_t CPUSubtype;
145 uint32_t Offset;
146 uint32_t Size;
147 uint32_t Align;
130148 };
131149
132150 // See .
0 //===- MachOUniversal.h - Mach-O universal binaries -------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file declares Mach-O fat/universal binaries.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_OBJECT_MACHOUNIVERSAL_H
14 #define LLVM_OBJECT_MACHOUNIVERSAL_H
15
16 #include "llvm/ADT/OwningPtr.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/ADT/Triple.h"
19 #include "llvm/Object/Binary.h"
20 #include "llvm/Object/MachOFormat.h"
21
22 namespace llvm {
23 namespace object {
24
25 class ObjectFile;
26
27 class MachOUniversalBinary : public Binary {
28 virtual void anchor();
29
30 uint32_t NumberOfObjects;
31 public:
32 class ObjectForArch {
33 const MachOUniversalBinary *Parent;
34 /// \brief Index of object in the universal binary.
35 uint32_t Index;
36 /// \brief Descriptor of the object.
37 macho::FatArchHeader Header;
38
39 public:
40 ObjectForArch(const MachOUniversalBinary *Parent, uint32_t Index);
41
42 void clear() {
43 Parent = 0;
44 Index = 0;
45 }
46
47 bool operator==(const ObjectForArch &Other) const {
48 return (Parent == Other.Parent) && (Index == Other.Index);
49 }
50
51 ObjectForArch getNext() const { return ObjectForArch(Parent, Index + 1); }
52 uint32_t getCPUType() const { return Header.CPUType; }
53
54 error_code getAsObjectFile(OwningPtr &Result) const;
55 };
56
57 class object_iterator {
58 ObjectForArch Obj;
59 public:
60 object_iterator(const ObjectForArch &Obj) : Obj(Obj) {}
61 const ObjectForArch* operator->() const {
62 return &Obj;
63 }
64
65 bool operator==(const object_iterator &Other) const {
66 return Obj == Other.Obj;
67 }
68 bool operator!=(const object_iterator &Other) const {
69 return !(*this == Other);
70 }
71
72 object_iterator& operator++() { // Preincrement
73 Obj = Obj.getNext();
74 return *this;
75 }
76 };
77
78 MachOUniversalBinary(MemoryBuffer *Source, error_code &ec);
79
80 object_iterator begin_objects() const {
81 return ObjectForArch(this, 0);
82 }
83 object_iterator end_objects() const {
84 return ObjectForArch(0, 0);
85 }
86
87 uint32_t getNumberOfObjects() const { return NumberOfObjects; }
88
89 // Cast methods.
90 static inline bool classof(Binary const *V) {
91 return V->isMachOUniversalBinary();
92 }
93
94 error_code getObjectForArch(Triple::ArchType Arch,
95 OwningPtr &Result) const;
96 };
97
98 }
99 }
100
101 #endif
198198 macho_bundle, ///< Mach-O Bundle file
199199 macho_dynamically_linked_shared_lib_stub, ///< Mach-O Shared lib stub
200200 macho_dsym_companion, ///< Mach-O dSYM companion file
201 macho_universal_binary, ///< Mach-O universal binary
201202 coff_object, ///< COFF object file
202203 pecoff_executable ///< PECOFF executable file
203204 };
526526 case sys::fs::file_magic::archive:
527527 case sys::fs::file_magic::coff_object:
528528 case sys::fs::file_magic::pecoff_executable:
529 case sys::fs::file_magic::macho_universal_binary:
529530 report_fatal_error("Incompatible object format!");
530531 }
531532 } else {
1919 // Include headers for createBinary.
2020 #include "llvm/Object/Archive.h"
2121 #include "llvm/Object/COFF.h"
22 #include "llvm/Object/MachOUniversal.h"
2223 #include "llvm/Object/ObjectFile.h"
2324
2425 using namespace llvm;
8182 Result.swap(ret);
8283 return object_error::success;
8384 }
85 case sys::fs::file_magic::macho_universal_binary: {
86 OwningPtr ret(new MachOUniversalBinary(scopedSource.take(), ec));
87 if (ec) return ec;
88 Result.swap(ret);
89 return object_error::success;
90 }
8491 case sys::fs::file_magic::coff_object:
8592 case sys::fs::file_magic::pecoff_executable: {
8693 OwningPtr ret(
66 ELFYAML.cpp
77 Error.cpp
88 MachOObjectFile.cpp
9 MachOUniversal.cpp
910 Object.cpp
1011 ObjectFile.cpp
1112 YAML.cpp
3333 object_error::Impl E = static_cast(ev);
3434 switch (E) {
3535 case object_error::success: return "Success";
36 case object_error::arch_not_found:
37 return "No object file for requested architecture";
3638 case object_error::invalid_file_type:
3739 return "The file was not recognized as a valid object file";
3840 case object_error::parse_failed:
12961296 }
12971297 }
12981298
1299 unsigned MachOObjectFile::getArch() const {
1300 switch (getCPUType(this)) {
1299 Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType) {
1300 switch (CPUType) {
13011301 case llvm::MachO::CPUTypeI386:
13021302 return Triple::x86;
13031303 case llvm::MachO::CPUTypeX86_64:
13111311 default:
13121312 return Triple::UnknownArch;
13131313 }
1314 }
1315
1316 unsigned MachOObjectFile::getArch() const {
1317 return getArch(getCPUType(this));
13141318 }
13151319
13161320 StringRef MachOObjectFile::getLoadName() const {
0 //===- MachOUniversal.cpp - Mach-O universal binary -------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the MachOUniversalBinary class.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "llvm/Object/MachOUniversal.h"
14
15 #include "llvm/Object/MachO.h"
16 #include "llvm/Object/ObjectFile.h"
17 #include "llvm/Support/Casting.h"
18 #include "llvm/Support/Host.h"
19 #include "llvm/Support/MemoryBuffer.h"
20
21 using namespace llvm;
22 using namespace object;
23
24 template
25 static void SwapValue(T &Value) {
26 Value = sys::SwapByteOrder(Value);
27 }
28
29 template
30 static void SwapStruct(T &Value);
31
32 template<>
33 void SwapStruct(macho::FatHeader &H) {
34 SwapValue(H.Magic);
35 SwapValue(H.NumFatArch);
36 }
37
38 template<>
39 void SwapStruct(macho::FatArchHeader &H) {
40 SwapValue(H.CPUType);
41 SwapValue(H.CPUSubtype);
42 SwapValue(H.Offset);
43 SwapValue(H.Size);
44 SwapValue(H.Align);
45 }
46
47 template
48 static T getUniversalBinaryStruct(const char *Ptr) {
49 T Res;
50 memcpy(&Res, Ptr, sizeof(T));
51 // Universal binary headers have big-endian byte order.
52 if (sys::IsLittleEndianHost)
53 SwapStruct(Res);
54 return Res;
55 }
56
57 MachOUniversalBinary::ObjectForArch::ObjectForArch(
58 const MachOUniversalBinary *Parent, uint32_t Index)
59 : Parent(Parent), Index(Index) {
60 if (Parent == 0 || Index > Parent->getNumberOfObjects()) {
61 clear();
62 } else {
63 // Parse object header.
64 StringRef ParentData = Parent->getData();
65 const char *HeaderPos = ParentData.begin() + macho::FatHeaderSize +
66 Index * macho::FatArchHeaderSize;
67 Header = getUniversalBinaryStruct(HeaderPos);
68 if (ParentData.size() < Header.Offset + Header.Size) {
69 clear();
70 }
71 }
72 }
73
74 error_code MachOUniversalBinary::ObjectForArch::getAsObjectFile(
75 OwningPtr &Result) const {
76 if (Parent) {
77 StringRef ParentData = Parent->getData();
78 StringRef ObjectData = ParentData.substr(Header.Offset, Header.Size);
79 Twine ObjectName =
80 Twine(Parent->getFileName()) + ":" +
81 Triple::getArchTypeName(MachOObjectFile::getArch(Header.CPUType));
82 MemoryBuffer *ObjBuffer = MemoryBuffer::getMemBuffer(
83 ObjectData, ObjectName.str(), false);
84 if (ObjectFile *Obj = ObjectFile::createMachOObjectFile(ObjBuffer)) {
85 Result.reset(Obj);
86 return object_error::success;
87 }
88 }
89 return object_error::parse_failed;
90 }
91
92 void MachOUniversalBinary::anchor() { }
93
94 MachOUniversalBinary::MachOUniversalBinary(MemoryBuffer *Source,
95 error_code &ec)
96 : Binary(Binary::ID_MachOUniversalBinary, Source),
97 NumberOfObjects(0) {
98 if (Source->getBufferSize() < macho::FatHeaderSize) {
99 ec = object_error::invalid_file_type;
100 return;
101 }
102 // Check for magic value and sufficient header size.
103 StringRef Buf = getData();
104 macho::FatHeader H = getUniversalBinaryStruct(Buf.begin());
105 NumberOfObjects = H.NumFatArch;
106 uint32_t MinSize = macho::FatHeaderSize +
107 macho::FatArchHeaderSize * NumberOfObjects;
108 if (H.Magic != macho::HM_Universal || Buf.size() < MinSize) {
109 ec = object_error::parse_failed;
110 return;
111 }
112 ec = object_error::success;
113 }
114
115 static bool getCTMForArch(Triple::ArchType Arch, mach::CPUTypeMachine &CTM) {
116 switch (Arch) {
117 case Triple::x86: CTM = mach::CTM_i386; return true;
118 case Triple::x86_64: CTM = mach::CTM_x86_64; return true;
119 case Triple::arm: CTM = mach::CTM_ARM; return true;
120 case Triple::sparc: CTM = mach::CTM_SPARC; return true;
121 case Triple::ppc: CTM = mach::CTM_PowerPC; return true;
122 case Triple::ppc64: CTM = mach::CTM_PowerPC64; return true;
123 default: return false;
124 }
125 }
126
127 error_code
128 MachOUniversalBinary::getObjectForArch(Triple::ArchType Arch,
129 OwningPtr &Result) const {
130 mach::CPUTypeMachine CTM;
131 if (!getCTMForArch(Arch, CTM))
132 return object_error::arch_not_found;
133 for (object_iterator I = begin_objects(), E = end_objects(); I != E; ++I) {
134 if (I->getCPUType() == static_cast(CTM))
135 return I->getAsObjectFile(Result);
136 }
137 return object_error::arch_not_found;
138 }
4545 case sys::fs::file_magic::unknown:
4646 case sys::fs::file_magic::bitcode:
4747 case sys::fs::file_magic::archive:
48 case sys::fs::file_magic::macho_universal_binary:
4849 return 0;
4950 case sys::fs::file_magic::elf_relocatable:
5051 case sys::fs::file_magic::elf_executable:
809809 // This is complicated by an overlap with Java class files.
810810 // See the Mach-O section in /usr/share/file/magic for details.
811811 if (Magic.size() >= 8 && Magic[7] < 43)
812 // FIXME: Universal Binary of any type.
813 return file_magic::macho_dynamically_linked_shared_lib;
812 return file_magic::macho_universal_binary;
814813 }
815814 break;
816815
0 RUN: llvm-nm %p/Inputs/macho-universal.x86_64.i386 | FileCheck %s
1
2 CHECK: macho-universal.x86_64.i386:x86_64
3 CHECK: main
4 CHECK: macho-universal.x86_64.i386:i386
5 CHECK: main
1919 #include "llvm/Bitcode/ReaderWriter.h"
2020 #include "llvm/IR/Module.h"
2121 #include "llvm/Object/Archive.h"
22 #include "llvm/Object/MachOUniversal.h"
2223 #include "llvm/Object/ObjectFile.h"
2324 #include "llvm/Support/CommandLine.h"
2425 #include "llvm/Support/FileSystem.h"
401402 }
402403 }
403404 }
405 } else if (magic == sys::fs::file_magic::macho_universal_binary) {
406 OwningPtr Bin;
407 if (error(object::createBinary(Buffer.take(), Bin), Filename))
408 return;
409
410 object::MachOUniversalBinary *UB =
411 cast(Bin.get());
412 for (object::MachOUniversalBinary::object_iterator
413 I = UB->begin_objects(),
414 E = UB->end_objects();
415 I != E; ++I) {
416 OwningPtr Obj;
417 if (!I->getAsObjectFile(Obj)) {
418 outs() << Obj->getFileName() << ":\n";
419 DumpSymbolNamesFromObject(Obj.get());
420 }
421 }
404422 } else if (magic.is_object()) {
405423 OwningPtr obj;
406424 if (error(object::createBinary(Buffer.take(), obj), Filename))