Skip to content

Commit c83c01f

Browse files
svs-quiclenary
andauthored
[RISCV] Vendor Relocations for Xqci extension (#135400)
This patch implements vendor relocation support for RISC-V, starting with the Xqci extensions. Vendor Relocations need to emit the vendor symbol, and add an `R_RISCV_VENDOR` relocation against that symbol before the specific vendor relocation itself. This patch adds a `maybeAddVendorReloc` function which is called from `addReloc`, to implement this functionality. Vendor identifier symbols are cached, so that at most one is emitted per vendor identifier. Vendor identifiers symbols do not interfere with identically named symbols used by assembly. Co-authored-by: Sam Elliott <[email protected]>
1 parent d2f06b2 commit c83c01f

File tree

6 files changed

+299
-96
lines changed

6 files changed

+299
-96
lines changed

llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "RISCVAsmBackend.h"
10+
#include "RISCVFixupKinds.h"
1011
#include "RISCVMCExpr.h"
1112
#include "llvm/ADT/APInt.h"
1213
#include "llvm/MC/MCAsmInfo.h"
@@ -611,6 +612,46 @@ bool RISCVAsmBackend::evaluateTargetFixup(const MCFixup &Fixup,
611612
isPCRelFixupResolved(AUIPCTarget.getAddSym(), *AUIPCDF);
612613
}
613614

615+
void RISCVAsmBackend::maybeAddVendorReloc(const MCFragment &F,
616+
const MCFixup &Fixup) {
617+
StringRef VendorIdentifier;
618+
switch (Fixup.getTargetKind()) {
619+
default:
620+
// No Vendor Relocation Required.
621+
return;
622+
case RISCV::fixup_riscv_qc_e_branch:
623+
case RISCV::fixup_riscv_qc_abs20_u:
624+
case RISCV::fixup_riscv_qc_e_32:
625+
case RISCV::fixup_riscv_qc_e_jump_plt:
626+
VendorIdentifier = "QUALCOMM";
627+
break;
628+
}
629+
630+
// Create a local symbol for the vendor relocation to reference. It's fine if
631+
// the symbol has the same name as an existing symbol.
632+
MCContext &Ctx = Asm->getContext();
633+
MCSymbol *VendorSymbol = Ctx.createLocalSymbol(VendorIdentifier);
634+
auto [It, Inserted] =
635+
VendorSymbols.try_emplace(VendorIdentifier, VendorSymbol);
636+
637+
if (Inserted) {
638+
// Setup the just-created symbol
639+
VendorSymbol->setVariableValue(MCConstantExpr::create(0, Ctx));
640+
Asm->registerSymbol(*VendorSymbol);
641+
} else {
642+
// Fetch the existing symbol
643+
VendorSymbol = It->getValue();
644+
}
645+
646+
MCFixup VendorFixup =
647+
MCFixup::create(Fixup.getOffset(), nullptr, ELF::R_RISCV_VENDOR);
648+
// Explicitly create MCValue rather than using an MCExpr and evaluating it so
649+
// that the absolute vendor symbol is not evaluated to constant 0.
650+
MCValue VendorTarget = MCValue::get(VendorSymbol);
651+
uint64_t VendorValue;
652+
Asm->getWriter().recordRelocation(F, VendorFixup, VendorTarget, VendorValue);
653+
}
654+
614655
bool RISCVAsmBackend::addReloc(const MCFragment &F, const MCFixup &Fixup,
615656
const MCValue &Target, uint64_t &FixedValue,
616657
bool IsResolved) {
@@ -660,7 +701,14 @@ bool RISCVAsmBackend::addReloc(const MCFragment &F, const MCFixup &Fixup,
660701
if (IsResolved &&
661702
(getFixupKindInfo(Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel))
662703
IsResolved = isPCRelFixupResolved(Target.getAddSym(), F);
663-
IsResolved = MCAsmBackend::addReloc(F, Fixup, Target, FixedValue, IsResolved);
704+
705+
if (!IsResolved) {
706+
// Some Fixups require a vendor relocation, record it (directly) before we
707+
// add the relocation.
708+
maybeAddVendorReloc(F, Fixup);
709+
710+
Asm->getWriter().recordRelocation(F, Fixup, Target, FixedValue);
711+
}
664712

665713
if (Fixup.isLinkerRelaxable()) {
666714
auto FA = MCFixup::create(Fixup.getOffset(), nullptr, ELF::R_RISCV_RELAX);

llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "MCTargetDesc/RISCVBaseInfo.h"
1313
#include "MCTargetDesc/RISCVFixupKinds.h"
1414
#include "MCTargetDesc/RISCVMCTargetDesc.h"
15+
#include "llvm/ADT/StringMap.h"
1516
#include "llvm/MC/MCAsmBackend.h"
1617
#include "llvm/MC/MCFixupKindInfo.h"
1718
#include "llvm/MC/MCSubtargetInfo.h"
@@ -31,6 +32,8 @@ class RISCVAsmBackend : public MCAsmBackend {
3132

3233
bool isPCRelFixupResolved(const MCSymbol *SymA, const MCFragment &F);
3334

35+
StringMap<MCSymbol *> VendorSymbols;
36+
3437
public:
3538
RISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI, bool Is64Bit,
3639
const MCTargetOptions &Options);
@@ -50,6 +53,8 @@ class RISCVAsmBackend : public MCAsmBackend {
5053
bool addReloc(const MCFragment &, const MCFixup &, const MCValue &,
5154
uint64_t &FixedValue, bool IsResolved) override;
5255

56+
void maybeAddVendorReloc(const MCFragment &, const MCFixup &);
57+
5358
void applyFixup(const MCFragment &, const MCFixup &, const MCValue &Target,
5459
MutableArrayRef<char> Data, uint64_t Value,
5560
bool IsResolved) override;

llvm/test/MC/RISCV/vendor-symbol.s

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcibi %s \
2+
# RUN: -filetype=obj -o - \
3+
# RUN: | llvm-readelf -sr - \
4+
# RUN: | FileCheck %s
5+
6+
7+
## This checks that the vendor identifier symbols required for vendor
8+
## relocations do not interfere with symbols with identical names that
9+
## are written in assembly.
10+
11+
.option exact
12+
13+
qc.e.bgeui s0, 20, QUALCOMM
14+
15+
.global QUALCOMM
16+
QUALCOMM:
17+
nop
18+
19+
qc.e.bgeui s0, 20, QUALCOMM
20+
21+
22+
# CHECK-LABEL: Relocation section '.rela.text'
23+
## Note the different values for the "Sym. Value" Field
24+
# CHECK: R_RISCV_VENDOR 00000000 QUALCOMM + 0
25+
# CHECK: R_RISCV_CUSTOM193 00000006 QUALCOMM + 0
26+
# CHECK: R_RISCV_VENDOR 00000000 QUALCOMM + 0
27+
# CHECK: R_RISCV_CUSTOM193 00000006 QUALCOMM + 0
28+
29+
30+
# CHECK-LABEL: Symbol table '.symtab'
31+
# CHECK-NOT: QUALCOMM
32+
# CHECK: 00000000 0 NOTYPE LOCAL DEFAULT ABS QUALCOMM
33+
# CHECK-NOT: QUALCOMM
34+
# CHECK: 00000006 0 NOTYPE GLOBAL DEFAULT 2 QUALCOMM
35+
# CHECK-NOT: QUALCOMM
Lines changed: 74 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,83 @@
1-
# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcibi %s -show-encoding \
2-
# RUN: | FileCheck -check-prefix=INSTR %s
3-
# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqcibi %s -o %t.o
4-
# RUN: llvm-readobj -r %t.o | FileCheck -check-prefix=RELOC %s
1+
# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcibi %s \
2+
# RUN: | FileCheck -check-prefix=ASM %s
3+
# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcibi %s \
4+
# RUN: -filetype=obj -o - \
5+
# RUN: | llvm-objdump -dr --mattr=+experimental-xqcibi - \
6+
# RUN: | FileCheck -check-prefix=OBJ %s
57

6-
# Check prefixes:
7-
# RELOC - Check the relocation in the object.
8-
# INSTR - Check the instruction is handled properly by the ASMPrinter.
8+
## This test checks that we emit the right relocations for Xqcibi
9+
## relative branches. These can be resolved within the same section
10+
## (when relaxations are disabled) but otherwise require a relocation.
11+
## The QC.E.B<op>I instructions also require a vendor relocation.
912

10-
.text
13+
# This is required so that the conditional branches requiring relocations
14+
# are not converted into inverted branches with long jumps by the assembler.
15+
.option exact
1116

12-
# Since foo is undefined, this will be relaxed to (qc.beqi + jal)
13-
qc.bnei x6, 10, foo
14-
# RELOC: R_RISCV_JAL foo 0x0
15-
# INSTR: qc.bnei t1, 10, foo
17+
# ASM-LABEL: this_section:
18+
# OBJ-LABEL: <this_section>:
19+
this_section:
1620

17-
# Since foo is undefined, this will be relaxed to (qc.e.bltui + jal)
18-
qc.e.bgeui x8, 12, foo
19-
# RELOC: R_RISCV_JAL foo 0x0
20-
# INSTR: qc.e.bgeui s0, 12, foo
21+
# ASM: qc.bnei t1, 10, undef
22+
# OBJ: qc.bnei t1, 0xa, 0x0 <this_section>
23+
# OBJ-NEXT: R_RISCV_BRANCH undef{{$}}
24+
qc.bnei t1, 10, undef
2125

22-
# Check that a label in a different section is handled similar to an undefined
23-
# symbol and gets relaxed to (qc.e.bgeui + jal)
24-
qc.e.bltui x4, 9, .bar
25-
# RELOC: R_RISCV_JAL .bar 0x0
26-
# INSTR: qc.e.bltui tp, 9, .bar
26+
# ASM: qc.e.bgeui s0, 20, undef
27+
# OBJ-NEXT: qc.e.bgeui s0, 0x14, 0x4 <this_section+0x4>
28+
# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
29+
# OBJ-NEXT: R_RISCV_CUSTOM193 undef{{$}}
30+
qc.e.bgeui s0, 20, undef
2731

28-
# Check that branches to a defined symbol are handled correctly
29-
qc.e.beqi x7, 8, .L1
30-
# INSTR: qc.e.beqi t2, 8, .L1
3132

32-
.L1:
33-
ret
33+
# ASM: qc.bnei t2, 11, same_section
34+
# OBJ-NEXT: qc.bnei t2, 0xb, 0x28 <same_section>
35+
qc.bnei t2, 11, same_section
3436

35-
.section .t2
37+
# ASM: qc.e.bgeui s1, 21, same_section
38+
# OBJ-NEXT: qc.e.bgeui s1, 0x15, 0x28 <same_section>
39+
qc.e.bgeui s1, 21, same_section
3640

37-
.bar:
38-
ret
41+
42+
# ASM: qc.bnei t2, 12, same_section_extern
43+
# OBJ-NEXT: qc.bnei t2, 0xc, 0x14 <this_section+0x14>
44+
# OBJ-NEXT: R_RISCV_BRANCH same_section_extern{{$}}
45+
qc.bnei t2, 12, same_section_extern
46+
47+
# ASM: qc.e.bgeui s1, 22, same_section_extern
48+
# OBJ-NEXT: qc.e.bgeui s1, 0x16, 0x18 <this_section+0x18>
49+
# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
50+
# OBJ-NEXT: R_RISCV_CUSTOM193 same_section_extern{{$}}
51+
qc.e.bgeui s1, 22, same_section_extern
52+
53+
54+
# ASM: qc.bnei t3, 13, other_section
55+
# OBJ-NEXT: qc.bnei t3, 0xd, 0x1e <this_section+0x1e>
56+
# OBJ-NEXT: R_RISCV_BRANCH other_section{{$}}
57+
qc.bnei t3, 13, other_section
58+
59+
# ASM: qc.e.bgeui s2, 23, other_section
60+
# OBJ-NEXT: qc.e.bgeui s2, 0x17, 0x22 <this_section+0x22>
61+
# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
62+
# OBJ-NEXT: R_RISCV_CUSTOM193 other_section{{$}}
63+
qc.e.bgeui s2, 23, other_section
64+
65+
66+
# ASM-LABEL: same_section:
67+
# OBJ-LABEL: <same_section>:
68+
same_section:
69+
nop
70+
71+
# ASM-LABEL: same_section_extern:
72+
# OBJ-LABEL: <same_section_extern>:
73+
.global same_section_extern
74+
same_section_extern:
75+
nop
76+
77+
78+
.section .text.second, "ax", @progbits
79+
80+
# ASM-LABEL: other_section:
81+
# OBJ-LABEL: <other_section>:
82+
other_section:
83+
nop
Lines changed: 71 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,84 @@
1-
# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcilb %s -show-encoding \
2-
# RUN: | FileCheck -check-prefix=INSTR %s
3-
# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-xqcilb %s -o %t.o
4-
# RUN: llvm-readobj -r %t.o | FileCheck -check-prefix=RELOC %s
1+
# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcilb %s \
2+
# RUN: | FileCheck -check-prefix=ASM %s
3+
# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcilb %s \
4+
# RUN: -filetype=obj -o - \
5+
# RUN: | llvm-objdump -dr --mattr=+experimental-xqcilb - \
6+
# RUN: | FileCheck -check-prefix=OBJ %s
57

6-
# Check prefixes:
7-
# RELOC - Check the relocation in the object.
8-
# INSTR - Check the instruction is handled properly by the ASMPrinter.
9-
10-
.text
8+
## This test checks that we emit the right relocations for Xqcilb
9+
## relative jumps. These can be resolved within the same section
10+
## (when relaxations are disabled) but otherwise require a
11+
## vendor-specific relocation pair.
1112

13+
# This is required so that the conditional jumps are not compressed
14+
# by the assembler
1215
.option exact
1316

14-
qc.e.j foo
15-
# RELOC: R_RISCV_CUSTOM195 foo 0x0
16-
# INSTR: qc.e.j foo
17+
# ASM-LABEL: this_section:
18+
# OBJ-LABEL: <this_section>:
19+
this_section:
20+
21+
# ASM: qc.e.j undef
22+
# OBJ: qc.e.j 0x0 <this_section>
23+
# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
24+
# OBJ-NEXT: R_RISCV_CUSTOM195 undef{{$}}
25+
qc.e.j undef
26+
27+
# ASM: qc.e.jal undef
28+
# OBJ-NEXT: qc.e.jal 0x6 <this_section+0x6>
29+
# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
30+
# OBJ-NEXT: R_RISCV_CUSTOM195 undef{{$}}
31+
qc.e.jal undef
32+
33+
34+
# ASM: qc.e.j same_section
35+
# OBJ-NEXT: qc.e.j 0x30 <same_section>
36+
qc.e.j same_section
37+
38+
# ASM: qc.e.jal same_section
39+
# OBJ-NEXT: qc.e.jal 0x30 <same_section>
40+
qc.e.jal same_section
41+
42+
# ASM: qc.e.j same_section_extern
43+
# OBJ-NEXT: qc.e.j 0x18 <this_section+0x18>
44+
# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
45+
# OBJ-NEXT: R_RISCV_CUSTOM195 same_section_extern{{$}}
46+
qc.e.j same_section_extern
1747

18-
qc.e.jal foo
19-
# RELOC: R_RISCV_CUSTOM195 foo 0x0
20-
# INSTR: qc.e.jal foo
48+
# ASM: qc.e.jal same_section_extern
49+
# OBJ-NEXT: qc.e.jal 0x1e <this_section+0x1e>
50+
# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
51+
# OBJ-NEXT: R_RISCV_CUSTOM195 same_section_extern{{$}}
52+
qc.e.jal same_section_extern
2153

22-
# Check that a label in a different section is handled similar to an undefined symbol
23-
qc.e.j .bar
24-
# RELOC: R_RISCV_CUSTOM195 .bar 0x0
25-
# INSTR: qc.e.j .bar
2654

27-
qc.e.jal .bar
28-
# RELOC: R_RISCV_CUSTOM195 .bar 0x0
29-
# INSTR: qc.e.jal .bar
55+
# ASM: qc.e.j other_section
56+
# OBJ-NEXT: qc.e.j 0x24 <this_section+0x24>
57+
# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
58+
# OBJ-NEXT: R_RISCV_CUSTOM195 other_section{{$}}
59+
qc.e.j other_section
3060

31-
# Check that jumps to a defined symbol are handled correctly
32-
qc.e.j .L1
33-
# INSTR:qc.e.j .L1
61+
# ASM: qc.e.jal other_section
62+
# OBJ-NEXT: qc.e.jal 0x2a <this_section+0x2a>
63+
# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
64+
# OBJ-NEXT: R_RISCV_CUSTOM195 other_section{{$}}
65+
qc.e.jal other_section
3466

35-
qc.e.jal .L1
36-
# INSTR:qc.e.jal .L1
3767

38-
.option noexact
68+
# ASM-LABEL: same_section:
69+
# OBJ-LABEL: <same_section>:
70+
same_section:
71+
nop
3972

40-
.L1:
41-
ret
73+
# ASM-LABEL: same_section_extern:
74+
# OBJ-LABEL: <same_section_extern>:
75+
.global same_section_extern
76+
same_section_extern:
77+
nop
4278

43-
.section .t2
79+
.section .text.other, "ax", @progbits
4480

45-
.bar:
46-
ret
81+
# ASM-LABEL: other_section:
82+
# OBJ-LABEL: <other_section>:
83+
other_section:
84+
nop

0 commit comments

Comments
 (0)