使用自定义 linker 脚本构建裸机应用程序时如何 link 数学库
how to link math library when building bare metal application with custom linker script
我正在构建一个 RISC-V cpu 核心,我正在尝试为其构建一些 C 代码。我有一些基本的代码编译和 linking 我想要的方式并且工作得很好,例如这个:
asm("li sp, 0x390");
asm("li s0, 0x390");
asm("li ra, 0");
int main(void){
char *memptr = 0 ;
int sum = 0;
for(int i = 0; i < 8; i++)
*(memptr + i) = i;
for(int i = 0; i < 8; i++)
sum += *(memptr + i);
*((int*)0xC) = sum;
asm("lw x31, 0xc(x0)");
}
和 compile/link 使用这些命令:
riscv64-unknown-elf-gcc -nostartfiles -nostdlib -mno-relax -march=rv32i -mabi=ilp32 -c main.c
riscv64-unknown-elf-ld -nostartfiles -nostdlib -march=rv32i -melf32lriscv -o main -T link.ld main.o
我的 linker 脚本如下:
OUTPUT_ARCH( "riscv" )
ENTRY(main)
MEMORY
{
progmem (rx) : ORIGIN = 0x10000000, LENGTH = 8K
ram (!rx) : ORIGIN = 0x20000000, LENGTH = 64K
}
SECTIONS
{
.text : {
main.o(.text)
} > progmem
.data : {
main.o(.rodata)
main.o(.data)
main.o(.sdata)
main.o(.bss)
} > ram
}
有了这个设置,我得到了我想要的结果没问题。我得到了我的文本部分(我把它放在程序内存中),我得到了数据部分,所有的子部分都放在了那里,并将它直接加载到 ram 中(它适用于我现在正在做的事情)。
当我尝试使用浮点加法时问题开始了:
asm("li sp, 0x390");
asm("li s0, 0x390");
asm("li ra, 0");
float a = 1.7;
float b = 0.7;
int main(void){
int *memptr = (int*)0x8;
float c = a - b;
}
编译后尝试 link 导致此错误:
riscv64-unknown-elf-ld -nostartfiles -march=rv32i -melf32lriscv -o main -T link.ld main.o
riscv64-unknown-elf-ld: main.o: in function `main':
main.c:(.text+0x3c): undefined reference to `__subsf3'
我可以在汇编文件中看到(使用 gcc -S 选项)有一条指令 call __subsf3,但是在任何地方都没有这样的标签.文本部分。我相信我必须以某种方式 link 数学库才能工作,所以我尝试添加 #include "math.h",然后向 ld 命令,如“-lc”、“-lgcc”、“-lm”,但会导致以下错误:
riscv64-unknown-elf-ld: cannot find -lc
riscv64-unknown-elf-ld: cannot find -lgcc
riscv64-unknown-elf-ld: cannot find -lm
通过反复试验,我设法想出了这个
riscv64-unknown-elf-gcc -nostartfiles -mno-relax -march=rv32i -mabi=ilp32 -Wl,-emain -lm main.c -o main
几乎可以满足我的要求,但不使用我的 link 脚本。如果我添加 -Wl,link.ld 然后它再次不起作用,给出错误:
/usr/lib/gcc/riscv64-unknown-elf/9.1.0/../../../../riscv64-unknown-elf/bin/ld: main.o:(.sdata+0x0): multiple definition of `a'; /tmp/cc0LmWB4.o:(.sdata+0x0): first defined here
/usr/lib/gcc/riscv64-unknown-elf/9.1.0/../../../../riscv64-unknown-elf/bin/ld: main.o:(.sdata+0x4): multiple definition of `b'; /tmp/cc0LmWB4.o:(.sdata+0x4): first defined here
/usr/lib/gcc/riscv64-unknown-elf/9.1.0/../../../../riscv64-unknown-elf/bin/ld: main.o: in function `main':
main.c:(.text+0xc): multiple definition of `main'; /tmp/cc0LmWB4.o:main.c:(.text+0xc): first defined here
/usr/lib/gcc/riscv64-unknown-elf/9.1.0/../../../../riscv64-unknown-elf/bin/ld: error: no memory region specified for loadable section `.sdata'
collect2: error: ld returned 1 exit status
如果有人能向我解释我做错了什么,以及我应该如何使用上面的浮点数学为裸机 RISC-V 构建代码,并让 ld 添加数学函数,我将不胜感激在我的 .text 部分。
问题是 gcc 不是链接器它是编译器,但在 gnu 世界中 gcc 知道它在哪里(从目录和相对路径的角度来看)。 Ld 是一个链接器,但不知道它在哪里(典型用例(按设计)它依赖 gcc 将库路径传递给它)所以...
bootstrap.s
.globl _start
_start:
lui x2,0x20010
jal notmain
j .
notmain.c
unsigned int abcd = 5;
float fun ( float a, float b)
{
return(a+b);
}
int notmain ( void )
{
return(0);
}
内存映射
MEMORY
{
rom : ORIGIN = 0x10000000, LENGTH = 8K
ram : ORIGIN = 0x20000000, LENGTH = 64K
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
.data : { *(.data*) } > ram
}
一种方式:
riscv32-none-elf-as --warn -march=rv32i -mabi=ilp32 bootstrap.s -o bootstrap.o
riscv32-none-elf-gcc -Wall -march=rv32i -mabi=ilp32 -O2 -nostdlib -nostartfiles -ffreestanding -c notmain.c -o notmain.o
riscv32-none-elf-ld -T memmap bootstrap.o notmain.o -lgcc -L /opt/gnuriscv32/lib/gcc/riscv32-none-elf/9.1.0/rv32i/ilp32 -o notmain.elf
riscv32-none-elf-objcopy notmain.elf -O binary notmain.bin
riscv32-none-elf-objdump -D notmain.elf > notmain.list
给予
10000000 <_start>:
10000000: 20010137 lui x2,0x20010
10000004: 020000ef jal x1,10000024 <notmain>
10000008: 0000006f j 10000008 <_start+0x8>
1000000c <fun>:
1000000c: ff010113 addi x2,x2,-16 # 2000fff0 <abcd+0xfff0>
10000010: 00112623 sw x1,12(x2)
10000014: 018000ef jal x1,1000002c <__addsf3>
10000018: 00c12083 lw x1,12(x2)
1000001c: 01010113 addi x2,x2,16
10000020: 00008067 ret
10000024 <notmain>:
10000024: 00000513 li x10,0
10000028: 00008067 ret
1000002c <__addsf3>:
1000002c: 008006b7 lui x13,0x800
10000030: ff010113 addi x2,x2,-16
10000034: 01755713 srli x14,x10,0x17
...
20000000 <abcd>:
20000000: 0005
...
同样令人反感:
riscv32-none-elf-as --warn -march=rv32i -mabi=ilp32 bootstrap.s -o bootstrap.o
riscv32-none-elf-gcc -Wall -march=rv32i -mabi=ilp32 -O2 -nostdlib -nostartfiles -ffreestanding -c notmain.c -o notmain.o
riscv32-none-elf-gcc -Wall -march=rv32i -mabi=ilp32 -O2 -nostdlib -nostartfiles -ffreestanding -Xlinker -T -Xlinker memmap bootstrap.o notmain.o -lgcc -o notmain.elf
riscv32-none-elf-objcopy notmain.elf -O binary notmain.bin
riscv32-none-elf-objdump -D notmain.elf > notmain.list
给予
10000000 <_start>:
10000000: 20010137 lui x2,0x20010
10000004: 020000ef jal x1,10000024 <notmain>
10000008: 0000006f j 10000008 <_start+0x8>
1000000c <fun>:
1000000c: ff010113 addi x2,x2,-16 # 2000fff0 <abcd+0xfff0>
10000010: 00112623 sw x1,12(x2)
10000014: 018000ef jal x1,1000002c <__addsf3>
10000018: 00c12083 lw x1,12(x2)
1000001c: 01010113 addi x2,x2,16
10000020: 00008067 ret
10000024 <notmain>:
10000024: 00000513 li x10,0
10000028: 00008067 ret
1000002c <__addsf3>:
1000002c: 008006b7 lui x13,0x800
10000030: ff010113 addi x2,x2,-16
...
20000000 <abcd>:
20000000: 0005
gcc 解决方案不那么痛苦,因为您不必 hard-code 库路径。
我正在构建一个 RISC-V cpu 核心,我正在尝试为其构建一些 C 代码。我有一些基本的代码编译和 linking 我想要的方式并且工作得很好,例如这个:
asm("li sp, 0x390");
asm("li s0, 0x390");
asm("li ra, 0");
int main(void){
char *memptr = 0 ;
int sum = 0;
for(int i = 0; i < 8; i++)
*(memptr + i) = i;
for(int i = 0; i < 8; i++)
sum += *(memptr + i);
*((int*)0xC) = sum;
asm("lw x31, 0xc(x0)");
}
和 compile/link 使用这些命令:
riscv64-unknown-elf-gcc -nostartfiles -nostdlib -mno-relax -march=rv32i -mabi=ilp32 -c main.c
riscv64-unknown-elf-ld -nostartfiles -nostdlib -march=rv32i -melf32lriscv -o main -T link.ld main.o
我的 linker 脚本如下:
OUTPUT_ARCH( "riscv" )
ENTRY(main)
MEMORY
{
progmem (rx) : ORIGIN = 0x10000000, LENGTH = 8K
ram (!rx) : ORIGIN = 0x20000000, LENGTH = 64K
}
SECTIONS
{
.text : {
main.o(.text)
} > progmem
.data : {
main.o(.rodata)
main.o(.data)
main.o(.sdata)
main.o(.bss)
} > ram
}
有了这个设置,我得到了我想要的结果没问题。我得到了我的文本部分(我把它放在程序内存中),我得到了数据部分,所有的子部分都放在了那里,并将它直接加载到 ram 中(它适用于我现在正在做的事情)。
当我尝试使用浮点加法时问题开始了:
asm("li sp, 0x390");
asm("li s0, 0x390");
asm("li ra, 0");
float a = 1.7;
float b = 0.7;
int main(void){
int *memptr = (int*)0x8;
float c = a - b;
}
编译后尝试 link 导致此错误:
riscv64-unknown-elf-ld -nostartfiles -march=rv32i -melf32lriscv -o main -T link.ld main.o
riscv64-unknown-elf-ld: main.o: in function `main':
main.c:(.text+0x3c): undefined reference to `__subsf3'
我可以在汇编文件中看到(使用 gcc -S 选项)有一条指令 call __subsf3,但是在任何地方都没有这样的标签.文本部分。我相信我必须以某种方式 link 数学库才能工作,所以我尝试添加 #include "math.h",然后向 ld 命令,如“-lc”、“-lgcc”、“-lm”,但会导致以下错误:
riscv64-unknown-elf-ld: cannot find -lc
riscv64-unknown-elf-ld: cannot find -lgcc
riscv64-unknown-elf-ld: cannot find -lm
通过反复试验,我设法想出了这个
riscv64-unknown-elf-gcc -nostartfiles -mno-relax -march=rv32i -mabi=ilp32 -Wl,-emain -lm main.c -o main
几乎可以满足我的要求,但不使用我的 link 脚本。如果我添加 -Wl,link.ld 然后它再次不起作用,给出错误:
/usr/lib/gcc/riscv64-unknown-elf/9.1.0/../../../../riscv64-unknown-elf/bin/ld: main.o:(.sdata+0x0): multiple definition of `a'; /tmp/cc0LmWB4.o:(.sdata+0x0): first defined here
/usr/lib/gcc/riscv64-unknown-elf/9.1.0/../../../../riscv64-unknown-elf/bin/ld: main.o:(.sdata+0x4): multiple definition of `b'; /tmp/cc0LmWB4.o:(.sdata+0x4): first defined here
/usr/lib/gcc/riscv64-unknown-elf/9.1.0/../../../../riscv64-unknown-elf/bin/ld: main.o: in function `main':
main.c:(.text+0xc): multiple definition of `main'; /tmp/cc0LmWB4.o:main.c:(.text+0xc): first defined here
/usr/lib/gcc/riscv64-unknown-elf/9.1.0/../../../../riscv64-unknown-elf/bin/ld: error: no memory region specified for loadable section `.sdata'
collect2: error: ld returned 1 exit status
如果有人能向我解释我做错了什么,以及我应该如何使用上面的浮点数学为裸机 RISC-V 构建代码,并让 ld 添加数学函数,我将不胜感激在我的 .text 部分。
问题是 gcc 不是链接器它是编译器,但在 gnu 世界中 gcc 知道它在哪里(从目录和相对路径的角度来看)。 Ld 是一个链接器,但不知道它在哪里(典型用例(按设计)它依赖 gcc 将库路径传递给它)所以...
bootstrap.s
.globl _start
_start:
lui x2,0x20010
jal notmain
j .
notmain.c
unsigned int abcd = 5;
float fun ( float a, float b)
{
return(a+b);
}
int notmain ( void )
{
return(0);
}
内存映射
MEMORY
{
rom : ORIGIN = 0x10000000, LENGTH = 8K
ram : ORIGIN = 0x20000000, LENGTH = 64K
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
.data : { *(.data*) } > ram
}
一种方式:
riscv32-none-elf-as --warn -march=rv32i -mabi=ilp32 bootstrap.s -o bootstrap.o
riscv32-none-elf-gcc -Wall -march=rv32i -mabi=ilp32 -O2 -nostdlib -nostartfiles -ffreestanding -c notmain.c -o notmain.o
riscv32-none-elf-ld -T memmap bootstrap.o notmain.o -lgcc -L /opt/gnuriscv32/lib/gcc/riscv32-none-elf/9.1.0/rv32i/ilp32 -o notmain.elf
riscv32-none-elf-objcopy notmain.elf -O binary notmain.bin
riscv32-none-elf-objdump -D notmain.elf > notmain.list
给予
10000000 <_start>:
10000000: 20010137 lui x2,0x20010
10000004: 020000ef jal x1,10000024 <notmain>
10000008: 0000006f j 10000008 <_start+0x8>
1000000c <fun>:
1000000c: ff010113 addi x2,x2,-16 # 2000fff0 <abcd+0xfff0>
10000010: 00112623 sw x1,12(x2)
10000014: 018000ef jal x1,1000002c <__addsf3>
10000018: 00c12083 lw x1,12(x2)
1000001c: 01010113 addi x2,x2,16
10000020: 00008067 ret
10000024 <notmain>:
10000024: 00000513 li x10,0
10000028: 00008067 ret
1000002c <__addsf3>:
1000002c: 008006b7 lui x13,0x800
10000030: ff010113 addi x2,x2,-16
10000034: 01755713 srli x14,x10,0x17
...
20000000 <abcd>:
20000000: 0005
...
同样令人反感:
riscv32-none-elf-as --warn -march=rv32i -mabi=ilp32 bootstrap.s -o bootstrap.o
riscv32-none-elf-gcc -Wall -march=rv32i -mabi=ilp32 -O2 -nostdlib -nostartfiles -ffreestanding -c notmain.c -o notmain.o
riscv32-none-elf-gcc -Wall -march=rv32i -mabi=ilp32 -O2 -nostdlib -nostartfiles -ffreestanding -Xlinker -T -Xlinker memmap bootstrap.o notmain.o -lgcc -o notmain.elf
riscv32-none-elf-objcopy notmain.elf -O binary notmain.bin
riscv32-none-elf-objdump -D notmain.elf > notmain.list
给予
10000000 <_start>:
10000000: 20010137 lui x2,0x20010
10000004: 020000ef jal x1,10000024 <notmain>
10000008: 0000006f j 10000008 <_start+0x8>
1000000c <fun>:
1000000c: ff010113 addi x2,x2,-16 # 2000fff0 <abcd+0xfff0>
10000010: 00112623 sw x1,12(x2)
10000014: 018000ef jal x1,1000002c <__addsf3>
10000018: 00c12083 lw x1,12(x2)
1000001c: 01010113 addi x2,x2,16
10000020: 00008067 ret
10000024 <notmain>:
10000024: 00000513 li x10,0
10000028: 00008067 ret
1000002c <__addsf3>:
1000002c: 008006b7 lui x13,0x800
10000030: ff010113 addi x2,x2,-16
...
20000000 <abcd>:
20000000: 0005
gcc 解决方案不那么痛苦,因为您不必 hard-code 库路径。