Dupidog Wu on Mar 3, 20222022-03-03T00:00:00+08:00
Updated Mar 302025-03-30T11:51:55+08:00 1 min read
RISC-V GCC在处理GP寄存器时的问题
背景
BareMetal
下需要在start.S
中初始化bss
段,不然里面的数值不一定为0
(所有未初始化或初始化为0
的全局变量会在bbs
段中)
start.S
1
2
3
4
5
6
7
| # zero-out bss
la t0, _bss_start
la t1, _bss_end
_bss_zero:
SREG zero, (t0)
add t0, t0, REGBYTES
blt t0, t1, _bss_zero
|
link.ldS
1
2
3
4
5
6
7
8
9
10
| # bss segment
_bss_start = .;
.sbss : {
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
}
.bss : {
*(.bss)
}
_bss_end = .;
|
踩坑
1
2
| la t0, _bss_start # 0x12c, 0x130 使用pc相对位置得到_bss_start
la t1, _bss_end # 0x134 使用gp相对位置得到_bss_end
|
![]()
解决
start.S
代码片段如下,可能此处有一个编译器的bug,如果gp
在t1
之后加载,而0x134
行中的t1
相对gp
的偏移-1944
是从ldS
脚本中的__global_pointer$
计算得到的,那么t1
就会加载到错误的地址(此时gp
中的值并非__global_pointer$
)。
把BSS
初始化放到gp
初始化后面就一切正常,具体原因还要仔细再追。
1
2
3
4
5
6
7
8
9
10
11
12
13
| # zero-out bss
la t0, _bss_start
la t1, _bss_end
_bss_zero:
SREG zero, (t0)
add t0, t0, REGBYTES
blt t0, t1, _bss_zero
# initialize global pointer
.option push
.option norelax
la gp, __global_pointer$
.option pop
|