Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MachO.cpp
213799 views
//===----------------- MachO.cpp - MachO format utilities -----------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/ExecutionEngine/Orc/MachO.h"910#include "llvm/ADT/ScopeExit.h"11#include "llvm/BinaryFormat/MachO.h"12#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"13#include "llvm/ExecutionEngine/Orc/Layer.h"14#include "llvm/Object/MachOUniversal.h"15#include "llvm/Support/FileSystem.h"1617#define DEBUG_TYPE "orc"1819namespace llvm {20namespace orc {2122static std::string objDesc(const MemoryBufferRef &Obj, const Triple &TT,23bool ObjIsSlice) {24std::string Desc;25if (ObjIsSlice)26Desc += (TT.getArchName() + " slice of universal binary").str();27Desc += Obj.getBufferIdentifier();28return Desc;29}3031template <typename HeaderType>32static Error checkMachORelocatableObject(MemoryBufferRef Obj,33bool SwapEndianness, const Triple &TT,34bool ObjIsSlice) {35StringRef Data = Obj.getBuffer();3637HeaderType Hdr;38memcpy(&Hdr, Data.data(), sizeof(HeaderType));3940if (SwapEndianness)41swapStruct(Hdr);4243if (Hdr.filetype != MachO::MH_OBJECT)44return make_error<StringError>(objDesc(Obj, TT, ObjIsSlice) +45" is not a MachO relocatable object",46inconvertibleErrorCode());4748auto ObjArch = object::MachOObjectFile::getArch(Hdr.cputype, Hdr.cpusubtype);49if (ObjArch != TT.getArch())50return make_error<StringError>(51objDesc(Obj, TT, ObjIsSlice) + Triple::getArchTypeName(ObjArch) +52", cannot be loaded into " + TT.str() + " process",53inconvertibleErrorCode());5455return Error::success();56}5758Error checkMachORelocatableObject(MemoryBufferRef Obj, const Triple &TT,59bool ObjIsSlice) {60StringRef Data = Obj.getBuffer();6162if (Data.size() < 4)63return make_error<StringError>(64objDesc(Obj, TT, ObjIsSlice) +65" is not a valid MachO relocatable object file (truncated header)",66inconvertibleErrorCode());6768uint32_t Magic;69memcpy(&Magic, Data.data(), sizeof(uint32_t));7071switch (Magic) {72case MachO::MH_MAGIC:73case MachO::MH_CIGAM:74return checkMachORelocatableObject<MachO::mach_header>(75std::move(Obj), Magic == MachO::MH_CIGAM, TT, ObjIsSlice);76case MachO::MH_MAGIC_64:77case MachO::MH_CIGAM_64:78return checkMachORelocatableObject<MachO::mach_header_64>(79std::move(Obj), Magic == MachO::MH_CIGAM_64, TT, ObjIsSlice);80default:81return make_error<StringError>(82objDesc(Obj, TT, ObjIsSlice) +83" is not a valid MachO relocatable object (bad magic value)",84inconvertibleErrorCode());85}86}8788Expected<std::unique_ptr<MemoryBuffer>>89checkMachORelocatableObject(std::unique_ptr<MemoryBuffer> Obj, const Triple &TT,90bool ObjIsSlice) {91if (auto Err =92checkMachORelocatableObject(Obj->getMemBufferRef(), TT, ObjIsSlice))93return std::move(Err);94return std::move(Obj);95}9697Expected<std::pair<std::unique_ptr<MemoryBuffer>, LinkableFileKind>>98loadMachORelocatableObject(StringRef Path, const Triple &TT, LoadArchives LA,99std::optional<StringRef> IdentifierOverride) {100assert((TT.getObjectFormat() == Triple::UnknownObjectFormat ||101TT.getObjectFormat() == Triple::MachO) &&102"TT must specify MachO or Unknown object format");103104if (!IdentifierOverride)105IdentifierOverride = Path;106107Expected<sys::fs::file_t> FDOrErr =108sys::fs::openNativeFileForRead(Path, sys::fs::OF_None);109if (!FDOrErr)110return createFileError(Path, FDOrErr.takeError());111sys::fs::file_t FD = *FDOrErr;112auto CloseFile = make_scope_exit([&]() { sys::fs::closeFile(FD); });113114auto Buf =115MemoryBuffer::getOpenFile(FD, *IdentifierOverride, /*FileSize=*/-1);116if (!Buf)117return make_error<StringError>(118StringRef("Could not load MachO object at path ") + Path,119Buf.getError());120121switch (identify_magic((*Buf)->getBuffer())) {122case file_magic::macho_object: {123auto CheckedObj = checkMachORelocatableObject(std::move(*Buf), TT, false);124if (!CheckedObj)125return CheckedObj.takeError();126return std::make_pair(std::move(*CheckedObj),127LinkableFileKind::RelocatableObject);128}129case file_magic::macho_universal_binary:130return loadLinkableSliceFromMachOUniversalBinary(FD, std::move(*Buf), TT,131LoadArchives::Never, Path,132*IdentifierOverride);133default:134return make_error<StringError>(135Path + " does not contain a relocatable object file compatible with " +136TT.str(),137inconvertibleErrorCode());138}139}140141Expected<std::pair<std::unique_ptr<MemoryBuffer>, LinkableFileKind>>142loadLinkableSliceFromMachOUniversalBinary(sys::fs::file_t FD,143std::unique_ptr<MemoryBuffer> UBBuf,144const Triple &TT, LoadArchives LA,145StringRef UBPath,146StringRef Identifier) {147148auto UniversalBin =149object::MachOUniversalBinary::create(UBBuf->getMemBufferRef());150if (!UniversalBin)151return UniversalBin.takeError();152153auto SliceRange = getMachOSliceRangeForTriple(**UniversalBin, TT);154if (!SliceRange)155return SliceRange.takeError();156157auto Buf = MemoryBuffer::getOpenFileSlice(FD, Identifier, SliceRange->second,158SliceRange->first);159if (!Buf)160return make_error<StringError>(161"Could not load " + TT.getArchName() +162" slice of MachO universal binary at path " + UBPath,163Buf.getError());164165switch (identify_magic((*Buf)->getBuffer())) {166case file_magic::archive:167if (LA != LoadArchives::Never)168return std::make_pair(std::move(*Buf), LinkableFileKind::Archive);169break;170case file_magic::macho_object: {171if (LA != LoadArchives::Required) {172auto CheckedObj = checkMachORelocatableObject(std::move(*Buf), TT, true);173if (!CheckedObj)174return CheckedObj.takeError();175return std::make_pair(std::move(*CheckedObj),176LinkableFileKind::RelocatableObject);177}178break;179}180default:181break;182}183184auto FT = [&] {185switch (LA) {186case LoadArchives::Never:187return "a mach-o relocatable object file";188case LoadArchives::Allowed:189return "a mach-o relocatable object file or archive";190case LoadArchives::Required:191return "an archive";192}193llvm_unreachable("Unknown LoadArchives enum");194};195196return make_error<StringError>(TT.getArchName() + " slice of " + UBPath +197" does not contain " + FT(),198inconvertibleErrorCode());199}200201Expected<std::pair<size_t, size_t>>202getMachOSliceRangeForTriple(object::MachOUniversalBinary &UB,203const Triple &TT) {204205for (const auto &Obj : UB.objects()) {206auto ObjTT = Obj.getTriple();207if (ObjTT.getArch() == TT.getArch() &&208ObjTT.getSubArch() == TT.getSubArch() &&209(TT.getVendor() == Triple::UnknownVendor ||210ObjTT.getVendor() == TT.getVendor())) {211// We found a match. Return the range for the slice.212return std::make_pair(Obj.getOffset(), Obj.getSize());213}214}215216return make_error<StringError>(Twine("Universal binary ") + UB.getFileName() +217" does not contain a slice for " +218TT.str(),219inconvertibleErrorCode());220}221222Expected<std::pair<size_t, size_t>>223getMachOSliceRangeForTriple(MemoryBufferRef UBBuf, const Triple &TT) {224225auto UB = object::MachOUniversalBinary::create(UBBuf);226if (!UB)227return UB.takeError();228229return getMachOSliceRangeForTriple(**UB, TT);230}231232Expected<bool> ForceLoadMachOArchiveMembers::operator()(233object::Archive &A, MemoryBufferRef MemberBuf, size_t Index) {234235auto LoadMember = [&]() {236return StaticLibraryDefinitionGenerator::createMemberBuffer(A, MemberBuf,237Index);238};239240if (!ObjCOnly) {241// If we're loading all files then just load the buffer immediately. Return242// false to indicate that there's no further loading to do here.243if (auto Err = L.add(JD, LoadMember()))244return Err;245return false;246}247248// We need to check whether this archive member contains any Objective-C249// or Swift metadata.250auto Obj = object::ObjectFile::createObjectFile(MemberBuf);251if (!Obj) {252// Invalid files are not loadable, but don't invalidate the archive.253consumeError(Obj.takeError());254return false;255}256257if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&**Obj)) {258// Load the object if any recognized special section is present.259for (auto Sec : MachOObj->sections()) {260auto SegName =261MachOObj->getSectionFinalSegmentName(Sec.getRawDataRefImpl());262if (auto SecName = Sec.getName()) {263if (*SecName == "__objc_classlist" || *SecName == "__objc_protolist" ||264*SecName == "__objc_clsrolist" || *SecName == "__objc_catlist" ||265*SecName == "__objc_catlist2" || *SecName == "__objc_nlcatlist" ||266(SegName == "__TEXT" && (*SecName).starts_with("__swift") &&267*SecName != "__swift_modhash")) {268if (auto Err = L.add(JD, LoadMember()))269return Err;270return false;271}272} else273return SecName.takeError();274}275}276277// This is an object file but we didn't load it, so return true to indicate278// that it's still loadable.279return true;280}281282} // End namespace orc.283} // End namespace llvm.284285286