1 //===----------------- MachO.cpp - MachO format utilities -----------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ExecutionEngine/Orc/MachO.h"
11 #include "llvm/ADT/ScopeExit.h"
12 #include "llvm/BinaryFormat/MachO.h"
13 #include "llvm/ExecutionEngine/Orc/Layer.h"
14 #include "llvm/Object/MachOUniversal.h"
15 #include "llvm/Support/FileSystem.h"
17 #define DEBUG_TYPE "orc"
22 static std::string
objDesc(const MemoryBufferRef
&Obj
, const Triple
&TT
,
26 Desc
+= (TT
.getArchName() + " slice of universal binary").str();
27 Desc
+= Obj
.getBufferIdentifier();
31 template <typename HeaderType
>
32 static Error
checkMachORelocatableObject(MemoryBufferRef Obj
,
33 bool SwapEndianness
, const Triple
&TT
,
35 StringRef Data
= Obj
.getBuffer();
38 memcpy(&Hdr
, Data
.data(), sizeof(HeaderType
));
43 if (Hdr
.filetype
!= MachO::MH_OBJECT
)
44 return make_error
<StringError
>(objDesc(Obj
, TT
, ObjIsSlice
) +
45 " is not a MachO relocatable object",
46 inconvertibleErrorCode());
48 auto ObjArch
= object::MachOObjectFile::getArch(Hdr
.cputype
, Hdr
.cpusubtype
);
49 if (ObjArch
!= TT
.getArch())
50 return make_error
<StringError
>(
51 objDesc(Obj
, TT
, ObjIsSlice
) + Triple::getArchTypeName(ObjArch
) +
52 ", cannot be loaded into " + TT
.str() + " process",
53 inconvertibleErrorCode());
55 return Error::success();
58 Error
checkMachORelocatableObject(MemoryBufferRef Obj
, const Triple
&TT
,
60 StringRef Data
= Obj
.getBuffer();
63 return make_error
<StringError
>(
64 objDesc(Obj
, TT
, ObjIsSlice
) +
65 " is not a valid MachO relocatable object file (truncated header)",
66 inconvertibleErrorCode());
69 memcpy(&Magic
, Data
.data(), sizeof(uint32_t));
74 return checkMachORelocatableObject
<MachO::mach_header
>(
75 std::move(Obj
), Magic
== MachO::MH_CIGAM
, TT
, ObjIsSlice
);
76 case MachO::MH_MAGIC_64
:
77 case MachO::MH_CIGAM_64
:
78 return checkMachORelocatableObject
<MachO::mach_header_64
>(
79 std::move(Obj
), Magic
== MachO::MH_CIGAM_64
, TT
, ObjIsSlice
);
81 return make_error
<StringError
>(
82 objDesc(Obj
, TT
, ObjIsSlice
) +
83 " is not a valid MachO relocatable object (bad magic value)",
84 inconvertibleErrorCode());
88 Expected
<std::unique_ptr
<MemoryBuffer
>>
89 checkMachORelocatableObject(std::unique_ptr
<MemoryBuffer
> Obj
, const Triple
&TT
,
92 checkMachORelocatableObject(Obj
->getMemBufferRef(), TT
, ObjIsSlice
))
93 return std::move(Err
);
94 return std::move(Obj
);
97 Expected
<std::pair
<std::unique_ptr
<MemoryBuffer
>, LinkableFileKind
>>
98 loadMachORelocatableObject(StringRef Path
, const Triple
&TT
, LoadArchives LA
,
99 std::optional
<StringRef
> IdentifierOverride
) {
100 assert((TT
.getObjectFormat() == Triple::UnknownObjectFormat
||
101 TT
.getObjectFormat() == Triple::MachO
) &&
102 "TT must specify MachO or Unknown object format");
104 if (!IdentifierOverride
)
105 IdentifierOverride
= Path
;
107 Expected
<sys::fs::file_t
> FDOrErr
=
108 sys::fs::openNativeFileForRead(Path
, sys::fs::OF_None
);
110 return createFileError(Path
, FDOrErr
.takeError());
111 sys::fs::file_t FD
= *FDOrErr
;
112 auto CloseFile
= make_scope_exit([&]() { sys::fs::closeFile(FD
); });
115 MemoryBuffer::getOpenFile(FD
, *IdentifierOverride
, /*FileSize=*/-1);
117 return make_error
<StringError
>(
118 StringRef("Could not load MachO object at path ") + Path
,
121 switch (identify_magic((*Buf
)->getBuffer())) {
122 case file_magic::macho_object
: {
123 auto CheckedObj
= checkMachORelocatableObject(std::move(*Buf
), TT
, false);
125 return CheckedObj
.takeError();
126 return std::make_pair(std::move(*CheckedObj
),
127 LinkableFileKind::RelocatableObject
);
129 case file_magic::macho_universal_binary
:
130 return loadLinkableSliceFromMachOUniversalBinary(FD
, std::move(*Buf
), TT
,
131 LoadArchives::Never
, Path
,
132 *IdentifierOverride
);
134 return make_error
<StringError
>(
135 Path
+ " does not contain a relocatable object file compatible with " +
137 inconvertibleErrorCode());
141 Expected
<std::pair
<std::unique_ptr
<MemoryBuffer
>, LinkableFileKind
>>
142 loadLinkableSliceFromMachOUniversalBinary(sys::fs::file_t FD
,
143 std::unique_ptr
<MemoryBuffer
> UBBuf
,
144 const Triple
&TT
, LoadArchives LA
,
146 StringRef Identifier
) {
149 object::MachOUniversalBinary::create(UBBuf
->getMemBufferRef());
151 return UniversalBin
.takeError();
153 auto SliceRange
= getMachOSliceRangeForTriple(**UniversalBin
, TT
);
155 return SliceRange
.takeError();
157 auto Buf
= MemoryBuffer::getOpenFileSlice(FD
, Identifier
, SliceRange
->second
,
160 return make_error
<StringError
>(
161 "Could not load " + TT
.getArchName() +
162 " slice of MachO universal binary at path " + UBPath
,
165 switch (identify_magic((*Buf
)->getBuffer())) {
166 case file_magic::archive
:
167 if (LA
!= LoadArchives::Never
)
168 return std::make_pair(std::move(*Buf
), LinkableFileKind::Archive
);
170 case file_magic::macho_object
: {
171 if (LA
!= LoadArchives::Required
) {
172 auto CheckedObj
= checkMachORelocatableObject(std::move(*Buf
), TT
, true);
174 return CheckedObj
.takeError();
175 return std::make_pair(std::move(*CheckedObj
),
176 LinkableFileKind::RelocatableObject
);
186 case LoadArchives::Never
:
187 return "a mach-o relocatable object file";
188 case LoadArchives::Allowed
:
189 return "a mach-o relocatable object file or archive";
190 case LoadArchives::Required
:
193 llvm_unreachable("Unknown LoadArchives enum");
196 return make_error
<StringError
>(TT
.getArchName() + " slice of " + UBPath
+
197 " does not contain " + FT(),
198 inconvertibleErrorCode());
201 Expected
<std::pair
<size_t, size_t>>
202 getMachOSliceRangeForTriple(object::MachOUniversalBinary
&UB
,
205 for (const auto &Obj
: UB
.objects()) {
206 auto ObjTT
= Obj
.getTriple();
207 if (ObjTT
.getArch() == TT
.getArch() &&
208 ObjTT
.getSubArch() == TT
.getSubArch() &&
209 (TT
.getVendor() == Triple::UnknownVendor
||
210 ObjTT
.getVendor() == TT
.getVendor())) {
211 // We found a match. Return the range for the slice.
212 return std::make_pair(Obj
.getOffset(), Obj
.getSize());
216 return make_error
<StringError
>(Twine("Universal binary ") + UB
.getFileName() +
217 " does not contain a slice for " +
219 inconvertibleErrorCode());
222 Expected
<std::pair
<size_t, size_t>>
223 getMachOSliceRangeForTriple(MemoryBufferRef UBBuf
, const Triple
&TT
) {
225 auto UB
= object::MachOUniversalBinary::create(UBBuf
);
227 return UB
.takeError();
229 return getMachOSliceRangeForTriple(**UB
, TT
);
232 Error
ForceLoadMachOArchiveMembers::operator()(MemoryBufferRef MemberBuf
) {
234 return L
.add(JD
, MemoryBuffer::getMemBuffer(MemberBuf
));
236 // We need to check whether this archive member contains any Objective-C
237 // or Swift metadata.
239 auto Obj
= object::ObjectFile::createObjectFile(MemberBuf
);
241 // We silently ignore invalid files.
242 consumeError(Obj
.takeError());
243 return Error::success();
246 if (auto *MachOObj
= dyn_cast
<object::MachOObjectFile
>(&**Obj
)) {
247 // Load the object if any recognized special section is present.
248 for (auto Sec
: MachOObj
->sections()) {
250 MachOObj
->getSectionFinalSegmentName(Sec
.getRawDataRefImpl());
251 if (auto SecName
= Sec
.getName()) {
252 if (*SecName
== "__objc_classlist" || *SecName
== "__objc_protolist" ||
253 *SecName
== "__objc_clsrolist" || *SecName
== "__objc_catlist" ||
254 *SecName
== "__objc_catlist2" || *SecName
== "__objc_nlcatlist" ||
255 (SegName
== "__TEXT" && (*SecName
).starts_with("__swift") &&
256 *SecName
!= "__swift_modhash"))
257 return L
.add(JD
, MemoryBuffer::getMemBuffer(MemberBuf
));
259 return SecName
.takeError();
263 return Error::success();
266 } // End namespace orc.
267 } // End namespace llvm.