Skip to content

Commit 7a4013f

Browse files
committed
[ORC] Generalize loadRelocatableObject to loadLinkableFile, add archive support.
This allows us to rewrite part of StaticLibraryDefinitionGenerator in terms of loadLinkableFile. It's also useful for clients who may not know (either from file extensions or context) whether a given path will be an object file, an archive, or a universal binary. rdar://134638070
1 parent b1d1c33 commit 7a4013f

File tree

11 files changed

+286
-209
lines changed

11 files changed

+286
-209
lines changed

llvm/include/llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "llvm/Support/Memory.h"
2626
#include "llvm/Support/RecyclingAllocator.h"
2727

28+
#include <cassert>
2829
#include <cstdint>
2930
#include <future>
3031
#include <mutex>
@@ -363,7 +364,9 @@ class InProcessMemoryManager : public JITLinkMemoryManager {
363364
static Expected<std::unique_ptr<InProcessMemoryManager>> Create();
364365

365366
/// Create an instance using the given page size.
366-
InProcessMemoryManager(uint64_t PageSize) : PageSize(PageSize) {}
367+
InProcessMemoryManager(uint64_t PageSize) : PageSize(PageSize) {
368+
assert(isPowerOf2_64(PageSize) && "PageSize must be a power of 2");
369+
}
367370

368371
void allocate(const JITLinkDylib *JD, LinkGraph &G,
369372
OnAllocatedFunction OnAllocated) override;
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//===--- LoadLinkableFile.h -- Load relocatables and archives ---*- 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. Handles relocatable object files, archives, and macho universal
12+
// binaries.
13+
// 2. Adds file paths to errors by default.
14+
// 3. Checks architecture compatibility up-front.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef LLVM_EXECUTIONENGINE_ORC_LOADLINKABLEFILE_H
19+
#define LLVM_EXECUTIONENGINE_ORC_LOADLINKABLEFILE_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+
enum class LinkableFileKind { Archive, RelocatableObject };
29+
30+
enum LoadArchives {
31+
Never, // Linkable file must not be an archive.
32+
Allowed, // Linkable file is allowed to be an archive.
33+
Required // Linkable file is required to be an archive.
34+
};
35+
36+
/// Create a MemoryBuffer covering the "linkable" part of the given path.
37+
///
38+
/// The path must contain a relocatable object file or universal binary, or
39+
/// (if AllowArchives is true) an archive.
40+
///
41+
/// If the path is a universal binary then it must contain a slice whose
42+
/// architecture matches the architecture in the triple (an error will be
43+
/// returned if there is no such slice, or if the triple does not specify an
44+
/// architectur).
45+
///
46+
/// If the path (or universal binary slice) is a relocatable object file then
47+
/// its architecture must match the architecture in the triple (if given).
48+
///
49+
/// If the path (or universal binary slice) is a relocatable object file then
50+
/// its format must match the format in the triple (if given).
51+
///
52+
/// No verification (e.g. architecture or format) is performed on the contents
53+
/// of archives.
54+
///
55+
/// If IdentifierOverride is provided then it will be used as the name of the
56+
/// resulting buffer, rather than Path.
57+
Expected<std::pair<std::unique_ptr<MemoryBuffer>, LinkableFileKind>>
58+
loadLinkableFile(StringRef Path, const Triple &TT, LoadArchives LA,
59+
std::optional<StringRef> IdentifierOverride = std::nullopt);
60+
61+
} // End namespace orc
62+
} // End namespace llvm
63+
64+
#endif // LLVM_EXECUTIONENGINE_ORC_LOADLINKABLEFILE_H

llvm/include/llvm/ExecutionEngine/Orc/LoadRelocatableObject.h

Lines changed: 0 additions & 37 deletions
This file was deleted.

llvm/include/llvm/ExecutionEngine/Orc/MachO.h

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef LLVM_EXECUTIONENGINE_ORC_MACHO_H
1414
#define LLVM_EXECUTIONENGINE_ORC_MACHO_H
1515

16+
#include "llvm/ExecutionEngine/Orc/LoadLinkableFile.h"
1617
#include "llvm/Support/Error.h"
1718
#include "llvm/Support/MemoryBuffer.h"
1819
#include "llvm/TargetParser/Triple.h"
@@ -45,16 +46,21 @@ checkMachORelocatableObject(std::unique_ptr<MemoryBuffer> Obj, const Triple &TT,
4546
/// Load a relocatable object compatible with TT from Path.
4647
/// If Path is a universal binary, this function will return a buffer for the
4748
/// slice compatible with Triple (if one is present).
48-
Expected<std::unique_ptr<MemoryBuffer>> loadMachORelocatableObject(
49-
StringRef Path, const Triple &TT,
49+
Expected<std::pair<std::unique_ptr<MemoryBuffer>, LinkableFileKind>>
50+
loadMachOLinkableFile(
51+
StringRef Path, const Triple &TT, LoadArchives LA,
5052
std::optional<StringRef> IdentifierOverride = std::nullopt);
5153

5254
/// Load a compatible relocatable object (if available) from a MachO universal
5355
/// binary.
54-
Expected<std::unique_ptr<MemoryBuffer>>
55-
loadMachORelocatableObjectFromUniversalBinary(
56-
StringRef UBPath, std::unique_ptr<MemoryBuffer> UBBuf, const Triple &TT,
57-
std::optional<StringRef> IdentifierOverride = std::nullopt);
56+
/// Path is only used for error reporting. Identifier will be used to name the
57+
/// resulting buffer.
58+
Expected<std::pair<std::unique_ptr<MemoryBuffer>, LinkableFileKind>>
59+
loadLinkableSliceFromMachOUniversalBinary(sys::fs::file_t FD,
60+
std::unique_ptr<MemoryBuffer> UBBuf,
61+
const Triple &TT, LoadArchives LA,
62+
StringRef UBPath,
63+
StringRef Identifier);
5864

5965
/// Utility for identifying the file-slice compatible with TT in a universal
6066
/// binary.

llvm/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -326,22 +326,21 @@ class InProcessMemoryManager::IPInFlightAlloc
326326

327327
Expected<std::unique_ptr<InProcessMemoryManager>>
328328
InProcessMemoryManager::Create() {
329-
if (auto PageSize = sys::Process::getPageSize())
329+
if (auto PageSize = sys::Process::getPageSize()) {
330+
// FIXME: Just check this once on startup.
331+
if (!isPowerOf2_64((uint64_t)*PageSize))
332+
return make_error<StringError>(
333+
"Could not create InProcessMemoryManager: Page size " +
334+
Twine(*PageSize) + " is not a power of 2",
335+
inconvertibleErrorCode());
336+
330337
return std::make_unique<InProcessMemoryManager>(*PageSize);
331-
else
338+
} else
332339
return PageSize.takeError();
333340
}
334341

335342
void InProcessMemoryManager::allocate(const JITLinkDylib *JD, LinkGraph &G,
336343
OnAllocatedFunction OnAllocated) {
337-
338-
// FIXME: Just check this once on startup.
339-
if (!isPowerOf2_64((uint64_t)PageSize)) {
340-
OnAllocated(make_error<StringError>("Page size is not a power of 2",
341-
inconvertibleErrorCode()));
342-
return;
343-
}
344-
345344
BasicLayout BL(G);
346345

347346
/// Scan the request and calculate the group and total sizes.

llvm/lib/ExecutionEngine/Orc/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ add_llvm_component_library(LLVMOrcJIT
2929
JITTargetMachineBuilder.cpp
3030
LazyReexports.cpp
3131
Layer.cpp
32-
LoadRelocatableObject.cpp
32+
LoadLinkableFile.cpp
3333
LookupAndRecordAddrs.cpp
3434
LLJIT.cpp
3535
MachO.cpp

llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp

Lines changed: 6 additions & 38 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/LoadLinkableFile.h"
1213
#include "llvm/ExecutionEngine/Orc/MachO.h"
1314
#include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h"
1415
#include "llvm/IR/Constants.h"
@@ -277,45 +278,12 @@ StaticLibraryDefinitionGenerator::Load(
277278
ObjectLayer &L, const char *FileName,
278279
GetObjectFileInterface GetObjFileInterface) {
279280

280-
auto B = object::createBinary(FileName);
281-
if (!B)
282-
return createFileError(FileName, B.takeError());
283-
284-
// If this is a regular archive then create an instance from it.
285-
if (isa<object::Archive>(B->getBinary())) {
286-
auto [Archive, ArchiveBuffer] = B->takeBinary();
287-
return Create(L, std::move(ArchiveBuffer),
288-
std::unique_ptr<object::Archive>(
289-
static_cast<object::Archive *>(Archive.release())),
290-
std::move(GetObjFileInterface));
291-
}
292-
293-
// If this is a universal binary then search for a slice matching the given
294-
// Triple.
295-
if (auto *UB = dyn_cast<object::MachOUniversalBinary>(B->getBinary())) {
281+
const auto &TT = L.getExecutionSession().getTargetTriple();
282+
auto Linkable = loadLinkableFile(FileName, TT, LoadArchives::Required);
283+
if (!Linkable)
284+
return Linkable.takeError();
296285

297-
const auto &TT = L.getExecutionSession().getTargetTriple();
298-
299-
auto SliceRange = getMachOSliceRangeForTriple(*UB, TT);
300-
if (!SliceRange)
301-
return SliceRange.takeError();
302-
303-
auto SliceBuffer = MemoryBuffer::getFileSlice(FileName, SliceRange->second,
304-
SliceRange->first);
305-
if (!SliceBuffer)
306-
return make_error<StringError>(
307-
Twine("Could not create buffer for ") + TT.str() + " slice of " +
308-
FileName + ": [ " + formatv("{0:x}", SliceRange->first) + " .. " +
309-
formatv("{0:x}", SliceRange->first + SliceRange->second) + ": " +
310-
SliceBuffer.getError().message(),
311-
SliceBuffer.getError());
312-
313-
return Create(L, std::move(*SliceBuffer), std::move(GetObjFileInterface));
314-
}
315-
316-
return make_error<StringError>(Twine("Unrecognized file type for ") +
317-
FileName,
318-
inconvertibleErrorCode());
286+
return Create(L, std::move(Linkable->first), std::move(GetObjFileInterface));
319287
}
320288

321289
Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>>
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//===------- LoadLinkableFile.cpp -- Load relocatables and archives -------===//
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/LoadLinkableFile.h"
10+
11+
#include "llvm/ADT/ScopeExit.h"
12+
#include "llvm/BinaryFormat/Magic.h"
13+
#include "llvm/ExecutionEngine/Orc/MachO.h"
14+
#include "llvm/Support/FileSystem.h"
15+
16+
#define DEBUG_TYPE "orc"
17+
18+
namespace llvm {
19+
namespace orc {
20+
21+
static Expected<std::unique_ptr<MemoryBuffer>>
22+
checkCOFFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj,
23+
const Triple &TT) {
24+
// TODO: Actually check the architecture of the file.
25+
return std::move(Obj);
26+
}
27+
28+
static Expected<std::unique_ptr<MemoryBuffer>>
29+
checkELFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj, const Triple &TT) {
30+
// TODO: Actually check the architecture of the file.
31+
return std::move(Obj);
32+
}
33+
34+
Expected<std::pair<std::unique_ptr<MemoryBuffer>, LinkableFileKind>>
35+
loadLinkableFile(StringRef Path, const Triple &TT, LoadArchives LA,
36+
std::optional<StringRef> IdentifierOverride) {
37+
if (!IdentifierOverride)
38+
IdentifierOverride = Path;
39+
40+
Expected<sys::fs::file_t> FDOrErr =
41+
sys::fs::openNativeFileForRead(Path, sys::fs::OF_None);
42+
if (!FDOrErr)
43+
return createFileError(Path, FDOrErr.takeError());
44+
sys::fs::file_t FD = *FDOrErr;
45+
auto CloseFile = make_scope_exit([&]() { sys::fs::closeFile(FD); });
46+
47+
auto Buf =
48+
MemoryBuffer::getOpenFile(FD, *IdentifierOverride, /*FileSize=*/-1);
49+
if (!Buf)
50+
return make_error<StringError>(
51+
StringRef("Could not load object at path ") + Path, Buf.getError());
52+
53+
std::optional<Triple::ObjectFormatType> RequireFormat;
54+
if (TT.getObjectFormat() != Triple::UnknownObjectFormat)
55+
RequireFormat = TT.getObjectFormat();
56+
57+
switch (identify_magic((*Buf)->getBuffer())) {
58+
case file_magic::archive:
59+
if (LA != LoadArchives::Never)
60+
return std::make_pair(std::move(*Buf), LinkableFileKind::Archive);
61+
return make_error<StringError>(
62+
Path + " does not contain a relocatable object file",
63+
inconvertibleErrorCode());
64+
case file_magic::coff_object:
65+
if (LA == LoadArchives::Required)
66+
return make_error<StringError>(Path + " does not contain an archive",
67+
inconvertibleErrorCode());
68+
69+
if (!RequireFormat || *RequireFormat == Triple::COFF) {
70+
auto CheckedBuf = checkCOFFRelocatableObject(std::move(*Buf), TT);
71+
if (!CheckedBuf)
72+
return CheckedBuf.takeError();
73+
return std::make_pair(std::move(*CheckedBuf),
74+
LinkableFileKind::RelocatableObject);
75+
}
76+
break;
77+
case file_magic::elf_relocatable:
78+
if (LA == LoadArchives::Required)
79+
return make_error<StringError>(Path + " does not contain an archive",
80+
inconvertibleErrorCode());
81+
82+
if (!RequireFormat || *RequireFormat == Triple::ELF) {
83+
auto CheckedBuf = checkELFRelocatableObject(std::move(*Buf), TT);
84+
if (!CheckedBuf)
85+
return CheckedBuf.takeError();
86+
return std::make_pair(std::move(*CheckedBuf),
87+
LinkableFileKind::RelocatableObject);
88+
}
89+
break;
90+
case file_magic::macho_object:
91+
if (LA == LoadArchives::Required)
92+
return make_error<StringError>(Path + " does not contain an archive",
93+
inconvertibleErrorCode());
94+
95+
if (!RequireFormat || *RequireFormat == Triple::MachO) {
96+
auto CheckedBuf = checkMachORelocatableObject(std::move(*Buf), TT, false);
97+
if (!CheckedBuf)
98+
return CheckedBuf.takeError();
99+
return std::make_pair(std::move(*CheckedBuf),
100+
LinkableFileKind::RelocatableObject);
101+
}
102+
break;
103+
case file_magic::macho_universal_binary:
104+
if (!RequireFormat || *RequireFormat == Triple::MachO)
105+
return loadLinkableSliceFromMachOUniversalBinary(
106+
FD, std::move(*Buf), TT, LA, Path, *IdentifierOverride);
107+
break;
108+
default:
109+
break;
110+
}
111+
112+
return make_error<StringError>(
113+
Path +
114+
" does not contain a relocatable object file or archive compatible "
115+
"with " +
116+
TT.str(),
117+
inconvertibleErrorCode());
118+
}
119+
120+
} // End namespace orc.
121+
} // End namespace llvm.

0 commit comments

Comments
 (0)