Skip to content

Commit eaa9ef6

Browse files
authored
[lld][LoongArch] Support the R_LARCH_{ADD,SUB}_ULEB128 relocation types (#81133)
For a label difference like `.uleb128 A-B`, MC generates a pair of R_LARCH_{ADD,SUB}_ULEB128 if A-B cannot be folded as a constant. GNU assembler generates a pair of relocations in more cases (when A or B is in a code section with linker relaxation). It is similar to RISCV. R_LARCH_{ADD,SUB}_ULEB128 relocations are created by Clang and GCC in `.gcc_except_table` and other debug sections with linker relaxation enabled. On LoongArch, first read the buf and count the available space. Then add or sub the value. Finally truncate the expected value and fill it into the available space.
1 parent 46f65e4 commit eaa9ef6

File tree

2 files changed

+121
-0
lines changed

2 files changed

+121
-0
lines changed

lld/ELF/Arch/LoongArch.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "Symbols.h"
1212
#include "SyntheticSections.h"
1313
#include "Target.h"
14+
#include "llvm/Support/LEB128.h"
1415

1516
using namespace llvm;
1617
using namespace llvm::object;
@@ -155,6 +156,16 @@ static bool isJirl(uint32_t insn) {
155156
return (insn & 0xfc000000) == JIRL;
156157
}
157158

159+
static void handleUleb128(uint8_t *loc, uint64_t val) {
160+
const uint32_t maxcount = 1 + 64 / 7;
161+
uint32_t count;
162+
uint64_t orig = decodeULEB128(loc, &count);
163+
if (count > maxcount)
164+
errorOrWarn(getErrorLocation(loc) + "extra space for uleb128");
165+
uint64_t mask = count < maxcount ? (1ULL << 7 * count) - 1 : -1ULL;
166+
encodeULEB128((orig + val) & mask, loc, count);
167+
}
168+
158169
LoongArch::LoongArch() {
159170
// The LoongArch ISA itself does not have a limit on page sizes. According to
160171
// the ISA manual, the PS (page size) field in MTLB entries and CSR.STLBPS is
@@ -396,11 +407,13 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
396407
case R_LARCH_ADD16:
397408
case R_LARCH_ADD32:
398409
case R_LARCH_ADD64:
410+
case R_LARCH_ADD_ULEB128:
399411
case R_LARCH_SUB6:
400412
case R_LARCH_SUB8:
401413
case R_LARCH_SUB16:
402414
case R_LARCH_SUB32:
403415
case R_LARCH_SUB64:
416+
case R_LARCH_SUB_ULEB128:
404417
// The LoongArch add/sub relocs behave like the RISCV counterparts; reuse
405418
// the RelExpr to avoid code duplication.
406419
return R_RISCV_ADD;
@@ -635,6 +648,9 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
635648
case R_LARCH_ADD64:
636649
write64le(loc, read64le(loc) + val);
637650
return;
651+
case R_LARCH_ADD_ULEB128:
652+
handleUleb128(loc, val);
653+
return;
638654
case R_LARCH_SUB6:
639655
*loc = (*loc & 0xc0) | ((*loc - val) & 0x3f);
640656
return;
@@ -650,6 +666,9 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
650666
case R_LARCH_SUB64:
651667
write64le(loc, read64le(loc) - val);
652668
return;
669+
case R_LARCH_SUB_ULEB128:
670+
handleUleb128(loc, -val);
671+
return;
653672

654673
case R_LARCH_MARK_LA:
655674
case R_LARCH_MARK_PCREL:

lld/test/ELF/loongarch-reloc-leb128.s

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# REQUIRES: loongarch
2+
# RUN: rm -rf %t && split-file %s %t && cd %t
3+
4+
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax a.s -o a.o
5+
# RUN: llvm-readobj -r -x .gcc_except_table -x .debug_rnglists -x .debug_loclists a.o | FileCheck %s --check-prefix=REL
6+
# RUN: ld.lld -shared --gc-sections a.o -o a.so
7+
# RUN: llvm-readelf -x .gcc_except_table -x .debug_rnglists -x .debug_loclists a.so | FileCheck %s
8+
9+
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax a.s -o a32.o
10+
# RUN: llvm-readobj -r -x .gcc_except_table -x .debug_rnglists -x .debug_loclists a32.o | FileCheck %s --check-prefix=REL
11+
# RUN: ld.lld -shared --gc-sections a32.o -o a32.so
12+
# RUN: llvm-readelf -x .gcc_except_table -x .debug_rnglists -x .debug_loclists a32.so | FileCheck %s
13+
14+
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax extraspace.s -o extraspace32.o
15+
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax extraspace.s -o extraspace64.o
16+
# RUN: not ld.lld -shared extraspace32.o 2>&1 | FileCheck %s --check-prefix=ERROR
17+
# RUN: not ld.lld -shared extraspace64.o 2>&1 | FileCheck %s --check-prefix=ERROR
18+
# ERROR: error: extraspace{{.*}}.o:(.rodata+0x0): extra space for uleb128
19+
20+
#--- a.s
21+
.cfi_startproc
22+
.cfi_lsda 0x1b,.LLSDA0
23+
.cfi_endproc
24+
25+
.section .text.w,"axR"
26+
break 0; break 0; break 0; w1:
27+
.p2align 4 # 4 bytes after relaxation
28+
w2: break 0
29+
30+
.section .text.x,"ax"
31+
break 0; break 0; break 0; x1:
32+
.p2align 4 # 4 bytes after relaxation
33+
x2: break 0
34+
35+
.section .gcc_except_table,"a"
36+
.LLSDA0:
37+
.uleb128 w2-w1+116 # initial value: 0x0080
38+
.uleb128 w1-w2+141 # initial value: 0x0080
39+
.uleb128 w2-w1+16372 # initial value: 0x008080
40+
.uleb128 w1-w2+16397 # initial value: 0x008080
41+
.uleb128 w2-w1+2097140 # initial value: 0x00808080
42+
.uleb128 w1-w2+2097165 # initial value: 0x00808080
43+
44+
.section .debug_rnglists
45+
.uleb128 w2-w1+116 # initial value: 0x0080
46+
.uleb128 w1-w2+141 # initial value: 0x0080
47+
.uleb128 w2-w1+16372 # initial value: 0x008080
48+
.uleb128 w1-w2+16397 # initial value: 0x008080
49+
.uleb128 w2-w1+2097140 # initial value: 0x00808080
50+
.uleb128 w1-w2+2097165 # initial value: 0x00808080
51+
52+
.section .debug_loclists
53+
.uleb128 x2-x1 # references discarded symbols
54+
55+
# REL: Section ({{.*}}) .rela.debug_rnglists {
56+
# REL-NEXT: 0x0 R_LARCH_ADD_ULEB128 w2 0x74
57+
# REL-NEXT: 0x0 R_LARCH_SUB_ULEB128 w1 0x0
58+
# REL-NEXT: 0x2 R_LARCH_ADD_ULEB128 w1 0x8D
59+
# REL-NEXT: 0x2 R_LARCH_SUB_ULEB128 w2 0x0
60+
# REL-NEXT: 0x4 R_LARCH_ADD_ULEB128 w2 0x3FF4
61+
# REL-NEXT: 0x4 R_LARCH_SUB_ULEB128 w1 0x0
62+
# REL-NEXT: 0x7 R_LARCH_ADD_ULEB128 w1 0x400D
63+
# REL-NEXT: 0x7 R_LARCH_SUB_ULEB128 w2 0x0
64+
# REL-NEXT: 0xA R_LARCH_ADD_ULEB128 w2 0x1FFFF4
65+
# REL-NEXT: 0xA R_LARCH_SUB_ULEB128 w1 0x0
66+
# REL-NEXT: 0xE R_LARCH_ADD_ULEB128 w1 0x20000D
67+
# REL-NEXT: 0xE R_LARCH_SUB_ULEB128 w2 0x0
68+
# REL-NEXT: }
69+
# REL: Section ({{.*}}) .rela.debug_loclists {
70+
# REL-NEXT: 0x0 R_LARCH_ADD_ULEB128 x2 0x0
71+
# REL-NEXT: 0x0 R_LARCH_SUB_ULEB128 x1 0x0
72+
# REL-NEXT: }
73+
74+
# REL: Hex dump of section '.gcc_except_table':
75+
# REL-NEXT: 0x00000000 80008000 80800080 80008080 80008080 .
76+
# REL-NEXT: 0x00000010 8000 .
77+
# REL: Hex dump of section '.debug_rnglists':
78+
# REL-NEXT: 0x00000000 80008000 80800080 80008080 80008080 .
79+
# REL-NEXT: 0x00000010 8000 .
80+
# REL: Hex dump of section '.debug_loclists':
81+
# REL-NEXT: 0x00000000 00 .
82+
83+
# CHECK: Hex dump of section '.gcc_except_table':
84+
# CHECK-NEXT: 0x[[#%x,]] f8008901 f8ff0089 8001f8ff ff008980 .
85+
# CHECK-NEXT: 0x[[#%x,]] 8001 .
86+
# CHECK: Hex dump of section '.debug_rnglists':
87+
# CHECK-NEXT: 0x00000000 f8008901 f8ff0089 8001f8ff ff008980 .
88+
# CHECK-NEXT: 0x00000010 8001 .
89+
# CHECK: Hex dump of section '.debug_loclists':
90+
# CHECK-NEXT: 0x00000000 00 .
91+
92+
#--- extraspace.s
93+
.text
94+
w1:
95+
la.pcrel $t0, w1
96+
w2:
97+
98+
.rodata
99+
.reloc ., R_LARCH_ADD_ULEB128, w2
100+
.reloc ., R_LARCH_SUB_ULEB128, w1
101+
.fill 10, 1, 0x80
102+
.byte 0

0 commit comments

Comments
 (0)