Skip to content

[ORC] Add LoadRelocatableObject: universal binary support, clearer er… #104406

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,9 +319,6 @@ class StaticLibraryDefinitionGenerator : public DefinitionGenerator {
Error &Err);
Error buildObjectFilesMap();

static Expected<std::pair<size_t, size_t>>
getSliceRangeForArch(object::MachOUniversalBinary &UB, const Triple &TT);

ObjectLayer &L;
GetObjectFileInterface GetObjFileInterface;
std::set<std::string> ImportedDynamicLibraries;
Expand Down
36 changes: 36 additions & 0 deletions llvm/include/llvm/ExecutionEngine/Orc/LoadRelocatableObject.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//===---- LoadRelocatableObject.h - Load relocatable objects ----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// A wrapper for `MemoryBuffer::getFile` / `MemoryBuffer::getFileSlice` that:
//
// 1. Adds file paths to errors by default.
// 2. Checks architecture compatibility up-front.
// 3. Handles MachO universal binaries, returning the MemoryBuffer for the
// requested slice only.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_EXECUTIONENGINE_ORC_LOADRELOCATABLEOBJECT_H
#define LLVM_EXECUTIONENGINE_ORC_LOADRELOCATABLEOBJECT_H

#include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/TargetParser/Triple.h"

namespace llvm {
namespace orc {

// Load an object file compatible with the given triple (if given) from the
// given path. May return a file slice if the path contains a universal binary.
Expected<std::unique_ptr<MemoryBuffer>> loadRelocatableObject(StringRef Path,
const Triple &TT);

} // End namespace orc
} // End namespace llvm

#endif // LLVM_EXECUTIONENGINE_ORC_LOADRELOCATABLEOBJECT_H
63 changes: 63 additions & 0 deletions llvm/include/llvm/ExecutionEngine/Orc/MachO.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//===------------- MachO.h - MachO format utilities -------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Contains utilities for load MachO relocatable object files.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_EXECUTIONENGINE_ORC_MACHO_H
#define LLVM_EXECUTIONENGINE_ORC_MACHO_H

#include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/TargetParser/Triple.h"

namespace llvm {

namespace object {

class MachOUniversalBinary;

} // namespace object

namespace orc {

/// Check that the given buffer contains a MachO object file compatible with the
/// given triple.
/// ObjIsSlice should be set to true if Obj is a slice of a universal binary
/// (that fact will then be reported in the error messages).
Expected<std::unique_ptr<MemoryBuffer>>
checkMachORelocatableObject(std::unique_ptr<MemoryBuffer> Obj, const Triple &TT,
bool ObjIsSlice);

/// Load a relocatable object compatible with TT from Path.
/// If Path is a universal binary, this function will return a buffer for the
/// slice compatible with Triple (if one is present).
Expected<std::unique_ptr<MemoryBuffer>>
loadMachORelocatableObject(StringRef Path, const Triple &TT);

/// Load a compatible relocatable object (if available) from a MachO universal
/// binary.
Expected<std::unique_ptr<MemoryBuffer>>
loadMachORelocatableObjectFromUniversalBinary(
StringRef UBPath, std::unique_ptr<MemoryBuffer> UBBuf, const Triple &TT);

/// Utility for identifying the file-slice compatible with TT in a universal
/// binary.
Expected<std::pair<size_t, size_t>>
getMachOSliceRangeForTriple(object::MachOUniversalBinary &UB, const Triple &TT);

/// Utility for identifying the file-slice compatible with TT in a universal
/// binary.
Expected<std::pair<size_t, size_t>>
getMachOSliceRangeForTriple(MemoryBufferRef UBBuf, const Triple &TT);

} // namespace orc
} // namespace llvm

#endif // LLVM_EXECUTIONENGINE_ORC_MACHO_H
2 changes: 2 additions & 0 deletions llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ add_llvm_component_library(LLVMOrcJIT
JITTargetMachineBuilder.cpp
LazyReexports.cpp
Layer.cpp
LoadRelocatableObject.cpp
LookupAndRecordAddrs.cpp
LLJIT.cpp
MachO.cpp
MachOPlatform.cpp
MapperJITLinkMemoryManager.cpp
MemoryMapper.cpp
Expand Down
26 changes: 3 additions & 23 deletions llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
#include "llvm/ExecutionEngine/JITLink/x86_64.h"
#include "llvm/ExecutionEngine/Orc/Layer.h"
#include "llvm/ExecutionEngine/Orc/MachO.h"
#include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
Expand Down Expand Up @@ -295,7 +296,7 @@ StaticLibraryDefinitionGenerator::Load(

const auto &TT = L.getExecutionSession().getTargetTriple();

auto SliceRange = getSliceRangeForArch(*UB, TT);
auto SliceRange = getMachOSliceRangeForTriple(*UB, TT);
if (!SliceRange)
return SliceRange.takeError();

Expand Down Expand Up @@ -358,7 +359,7 @@ StaticLibraryDefinitionGenerator::Create(

const auto &TT = L.getExecutionSession().getTargetTriple();

auto SliceRange = getSliceRangeForArch(*UB, TT);
auto SliceRange = getMachOSliceRangeForTriple(*UB, TT);
if (!SliceRange)
return SliceRange.takeError();

Expand Down Expand Up @@ -460,27 +461,6 @@ Error StaticLibraryDefinitionGenerator::buildObjectFilesMap() {
return Error::success();
}

Expected<std::pair<size_t, size_t>>
StaticLibraryDefinitionGenerator::getSliceRangeForArch(
object::MachOUniversalBinary &UB, const Triple &TT) {

for (const auto &Obj : UB.objects()) {
auto ObjTT = Obj.getTriple();
if (ObjTT.getArch() == TT.getArch() &&
ObjTT.getSubArch() == TT.getSubArch() &&
(TT.getVendor() == Triple::UnknownVendor ||
ObjTT.getVendor() == TT.getVendor())) {
// We found a match. Return the range for the slice.
return std::make_pair(Obj.getOffset(), Obj.getSize());
}
}

return make_error<StringError>(Twine("Universal binary ") + UB.getFileName() +
" does not contain a slice for " +
TT.str(),
inconvertibleErrorCode());
}

StaticLibraryDefinitionGenerator::StaticLibraryDefinitionGenerator(
ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer,
std::unique_ptr<object::Archive> Archive,
Expand Down
69 changes: 69 additions & 0 deletions llvm/lib/ExecutionEngine/Orc/LoadRelocatableObject.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//===----- LoadRelocatableObject.cpp -- Load relocatable object files -----===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/ExecutionEngine/Orc/LoadRelocatableObject.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/ExecutionEngine/Orc/MachO.h"

#define DEBUG_TYPE "orc"

namespace llvm {
namespace orc {

static Expected<std::unique_ptr<MemoryBuffer>>
checkCOFFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj,
const Triple &TT) {
// TODO: Actually check the architecture of the file.
return std::move(Obj);
}

static Expected<std::unique_ptr<MemoryBuffer>>
checkELFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj, const Triple &TT) {
// TODO: Actually check the architecture of the file.
return std::move(Obj);
}

Expected<std::unique_ptr<MemoryBuffer>>
loadRelocatableObject(StringRef Path, const Triple &TT) {
auto Buf = MemoryBuffer::getFile(Path);
if (!Buf)
return createFileError(Path, Buf.getError());

std::optional<Triple::ObjectFormatType> RequireFormat;
if (TT.getObjectFormat() != Triple::UnknownObjectFormat)
RequireFormat = TT.getObjectFormat();

switch (identify_magic((*Buf)->getBuffer())) {
case file_magic::coff_object:
if (!RequireFormat || *RequireFormat == Triple::COFF)
return checkCOFFRelocatableObject(std::move(*Buf), TT);
break;
case file_magic::elf_relocatable:
if (!RequireFormat || *RequireFormat == Triple::ELF)
return checkELFRelocatableObject(std::move(*Buf), TT);
break;
case file_magic::macho_object:
if (!RequireFormat || *RequireFormat == Triple::MachO)
return checkMachORelocatableObject(std::move(*Buf), TT, false);
break;
case file_magic::macho_universal_binary:
if (!RequireFormat || *RequireFormat == Triple::MachO)
return loadMachORelocatableObjectFromUniversalBinary(Path,
std::move(*Buf), TT);
break;
default:
break;
}
return make_error<StringError>(
Path + " does not contain a relocatable object file compatible with " +
TT.str(),
inconvertibleErrorCode());
}

} // End namespace orc.
} // End namespace llvm.
Loading
Loading