在过去的几个月里,我在 FPGA 上实现了 RV32I CPU。到目前为止,我只是使用一些汇编代码对其进行了测试。这周我决定用 C 语言尝试一个简单的测试程序。源码如下:
int main(){
register unsigned int a = 1;
register unsigned int b = 1;
while(1){
a = a << b;
if(a == 0x80000000){
a = 1;
}
}
return 0;
}
这一切都简单明了,这样我就可以在分配了“a”的寄存器中看到步行模式。
在进行 objdump 时,我仍然对堆栈放置的位置感到非常困惑:
test.elf: file format elf32-littleriscv
Disassembly of section .text:
00000000 <main>:
0: ff010113 add sp,sp,-16
4: 00112623 sw ra,12(sp)
8: 00812423 sw s0,8(sp)
c: 00912223 sw s1,4(sp)
10: 01010413 add s0,sp,16
14: 00100093 li ra,1
18: 00100493 li s1,1
1c: 009090b3 sll ra,ra,s1
20: 800007b7 lui a5,0x80000
24: fef09ce3 bne ra,a5,1c <main+0x1c>
28: 00100093 li ra,1
2c: ff1ff06f j 1c <main+0x1c>
鉴于我在链接描述文件中说了我的内存在哪里,我不明白为什么编译器使用低于 4GB 限制的最高可能地址作为堆栈基地址。这可以在前四个指令中看到,我们将值保存到堆栈中。我的链接器脚本如下:
ENTRY(main)
BRAM_SIZE = 1024;
MEMORY{
INSTR(RX) : ORIGIN =0x00000000 , LENGTH = BRAM_SIZE
DATA(RWX) : ORIGIN =0x01000000 , LENGTH = BRAM_SIZE
}
STACK_SIZE = 0x100;
/* Section Definitions */
SECTIONS
{
.text :
{
KEEP(*(.vectors .vectors.*))
*(.text*)
*(.rodata*)
} > INSTR
/* .bss section which is used for uninitialized data */
.bss (NOLOAD) :
{
*(.bss*)
*(COMMON)
} > DATA
.data :
{
*(.data*);
} > DATA AT >INSTR
/* stack section */
.stack (NOLOAD):
{
. = ALIGN(8);
. = . + STACK_SIZE;
. = ALIGN(8);
} > DATA
_end = . ;
}
我正在使用以下命令和工具链进行编译:
riscv64-unknown-elf-gcc -march=rv32i -mabi=ilp32 -nostdlib -ffreestanding -T linkerscript_reduced.ld -o test.elf test.c
我做错了什么?预先感谢,并对菜鸟问题表示歉意。
由于您添加了选项“-nostdlib -ffreestand”,您需要自己提供每个细节。这包括标准所承诺的 C 环境设置,以及您的特定目标期望的任何内容。
这说的是链接选项的文档(我强调过):
-nostdlib
链接时不要使用标准系统启动文件或库。 没有启动文件,仅将您指定的库传递给链接器,并且忽略指定系统库链接的选项,例如
或-static-libgcc
。-shared-libgcc
这说明了 C 方言选项的文档:
-ffreestanding
断言编译目标是独立环境。这意味着
。独立环境是标准库可能不存在的环境,程序启动不一定在-fno-builtin
。main
因此,您需要添加代码,将堆栈指针初始化为您想要的值,将其归零
.bss
并将初始化的数据复制到 .data
部分。这通常是用汇编语言编写的,但是通过一些内联汇编,您也可以编写 C 源代码。