riscv-gcc工具编译firmware进行仿真问题总结

3 篇文章 0 订阅
2 篇文章 0 订阅

Q1 riscv裸机编程undefined reference to `_memcpy` :c代码中数组长度超过16,并在定义时做初始化,编译报错问题,

Q2 全局变量初始化问题

Q3 riscv裸机编程undefined reference to `_memcpy` :c代码中字符数组长度超过16,并在定义时做初始化,编译报错问题.

Q4 字符串常量初始化问题。

A.Q1,QQ3两个问题使用gcc三级优化选项解决

B.Q2,Q4两个问题是,反汇编时,objump,只选取了.text段的代码(使用的的是-d,只disassembly了.text段),而应该将.rodata段的也进行反汇编,应该使用-D将所有段进行反汇编。

objdump -d app.elf    //对包含机器指令的段进行反汇编

objdump -D app.elf    //-D 与 -d 类似,但对所有段进行反汇编

Q1.现象c代码中数组长度超过16,并在定义时做初始化,链接时报错undefined reference to `_memcpy`,如果长的字符串也是一样的。

代码:

报错,推测(对编译不是特别了解)是由于数组过程,直接初始化,会使得编译器调用memcpy这个函数(可能是编译器自身做的优化,如果数组长度比较小,那么可以直接赋值,如果长的化,编译器就会优化出来调用这个memcpy这个函数,如果你没有定义就会报错)

但是系统或者工具链里面没有这个函数,所以,编译完成后,在链接时,就会报错(因为链接器找不到这个函数):

如果定义成16长度的数组:

编译结果,汇编代码中会一个个去初始化数组的值。;

所以数组过长,避免这个错误的方式:这里采用的方法是,可以在c代码里面使用循环来初始化。或者使用一个个手动初始化。

Q2.另外全局变量定义后初始化时也不成功。

所以全局变量单独使用了一个函数来做初始化(这是其中一种做法)。

注意更新了一下链接脚本。

比如有如下代码:

func.c编译结果,如下,可以看见全局变量的初始化值被放入了data段(.sdata包含其中):

注意我把链接脚本做了修改,主要修改时是ram段的地址,因为若是原来的地址(见Q4中的链接脚本中的地址段),仿真时访问的是fffffff地址而不是5208000:

但是, 我仿真时没有,并没有读到初始化的值,读到是0,说明全局变量没有被初始化。但是从链接结果来看,全局变量的初始值是放入data段的。

仿真波形如下。可以看到5b000000读出来的值为X,说明并没有被初始化:

Q3.另外长字符串常量也编译不成功(这个和Q1是同一个问题)。

比如代码:

编译结果中可以看到,也是调用memcpy这个函数,所以链接时也会报错:

Q4.字符串常量的另外一个问题:

当我把字符串长度减少,可能是编译觉得不用优化,就没有调用memcpy这个函数。比如下面这个代码:

编译结果,注意这种情况下,没有调用memcpy,并且常量也没有放在rodata段。程序可以正常使用,也可以正常连接:

但是,如果我在一个函数的参数中使用了一个字符串常量.比如:

此时编译结果,会将这printstr("abcd\n")中所使用的字符串常量放在.rodata段:

连接结果的map中显示,的确存在firmware的常量连接到了rodata段(但是我实际去跑代码时这段地址仍然没有被初始化为X态):

rodata段地址,见下面的链接脚本:

波形如下,当去读取0xa000_0000这个rodata地址时,读出来的值是x.

所以没法这样使用字符串常量。

解决:

(一)GCC的三级优化。(解决Q1和Q3)

GNU编译器提供-O选项供程序优化使用:

-O 提供基础级别的优化

-O2 提供更加高级的代码优化,会占用更长的编译时间

-O3 提供最高级的代码优化

-O4 不优化,这是默认值

上面Q1,3这两个问题,会得到解决。编译器不会再调用memcpy函数。

(二)反汇编生成firmware时,只使用了.text段,其他段并没有使用。

如下所示,第31行,-d这个选项只会对对包含机器指令的段进行反汇编

比如Q2这个问题。使用riscv32-bst-elf-objdump -d isp_firmware得到的结果如下,结果中只对.text进行了disassembly。这样在

第35-36句时只会使用生成,.text段相关的地址和数据。

如果使用-D,就会包含所有段的disassembly:

按照-d,生成的最终仿真使用的文件coreisp.elf.txt如下,可以看见最终firmware中并没有5b00_0000地址段(Q2中链接脚本中ram地址段)。

Q4这个问题也是一样的,并没有将rodata段写入到最终firmware中(Q4中rodata段地址是a000_0000开始的)。

需要修改地方,0.对于data段(ram)地址范围也需要修改下。

                        1.makefile的31行改为-D。 这样会把所有段都包含进结果。

                        2.修改脚本od2txt.py脚本从包含的所有段的结果中筛选出需要的段。(除了.text段外还有,比如Q4的rodata段和Q2的.data(其中包含.sdata)段)

                        原来的:

                        

                        修改后的:

                        

修改后例子:

编译之后再使用objdump -D反汇编的得到:

   

然后使用修改后od2txt.py得到下面结果,最后几行是sdata和rodata的值,和代码是对应上的:

仿真波形,haddr依次是a000_0000,1000,5b00_0000,1000:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值