1 //===----- ELF_aarch32.cpp - JIT linker implementation for arm/thumb ------===//
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
7 //===----------------------------------------------------------------------===//
9 // ELF/aarch32 jit-link implementation.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ExecutionEngine/JITLink/ELF_aarch32.h"
15 #include "llvm/BinaryFormat/ELF.h"
16 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
17 #include "llvm/ExecutionEngine/JITLink/aarch32.h"
18 #include "llvm/Object/ELF.h"
19 #include "llvm/Object/ELFObjectFile.h"
20 #include "llvm/Support/Endian.h"
21 #include "llvm/Support/ErrorHandling.h"
22 #include "llvm/TargetParser/ARMTargetParser.h"
24 #include "ELFLinkGraphBuilder.h"
25 #include "JITLinkGeneric.h"
27 #define DEBUG_TYPE "jitlink"
29 using namespace llvm::object
;
34 /// Translate from ELF relocation type to JITLink-internal edge kind.
35 Expected
<aarch32::EdgeKind_aarch32
> getJITLinkEdgeKind(uint32_t ELFType
) {
37 case ELF::R_ARM_ABS32
:
38 return aarch32::Data_Pointer32
;
39 case ELF::R_ARM_REL32
:
40 return aarch32::Data_Delta32
;
42 return aarch32::Arm_Call
;
43 case ELF::R_ARM_JUMP24
:
44 return aarch32::Arm_Jump24
;
45 case ELF::R_ARM_MOVW_ABS_NC
:
46 return aarch32::Arm_MovwAbsNC
;
47 case ELF::R_ARM_MOVT_ABS
:
48 return aarch32::Arm_MovtAbs
;
49 case ELF::R_ARM_THM_CALL
:
50 return aarch32::Thumb_Call
;
51 case ELF::R_ARM_THM_JUMP24
:
52 return aarch32::Thumb_Jump24
;
53 case ELF::R_ARM_THM_MOVW_ABS_NC
:
54 return aarch32::Thumb_MovwAbsNC
;
55 case ELF::R_ARM_THM_MOVT_ABS
:
56 return aarch32::Thumb_MovtAbs
;
59 return make_error
<JITLinkError
>(
60 "Unsupported aarch32 relocation " + formatv("{0:d}: ", ELFType
) +
61 object::getELFRelocationTypeName(ELF::EM_ARM
, ELFType
));
64 /// Translate from JITLink-internal edge kind back to ELF relocation type.
65 Expected
<uint32_t> getELFRelocationType(Edge::Kind Kind
) {
66 switch (static_cast<aarch32::EdgeKind_aarch32
>(Kind
)) {
67 case aarch32::Data_Delta32
:
68 return ELF::R_ARM_REL32
;
69 case aarch32::Data_Pointer32
:
70 return ELF::R_ARM_ABS32
;
71 case aarch32::Arm_Call
:
72 return ELF::R_ARM_CALL
;
73 case aarch32::Arm_Jump24
:
74 return ELF::R_ARM_JUMP24
;
75 case aarch32::Arm_MovwAbsNC
:
76 return ELF::R_ARM_MOVW_ABS_NC
;
77 case aarch32::Arm_MovtAbs
:
78 return ELF::R_ARM_MOVT_ABS
;
79 case aarch32::Thumb_Call
:
80 return ELF::R_ARM_THM_CALL
;
81 case aarch32::Thumb_Jump24
:
82 return ELF::R_ARM_THM_JUMP24
;
83 case aarch32::Thumb_MovwAbsNC
:
84 return ELF::R_ARM_THM_MOVW_ABS_NC
;
85 case aarch32::Thumb_MovtAbs
:
86 return ELF::R_ARM_THM_MOVT_ABS
;
89 return make_error
<JITLinkError
>(formatv("Invalid aarch32 edge {0:d}: ",
93 /// Get a human-readable name for the given ELF AArch32 edge kind.
94 const char *getELFAArch32EdgeKindName(Edge::Kind R
) {
95 // No ELF-specific edge kinds yet
96 return aarch32::getEdgeKindName(R
);
99 class ELFJITLinker_aarch32
: public JITLinker
<ELFJITLinker_aarch32
> {
100 friend class JITLinker
<ELFJITLinker_aarch32
>;
103 ELFJITLinker_aarch32(std::unique_ptr
<JITLinkContext
> Ctx
,
104 std::unique_ptr
<LinkGraph
> G
, PassConfiguration PassCfg
,
105 aarch32::ArmConfig ArmCfg
)
106 : JITLinker(std::move(Ctx
), std::move(G
), std::move(PassCfg
)),
107 ArmCfg(std::move(ArmCfg
)) {}
110 aarch32::ArmConfig ArmCfg
;
112 Error
applyFixup(LinkGraph
&G
, Block
&B
, const Edge
&E
) const {
113 return aarch32::applyFixup(G
, B
, E
, ArmCfg
);
117 template <support::endianness DataEndianness
>
118 class ELFLinkGraphBuilder_aarch32
119 : public ELFLinkGraphBuilder
<ELFType
<DataEndianness
, false>> {
121 using ELFT
= ELFType
<DataEndianness
, false>;
122 using Base
= ELFLinkGraphBuilder
<ELFT
>;
124 bool excludeSection(const typename
ELFT::Shdr
&Sect
) const override
{
125 // TODO: An .ARM.exidx (Exception Index table) entry is 8-bytes in size and
126 // consists of 2 words. It might be sufficient to process only relocations
127 // in the the second word (offset 4). Please find more details in: Exception
128 // Handling ABI for the ArmĀ® Architecture -> Index table entries
129 if (Sect
.sh_type
== ELF::SHT_ARM_EXIDX
)
134 Error
addRelocations() override
{
135 LLVM_DEBUG(dbgs() << "Processing relocations:\n");
136 using Self
= ELFLinkGraphBuilder_aarch32
<DataEndianness
>;
137 for (const auto &RelSect
: Base::Sections
) {
138 if (Error Err
= Base::forEachRelRelocation(RelSect
, this,
139 &Self::addSingleRelRelocation
))
142 return Error::success();
145 Error
addSingleRelRelocation(const typename
ELFT::Rel
&Rel
,
146 const typename
ELFT::Shdr
&FixupSect
,
148 uint32_t SymbolIndex
= Rel
.getSymbol(false);
149 auto ObjSymbol
= Base::Obj
.getRelocationSymbol(Rel
, Base::SymTabSec
);
151 return ObjSymbol
.takeError();
153 Symbol
*GraphSymbol
= Base::getGraphSymbol(SymbolIndex
);
155 return make_error
<StringError
>(
156 formatv("Could not find symbol at given index, did you add it to "
157 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
158 SymbolIndex
, (*ObjSymbol
)->st_shndx
,
159 Base::GraphSymbols
.size()),
160 inconvertibleErrorCode());
162 uint32_t Type
= Rel
.getType(false);
163 Expected
<aarch32::EdgeKind_aarch32
> Kind
= getJITLinkEdgeKind(Type
);
165 return Kind
.takeError();
167 auto FixupAddress
= orc::ExecutorAddr(FixupSect
.sh_addr
) + Rel
.r_offset
;
168 Edge::OffsetT Offset
= FixupAddress
- BlockToFix
.getAddress();
169 Edge
E(*Kind
, Offset
, *GraphSymbol
, 0);
171 Expected
<int64_t> Addend
=
172 aarch32::readAddend(*Base::G
, BlockToFix
, E
, ArmCfg
);
174 return Addend
.takeError();
176 E
.setAddend(*Addend
);
179 printEdge(dbgs(), BlockToFix
, E
, getELFAArch32EdgeKindName(*Kind
));
183 BlockToFix
.addEdge(std::move(E
));
184 return Error::success();
187 aarch32::ArmConfig ArmCfg
;
190 TargetFlagsType
makeTargetFlags(const typename
ELFT::Sym
&Sym
) override
{
191 if (Sym
.getValue() & 0x01)
192 return aarch32::ThumbSymbol
;
193 return TargetFlagsType
{};
196 orc::ExecutorAddrDiff
getRawOffset(const typename
ELFT::Sym
&Sym
,
197 TargetFlagsType Flags
) override
{
198 assert((makeTargetFlags(Sym
) & Flags
) == Flags
);
199 static constexpr uint64_t ThumbBit
= 0x01;
200 return Sym
.getValue() & ~ThumbBit
;
204 ELFLinkGraphBuilder_aarch32(StringRef FileName
,
205 const llvm::object::ELFFile
<ELFT
> &Obj
, Triple TT
,
206 SubtargetFeatures Features
,
207 aarch32::ArmConfig ArmCfg
)
208 : ELFLinkGraphBuilder
<ELFT
>(Obj
, std::move(TT
), std::move(Features
),
209 FileName
, getELFAArch32EdgeKindName
),
210 ArmCfg(std::move(ArmCfg
)) {}
213 template <aarch32::StubsFlavor Flavor
>
214 Error
buildTables_ELF_aarch32(LinkGraph
&G
) {
215 LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
217 aarch32::StubsManager
<Flavor
> PLT
;
218 visitExistingEdges(G
, PLT
);
219 return Error::success();
222 Expected
<std::unique_ptr
<LinkGraph
>>
223 createLinkGraphFromELFObject_aarch32(MemoryBufferRef ObjectBuffer
) {
225 dbgs() << "Building jitlink graph for new input "
226 << ObjectBuffer
.getBufferIdentifier() << "...\n";
229 auto ELFObj
= ObjectFile::createELFObjectFile(ObjectBuffer
);
231 return ELFObj
.takeError();
233 auto Features
= (*ELFObj
)->getFeatures();
235 return Features
.takeError();
237 // Find out what exact AArch32 instruction set and features we target.
238 auto TT
= (*ELFObj
)->makeTriple();
239 ARM::ArchKind AK
= ARM::parseArch(TT
.getArchName());
240 if (AK
== ARM::ArchKind::INVALID
)
241 return make_error
<JITLinkError
>(
242 "Failed to build ELF link graph: Invalid ARM ArchKind");
244 // Resolve our internal configuration for the target. If at some point the
245 // CPUArch alone becomes too unprecise, we can find more details in the
246 // Tag_CPU_arch_profile.
247 aarch32::ArmConfig ArmCfg
;
248 using namespace ARMBuildAttrs
;
249 auto Arch
= static_cast<CPUArch
>(ARM::getArchAttr(AK
));
253 ArmCfg
= aarch32::getArmConfigForCPUArch(Arch
);
254 assert(ArmCfg
.Stubs
!= aarch32::Unsupported
&&
255 "Provide a config for each supported CPU");
258 return make_error
<JITLinkError
>(
259 "Failed to build ELF link graph: Unsupported CPU arch " +
260 StringRef(aarch32::getCPUArchName(Arch
)));
263 // Populate the link-graph.
264 switch (TT
.getArch()) {
266 case Triple::thumb
: {
267 auto &ELFFile
= cast
<ELFObjectFile
<ELF32LE
>>(**ELFObj
).getELFFile();
268 return ELFLinkGraphBuilder_aarch32
<support::little
>(
269 (*ELFObj
)->getFileName(), ELFFile
, TT
, std::move(*Features
),
274 case Triple::thumbeb
: {
275 auto &ELFFile
= cast
<ELFObjectFile
<ELF32BE
>>(**ELFObj
).getELFFile();
276 return ELFLinkGraphBuilder_aarch32
<support::big
>(
277 (*ELFObj
)->getFileName(), ELFFile
, TT
, std::move(*Features
),
282 return make_error
<JITLinkError
>(
283 "Failed to build ELF/aarch32 link graph: Invalid target triple " +
288 void link_ELF_aarch32(std::unique_ptr
<LinkGraph
> G
,
289 std::unique_ptr
<JITLinkContext
> Ctx
) {
290 const Triple
&TT
= G
->getTargetTriple();
292 using namespace ARMBuildAttrs
;
293 ARM::ArchKind AK
= ARM::parseArch(TT
.getArchName());
294 auto CPU
= static_cast<CPUArch
>(ARM::getArchAttr(AK
));
295 aarch32::ArmConfig ArmCfg
= aarch32::getArmConfigForCPUArch(CPU
);
297 PassConfiguration PassCfg
;
298 if (Ctx
->shouldAddDefaultTargetPasses(TT
)) {
299 // Add a mark-live pass.
300 if (auto MarkLive
= Ctx
->getMarkLivePass(TT
))
301 PassCfg
.PrePrunePasses
.push_back(std::move(MarkLive
));
303 PassCfg
.PrePrunePasses
.push_back(markAllSymbolsLive
);
305 switch (ArmCfg
.Stubs
) {
306 case aarch32::Thumbv7
:
307 PassCfg
.PostPrunePasses
.push_back(
308 buildTables_ELF_aarch32
<aarch32::Thumbv7
>);
310 case aarch32::Unsupported
:
311 llvm_unreachable("Check before building graph");
315 if (auto Err
= Ctx
->modifyPassConfig(*G
, PassCfg
))
316 return Ctx
->notifyFailed(std::move(Err
));
318 ELFJITLinker_aarch32::link(std::move(Ctx
), std::move(G
), std::move(PassCfg
),
322 } // namespace jitlink