xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/LoadLinkableFile.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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