[sanitizer] Improve FreeBSD ASLR detection
[llvm-project.git] / llvm / lib / ExecutionEngine / JITLink / ELF_riscv.cpp
blob291a2ac46bd069e53f27decbd3dd18dbec1275a1
1 //===------- ELF_riscv.cpp -JIT linker implementation for ELF/riscv -------===//
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 // ELF/riscv jit-link implementation.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ExecutionEngine/JITLink/ELF_riscv.h"
14 #include "ELFLinkGraphBuilder.h"
15 #include "JITLinkGeneric.h"
16 #include "PerGraphGOTAndPLTStubsBuilder.h"
17 #include "llvm/BinaryFormat/ELF.h"
18 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
19 #include "llvm/ExecutionEngine/JITLink/riscv.h"
20 #include "llvm/Object/ELF.h"
21 #include "llvm/Object/ELFObjectFile.h"
23 #define DEBUG_TYPE "jitlink"
24 using namespace llvm;
25 using namespace llvm::jitlink;
26 using namespace llvm::jitlink::riscv;
28 namespace {
30 class PerGraphGOTAndPLTStubsBuilder_ELF_riscv
31 : public PerGraphGOTAndPLTStubsBuilder<
32 PerGraphGOTAndPLTStubsBuilder_ELF_riscv> {
33 public:
34 static constexpr size_t StubEntrySize = 16;
35 static const uint8_t NullGOTEntryContent[8];
36 static const uint8_t RV64StubContent[StubEntrySize];
37 static const uint8_t RV32StubContent[StubEntrySize];
39 using PerGraphGOTAndPLTStubsBuilder<
40 PerGraphGOTAndPLTStubsBuilder_ELF_riscv>::PerGraphGOTAndPLTStubsBuilder;
42 bool isRV64() const { return G.getPointerSize() == 8; }
44 bool isGOTEdgeToFix(Edge &E) const { return E.getKind() == R_RISCV_GOT_HI20; }
46 Symbol &createGOTEntry(Symbol &Target) {
47 Block &GOTBlock =
48 G.createContentBlock(getGOTSection(), getGOTEntryBlockContent(),
49 orc::ExecutorAddr(), G.getPointerSize(), 0);
50 GOTBlock.addEdge(isRV64() ? R_RISCV_64 : R_RISCV_32, 0, Target, 0);
51 return G.addAnonymousSymbol(GOTBlock, 0, G.getPointerSize(), false, false);
54 Symbol &createPLTStub(Symbol &Target) {
55 Block &StubContentBlock = G.createContentBlock(
56 getStubsSection(), getStubBlockContent(), orc::ExecutorAddr(), 4, 0);
57 auto &GOTEntrySymbol = getGOTEntry(Target);
58 StubContentBlock.addEdge(R_RISCV_CALL, 0, GOTEntrySymbol, 0);
59 return G.addAnonymousSymbol(StubContentBlock, 0, StubEntrySize, true,
60 false);
63 void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
64 // Replace the relocation pair (R_RISCV_GOT_HI20, R_RISCV_PCREL_LO12)
65 // with (R_RISCV_PCREL_HI20, R_RISCV_PCREL_LO12)
66 // Therefore, here just change the R_RISCV_GOT_HI20 to R_RISCV_PCREL_HI20
67 E.setKind(R_RISCV_PCREL_HI20);
68 E.setTarget(GOTEntry);
71 void fixPLTEdge(Edge &E, Symbol &PLTStubs) {
72 assert(E.getKind() == R_RISCV_CALL_PLT && "Not a R_RISCV_CALL_PLT edge?");
73 E.setKind(R_RISCV_CALL);
74 E.setTarget(PLTStubs);
77 bool isExternalBranchEdge(Edge &E) const {
78 return E.getKind() == R_RISCV_CALL_PLT;
81 private:
82 Section &getGOTSection() const {
83 if (!GOTSection)
84 GOTSection = &G.createSection("$__GOT", MemProt::Read);
85 return *GOTSection;
88 Section &getStubsSection() const {
89 if (!StubsSection)
90 StubsSection =
91 &G.createSection("$__STUBS", MemProt::Read | MemProt::Exec);
92 return *StubsSection;
95 ArrayRef<char> getGOTEntryBlockContent() {
96 return {reinterpret_cast<const char *>(NullGOTEntryContent),
97 G.getPointerSize()};
100 ArrayRef<char> getStubBlockContent() {
101 auto StubContent = isRV64() ? RV64StubContent : RV32StubContent;
102 return {reinterpret_cast<const char *>(StubContent), StubEntrySize};
105 mutable Section *GOTSection = nullptr;
106 mutable Section *StubsSection = nullptr;
109 const uint8_t PerGraphGOTAndPLTStubsBuilder_ELF_riscv::NullGOTEntryContent[8] =
110 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
112 const uint8_t
113 PerGraphGOTAndPLTStubsBuilder_ELF_riscv::RV64StubContent[StubEntrySize] = {
114 0x17, 0x0e, 0x00, 0x00, // auipc t3, literal
115 0x03, 0x3e, 0x0e, 0x00, // ld t3, literal(t3)
116 0x67, 0x00, 0x0e, 0x00, // jr t3
117 0x13, 0x00, 0x00, 0x00}; // nop
119 const uint8_t
120 PerGraphGOTAndPLTStubsBuilder_ELF_riscv::RV32StubContent[StubEntrySize] = {
121 0x17, 0x0e, 0x00, 0x00, // auipc t3, literal
122 0x03, 0x2e, 0x0e, 0x00, // lw t3, literal(t3)
123 0x67, 0x00, 0x0e, 0x00, // jr t3
124 0x13, 0x00, 0x00, 0x00}; // nop
125 } // namespace
126 namespace llvm {
127 namespace jitlink {
129 static Expected<const Edge &> getRISCVPCRelHi20(const Edge &E) {
130 using namespace riscv;
131 assert((E.getKind() == R_RISCV_PCREL_LO12_I ||
132 E.getKind() == R_RISCV_PCREL_LO12_S) &&
133 "Can only have high relocation for R_RISCV_PCREL_LO12_I or "
134 "R_RISCV_PCREL_LO12_S");
136 const Symbol &Sym = E.getTarget();
137 const Block &B = Sym.getBlock();
138 orc::ExecutorAddrDiff Offset = Sym.getOffset();
140 struct Comp {
141 bool operator()(const Edge &Lhs, orc::ExecutorAddrDiff Offset) {
142 return Lhs.getOffset() < Offset;
144 bool operator()(orc::ExecutorAddrDiff Offset, const Edge &Rhs) {
145 return Offset < Rhs.getOffset();
149 auto Bound =
150 std::equal_range(B.edges().begin(), B.edges().end(), Offset, Comp{});
152 for (auto It = Bound.first; It != Bound.second; ++It) {
153 if (It->getKind() == R_RISCV_PCREL_HI20)
154 return *It;
157 return make_error<JITLinkError>(
158 "No HI20 PCREL relocation type be found for LO12 PCREL relocation type");
161 static uint32_t extractBits(uint32_t Num, unsigned Low, unsigned Size) {
162 return (Num & (((1ULL << (Size + 1)) - 1) << Low)) >> Low;
165 inline Error checkAlignment(llvm::orc::ExecutorAddr loc, uint64_t v, int n,
166 const Edge &E) {
167 if (v & (n - 1))
168 return make_error<JITLinkError>("0x" + llvm::utohexstr(loc.getValue()) +
169 " improper alignment for relocation " +
170 formatv("{0:d}", E.getKind()) + ": 0x" +
171 llvm::utohexstr(v) + " is not aligned to " +
172 Twine(n) + " bytes");
173 return Error::success();
176 static inline bool isInRangeForImmS32(int64_t Value) {
177 return (Value >= std::numeric_limits<int32_t>::min() &&
178 Value <= std::numeric_limits<int32_t>::max());
181 class ELFJITLinker_riscv : public JITLinker<ELFJITLinker_riscv> {
182 friend class JITLinker<ELFJITLinker_riscv>;
184 public:
185 ELFJITLinker_riscv(std::unique_ptr<JITLinkContext> Ctx,
186 std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig)
187 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
189 private:
190 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
191 using namespace riscv;
192 using namespace llvm::support;
194 char *BlockWorkingMem = B.getAlreadyMutableContent().data();
195 char *FixupPtr = BlockWorkingMem + E.getOffset();
196 orc::ExecutorAddr FixupAddress = B.getAddress() + E.getOffset();
197 switch (E.getKind()) {
198 case R_RISCV_32: {
199 int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue();
200 *(little32_t *)FixupPtr = static_cast<uint32_t>(Value);
201 break;
203 case R_RISCV_64: {
204 int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue();
205 *(little64_t *)FixupPtr = static_cast<uint64_t>(Value);
206 break;
208 case R_RISCV_BRANCH: {
209 int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
210 Error AlignmentIssue = checkAlignment(FixupAddress, Value, 2, E);
211 if (AlignmentIssue) {
212 return AlignmentIssue;
214 int64_t Lo = Value & 0xFFF;
215 uint32_t Imm31_25 = extractBits(Lo, 5, 6) << 25 | extractBits(Lo, 12, 1)
216 << 31;
217 uint32_t Imm11_7 = extractBits(Lo, 1, 4) << 8 | extractBits(Lo, 11, 1)
218 << 7;
219 uint32_t RawInstr = *(little32_t *)FixupPtr;
220 *(little32_t *)FixupPtr = (RawInstr & 0x1FFF07F) | Imm31_25 | Imm11_7;
221 break;
223 case R_RISCV_HI20: {
224 int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue();
225 int64_t Hi = Value + 0x800;
226 if (LLVM_UNLIKELY(!isInRangeForImmS32(Hi)))
227 return makeTargetOutOfRangeError(G, B, E);
228 uint32_t RawInstr = *(little32_t *)FixupPtr;
229 *(little32_t *)FixupPtr =
230 (RawInstr & 0xFFF) | (static_cast<uint32_t>(Hi & 0xFFFFF000));
231 break;
233 case R_RISCV_LO12_I: {
234 // FIXME: We assume that R_RISCV_HI20 is present in object code and pairs
235 // with current relocation R_RISCV_LO12_I. So here may need a check.
236 int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue();
237 int32_t Lo = Value & 0xFFF;
238 uint32_t RawInstr = *(little32_t *)FixupPtr;
239 *(little32_t *)FixupPtr =
240 (RawInstr & 0xFFFFF) | (static_cast<uint32_t>(Lo & 0xFFF) << 20);
241 break;
243 case R_RISCV_CALL: {
244 int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
245 int64_t Hi = Value + 0x800;
246 if (LLVM_UNLIKELY(!isInRangeForImmS32(Hi)))
247 return makeTargetOutOfRangeError(G, B, E);
248 int32_t Lo = Value & 0xFFF;
249 uint32_t RawInstrAuipc = *(little32_t *)FixupPtr;
250 uint32_t RawInstrJalr = *(little32_t *)(FixupPtr + 4);
251 *(little32_t *)FixupPtr =
252 RawInstrAuipc | (static_cast<uint32_t>(Hi & 0xFFFFF000));
253 *(little32_t *)(FixupPtr + 4) =
254 RawInstrJalr | (static_cast<uint32_t>(Lo) << 20);
255 break;
257 case R_RISCV_PCREL_HI20: {
258 int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
259 int64_t Hi = Value + 0x800;
260 if (LLVM_UNLIKELY(!isInRangeForImmS32(Hi)))
261 return makeTargetOutOfRangeError(G, B, E);
262 uint32_t RawInstr = *(little32_t *)FixupPtr;
263 *(little32_t *)FixupPtr =
264 (RawInstr & 0xFFF) | (static_cast<uint32_t>(Hi & 0xFFFFF000));
265 break;
267 case R_RISCV_PCREL_LO12_I: {
268 // FIXME: We assume that R_RISCV_PCREL_HI20 is present in object code and
269 // pairs with current relocation R_RISCV_PCREL_LO12_I. So here may need a
270 // check.
271 auto RelHI20 = getRISCVPCRelHi20(E);
272 if (!RelHI20)
273 return RelHI20.takeError();
274 int64_t Value = RelHI20->getTarget().getAddress() +
275 RelHI20->getAddend() - E.getTarget().getAddress();
276 int64_t Lo = Value & 0xFFF;
277 uint32_t RawInstr = *(little32_t *)FixupPtr;
278 *(little32_t *)FixupPtr =
279 (RawInstr & 0xFFFFF) | (static_cast<uint32_t>(Lo & 0xFFF) << 20);
280 break;
282 case R_RISCV_PCREL_LO12_S: {
283 // FIXME: We assume that R_RISCV_PCREL_HI20 is present in object code and
284 // pairs with current relocation R_RISCV_PCREL_LO12_S. So here may need a
285 // check.
286 auto RelHI20 = getRISCVPCRelHi20(E);
287 int64_t Value = RelHI20->getTarget().getAddress() +
288 RelHI20->getAddend() - E.getTarget().getAddress();
289 int64_t Lo = Value & 0xFFF;
290 uint32_t Imm31_25 = extractBits(Lo, 5, 7) << 25;
291 uint32_t Imm11_7 = extractBits(Lo, 0, 5) << 7;
292 uint32_t RawInstr = *(little32_t *)FixupPtr;
294 *(little32_t *)FixupPtr = (RawInstr & 0x1FFF07F) | Imm31_25 | Imm11_7;
295 break;
298 return Error::success();
302 template <typename ELFT>
303 class ELFLinkGraphBuilder_riscv : public ELFLinkGraphBuilder<ELFT> {
304 private:
305 static Expected<riscv::EdgeKind_riscv>
306 getRelocationKind(const uint32_t Type) {
307 using namespace riscv;
308 switch (Type) {
309 case ELF::R_RISCV_32:
310 return EdgeKind_riscv::R_RISCV_32;
311 case ELF::R_RISCV_64:
312 return EdgeKind_riscv::R_RISCV_64;
313 case ELF::R_RISCV_BRANCH:
314 return EdgeKind_riscv::R_RISCV_BRANCH;
315 case ELF::R_RISCV_HI20:
316 return EdgeKind_riscv::R_RISCV_HI20;
317 case ELF::R_RISCV_LO12_I:
318 return EdgeKind_riscv::R_RISCV_LO12_I;
319 case ELF::R_RISCV_CALL:
320 return EdgeKind_riscv::R_RISCV_CALL;
321 case ELF::R_RISCV_PCREL_HI20:
322 return EdgeKind_riscv::R_RISCV_PCREL_HI20;
323 case ELF::R_RISCV_PCREL_LO12_I:
324 return EdgeKind_riscv::R_RISCV_PCREL_LO12_I;
325 case ELF::R_RISCV_PCREL_LO12_S:
326 return EdgeKind_riscv::R_RISCV_PCREL_LO12_S;
327 case ELF::R_RISCV_GOT_HI20:
328 return EdgeKind_riscv::R_RISCV_GOT_HI20;
329 case ELF::R_RISCV_CALL_PLT:
330 return EdgeKind_riscv::R_RISCV_CALL_PLT;
333 return make_error<JITLinkError>("Unsupported riscv relocation:" +
334 formatv("{0:d}", Type));
337 Error addRelocations() override {
338 LLVM_DEBUG(dbgs() << "Processing relocations:\n");
340 using Base = ELFLinkGraphBuilder<ELFT>;
341 using Self = ELFLinkGraphBuilder_riscv<ELFT>;
342 for (const auto &RelSect : Base::Sections)
343 if (Error Err = Base::forEachRelocation(RelSect, this,
344 &Self::addSingleRelocation))
345 return Err;
347 return Error::success();
350 Error addSingleRelocation(const typename ELFT::Rela &Rel,
351 const typename ELFT::Shdr &FixupSect,
352 Block &BlockToFix) {
353 using Base = ELFLinkGraphBuilder<ELFT>;
355 uint32_t SymbolIndex = Rel.getSymbol(false);
356 auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
357 if (!ObjSymbol)
358 return ObjSymbol.takeError();
360 Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
361 if (!GraphSymbol)
362 return make_error<StringError>(
363 formatv("Could not find symbol at given index, did you add it to "
364 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
365 SymbolIndex, (*ObjSymbol)->st_shndx,
366 Base::GraphSymbols.size()),
367 inconvertibleErrorCode());
369 uint32_t Type = Rel.getType(false);
370 Expected<riscv::EdgeKind_riscv> Kind = getRelocationKind(Type);
371 if (!Kind)
372 return Kind.takeError();
374 int64_t Addend = Rel.r_addend;
375 auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;
376 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
377 Edge GE(*Kind, Offset, *GraphSymbol, Addend);
378 LLVM_DEBUG({
379 dbgs() << " ";
380 printEdge(dbgs(), BlockToFix, GE, riscv::getEdgeKindName(*Kind));
381 dbgs() << "\n";
384 BlockToFix.addEdge(std::move(GE));
385 return Error::success();
388 public:
389 ELFLinkGraphBuilder_riscv(StringRef FileName,
390 const object::ELFFile<ELFT> &Obj, const Triple T)
391 : ELFLinkGraphBuilder<ELFT>(Obj, std::move(T), FileName,
392 riscv::getEdgeKindName) {}
395 Expected<std::unique_ptr<LinkGraph>>
396 createLinkGraphFromELFObject_riscv(MemoryBufferRef ObjectBuffer) {
397 LLVM_DEBUG({
398 dbgs() << "Building jitlink graph for new input "
399 << ObjectBuffer.getBufferIdentifier() << "...\n";
402 auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
403 if (!ELFObj)
404 return ELFObj.takeError();
406 if ((*ELFObj)->getArch() == Triple::riscv64) {
407 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
408 return ELFLinkGraphBuilder_riscv<object::ELF64LE>(
409 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(),
410 (*ELFObj)->makeTriple())
411 .buildGraph();
412 } else {
413 assert((*ELFObj)->getArch() == Triple::riscv32 &&
414 "Invalid triple for RISCV ELF object file");
415 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj);
416 return ELFLinkGraphBuilder_riscv<object::ELF32LE>(
417 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(),
418 (*ELFObj)->makeTriple())
419 .buildGraph();
423 void link_ELF_riscv(std::unique_ptr<LinkGraph> G,
424 std::unique_ptr<JITLinkContext> Ctx) {
425 PassConfiguration Config;
426 const Triple &TT = G->getTargetTriple();
427 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
428 if (auto MarkLive = Ctx->getMarkLivePass(TT))
429 Config.PrePrunePasses.push_back(std::move(MarkLive));
430 else
431 Config.PrePrunePasses.push_back(markAllSymbolsLive);
432 Config.PostPrunePasses.push_back(
433 PerGraphGOTAndPLTStubsBuilder_ELF_riscv::asPass);
435 if (auto Err = Ctx->modifyPassConfig(*G, Config))
436 return Ctx->notifyFailed(std::move(Err));
438 ELFJITLinker_riscv::link(std::move(Ctx), std::move(G), std::move(Config));
441 } // namespace jitlink
442 } // namespace llvm