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>>
checkCOFFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj,const Triple & TT)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>>
checkXCOFFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj,const Triple & TT)29 checkXCOFFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj,
30 const Triple &TT) {
31 // TODO: Actually check the architecture of the file.
32 return std::move(Obj);
33 }
34
35 static Expected<std::unique_ptr<MemoryBuffer>>
checkELFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj,const Triple & TT)36 checkELFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj, const Triple &TT) {
37 // TODO: Actually check the architecture of the file.
38 return std::move(Obj);
39 }
40
41 Expected<std::pair<std::unique_ptr<MemoryBuffer>, LinkableFileKind>>
loadLinkableFile(StringRef Path,const Triple & TT,LoadArchives LA,std::optional<StringRef> IdentifierOverride)42 loadLinkableFile(StringRef Path, const Triple &TT, LoadArchives LA,
43 std::optional<StringRef> IdentifierOverride) {
44 if (!IdentifierOverride)
45 IdentifierOverride = Path;
46
47 Expected<sys::fs::file_t> FDOrErr =
48 sys::fs::openNativeFileForRead(Path, sys::fs::OF_None);
49 if (!FDOrErr)
50 return createFileError(Path, FDOrErr.takeError());
51 sys::fs::file_t FD = *FDOrErr;
52 auto CloseFile = make_scope_exit([&]() { sys::fs::closeFile(FD); });
53
54 auto Buf =
55 MemoryBuffer::getOpenFile(FD, *IdentifierOverride, /*FileSize=*/-1);
56 if (!Buf)
57 return make_error<StringError>(
58 StringRef("Could not load object at path ") + Path, Buf.getError());
59
60 std::optional<Triple::ObjectFormatType> RequireFormat;
61 if (TT.getObjectFormat() != Triple::UnknownObjectFormat)
62 RequireFormat = TT.getObjectFormat();
63
64 switch (identify_magic((*Buf)->getBuffer())) {
65 case file_magic::archive:
66 if (LA != LoadArchives::Never)
67 return std::make_pair(std::move(*Buf), LinkableFileKind::Archive);
68 return make_error<StringError>(
69 Path + " does not contain a relocatable object file",
70 inconvertibleErrorCode());
71 case file_magic::coff_object:
72 if (LA == LoadArchives::Required)
73 return make_error<StringError>(Path + " does not contain an archive",
74 inconvertibleErrorCode());
75
76 if (!RequireFormat || *RequireFormat == Triple::COFF) {
77 auto CheckedBuf = checkCOFFRelocatableObject(std::move(*Buf), TT);
78 if (!CheckedBuf)
79 return CheckedBuf.takeError();
80 return std::make_pair(std::move(*CheckedBuf),
81 LinkableFileKind::RelocatableObject);
82 }
83 break;
84 case file_magic::elf_relocatable:
85 if (LA == LoadArchives::Required)
86 return make_error<StringError>(Path + " does not contain an archive",
87 inconvertibleErrorCode());
88
89 if (!RequireFormat || *RequireFormat == Triple::ELF) {
90 auto CheckedBuf = checkELFRelocatableObject(std::move(*Buf), TT);
91 if (!CheckedBuf)
92 return CheckedBuf.takeError();
93 return std::make_pair(std::move(*CheckedBuf),
94 LinkableFileKind::RelocatableObject);
95 }
96 break;
97 case file_magic::macho_object:
98 if (LA == LoadArchives::Required)
99 return make_error<StringError>(Path + " does not contain an archive",
100 inconvertibleErrorCode());
101
102 if (!RequireFormat || *RequireFormat == Triple::MachO) {
103 auto CheckedBuf = checkMachORelocatableObject(std::move(*Buf), TT, false);
104 if (!CheckedBuf)
105 return CheckedBuf.takeError();
106 return std::make_pair(std::move(*CheckedBuf),
107 LinkableFileKind::RelocatableObject);
108 }
109 break;
110 case file_magic::macho_universal_binary:
111 if (!RequireFormat || *RequireFormat == Triple::MachO)
112 return loadLinkableSliceFromMachOUniversalBinary(
113 FD, std::move(*Buf), TT, LA, Path, *IdentifierOverride);
114 break;
115 case file_magic::xcoff_object_64:
116 if (!RequireFormat || *RequireFormat == Triple::XCOFF) {
117 auto CheckedBuf = checkXCOFFRelocatableObject(std::move(*Buf), TT);
118 if (!CheckedBuf)
119 return CheckedBuf.takeError();
120 return std::make_pair(std::move(*CheckedBuf),
121 LinkableFileKind::RelocatableObject);
122 }
123 break;
124 default:
125 break;
126 }
127
128 return make_error<StringError>(
129 Path +
130 " does not contain a relocatable object file or archive compatible "
131 "with " +
132 TT.str(),
133 inconvertibleErrorCode());
134 }
135
136 } // End namespace orc.
137 } // End namespace llvm.
138