xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1*06c3fb27SDimitry Andric //===----- ELF_aarch32.cpp - JIT linker implementation for arm/thumb ------===//
2*06c3fb27SDimitry Andric //
3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*06c3fb27SDimitry Andric //
7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
8*06c3fb27SDimitry Andric //
9*06c3fb27SDimitry Andric // ELF/aarch32 jit-link implementation.
10*06c3fb27SDimitry Andric //
11*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
12*06c3fb27SDimitry Andric 
13*06c3fb27SDimitry Andric #include "llvm/ExecutionEngine/JITLink/ELF_aarch32.h"
14*06c3fb27SDimitry Andric 
15*06c3fb27SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
16*06c3fb27SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h"
17*06c3fb27SDimitry Andric #include "llvm/ExecutionEngine/JITLink/aarch32.h"
18*06c3fb27SDimitry Andric #include "llvm/Object/ELF.h"
19*06c3fb27SDimitry Andric #include "llvm/Object/ELFObjectFile.h"
20*06c3fb27SDimitry Andric #include "llvm/Support/Endian.h"
21*06c3fb27SDimitry Andric #include "llvm/Support/ErrorHandling.h"
22*06c3fb27SDimitry Andric #include "llvm/TargetParser/ARMTargetParser.h"
23*06c3fb27SDimitry Andric 
24*06c3fb27SDimitry Andric #include "ELFLinkGraphBuilder.h"
25*06c3fb27SDimitry Andric #include "JITLinkGeneric.h"
26*06c3fb27SDimitry Andric 
27*06c3fb27SDimitry Andric #define DEBUG_TYPE "jitlink"
28*06c3fb27SDimitry Andric 
29*06c3fb27SDimitry Andric using namespace llvm::object;
30*06c3fb27SDimitry Andric 
31*06c3fb27SDimitry Andric namespace llvm {
32*06c3fb27SDimitry Andric namespace jitlink {
33*06c3fb27SDimitry Andric 
34*06c3fb27SDimitry Andric /// Translate from ELF relocation type to JITLink-internal edge kind.
35*06c3fb27SDimitry Andric Expected<aarch32::EdgeKind_aarch32> getJITLinkEdgeKind(uint32_t ELFType) {
36*06c3fb27SDimitry Andric   switch (ELFType) {
37*06c3fb27SDimitry Andric   case ELF::R_ARM_ABS32:
38*06c3fb27SDimitry Andric     return aarch32::Data_Pointer32;
39*06c3fb27SDimitry Andric   case ELF::R_ARM_REL32:
40*06c3fb27SDimitry Andric     return aarch32::Data_Delta32;
41*06c3fb27SDimitry Andric   case ELF::R_ARM_CALL:
42*06c3fb27SDimitry Andric     return aarch32::Arm_Call;
43*06c3fb27SDimitry Andric   case ELF::R_ARM_THM_CALL:
44*06c3fb27SDimitry Andric     return aarch32::Thumb_Call;
45*06c3fb27SDimitry Andric   case ELF::R_ARM_THM_JUMP24:
46*06c3fb27SDimitry Andric     return aarch32::Thumb_Jump24;
47*06c3fb27SDimitry Andric   case ELF::R_ARM_THM_MOVW_ABS_NC:
48*06c3fb27SDimitry Andric     return aarch32::Thumb_MovwAbsNC;
49*06c3fb27SDimitry Andric   case ELF::R_ARM_THM_MOVT_ABS:
50*06c3fb27SDimitry Andric     return aarch32::Thumb_MovtAbs;
51*06c3fb27SDimitry Andric   }
52*06c3fb27SDimitry Andric 
53*06c3fb27SDimitry Andric   return make_error<JITLinkError>(
54*06c3fb27SDimitry Andric       "Unsupported aarch32 relocation " + formatv("{0:d}: ", ELFType) +
55*06c3fb27SDimitry Andric       object::getELFRelocationTypeName(ELF::EM_ARM, ELFType));
56*06c3fb27SDimitry Andric }
57*06c3fb27SDimitry Andric 
58*06c3fb27SDimitry Andric /// Translate from JITLink-internal edge kind back to ELF relocation type.
59*06c3fb27SDimitry Andric Expected<uint32_t> getELFRelocationType(Edge::Kind Kind) {
60*06c3fb27SDimitry Andric   switch (static_cast<aarch32::EdgeKind_aarch32>(Kind)) {
61*06c3fb27SDimitry Andric   case aarch32::Data_Delta32:
62*06c3fb27SDimitry Andric     return ELF::R_ARM_REL32;
63*06c3fb27SDimitry Andric   case aarch32::Data_Pointer32:
64*06c3fb27SDimitry Andric     return ELF::R_ARM_ABS32;
65*06c3fb27SDimitry Andric   case aarch32::Arm_Call:
66*06c3fb27SDimitry Andric     return ELF::R_ARM_CALL;
67*06c3fb27SDimitry Andric   case aarch32::Thumb_Call:
68*06c3fb27SDimitry Andric     return ELF::R_ARM_THM_CALL;
69*06c3fb27SDimitry Andric   case aarch32::Thumb_Jump24:
70*06c3fb27SDimitry Andric     return ELF::R_ARM_THM_JUMP24;
71*06c3fb27SDimitry Andric   case aarch32::Thumb_MovwAbsNC:
72*06c3fb27SDimitry Andric     return ELF::R_ARM_THM_MOVW_ABS_NC;
73*06c3fb27SDimitry Andric   case aarch32::Thumb_MovtAbs:
74*06c3fb27SDimitry Andric     return ELF::R_ARM_THM_MOVT_ABS;
75*06c3fb27SDimitry Andric   }
76*06c3fb27SDimitry Andric 
77*06c3fb27SDimitry Andric   return make_error<JITLinkError>(formatv("Invalid aarch32 edge {0:d}: ",
78*06c3fb27SDimitry Andric                                           Kind));
79*06c3fb27SDimitry Andric }
80*06c3fb27SDimitry Andric 
81*06c3fb27SDimitry Andric /// Get a human-readable name for the given ELF AArch32 edge kind.
82*06c3fb27SDimitry Andric const char *getELFAArch32EdgeKindName(Edge::Kind R) {
83*06c3fb27SDimitry Andric   // No ELF-specific edge kinds yet
84*06c3fb27SDimitry Andric   return aarch32::getEdgeKindName(R);
85*06c3fb27SDimitry Andric }
86*06c3fb27SDimitry Andric 
87*06c3fb27SDimitry Andric class ELFJITLinker_aarch32 : public JITLinker<ELFJITLinker_aarch32> {
88*06c3fb27SDimitry Andric   friend class JITLinker<ELFJITLinker_aarch32>;
89*06c3fb27SDimitry Andric 
90*06c3fb27SDimitry Andric public:
91*06c3fb27SDimitry Andric   ELFJITLinker_aarch32(std::unique_ptr<JITLinkContext> Ctx,
92*06c3fb27SDimitry Andric                        std::unique_ptr<LinkGraph> G, PassConfiguration PassCfg,
93*06c3fb27SDimitry Andric                        aarch32::ArmConfig ArmCfg)
94*06c3fb27SDimitry Andric       : JITLinker(std::move(Ctx), std::move(G), std::move(PassCfg)),
95*06c3fb27SDimitry Andric         ArmCfg(std::move(ArmCfg)) {}
96*06c3fb27SDimitry Andric 
97*06c3fb27SDimitry Andric private:
98*06c3fb27SDimitry Andric   aarch32::ArmConfig ArmCfg;
99*06c3fb27SDimitry Andric 
100*06c3fb27SDimitry Andric   Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
101*06c3fb27SDimitry Andric     return aarch32::applyFixup(G, B, E, ArmCfg);
102*06c3fb27SDimitry Andric   }
103*06c3fb27SDimitry Andric };
104*06c3fb27SDimitry Andric 
105*06c3fb27SDimitry Andric template <support::endianness DataEndianness>
106*06c3fb27SDimitry Andric class ELFLinkGraphBuilder_aarch32
107*06c3fb27SDimitry Andric     : public ELFLinkGraphBuilder<ELFType<DataEndianness, false>> {
108*06c3fb27SDimitry Andric private:
109*06c3fb27SDimitry Andric   using ELFT = ELFType<DataEndianness, false>;
110*06c3fb27SDimitry Andric   using Base = ELFLinkGraphBuilder<ELFT>;
111*06c3fb27SDimitry Andric 
112*06c3fb27SDimitry Andric   bool excludeSection(const typename ELFT::Shdr &Sect) const override {
113*06c3fb27SDimitry Andric     // TODO: An .ARM.exidx (Exception Index table) entry is 8-bytes in size and
114*06c3fb27SDimitry Andric     // consists of 2 words. It might be sufficient to process only relocations
115*06c3fb27SDimitry Andric     // in the the second word (offset 4). Please find more details in: Exception
116*06c3fb27SDimitry Andric     // Handling ABI for the Arm® Architecture -> Index table entries
117*06c3fb27SDimitry Andric     if (Sect.sh_type == ELF::SHT_ARM_EXIDX)
118*06c3fb27SDimitry Andric       return true;
119*06c3fb27SDimitry Andric     return false;
120*06c3fb27SDimitry Andric   }
121*06c3fb27SDimitry Andric 
122*06c3fb27SDimitry Andric   Error addRelocations() override {
123*06c3fb27SDimitry Andric     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
124*06c3fb27SDimitry Andric     using Self = ELFLinkGraphBuilder_aarch32<DataEndianness>;
125*06c3fb27SDimitry Andric     for (const auto &RelSect : Base::Sections) {
126*06c3fb27SDimitry Andric       if (Error Err = Base::forEachRelRelocation(RelSect, this,
127*06c3fb27SDimitry Andric                                                  &Self::addSingleRelRelocation))
128*06c3fb27SDimitry Andric         return Err;
129*06c3fb27SDimitry Andric     }
130*06c3fb27SDimitry Andric     return Error::success();
131*06c3fb27SDimitry Andric   }
132*06c3fb27SDimitry Andric 
133*06c3fb27SDimitry Andric   Error addSingleRelRelocation(const typename ELFT::Rel &Rel,
134*06c3fb27SDimitry Andric                                const typename ELFT::Shdr &FixupSect,
135*06c3fb27SDimitry Andric                                Block &BlockToFix) {
136*06c3fb27SDimitry Andric     uint32_t SymbolIndex = Rel.getSymbol(false);
137*06c3fb27SDimitry Andric     auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
138*06c3fb27SDimitry Andric     if (!ObjSymbol)
139*06c3fb27SDimitry Andric       return ObjSymbol.takeError();
140*06c3fb27SDimitry Andric 
141*06c3fb27SDimitry Andric     Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
142*06c3fb27SDimitry Andric     if (!GraphSymbol)
143*06c3fb27SDimitry Andric       return make_error<StringError>(
144*06c3fb27SDimitry Andric           formatv("Could not find symbol at given index, did you add it to "
145*06c3fb27SDimitry Andric                   "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
146*06c3fb27SDimitry Andric                   SymbolIndex, (*ObjSymbol)->st_shndx,
147*06c3fb27SDimitry Andric                   Base::GraphSymbols.size()),
148*06c3fb27SDimitry Andric           inconvertibleErrorCode());
149*06c3fb27SDimitry Andric 
150*06c3fb27SDimitry Andric     uint32_t Type = Rel.getType(false);
151*06c3fb27SDimitry Andric     Expected<aarch32::EdgeKind_aarch32> Kind = getJITLinkEdgeKind(Type);
152*06c3fb27SDimitry Andric     if (!Kind)
153*06c3fb27SDimitry Andric       return Kind.takeError();
154*06c3fb27SDimitry Andric 
155*06c3fb27SDimitry Andric     auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;
156*06c3fb27SDimitry Andric     Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
157*06c3fb27SDimitry Andric     Edge E(*Kind, Offset, *GraphSymbol, 0);
158*06c3fb27SDimitry Andric 
159*06c3fb27SDimitry Andric     Expected<int64_t> Addend =
160*06c3fb27SDimitry Andric         aarch32::readAddend(*Base::G, BlockToFix, E, ArmCfg);
161*06c3fb27SDimitry Andric     if (!Addend)
162*06c3fb27SDimitry Andric       return Addend.takeError();
163*06c3fb27SDimitry Andric 
164*06c3fb27SDimitry Andric     E.setAddend(*Addend);
165*06c3fb27SDimitry Andric     LLVM_DEBUG({
166*06c3fb27SDimitry Andric       dbgs() << "    ";
167*06c3fb27SDimitry Andric       printEdge(dbgs(), BlockToFix, E, getELFAArch32EdgeKindName(*Kind));
168*06c3fb27SDimitry Andric       dbgs() << "\n";
169*06c3fb27SDimitry Andric     });
170*06c3fb27SDimitry Andric 
171*06c3fb27SDimitry Andric     BlockToFix.addEdge(std::move(E));
172*06c3fb27SDimitry Andric     return Error::success();
173*06c3fb27SDimitry Andric   }
174*06c3fb27SDimitry Andric 
175*06c3fb27SDimitry Andric   aarch32::ArmConfig ArmCfg;
176*06c3fb27SDimitry Andric 
177*06c3fb27SDimitry Andric protected:
178*06c3fb27SDimitry Andric   TargetFlagsType makeTargetFlags(const typename ELFT::Sym &Sym) override {
179*06c3fb27SDimitry Andric     if (Sym.getValue() & 0x01)
180*06c3fb27SDimitry Andric       return aarch32::ThumbSymbol;
181*06c3fb27SDimitry Andric     return TargetFlagsType{};
182*06c3fb27SDimitry Andric   }
183*06c3fb27SDimitry Andric 
184*06c3fb27SDimitry Andric   orc::ExecutorAddrDiff getRawOffset(const typename ELFT::Sym &Sym,
185*06c3fb27SDimitry Andric                                      TargetFlagsType Flags) override {
186*06c3fb27SDimitry Andric     assert((makeTargetFlags(Sym) & Flags) == Flags);
187*06c3fb27SDimitry Andric     static constexpr uint64_t ThumbBit = 0x01;
188*06c3fb27SDimitry Andric     return Sym.getValue() & ~ThumbBit;
189*06c3fb27SDimitry Andric   }
190*06c3fb27SDimitry Andric 
191*06c3fb27SDimitry Andric public:
192*06c3fb27SDimitry Andric   ELFLinkGraphBuilder_aarch32(StringRef FileName,
193*06c3fb27SDimitry Andric                               const llvm::object::ELFFile<ELFT> &Obj, Triple TT,
194*06c3fb27SDimitry Andric                               SubtargetFeatures Features,
195*06c3fb27SDimitry Andric                               aarch32::ArmConfig ArmCfg)
196*06c3fb27SDimitry Andric       : ELFLinkGraphBuilder<ELFT>(Obj, std::move(TT), std::move(Features),
197*06c3fb27SDimitry Andric                                   FileName, getELFAArch32EdgeKindName),
198*06c3fb27SDimitry Andric         ArmCfg(std::move(ArmCfg)) {}
199*06c3fb27SDimitry Andric };
200*06c3fb27SDimitry Andric 
201*06c3fb27SDimitry Andric template <aarch32::StubsFlavor Flavor>
202*06c3fb27SDimitry Andric Error buildTables_ELF_aarch32(LinkGraph &G) {
203*06c3fb27SDimitry Andric   LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
204*06c3fb27SDimitry Andric 
205*06c3fb27SDimitry Andric   aarch32::StubsManager<Flavor> PLT;
206*06c3fb27SDimitry Andric   visitExistingEdges(G, PLT);
207*06c3fb27SDimitry Andric   return Error::success();
208*06c3fb27SDimitry Andric }
209*06c3fb27SDimitry Andric 
210*06c3fb27SDimitry Andric Expected<std::unique_ptr<LinkGraph>>
211*06c3fb27SDimitry Andric createLinkGraphFromELFObject_aarch32(MemoryBufferRef ObjectBuffer) {
212*06c3fb27SDimitry Andric   LLVM_DEBUG({
213*06c3fb27SDimitry Andric     dbgs() << "Building jitlink graph for new input "
214*06c3fb27SDimitry Andric            << ObjectBuffer.getBufferIdentifier() << "...\n";
215*06c3fb27SDimitry Andric   });
216*06c3fb27SDimitry Andric 
217*06c3fb27SDimitry Andric   auto ELFObj = ObjectFile::createELFObjectFile(ObjectBuffer);
218*06c3fb27SDimitry Andric   if (!ELFObj)
219*06c3fb27SDimitry Andric     return ELFObj.takeError();
220*06c3fb27SDimitry Andric 
221*06c3fb27SDimitry Andric   auto Features = (*ELFObj)->getFeatures();
222*06c3fb27SDimitry Andric   if (!Features)
223*06c3fb27SDimitry Andric     return Features.takeError();
224*06c3fb27SDimitry Andric 
225*06c3fb27SDimitry Andric   // Find out what exact AArch32 instruction set and features we target.
226*06c3fb27SDimitry Andric   auto TT = (*ELFObj)->makeTriple();
227*06c3fb27SDimitry Andric   ARM::ArchKind AK = ARM::parseArch(TT.getArchName());
228*06c3fb27SDimitry Andric   if (AK == ARM::ArchKind::INVALID)
229*06c3fb27SDimitry Andric     return make_error<JITLinkError>(
230*06c3fb27SDimitry Andric         "Failed to build ELF link graph: Invalid ARM ArchKind");
231*06c3fb27SDimitry Andric 
232*06c3fb27SDimitry Andric   // Resolve our internal configuration for the target. If at some point the
233*06c3fb27SDimitry Andric   // CPUArch alone becomes too unprecise, we can find more details in the
234*06c3fb27SDimitry Andric   // Tag_CPU_arch_profile.
235*06c3fb27SDimitry Andric   aarch32::ArmConfig ArmCfg;
236*06c3fb27SDimitry Andric   using namespace ARMBuildAttrs;
237*06c3fb27SDimitry Andric   auto Arch = static_cast<CPUArch>(ARM::getArchAttr(AK));
238*06c3fb27SDimitry Andric   switch (Arch) {
239*06c3fb27SDimitry Andric   case v7:
240*06c3fb27SDimitry Andric   case v8_A:
241*06c3fb27SDimitry Andric     ArmCfg = aarch32::getArmConfigForCPUArch(Arch);
242*06c3fb27SDimitry Andric     assert(ArmCfg.Stubs != aarch32::Unsupported &&
243*06c3fb27SDimitry Andric            "Provide a config for each supported CPU");
244*06c3fb27SDimitry Andric     break;
245*06c3fb27SDimitry Andric   default:
246*06c3fb27SDimitry Andric     return make_error<JITLinkError>(
247*06c3fb27SDimitry Andric         "Failed to build ELF link graph: Unsupported CPU arch " +
248*06c3fb27SDimitry Andric         StringRef(aarch32::getCPUArchName(Arch)));
249*06c3fb27SDimitry Andric   }
250*06c3fb27SDimitry Andric 
251*06c3fb27SDimitry Andric   // Populate the link-graph.
252*06c3fb27SDimitry Andric   switch (TT.getArch()) {
253*06c3fb27SDimitry Andric   case Triple::arm:
254*06c3fb27SDimitry Andric   case Triple::thumb: {
255*06c3fb27SDimitry Andric     auto &ELFFile = cast<ELFObjectFile<ELF32LE>>(**ELFObj).getELFFile();
256*06c3fb27SDimitry Andric     return ELFLinkGraphBuilder_aarch32<support::little>(
257*06c3fb27SDimitry Andric                (*ELFObj)->getFileName(), ELFFile, TT, std::move(*Features),
258*06c3fb27SDimitry Andric                ArmCfg)
259*06c3fb27SDimitry Andric         .buildGraph();
260*06c3fb27SDimitry Andric   }
261*06c3fb27SDimitry Andric   case Triple::armeb:
262*06c3fb27SDimitry Andric   case Triple::thumbeb: {
263*06c3fb27SDimitry Andric     auto &ELFFile = cast<ELFObjectFile<ELF32BE>>(**ELFObj).getELFFile();
264*06c3fb27SDimitry Andric     return ELFLinkGraphBuilder_aarch32<support::big>(
265*06c3fb27SDimitry Andric                (*ELFObj)->getFileName(), ELFFile, TT, std::move(*Features),
266*06c3fb27SDimitry Andric                ArmCfg)
267*06c3fb27SDimitry Andric         .buildGraph();
268*06c3fb27SDimitry Andric   }
269*06c3fb27SDimitry Andric   default:
270*06c3fb27SDimitry Andric     return make_error<JITLinkError>(
271*06c3fb27SDimitry Andric         "Failed to build ELF/aarch32 link graph: Invalid target triple " +
272*06c3fb27SDimitry Andric         TT.getTriple());
273*06c3fb27SDimitry Andric   }
274*06c3fb27SDimitry Andric }
275*06c3fb27SDimitry Andric 
276*06c3fb27SDimitry Andric void link_ELF_aarch32(std::unique_ptr<LinkGraph> G,
277*06c3fb27SDimitry Andric                       std::unique_ptr<JITLinkContext> Ctx) {
278*06c3fb27SDimitry Andric   const Triple &TT = G->getTargetTriple();
279*06c3fb27SDimitry Andric 
280*06c3fb27SDimitry Andric   using namespace ARMBuildAttrs;
281*06c3fb27SDimitry Andric   ARM::ArchKind AK = ARM::parseArch(TT.getArchName());
282*06c3fb27SDimitry Andric   auto CPU = static_cast<CPUArch>(ARM::getArchAttr(AK));
283*06c3fb27SDimitry Andric   aarch32::ArmConfig ArmCfg = aarch32::getArmConfigForCPUArch(CPU);
284*06c3fb27SDimitry Andric 
285*06c3fb27SDimitry Andric   PassConfiguration PassCfg;
286*06c3fb27SDimitry Andric   if (Ctx->shouldAddDefaultTargetPasses(TT)) {
287*06c3fb27SDimitry Andric     // Add a mark-live pass.
288*06c3fb27SDimitry Andric     if (auto MarkLive = Ctx->getMarkLivePass(TT))
289*06c3fb27SDimitry Andric       PassCfg.PrePrunePasses.push_back(std::move(MarkLive));
290*06c3fb27SDimitry Andric     else
291*06c3fb27SDimitry Andric       PassCfg.PrePrunePasses.push_back(markAllSymbolsLive);
292*06c3fb27SDimitry Andric 
293*06c3fb27SDimitry Andric     switch (ArmCfg.Stubs) {
294*06c3fb27SDimitry Andric     case aarch32::Thumbv7:
295*06c3fb27SDimitry Andric       PassCfg.PostPrunePasses.push_back(
296*06c3fb27SDimitry Andric           buildTables_ELF_aarch32<aarch32::Thumbv7>);
297*06c3fb27SDimitry Andric       break;
298*06c3fb27SDimitry Andric     case aarch32::Unsupported:
299*06c3fb27SDimitry Andric       llvm_unreachable("Check before building graph");
300*06c3fb27SDimitry Andric     }
301*06c3fb27SDimitry Andric   }
302*06c3fb27SDimitry Andric 
303*06c3fb27SDimitry Andric   if (auto Err = Ctx->modifyPassConfig(*G, PassCfg))
304*06c3fb27SDimitry Andric     return Ctx->notifyFailed(std::move(Err));
305*06c3fb27SDimitry Andric 
306*06c3fb27SDimitry Andric   ELFJITLinker_aarch32::link(std::move(Ctx), std::move(G), std::move(PassCfg),
307*06c3fb27SDimitry Andric                              std::move(ArmCfg));
308*06c3fb27SDimitry Andric }
309*06c3fb27SDimitry Andric 
310*06c3fb27SDimitry Andric } // namespace jitlink
311*06c3fb27SDimitry Andric } // namespace llvm
312