xref: /llvm-project/llvm/lib/ExecutionEngine/Orc/LoadLinkableFile.cpp (revision 7a4013f029c4d360a9374ff49b5d17479fcb03df)
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.
122