1//===----------------------------------------------------------------------===//
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#ifndef LLD_ELF_ARCH_RISCVINTERNALRELOCATIONS_H
10#define LLD_ELF_ARCH_RISCVINTERNALRELOCATIONS_H
11
12#include "Relocations.h"
13#include "Symbols.h"
14
15namespace lld::elf {
16
17// Bit 8 of RelType is used to indicate linker-internal relocations that are
18// not vendor-specific.
19// These are internal relocation numbers for GP/X0 relaxation. They aren't part
20// of the psABI spec.
21constexpr uint32_t INTERNAL_R_RISCV_GPREL_I = 256;
22constexpr uint32_t INTERNAL_R_RISCV_GPREL_S = 257;
23constexpr uint32_t INTERNAL_R_RISCV_X0REL_I = 258;
24constexpr uint32_t INTERNAL_R_RISCV_X0REL_S = 259;
25
26// Bits 9 -> 31 of RelType are used to indicate vendor-specific relocations.
27constexpr uint32_t INTERNAL_RISCV_VENDOR_MASK = 0xFFFFFFFF << 9;
28constexpr uint32_t INTERNAL_RISCV_VENDOR_QUALCOMM = 1 << 9;
29constexpr uint32_t INTERNAL_RISCV_VENDOR_ANDES = 2 << 9;
30
31constexpr uint32_t INTERNAL_RISCV_QC_ABS20_U =
32 INTERNAL_RISCV_VENDOR_QUALCOMM | llvm::ELF::R_RISCV_QC_ABS20_U;
33constexpr uint32_t INTERNAL_RISCV_QC_E_BRANCH =
34 INTERNAL_RISCV_VENDOR_QUALCOMM | llvm::ELF::R_RISCV_QC_E_BRANCH;
35constexpr uint32_t INTERNAL_RISCV_QC_E_32 =
36 INTERNAL_RISCV_VENDOR_QUALCOMM | llvm::ELF::R_RISCV_QC_E_32;
37constexpr uint32_t INTERNAL_RISCV_QC_E_CALL_PLT =
38 INTERNAL_RISCV_VENDOR_QUALCOMM | llvm::ELF::R_RISCV_QC_E_CALL_PLT;
39
40constexpr uint32_t INTERNAL_RISCV_NDS_BRANCH_10 =
41 INTERNAL_RISCV_VENDOR_ANDES | llvm::ELF::R_RISCV_NDS_BRANCH_10;
42
43uint32_t getRISCVVendorRelMarker(llvm::StringRef rvVendor);
44std::optional<llvm::StringRef> getRISCVVendorString(RelType ty);
45
46class vendor_reloc_iterator {
47public:
48 using iterator_category = std::forward_iterator_tag;
49 using value_type = Relocation;
50 using difference_type = std::ptrdiff_t;
51 using pointer = Relocation *;
52 using reference = Relocation; // returned by value
53
54 vendor_reloc_iterator(MutableArrayRef<Relocation>::iterator i,
55 MutableArrayRef<Relocation>::iterator e)
56 : it(i), end(e) {}
57
58 // Dereference
59 Relocation operator*() const {
60 Relocation r = *it;
61 r.type.v |= rvVendorFlag;
62 return r;
63 }
64
65 struct vendor_reloc_proxy {
66 Relocation r;
67 const Relocation *operator->() const { return &r; }
68 };
69
70 vendor_reloc_proxy operator->() const {
71 return vendor_reloc_proxy{.r: this->operator*()};
72 }
73
74 vendor_reloc_iterator &operator++() {
75 ++it;
76 if (it != end && it->type == llvm::ELF::R_RISCV_VENDOR) {
77 rvVendorFlag = getRISCVVendorRelMarker(rvVendor: it->sym->getName());
78 ++it;
79 } else {
80 rvVendorFlag = 0;
81 }
82 return *this;
83 }
84
85 vendor_reloc_iterator operator++(int) {
86 vendor_reloc_iterator tmp(*this);
87 ++(*this);
88 return tmp;
89 }
90
91 bool operator==(const vendor_reloc_iterator &other) const {
92 return it == other.it;
93 }
94 bool operator!=(const vendor_reloc_iterator &other) const {
95 return it != other.it;
96 }
97
98 Relocation *getUnderlyingRelocation() const { return &*it; }
99
100private:
101 MutableArrayRef<Relocation>::iterator it;
102 MutableArrayRef<Relocation>::iterator end;
103 uint32_t rvVendorFlag = 0;
104};
105
106inline auto riscv_vendor_relocs(MutableArrayRef<Relocation> arr) {
107 return llvm::make_range(x: vendor_reloc_iterator(arr.begin(), arr.end()),
108 y: vendor_reloc_iterator(arr.end(), arr.end()));
109}
110
111} // namespace lld::elf
112
113#endif
114