1 //===--- ELF_loongarch.cpp - JIT linker implementation for ELF/loongarch --===//
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/loongarch jit-link implementation.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ExecutionEngine/JITLink/ELF_loongarch.h"
14 #include "llvm/BinaryFormat/ELF.h"
15 #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"
16 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
17 #include "llvm/ExecutionEngine/JITLink/loongarch.h"
18 #include "llvm/Object/ELF.h"
19 #include "llvm/Object/ELFObjectFile.h"
21 #include "EHFrameSupportImpl.h"
22 #include "ELFLinkGraphBuilder.h"
23 #include "JITLinkGeneric.h"
25 #define DEBUG_TYPE "jitlink"
28 using namespace llvm::jitlink
;
29 using namespace llvm::jitlink::loongarch
;
33 class ELFJITLinker_loongarch
: public JITLinker
<ELFJITLinker_loongarch
> {
34 friend class JITLinker
<ELFJITLinker_loongarch
>;
37 ELFJITLinker_loongarch(std::unique_ptr
<JITLinkContext
> Ctx
,
38 std::unique_ptr
<LinkGraph
> G
,
39 PassConfiguration PassConfig
)
40 : JITLinker(std::move(Ctx
), std::move(G
), std::move(PassConfig
)) {}
43 Error
applyFixup(LinkGraph
&G
, Block
&B
, const Edge
&E
) const {
44 return loongarch::applyFixup(G
, B
, E
);
48 template <typename ELFT
>
49 class ELFLinkGraphBuilder_loongarch
: public ELFLinkGraphBuilder
<ELFT
> {
51 static Expected
<loongarch::EdgeKind_loongarch
>
52 getRelocationKind(const uint32_t Type
) {
53 using namespace loongarch
;
59 case ELF::R_LARCH_32_PCREL
:
61 case ELF::R_LARCH_B26
:
63 case ELF::R_LARCH_PCALA_HI20
:
65 case ELF::R_LARCH_PCALA_LO12
:
67 case ELF::R_LARCH_GOT_PC_HI20
:
68 return RequestGOTAndTransformToPage20
;
69 case ELF::R_LARCH_GOT_PC_LO12
:
70 return RequestGOTAndTransformToPageOffset12
;
73 return make_error
<JITLinkError
>(
74 "Unsupported loongarch relocation:" + formatv("{0:d}: ", Type
) +
75 object::getELFRelocationTypeName(ELF::EM_LOONGARCH
, Type
));
78 Error
addRelocations() override
{
79 LLVM_DEBUG(dbgs() << "Processing relocations:\n");
81 using Base
= ELFLinkGraphBuilder
<ELFT
>;
82 using Self
= ELFLinkGraphBuilder_loongarch
<ELFT
>;
83 for (const auto &RelSect
: Base::Sections
)
84 if (Error Err
= Base::forEachRelaRelocation(RelSect
, this,
85 &Self::addSingleRelocation
))
88 return Error::success();
91 Error
addSingleRelocation(const typename
ELFT::Rela
&Rel
,
92 const typename
ELFT::Shdr
&FixupSect
,
94 using Base
= ELFLinkGraphBuilder
<ELFT
>;
96 uint32_t SymbolIndex
= Rel
.getSymbol(false);
97 auto ObjSymbol
= Base::Obj
.getRelocationSymbol(Rel
, Base::SymTabSec
);
99 return ObjSymbol
.takeError();
101 Symbol
*GraphSymbol
= Base::getGraphSymbol(SymbolIndex
);
103 return make_error
<StringError
>(
104 formatv("Could not find symbol at given index, did you add it to "
105 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
106 SymbolIndex
, (*ObjSymbol
)->st_shndx
,
107 Base::GraphSymbols
.size()),
108 inconvertibleErrorCode());
110 uint32_t Type
= Rel
.getType(false);
111 Expected
<loongarch::EdgeKind_loongarch
> Kind
= getRelocationKind(Type
);
113 return Kind
.takeError();
115 int64_t Addend
= Rel
.r_addend
;
116 auto FixupAddress
= orc::ExecutorAddr(FixupSect
.sh_addr
) + Rel
.r_offset
;
117 Edge::OffsetT Offset
= FixupAddress
- BlockToFix
.getAddress();
118 Edge
GE(*Kind
, Offset
, *GraphSymbol
, Addend
);
121 printEdge(dbgs(), BlockToFix
, GE
, loongarch::getEdgeKindName(*Kind
));
125 BlockToFix
.addEdge(std::move(GE
));
127 return Error::success();
131 ELFLinkGraphBuilder_loongarch(StringRef FileName
,
132 const object::ELFFile
<ELFT
> &Obj
, Triple TT
,
133 SubtargetFeatures Features
)
134 : ELFLinkGraphBuilder
<ELFT
>(Obj
, std::move(TT
), std::move(Features
),
135 FileName
, loongarch::getEdgeKindName
) {}
138 Error
buildTables_ELF_loongarch(LinkGraph
&G
) {
139 LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
142 PLTTableManager
PLT(GOT
);
143 visitExistingEdges(G
, GOT
, PLT
);
144 return Error::success();
152 Expected
<std::unique_ptr
<LinkGraph
>>
153 createLinkGraphFromELFObject_loongarch(MemoryBufferRef ObjectBuffer
) {
155 dbgs() << "Building jitlink graph for new input "
156 << ObjectBuffer
.getBufferIdentifier() << "...\n";
159 auto ELFObj
= object::ObjectFile::createELFObjectFile(ObjectBuffer
);
161 return ELFObj
.takeError();
163 auto Features
= (*ELFObj
)->getFeatures();
165 return Features
.takeError();
167 if ((*ELFObj
)->getArch() == Triple::loongarch64
) {
168 auto &ELFObjFile
= cast
<object::ELFObjectFile
<object::ELF64LE
>>(**ELFObj
);
169 return ELFLinkGraphBuilder_loongarch
<object::ELF64LE
>(
170 (*ELFObj
)->getFileName(), ELFObjFile
.getELFFile(),
171 (*ELFObj
)->makeTriple(), std::move(*Features
))
175 assert((*ELFObj
)->getArch() == Triple::loongarch32
&&
176 "Invalid triple for LoongArch ELF object file");
177 auto &ELFObjFile
= cast
<object::ELFObjectFile
<object::ELF32LE
>>(**ELFObj
);
178 return ELFLinkGraphBuilder_loongarch
<object::ELF32LE
>(
179 (*ELFObj
)->getFileName(), ELFObjFile
.getELFFile(),
180 (*ELFObj
)->makeTriple(), std::move(*Features
))
184 void link_ELF_loongarch(std::unique_ptr
<LinkGraph
> G
,
185 std::unique_ptr
<JITLinkContext
> Ctx
) {
186 PassConfiguration Config
;
187 const Triple
&TT
= G
->getTargetTriple();
188 if (Ctx
->shouldAddDefaultTargetPasses(TT
)) {
189 // Add eh-frame passes.
190 Config
.PrePrunePasses
.push_back(DWARFRecordSectionSplitter(".eh_frame"));
191 Config
.PrePrunePasses
.push_back(
192 EHFrameEdgeFixer(".eh_frame", G
->getPointerSize(), Pointer32
, Pointer64
,
193 Delta32
, Delta64
, NegDelta32
));
194 Config
.PrePrunePasses
.push_back(EHFrameNullTerminator(".eh_frame"));
196 // Add a mark-live pass.
197 if (auto MarkLive
= Ctx
->getMarkLivePass(TT
))
198 Config
.PrePrunePasses
.push_back(std::move(MarkLive
));
200 Config
.PrePrunePasses
.push_back(markAllSymbolsLive
);
202 // Add an in-place GOT/PLTStubs build pass.
203 Config
.PostPrunePasses
.push_back(buildTables_ELF_loongarch
);
206 if (auto Err
= Ctx
->modifyPassConfig(*G
, Config
))
207 return Ctx
->notifyFailed(std::move(Err
));
209 ELFJITLinker_loongarch::link(std::move(Ctx
), std::move(G
), std::move(Config
));
212 } // namespace jitlink