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