Skip to content

Commit 3e1d4ec

Browse files
authored
[ORC] loadRelocatableObject: universal binary support, clearer errors (#104406)
ORC supports loading relocatable object files into a JIT'd process. The raw "add object file" API (ObjectLayer::add) accepts plain relocatable object files as llvm::MemoryBuffers only and does not check that the object file's format or architecture are compatible with the process that it will be linked in to. This API is flexible, but places the burden of error checking and universal binary support on clients. This commit introduces a new utility, loadRelocatableObject, that takes a path to load and a target triple and then: 1. If the path does not exist, returns a FileError containing the invalid path. 2. If the path points to a MachO universal binary, identifies and returns MemoryBuffer covering the slice that matches the given triple (checking that the slice really does contains a valid MachO relocatable object with a compatible arch). 3. If the path points to a regular relocatable object file, verifies that the format and architecture are compatible with the triple. Clients can use loadRelocatableObject in the common case of loading object files from disk to simplify their code. Note: Error checking for ELF and COFF is left as a FIXME. rdar://133653290
1 parent 039a86d commit 3e1d4ec

File tree

9 files changed

+379
-32
lines changed

9 files changed

+379
-32
lines changed

llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -319,9 +319,6 @@ class StaticLibraryDefinitionGenerator : public DefinitionGenerator {
319319
Error &Err);
320320
Error buildObjectFilesMap();
321321

322-
static Expected<std::pair<size_t, size_t>>
323-
getSliceRangeForArch(object::MachOUniversalBinary &UB, const Triple &TT);
324-
325322
ObjectLayer &L;
326323
GetObjectFileInterface GetObjFileInterface;
327324
std::set<std::string> ImportedDynamicLibraries;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===---- LoadRelocatableObject.h - Load relocatable objects ----*- C++ -*-===//
2+
//
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
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// A wrapper for `MemoryBuffer::getFile` / `MemoryBuffer::getFileSlice` that:
10+
//
11+
// 1. Adds file paths to errors by default.
12+
// 2. Checks architecture compatibility up-front.
13+
// 3. Handles MachO universal binaries, returning the MemoryBuffer for the
14+
// requested slice only.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef LLVM_EXECUTIONENGINE_ORC_LOADRELOCATABLEOBJECT_H
19+
#define LLVM_EXECUTIONENGINE_ORC_LOADRELOCATABLEOBJECT_H
20+
21+
#include "llvm/Support/Error.h"
22+
#include "llvm/Support/MemoryBuffer.h"
23+
#include "llvm/TargetParser/Triple.h"
24+
25+
namespace llvm {
26+
namespace orc {
27+
28+
// Load an object file compatible with the given triple (if given) from the
29+
// given path. May return a file slice if the path contains a universal binary.
30+
Expected<std::unique_ptr<MemoryBuffer>> loadRelocatableObject(StringRef Path,
31+
const Triple &TT);
32+
33+
} // End namespace orc
34+
} // End namespace llvm
35+
36+
#endif // LLVM_EXECUTIONENGINE_ORC_LOADRELOCATABLEOBJECT_H
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//===------------- MachO.h - MachO format utilities -------------*- C++ -*-===//
2+
//
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
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Contains utilities for load MachO relocatable object files.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_EXECUTIONENGINE_ORC_MACHO_H
14+
#define LLVM_EXECUTIONENGINE_ORC_MACHO_H
15+
16+
#include "llvm/Support/Error.h"
17+
#include "llvm/Support/MemoryBuffer.h"
18+
#include "llvm/TargetParser/Triple.h"
19+
20+
namespace llvm {
21+
22+
namespace object {
23+
24+
class MachOUniversalBinary;
25+
26+
} // namespace object
27+
28+
namespace orc {
29+
30+
/// Check that the given buffer contains a MachO object file compatible with the
31+
/// given triple.
32+
/// ObjIsSlice should be set to true if Obj is a slice of a universal binary
33+
/// (that fact will then be reported in the error messages).
34+
Expected<std::unique_ptr<MemoryBuffer>>
35+
checkMachORelocatableObject(std::unique_ptr<MemoryBuffer> Obj, const Triple &TT,
36+
bool ObjIsSlice);
37+
38+
/// Load a relocatable object compatible with TT from Path.
39+
/// If Path is a universal binary, this function will return a buffer for the
40+
/// slice compatible with Triple (if one is present).
41+
Expected<std::unique_ptr<MemoryBuffer>>
42+
loadMachORelocatableObject(StringRef Path, const Triple &TT);
43+
44+
/// Load a compatible relocatable object (if available) from a MachO universal
45+
/// binary.
46+
Expected<std::unique_ptr<MemoryBuffer>>
47+
loadMachORelocatableObjectFromUniversalBinary(
48+
StringRef UBPath, std::unique_ptr<MemoryBuffer> UBBuf, const Triple &TT);
49+
50+
/// Utility for identifying the file-slice compatible with TT in a universal
51+
/// binary.
52+
Expected<std::pair<size_t, size_t>>
53+
getMachOSliceRangeForTriple(object::MachOUniversalBinary &UB, const Triple &TT);
54+
55+
/// Utility for identifying the file-slice compatible with TT in a universal
56+
/// binary.
57+
Expected<std::pair<size_t, size_t>>
58+
getMachOSliceRangeForTriple(MemoryBufferRef UBBuf, const Triple &TT);
59+
60+
} // namespace orc
61+
} // namespace llvm
62+
63+
#endif // LLVM_EXECUTIONENGINE_ORC_MACHO_H

llvm/lib/ExecutionEngine/Orc/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ add_llvm_component_library(LLVMOrcJIT
2929
JITTargetMachineBuilder.cpp
3030
LazyReexports.cpp
3131
Layer.cpp
32+
LoadRelocatableObject.cpp
3233
LookupAndRecordAddrs.cpp
3334
LLJIT.cpp
35+
MachO.cpp
3436
MachOPlatform.cpp
3537
MapperJITLinkMemoryManager.cpp
3638
MemoryMapper.cpp

llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
1010
#include "llvm/ExecutionEngine/JITLink/x86_64.h"
1111
#include "llvm/ExecutionEngine/Orc/Layer.h"
12+
#include "llvm/ExecutionEngine/Orc/MachO.h"
1213
#include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h"
1314
#include "llvm/IR/Constants.h"
1415
#include "llvm/IR/Function.h"
@@ -295,7 +296,7 @@ StaticLibraryDefinitionGenerator::Load(
295296

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

298-
auto SliceRange = getSliceRangeForArch(*UB, TT);
299+
auto SliceRange = getMachOSliceRangeForTriple(*UB, TT);
299300
if (!SliceRange)
300301
return SliceRange.takeError();
301302

@@ -358,7 +359,7 @@ StaticLibraryDefinitionGenerator::Create(
358359

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

361-
auto SliceRange = getSliceRangeForArch(*UB, TT);
362+
auto SliceRange = getMachOSliceRangeForTriple(*UB, TT);
362363
if (!SliceRange)
363364
return SliceRange.takeError();
364365

@@ -460,27 +461,6 @@ Error StaticLibraryDefinitionGenerator::buildObjectFilesMap() {
460461
return Error::success();
461462
}
462463

463-
Expected<std::pair<size_t, size_t>>
464-
StaticLibraryDefinitionGenerator::getSliceRangeForArch(
465-
object::MachOUniversalBinary &UB, const Triple &TT) {
466-
467-
for (const auto &Obj : UB.objects()) {
468-
auto ObjTT = Obj.getTriple();
469-
if (ObjTT.getArch() == TT.getArch() &&
470-
ObjTT.getSubArch() == TT.getSubArch() &&
471-
(TT.getVendor() == Triple::UnknownVendor ||
472-
ObjTT.getVendor() == TT.getVendor())) {
473-
// We found a match. Return the range for the slice.
474-
return std::make_pair(Obj.getOffset(), Obj.getSize());
475-
}
476-
}
477-
478-
return make_error<StringError>(Twine("Universal binary ") + UB.getFileName() +
479-
" does not contain a slice for " +
480-
TT.str(),
481-
inconvertibleErrorCode());
482-
}
483-
484464
StaticLibraryDefinitionGenerator::StaticLibraryDefinitionGenerator(
485465
ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer,
486466
std::unique_ptr<object::Archive> Archive,
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//===----- LoadRelocatableObject.cpp -- Load relocatable object files -----===//
2+
//
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
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/ExecutionEngine/Orc/LoadRelocatableObject.h"
10+
#include "llvm/BinaryFormat/Magic.h"
11+
#include "llvm/ExecutionEngine/Orc/MachO.h"
12+
13+
#define DEBUG_TYPE "orc"
14+
15+
namespace llvm {
16+
namespace orc {
17+
18+
static Expected<std::unique_ptr<MemoryBuffer>>
19+
checkCOFFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj,
20+
const Triple &TT) {
21+
// TODO: Actually check the architecture of the file.
22+
return std::move(Obj);
23+
}
24+
25+
static Expected<std::unique_ptr<MemoryBuffer>>
26+
checkELFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj, const Triple &TT) {
27+
// TODO: Actually check the architecture of the file.
28+
return std::move(Obj);
29+
}
30+
31+
Expected<std::unique_ptr<MemoryBuffer>>
32+
loadRelocatableObject(StringRef Path, const Triple &TT) {
33+
auto Buf = MemoryBuffer::getFile(Path);
34+
if (!Buf)
35+
return createFileError(Path, Buf.getError());
36+
37+
std::optional<Triple::ObjectFormatType> RequireFormat;
38+
if (TT.getObjectFormat() != Triple::UnknownObjectFormat)
39+
RequireFormat = TT.getObjectFormat();
40+
41+
switch (identify_magic((*Buf)->getBuffer())) {
42+
case file_magic::coff_object:
43+
if (!RequireFormat || *RequireFormat == Triple::COFF)
44+
return checkCOFFRelocatableObject(std::move(*Buf), TT);
45+
break;
46+
case file_magic::elf_relocatable:
47+
if (!RequireFormat || *RequireFormat == Triple::ELF)
48+
return checkELFRelocatableObject(std::move(*Buf), TT);
49+
break;
50+
case file_magic::macho_object:
51+
if (!RequireFormat || *RequireFormat == Triple::MachO)
52+
return checkMachORelocatableObject(std::move(*Buf), TT, false);
53+
break;
54+
case file_magic::macho_universal_binary:
55+
if (!RequireFormat || *RequireFormat == Triple::MachO)
56+
return loadMachORelocatableObjectFromUniversalBinary(Path,
57+
std::move(*Buf), TT);
58+
break;
59+
default:
60+
break;
61+
}
62+
return make_error<StringError>(
63+
Path + " does not contain a relocatable object file compatible with " +
64+
TT.str(),
65+
inconvertibleErrorCode());
66+
}
67+
68+
} // End namespace orc.
69+
} // End namespace llvm.

0 commit comments

Comments
 (0)