Skip to content

Commit 6fbe491

Browse files
authored
[lld][LoongArch] Relax call36/tail36: R_LARCH_CALL36 (#123576)
Instructions with relocation `R_LARCH_CALL36` may be relax as follows: ``` From: pcaddu18i $dest, %call36(foo) R_LARCH_CALL36, R_LARCH_RELAX jirl $r, $dest, 0 To: b/bl foo # bl if r=$ra, b if r=$zero R_LARCH_B26 ```
1 parent 99d2b3b commit 6fbe491

File tree

4 files changed

+279
-7
lines changed

4 files changed

+279
-7
lines changed

lld/ELF/Arch/LoongArch.cpp

+41
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ enum Op {
5858
LD_W = 0x28800000,
5959
LD_D = 0x28c00000,
6060
JIRL = 0x4c000000,
61+
B = 0x50000000,
62+
BL = 0x54000000,
6163
};
6264

6365
enum Reg {
@@ -830,6 +832,37 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
830832
remove = 4;
831833
}
832834

835+
// Relax code sequence.
836+
// From:
837+
// pcaddu18i $ra, %call36(foo)
838+
// jirl $ra, $ra, 0
839+
// To:
840+
// b/bl foo
841+
static void relaxCall36(Ctx &ctx, const InputSection &sec, size_t i,
842+
uint64_t loc, Relocation &r, uint32_t &remove) {
843+
const uint64_t dest =
844+
(r.expr == R_PLT_PC ? r.sym->getPltVA(ctx) : r.sym->getVA(ctx)) +
845+
r.addend;
846+
847+
const int64_t displace = dest - loc;
848+
// Check if the displace aligns 4 bytes or exceeds the range of b[l].
849+
if ((displace & 0x3) != 0 || !isInt<28>(displace))
850+
return;
851+
852+
const uint32_t nextInsn = read32le(sec.content().data() + r.offset + 4);
853+
if (getD5(nextInsn) == R_RA) {
854+
// convert jirl to bl
855+
sec.relaxAux->relocTypes[i] = R_LARCH_B26;
856+
sec.relaxAux->writes.push_back(insn(BL, 0, 0, 0));
857+
remove = 4;
858+
} else if (getD5(nextInsn) == R_ZERO) {
859+
// convert jirl to b
860+
sec.relaxAux->relocTypes[i] = R_LARCH_B26;
861+
sec.relaxAux->writes.push_back(insn(B, 0, 0, 0));
862+
remove = 4;
863+
}
864+
}
865+
833866
static bool relax(Ctx &ctx, InputSection &sec) {
834867
const uint64_t secAddr = sec.getVA();
835868
const MutableArrayRef<Relocation> relocs = sec.relocs();
@@ -874,6 +907,10 @@ static bool relax(Ctx &ctx, InputSection &sec) {
874907
if (isPairRelaxable(relocs, i))
875908
relaxPCHi20Lo12(ctx, sec, i, loc, r, relocs[i + 2], remove);
876909
break;
910+
case R_LARCH_CALL36:
911+
if (relaxable(relocs, i))
912+
relaxCall36(ctx, sec, i, loc, r, remove);
913+
break;
877914
}
878915

879916
// For all anchors whose offsets are <= r.offset, they are preceded by
@@ -977,6 +1014,10 @@ void LoongArch::finalizeRelax(int passes) const {
9771014
// RelExpr is needed for relocating.
9781015
r.expr = r.sym->hasFlag(NEEDS_PLT) ? R_PLT_PC : R_PC;
9791016
break;
1017+
case R_LARCH_B26:
1018+
skip = 4;
1019+
write32le(p, aux.writes[writesIdx++]);
1020+
break;
9801021
default:
9811022
llvm_unreachable("unsupported type");
9821023
}
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# REQUIRES: loongarch
2+
## Relax R_LARCH_CALL36. This test tests boundary cases and some special symbols.
3+
4+
# RUN: rm -rf %t && split-file %s %t && cd %t
5+
# RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax a.s -o a.o
6+
7+
# RUN: ld.lld -T lds a.o -o a
8+
# RUN: llvm-objdump -d --no-show-raw-insn a | FileCheck %s --check-prefixes=RELAX,RELAX-MID
9+
10+
## Unsure whether this needs a diagnostic. GNU ld allows this.
11+
# RUN: ld.lld -T lds -pie a.o -o a.pie
12+
# RUN: llvm-objdump -d --no-show-raw-insn a.pie | FileCheck %s --check-prefixes=RELAX,RELAX-MID
13+
14+
# RUN: ld.lld -T lds -pie -z notext -z ifunc-noplt a.o -o a.ifunc-noplt
15+
# RUN: llvm-objdump -d --no-show-raw-insn a.ifunc-noplt | FileCheck %s --check-prefixes=RELAX,NORELAX-MID
16+
17+
# RELAX-LABEL: <_start>:
18+
## offset = 0x10000000 - 0x8000000 = 0x8000000(134217728), hi=512, lo18=0
19+
# RELAX-NEXT: 8000000: pcaddu18i $ra, 512
20+
# RELAX-NEXT: jirl $ra, $ra, 0
21+
# RELAX-NEXT: bl 134217720
22+
# RELAX-NEXT: bl -134217728
23+
## offset = 12 - 0x8000010 = -0x8000004(-134217732), hi=512, lo18=-4
24+
# RELAX-NEXT: 8000010: pcaddu18i $ra, -512
25+
# RELAX-NEXT: jirl $ra, $ra, -4
26+
# RELAX-EMPTY:
27+
28+
# RELAX-MID-LABEL: <.mid>:
29+
## offset = 0x8010000 - 0x8008000 = 32768
30+
# RELAX-MID-NEXT: 8008000: bl 32768
31+
# RELAX-MID-NEXT: b 32764
32+
# RELAX-MID-EMPTY:
33+
34+
# NORELAX-MID-LABEL: <.mid>:
35+
# NORELAX-MID-NEXT: 8008000: pcaddu18i $ra, 0
36+
# NORELAX-MID-NEXT: jirl $ra, $ra, 0
37+
# NORELAX-MID-NEXT: pcaddu18i $t0, 0
38+
# NORELAX-MID-NEXT: jr $t0
39+
# NORELAX-MID-EMPTY:
40+
41+
#--- a.s
42+
.global _start, ifunc
43+
_start:
44+
call36 pos # exceed positive range (.text+0x7fffffc), not relaxed
45+
call36 pos # relaxed
46+
call36 neg # relaxed
47+
call36 neg # exceed negative range (.text+16-0x8000000), not relaxed
48+
49+
.section .mid,"ax",@progbits
50+
.balign 16
51+
call36 ifunc@plt # enable ifunc, not relaxed
52+
tail36 $t0, ifunc@plt # enable ifunc, not relaxed
53+
54+
.type ifunc, @gnu_indirect_function
55+
ifunc:
56+
ret
57+
58+
#--- lds
59+
SECTIONS {
60+
.text 0x8000000 : { *(.text) }
61+
.mid 0x8008000 : { *(.mid) }
62+
.iplt 0x8010000 : { *(.iplt) }
63+
}
64+
neg = 12;
65+
pos = 0x10000000;

lld/test/ELF/loongarch-relax-call36.s

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# REQUIRES: loongarch
2+
## Relax R_LARCH_CALL36, which involves the macro instructions call36/tail36.
3+
4+
# RUN: rm -rf %t && split-file %s %t && cd %t
5+
6+
# RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax a.s -o a.64.o
7+
# RUN: llvm-mc -filetype=obj -triple=loongarch64 -mattr=+relax b.s -o b.64.o
8+
# RUN: ld.lld -shared -soname=b.so b.64.o -o b.64.so
9+
# RUN: ld.lld -T lds a.64.o b.64.so -o 64
10+
# RUN: llvm-objdump -td --no-show-raw-insn 64 | FileCheck %s --check-prefix=RELAX
11+
12+
## --no-relax disables relaxation.
13+
# RUN: ld.lld -T lds a.64.o b.64.so --no-relax -o 64.norelax
14+
# RUN: llvm-objdump -td --no-show-raw-insn 64.norelax | FileCheck %s --check-prefix=NORELAX
15+
16+
# RELAX: {{0*}}00010000 g .text {{0*}}0000001c _start
17+
# RELAX: {{0*}}0001001c g .text {{0*}}00000000 _start_end
18+
# RELAX: {{0*}}00010808 g .mid {{0*}}00000000 mid_end
19+
# RELAX: {{0*}}10010010 g .high {{0*}}00000000 high_end
20+
21+
# RELAX-LABEL: <_start>:
22+
## offset = 0x10018 - 0x10000 = 24
23+
# RELAX-NEXT: 10000: bl 24 <a>
24+
# RELAX-NEXT: b 20 <a>
25+
# RELAX-NEXT: nop
26+
# RELAX-NEXT: nop
27+
## offset = .plt(0x10400)+32 - 0x10010 = 1040
28+
# RELAX-NEXT: 10010: bl 1040 <bar+0x10420>
29+
# RELAX-NEXT: b 1036 <bar+0x10420>
30+
# RELAX-EMPTY:
31+
# RELAX-NEXT: <a>:
32+
# RELAX-NEXT: 10018: ret
33+
# RELAX-EMPTY:
34+
35+
# RELAX-LABEL: <.mid>:
36+
## offset = 0x10000 - 0x10800 = -2048
37+
# RELAX-NEXT: 10800: bl -2048 <_start>
38+
# RELAX-NEXT: b -2052 <_start>
39+
# RELAX-EMPTY:
40+
41+
# RELAX-LABEL: <.mid2>:
42+
## offset = 0x10000 - 0x1010000 = -16777216
43+
# RELAX-NEXT: 1010000: bl -16777216 <_start>
44+
# RELAX-NEXT: b -16777220 <_start>
45+
# RELAX-EMPTY:
46+
47+
# RELAX-LABEL: <.high>:
48+
## offset = 0x10000 - 0x10010000 = -0x10000000, hi=-1024, lo18=0
49+
# RELAX-NEXT: 10010000: pcaddu18i $ra, -1024
50+
# RELAX-NEXT: jirl $ra, $ra, 0
51+
# RELAX-NEXT: pcaddu18i $t0, -1024
52+
# RELAX-NEXT: jirl $zero, $t0, -8
53+
# RELAX-EMPTY:
54+
55+
56+
# NORELAX-LABEL: <_start>:
57+
## offset = 0x10020 - 0x10000 = 0x20, hi=0, lo18=32
58+
# NORELAX-NEXT: 10000: pcaddu18i $ra, 0
59+
# NORELAX-NEXT: jirl $ra, $ra, 32
60+
## offset = 0x10020 - 0x10008 = 0x18, hi=0, lo18=24
61+
# NORELAX-NEXT: 10008: pcaddu18i $t0, 0
62+
# NORELAX-NEXT: jirl $zero, $t0, 24
63+
## offset = .plt(0x10400)+32 - 0x10010 = 0x410, hi=0, lo18=1040
64+
# NORELAX-NEXT: 10010: pcaddu18i $ra, 0
65+
# NORELAX-NEXT: jirl $ra, $ra, 1040
66+
## offset = .plt(0x10400)+32 - 0x10018 = 0x408, hi=0, lo18=1032
67+
# NORELAX-NEXT: 10018: pcaddu18i $t0, 0
68+
# NORELAX-NEXT: jirl $zero, $t0, 1032
69+
# NORELAX-EMPTY:
70+
# NORELAX-NEXT: <a>:
71+
# NORELAX-NEXT: 10020: ret
72+
# NORELAX-EMPTY:
73+
74+
# NORELAX-LABEL: <.mid>:
75+
## offset = 0x10000 - 0x10800 = -0x800, hi=0, lo18=-2048
76+
# NORELAX-NEXT: 10800: pcaddu18i $ra, 0
77+
# NORELAX-NEXT: jirl $ra, $ra, -2048
78+
# NORELAX-NEXT: pcaddu18i $t0, 0
79+
# NORELAX-NEXT: jirl $zero, $t0, -2056
80+
# NORELAX-EMPTY:
81+
82+
# NORELAX-LABEL: <.mid2>:
83+
## offset = 0x10000 - 0x1010000 = -0x1000000, hi=-64, lo18=0
84+
# NORELAX-NEXT: 1010000: pcaddu18i $ra, -64
85+
# NORELAX-NEXT: jirl $ra, $ra, 0
86+
# NORELAX-NEXT: pcaddu18i $t0, -64
87+
# NORELAX-NEXT: jirl $zero, $t0, -8
88+
# NORELAX-EMPTY:
89+
90+
# NORELAX-LABEL: <.high>:
91+
## offset = 0x10000 - 0x10010000 = -0x10000000, hi=-1024, lo18=0
92+
# NORELAX-NEXT: 10010000: pcaddu18i $ra, -1024
93+
# NORELAX-NEXT: jirl $ra, $ra, 0
94+
# NORELAX-NEXT: pcaddu18i $t0, -1024
95+
# NORELAX-NEXT: jirl $zero, $t0, -8
96+
# NORELAX-EMPTY:
97+
98+
#--- a.s
99+
.global _start, _start_end
100+
_start:
101+
call36 a # relaxed. la64: bl
102+
tail36 $t0, a@plt # relaxed. la64: b
103+
.balign 16
104+
call36 bar # PLT call36 can be relaxed. la64: bl
105+
tail36 $t0, bar # PLT tail36 can be relaxed. la64: bl
106+
107+
a:
108+
ret
109+
.size _start, . - _start
110+
_start_end:
111+
112+
.section .mid,"ax",@progbits
113+
call36 _start@plt # relaxed. la64: bl
114+
tail36 $t0, _start@plt # relaxed. la64: b
115+
116+
.section .mid2,"ax",@progbits
117+
call36 _start@plt # relaxed. la64: bl
118+
tail36 $t0, _start@plt # relaxed. la64: b
119+
120+
.section .high,"ax",@progbits
121+
call36 _start@plt # exceed range, not relaxed
122+
tail36 $t0,_start@plt # exceed range, not relaxed
123+
124+
#--- b.s
125+
.globl bar
126+
bar:
127+
ret
128+
129+
#--- lds
130+
SECTIONS {
131+
.text 0x10000 : { *(.text) }
132+
.plt 0x10400 : { *(.plt) }
133+
.mid 0x10800 : { *(.mid); mid_end = .; }
134+
.mid2 0x1010000 : { *(.mid2) }
135+
.high 0x10010000 : { *(.high); high_end = .; }
136+
}

lld/test/ELF/loongarch-relax-emit-relocs.s

+37-7
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
## Test that we can handle --emit-relocs while relaxing.
33

44
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o
5-
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
5+
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax --defsym ELF64=1 %s -o %t.64.o
66
# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs %t.32.o -o %t.32
77
# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs %t.64.o -o %t.64
8-
# RUN: llvm-objdump -dr %t.32 | FileCheck %s --check-prefix=RELAX
9-
# RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=RELAX
8+
# RUN: llvm-objdump -dr %t.32 | FileCheck %s --check-prefixes=RELAX,RELAX32
9+
# RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefixes=RELAX,RELAX64
1010

1111
## -r should keep original relocations.
1212
# RUN: ld.lld -r %t.64.o -o %t.64.r
@@ -27,10 +27,19 @@
2727
# RELAX-NEXT: R_LARCH_RELAX *ABS*
2828
# RELAX-NEXT: R_LARCH_PCREL20_S2 _start
2929
# RELAX-NEXT: R_LARCH_RELAX *ABS*
30-
# RELAX-NEXT: nop
31-
# RELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc
32-
# RELAX-NEXT: nop
33-
# RELAX-NEXT: ret
30+
# RELAX32-NEXT: nop
31+
# RELAX32-NEXT: R_LARCH_ALIGN *ABS*+0xc
32+
# RELAX32-NEXT: nop
33+
# RELAX32-NEXT: ret
34+
35+
# RELAX64-NEXT: bl -8
36+
# RELAX64-NEXT: R_LARCH_B26 _start
37+
# RELAX64-NEXT: R_LARCH_RELAX *ABS*
38+
# RELAX64-NEXT: b -12
39+
# RELAX64-NEXT: R_LARCH_B26 _start
40+
# RELAX64-NEXT: R_LARCH_RELAX *ABS*
41+
# RELAX64-NEXT: ret
42+
# RELAX64-NEXT: R_LARCH_ALIGN *ABS*+0xc
3443

3544
# NORELAX: <_start>:
3645
# NORELAX-NEXT: pcalau12i $a0, 0
@@ -45,6 +54,14 @@
4554
# NORELAX-NEXT: ld.d $a0, $a0, 0
4655
# NORELAX-NEXT: R_LARCH_GOT_PC_LO12 _start
4756
# NORELAX-NEXT: R_LARCH_RELAX *ABS*
57+
# NORELAX-NEXT: pcaddu18i $ra, 0
58+
# NORELAX-NEXT: R_LARCH_CALL36 _start
59+
# NORELAX-NEXT: R_LARCH_RELAX *ABS*
60+
# NORELAX-NEXT: jirl $ra, $ra, -16
61+
# NORELAX-NEXT: pcaddu18i $a0, 0
62+
# NORELAX-NEXT: R_LARCH_CALL36 _start
63+
# NORELAX-NEXT: R_LARCH_RELAX *ABS*
64+
# NORELAX-NEXT: jirl $zero, $a0, -24
4865
# NORELAX-NEXT: ret
4966
# NORELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc
5067

@@ -61,6 +78,14 @@
6178
# CHECKR-NEXT: ld.d $a0, $a0, 0
6279
# CHECKR-NEXT: R_LARCH_GOT_PC_LO12 _start
6380
# CHECKR-NEXT: R_LARCH_RELAX *ABS*
81+
# CHECKR-NEXT: pcaddu18i $ra, 0
82+
# CHECKR-NEXT: R_LARCH_CALL36 _start
83+
# CHECKR-NEXT: R_LARCH_RELAX *ABS*
84+
# CHECKR-NEXT: jirl $ra, $ra, 0
85+
# CHECKR-NEXT: pcaddu18i $a0, 0
86+
# CHECKR-NEXT: R_LARCH_CALL36 _start
87+
# CHECKR-NEXT: R_LARCH_RELAX *ABS*
88+
# CHECKR-NEXT: jr $a0
6489
# CHECKR-NEXT: nop
6590
# CHECKR-NEXT: R_LARCH_ALIGN *ABS*+0xc
6691
# CHECKR-NEXT: nop
@@ -71,5 +96,10 @@
7196
_start:
7297
la.pcrel $a0, _start
7398
la.got $a0, _start
99+
100+
.ifdef ELF64
101+
call36 _start
102+
tail36 $a0, _start
103+
.endif
74104
.p2align 4
75105
ret

0 commit comments

Comments
 (0)