xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/LoadLinkableFile.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===------- LoadLinkableFile.cpp -- Load relocatables and archives -------===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric 
9*700637cbSDimitry Andric #include "llvm/ExecutionEngine/Orc/LoadLinkableFile.h"
10*700637cbSDimitry Andric 
11*700637cbSDimitry Andric #include "llvm/ADT/ScopeExit.h"
12*700637cbSDimitry Andric #include "llvm/BinaryFormat/Magic.h"
13*700637cbSDimitry Andric #include "llvm/ExecutionEngine/Orc/MachO.h"
14*700637cbSDimitry Andric #include "llvm/Support/FileSystem.h"
15*700637cbSDimitry Andric 
16*700637cbSDimitry Andric #define DEBUG_TYPE "orc"
17*700637cbSDimitry Andric 
18*700637cbSDimitry Andric namespace llvm {
19*700637cbSDimitry Andric namespace orc {
20*700637cbSDimitry Andric 
21*700637cbSDimitry Andric static Expected<std::unique_ptr<MemoryBuffer>>
checkCOFFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj,const Triple & TT)22*700637cbSDimitry Andric checkCOFFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj,
23*700637cbSDimitry Andric                            const Triple &TT) {
24*700637cbSDimitry Andric   // TODO: Actually check the architecture of the file.
25*700637cbSDimitry Andric   return std::move(Obj);
26*700637cbSDimitry Andric }
27*700637cbSDimitry Andric 
28*700637cbSDimitry Andric static Expected<std::unique_ptr<MemoryBuffer>>
checkXCOFFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj,const Triple & TT)29*700637cbSDimitry Andric checkXCOFFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj,
30*700637cbSDimitry Andric                             const Triple &TT) {
31*700637cbSDimitry Andric   // TODO: Actually check the architecture of the file.
32*700637cbSDimitry Andric   return std::move(Obj);
33*700637cbSDimitry Andric }
34*700637cbSDimitry Andric 
35*700637cbSDimitry Andric static Expected<std::unique_ptr<MemoryBuffer>>
checkELFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj,const Triple & TT)36*700637cbSDimitry Andric checkELFRelocatableObject(std::unique_ptr<MemoryBuffer> Obj, const Triple &TT) {
37*700637cbSDimitry Andric   // TODO: Actually check the architecture of the file.
38*700637cbSDimitry Andric   return std::move(Obj);
39*700637cbSDimitry Andric }
40*700637cbSDimitry Andric 
41*700637cbSDimitry Andric Expected<std::pair<std::unique_ptr<MemoryBuffer>, LinkableFileKind>>
loadLinkableFile(StringRef Path,const Triple & TT,LoadArchives LA,std::optional<StringRef> IdentifierOverride)42*700637cbSDimitry Andric loadLinkableFile(StringRef Path, const Triple &TT, LoadArchives LA,
43*700637cbSDimitry Andric                  std::optional<StringRef> IdentifierOverride) {
44*700637cbSDimitry Andric   if (!IdentifierOverride)
45*700637cbSDimitry Andric     IdentifierOverride = Path;
46*700637cbSDimitry Andric 
47*700637cbSDimitry Andric   Expected<sys::fs::file_t> FDOrErr =
48*700637cbSDimitry Andric       sys::fs::openNativeFileForRead(Path, sys::fs::OF_None);
49*700637cbSDimitry Andric   if (!FDOrErr)
50*700637cbSDimitry Andric     return createFileError(Path, FDOrErr.takeError());
51*700637cbSDimitry Andric   sys::fs::file_t FD = *FDOrErr;
52*700637cbSDimitry Andric   auto CloseFile = make_scope_exit([&]() { sys::fs::closeFile(FD); });
53*700637cbSDimitry Andric 
54*700637cbSDimitry Andric   auto Buf =
55*700637cbSDimitry Andric       MemoryBuffer::getOpenFile(FD, *IdentifierOverride, /*FileSize=*/-1);
56*700637cbSDimitry Andric   if (!Buf)
57*700637cbSDimitry Andric     return make_error<StringError>(
58*700637cbSDimitry Andric         StringRef("Could not load object at path ") + Path, Buf.getError());
59*700637cbSDimitry Andric 
60*700637cbSDimitry Andric   std::optional<Triple::ObjectFormatType> RequireFormat;
61*700637cbSDimitry Andric   if (TT.getObjectFormat() != Triple::UnknownObjectFormat)
62*700637cbSDimitry Andric     RequireFormat = TT.getObjectFormat();
63*700637cbSDimitry Andric 
64*700637cbSDimitry Andric   switch (identify_magic((*Buf)->getBuffer())) {
65*700637cbSDimitry Andric   case file_magic::archive:
66*700637cbSDimitry Andric     if (LA != LoadArchives::Never)
67*700637cbSDimitry Andric       return std::make_pair(std::move(*Buf), LinkableFileKind::Archive);
68*700637cbSDimitry Andric     return make_error<StringError>(
69*700637cbSDimitry Andric         Path + " does not contain a relocatable object file",
70*700637cbSDimitry Andric         inconvertibleErrorCode());
71*700637cbSDimitry Andric   case file_magic::coff_object:
72*700637cbSDimitry Andric     if (LA == LoadArchives::Required)
73*700637cbSDimitry Andric       return make_error<StringError>(Path + " does not contain an archive",
74*700637cbSDimitry Andric                                      inconvertibleErrorCode());
75*700637cbSDimitry Andric 
76*700637cbSDimitry Andric     if (!RequireFormat || *RequireFormat == Triple::COFF) {
77*700637cbSDimitry Andric       auto CheckedBuf = checkCOFFRelocatableObject(std::move(*Buf), TT);
78*700637cbSDimitry Andric       if (!CheckedBuf)
79*700637cbSDimitry Andric         return CheckedBuf.takeError();
80*700637cbSDimitry Andric       return std::make_pair(std::move(*CheckedBuf),
81*700637cbSDimitry Andric                             LinkableFileKind::RelocatableObject);
82*700637cbSDimitry Andric     }
83*700637cbSDimitry Andric     break;
84*700637cbSDimitry Andric   case file_magic::elf_relocatable:
85*700637cbSDimitry Andric     if (LA == LoadArchives::Required)
86*700637cbSDimitry Andric       return make_error<StringError>(Path + " does not contain an archive",
87*700637cbSDimitry Andric                                      inconvertibleErrorCode());
88*700637cbSDimitry Andric 
89*700637cbSDimitry Andric     if (!RequireFormat || *RequireFormat == Triple::ELF) {
90*700637cbSDimitry Andric       auto CheckedBuf = checkELFRelocatableObject(std::move(*Buf), TT);
91*700637cbSDimitry Andric       if (!CheckedBuf)
92*700637cbSDimitry Andric         return CheckedBuf.takeError();
93*700637cbSDimitry Andric       return std::make_pair(std::move(*CheckedBuf),
94*700637cbSDimitry Andric                             LinkableFileKind::RelocatableObject);
95*700637cbSDimitry Andric     }
96*700637cbSDimitry Andric     break;
97*700637cbSDimitry Andric   case file_magic::macho_object:
98*700637cbSDimitry Andric     if (LA == LoadArchives::Required)
99*700637cbSDimitry Andric       return make_error<StringError>(Path + " does not contain an archive",
100*700637cbSDimitry Andric                                      inconvertibleErrorCode());
101*700637cbSDimitry Andric 
102*700637cbSDimitry Andric     if (!RequireFormat || *RequireFormat == Triple::MachO) {
103*700637cbSDimitry Andric       auto CheckedBuf = checkMachORelocatableObject(std::move(*Buf), TT, false);
104*700637cbSDimitry Andric       if (!CheckedBuf)
105*700637cbSDimitry Andric         return CheckedBuf.takeError();
106*700637cbSDimitry Andric       return std::make_pair(std::move(*CheckedBuf),
107*700637cbSDimitry Andric                             LinkableFileKind::RelocatableObject);
108*700637cbSDimitry Andric     }
109*700637cbSDimitry Andric     break;
110*700637cbSDimitry Andric   case file_magic::macho_universal_binary:
111*700637cbSDimitry Andric     if (!RequireFormat || *RequireFormat == Triple::MachO)
112*700637cbSDimitry Andric       return loadLinkableSliceFromMachOUniversalBinary(
113*700637cbSDimitry Andric           FD, std::move(*Buf), TT, LA, Path, *IdentifierOverride);
114*700637cbSDimitry Andric     break;
115*700637cbSDimitry Andric   case file_magic::xcoff_object_64:
116*700637cbSDimitry Andric     if (!RequireFormat || *RequireFormat == Triple::XCOFF) {
117*700637cbSDimitry Andric       auto CheckedBuf = checkXCOFFRelocatableObject(std::move(*Buf), TT);
118*700637cbSDimitry Andric       if (!CheckedBuf)
119*700637cbSDimitry Andric         return CheckedBuf.takeError();
120*700637cbSDimitry Andric       return std::make_pair(std::move(*CheckedBuf),
121*700637cbSDimitry Andric                             LinkableFileKind::RelocatableObject);
122*700637cbSDimitry Andric     }
123*700637cbSDimitry Andric     break;
124*700637cbSDimitry Andric   default:
125*700637cbSDimitry Andric     break;
126*700637cbSDimitry Andric   }
127*700637cbSDimitry Andric 
128*700637cbSDimitry Andric   return make_error<StringError>(
129*700637cbSDimitry Andric       Path +
130*700637cbSDimitry Andric           " does not contain a relocatable object file or archive compatible "
131*700637cbSDimitry Andric           "with " +
132*700637cbSDimitry Andric           TT.str(),
133*700637cbSDimitry Andric       inconvertibleErrorCode());
134*700637cbSDimitry Andric }
135*700637cbSDimitry Andric 
136*700637cbSDimitry Andric } // End namespace orc.
137*700637cbSDimitry Andric } // End namespace llvm.
138