Skip to content

Commit 0c6d7a4

Browse files
authored
[LLD] Add support for statically resolved vendor-specific RISCV relocations. (llvm#169273)
This is achieved by using some of the bits of RelType to tag vendor namespaces. This change also adds a relocation iterator for RISCV that folds vendor namespaces into the RelType of the following relocation. This patch is extracted from the implementation of RISCV vendor-specific relocations in the CHERIoT LLVM downstream: CHERIoT-Platform/llvm-project@3d6d6f7
1 parent b142912 commit 0c6d7a4

File tree

4 files changed

+174
-12
lines changed

4 files changed

+174
-12
lines changed

lld/ELF/Arch/RISCV.cpp

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "InputFiles.h"
1010
#include "OutputSections.h"
11+
#include "RISCVInternalRelocations.h"
1112
#include "RelocScan.h"
1213
#include "Symbols.h"
1314
#include "SyntheticSections.h"
@@ -345,8 +346,15 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
345346
case R_RISCV_SUB_ULEB128:
346347
return RE_RISCV_LEB128;
347348
default:
348-
Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v
349-
<< ") against symbol " << &s;
349+
if (type.v & INTERNAL_RISCV_VENDOR_MASK) {
350+
Err(ctx) << getErrorLoc(ctx, loc)
351+
<< "unsupported vendor-specific relocation " << type
352+
<< " against symbol " << &s;
353+
return R_NONE;
354+
}
355+
Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation ("
356+
<< (type.v & ~INTERNAL_RISCV_VENDOR_MASK) << ") against symbol "
357+
<< &s;
350358
return R_NONE;
351359
}
352360
}
@@ -859,7 +867,7 @@ static bool relax(Ctx &ctx, int pass, InputSection &sec) {
859867

860868
std::fill_n(aux.relocTypes.get(), relocs.size(), R_RISCV_NONE);
861869
aux.writes.clear();
862-
for (auto [i, r] : llvm::enumerate(relocs)) {
870+
for (auto [i, r] : llvm::enumerate(riscv_vendor_relocs(relocs))) {
863871
const uint64_t loc = secAddr + r.offset - delta;
864872
uint32_t &cur = aux.relocDeltas[i], remove = 0;
865873
switch (r.type) {
@@ -1503,12 +1511,19 @@ void RISCV::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
15031511
rvVendor = sym.getName();
15041512
continue;
15051513
} else if (!rvVendor.empty()) {
1506-
Err(ctx) << getErrorLoc(ctx, loc)
1507-
<< "unknown vendor-specific relocation (" << type.v
1508-
<< ") in namespace '" << rvVendor << "' against symbol '" << &sym
1509-
<< "'";
1514+
uint32_t VendorFlag = getRISCVVendorRelMarker(rvVendor);
1515+
if (!VendorFlag) {
1516+
Err(ctx) << getErrorLoc(ctx, loc)
1517+
<< "unknown vendor-specific relocation (" << type.v
1518+
<< ") in namespace '" << rvVendor << "' against symbol '"
1519+
<< &sym << "'";
1520+
rvVendor = "";
1521+
continue;
1522+
}
1523+
15101524
rvVendor = "";
1511-
continue;
1525+
assert((type.v < 256) && "Out of range relocation detected!");
1526+
type.v |= VendorFlag;
15121527
}
15131528

15141529
rs.scan<ELFT, RelTy>(it, type, rs.getAddend<ELFT>(*it, type));
@@ -1533,3 +1548,21 @@ template <class ELFT> void RISCV::scanSection1(InputSectionBase &sec) {
15331548
void RISCV::scanSection(InputSectionBase &sec) {
15341549
invokeELFT(scanSection1, sec);
15351550
}
1551+
1552+
namespace lld::elf {
1553+
uint32_t getRISCVVendorRelMarker(StringRef rvVendor) {
1554+
return StringSwitch<uint32_t>(rvVendor)
1555+
.Case("QUALCOMM", INTERNAL_RISCV_VENDOR_QUALCOMM)
1556+
.Case("ANDES", INTERNAL_RISCV_VENDOR_ANDES)
1557+
.Default(0);
1558+
}
1559+
1560+
std::optional<StringRef> getRISCVVendorString(RelType ty) {
1561+
if ((ty.v & INTERNAL_RISCV_VENDOR_MASK) == INTERNAL_RISCV_VENDOR_QUALCOMM)
1562+
return "QUALCOMM";
1563+
if ((ty.v & INTERNAL_RISCV_VENDOR_MASK) == INTERNAL_RISCV_VENDOR_ANDES)
1564+
return "ANDES";
1565+
return std::nullopt;
1566+
}
1567+
1568+
} // namespace lld::elf
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
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+
15+
namespace 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.
21+
constexpr uint32_t INTERNAL_R_RISCV_GPREL_I = 256;
22+
constexpr uint32_t INTERNAL_R_RISCV_GPREL_S = 257;
23+
constexpr uint32_t INTERNAL_R_RISCV_X0REL_I = 258;
24+
constexpr uint32_t INTERNAL_R_RISCV_X0REL_S = 259;
25+
26+
// Bits 9 -> 31 of RelType are used to indicate vendor-specific relocations.
27+
constexpr uint32_t INTERNAL_RISCV_VENDOR_MASK = 0xFFFFFFFF << 9;
28+
constexpr uint32_t INTERNAL_RISCV_VENDOR_QUALCOMM = 1 << 9;
29+
constexpr uint32_t INTERNAL_RISCV_VENDOR_ANDES = 2 << 9;
30+
31+
constexpr uint32_t INTERNAL_RISCV_QC_ABS20_U =
32+
INTERNAL_RISCV_VENDOR_QUALCOMM | llvm::ELF::R_RISCV_QC_ABS20_U;
33+
constexpr uint32_t INTERNAL_RISCV_QC_E_BRANCH =
34+
INTERNAL_RISCV_VENDOR_QUALCOMM | llvm::ELF::R_RISCV_QC_E_BRANCH;
35+
constexpr uint32_t INTERNAL_RISCV_QC_E_32 =
36+
INTERNAL_RISCV_VENDOR_QUALCOMM | llvm::ELF::R_RISCV_QC_E_32;
37+
constexpr uint32_t INTERNAL_RISCV_QC_E_CALL_PLT =
38+
INTERNAL_RISCV_VENDOR_QUALCOMM | llvm::ELF::R_RISCV_QC_E_CALL_PLT;
39+
40+
constexpr uint32_t INTERNAL_RISCV_NDS_BRANCH_10 =
41+
INTERNAL_RISCV_VENDOR_ANDES | llvm::ELF::R_RISCV_NDS_BRANCH_10;
42+
43+
uint32_t getRISCVVendorRelMarker(llvm::StringRef rvVendor);
44+
std::optional<llvm::StringRef> getRISCVVendorString(RelType ty);
45+
46+
class vendor_reloc_iterator {
47+
public:
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{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(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+
100+
private:
101+
MutableArrayRef<Relocation>::iterator it;
102+
MutableArrayRef<Relocation>::iterator end;
103+
uint32_t rvVendorFlag = 0;
104+
};
105+
106+
inline auto riscv_vendor_relocs(MutableArrayRef<Relocation> arr) {
107+
return llvm::make_range(vendor_reloc_iterator(arr.begin(), arr.end()),
108+
vendor_reloc_iterator(arr.end(), arr.end()));
109+
}
110+
111+
} // namespace lld::elf
112+
113+
#endif

lld/ELF/Target.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
//===----------------------------------------------------------------------===//
2525

2626
#include "Target.h"
27+
#include "Arch/RISCVInternalRelocations.h"
2728
#include "InputFiles.h"
2829
#include "OutputSections.h"
2930
#include "RelocScan.h"
@@ -40,6 +41,14 @@ using namespace lld::elf;
4041

4142
std::string elf::toStr(Ctx &ctx, RelType type) {
4243
StringRef s = getELFRelocationTypeName(ctx.arg.emachine, type);
44+
if (ctx.arg.emachine == EM_RISCV && s == "Unknown") {
45+
auto VendorString = getRISCVVendorString(type);
46+
if (VendorString)
47+
s = getRISCVVendorRelocationTypeName(type & ~INTERNAL_RISCV_VENDOR_MASK,
48+
*VendorString);
49+
if (s == "Unknown")
50+
return ("Unknown vendor-specific (" + Twine(type) + ")").str();
51+
}
4352
if (s == "Unknown")
4453
return ("Unknown (" + Twine(type) + ")").str();
4554
return std::string(s);

lld/test/ELF/riscv-vendor-relocations.s

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,19 @@
88
TARGET:
99
nop
1010

11-
.global INVALID_VENDOR
11+
.local INVALID_VENDOR
12+
.local QUALCOMM
13+
.local ANDES
1214
.reloc 1f, R_RISCV_VENDOR, INVALID_VENDOR+0
1315
.reloc 1f, R_RISCV_VENDOR, INVALID_VENDOR+0
1416
.reloc 1f, R_RISCV_CUSTOM255, TARGET
15-
1:
16-
nop
17-
1817
# CHECK: error: {{.*}}:(.text+0x4): malformed consecutive R_RISCV_VENDOR relocations
1918
# CHECK: error: {{.*}}:(.text+0x4): unknown vendor-specific relocation (255) in namespace 'INVALID_VENDOR' against symbol 'TARGET'
19+
.reloc 1f, R_RISCV_VENDOR, QUALCOMM+0
20+
.reloc 1f, R_RISCV_CUSTOM192, TARGET
21+
# CHECK: error: {{.*}}:(.text+0x4): unsupported vendor-specific relocation R_RISCV_QC_ABS20_U against symbol TARGET
22+
.reloc 1f, R_RISCV_VENDOR, ANDES+0
23+
.reloc 1f, R_RISCV_CUSTOM241, TARGET
24+
# CHECK: error: {{.*}}:(.text+0x4): unsupported vendor-specific relocation R_RISCV_NDS_BRANCH_10 against symbol TARGET
25+
1:
26+
nop

0 commit comments

Comments
 (0)