上一篇有提到,我们porting时发生printf()在有format string印不出东西、segfault掉的状况,这下该怎麽办呢?
一样先来上首歌:《Nobody Speak》https://www.youtube.com/watch?v=NUC2EQvdzmY
好的,我们接下来正式踏入一步一脚印porting中较为麻烦的步骤了,万幸的是我们现在有qemu的linux-user mode可以用,配合着gdb stub,我们可以快速地进行除错。首先,我们将qemu linux-user运行起来:
qemu-riscv32 -g 1234 ./test_time
紧接着我们可以使用gdb连上它:
riscv32-linux-gdb -ex 'target remote localhost:1234'
然而眼尖的朋友可能会注意到我换toolchain了,不再是前几偏中使用riscv-gnu-toolchain
那边release的prebuilt elf toolchain。其实这是一个想偷偷藉机推销一下buildroot埋下的伏笔,我们在Linux环境开发时,有时会遇到一种状况:BSP的工具链太旧、相依的函式库有状况,或选项开启不足......等等。小弟我遇到的情形是,因为我日常开发的环境是Arch Linux
,因为采取rolling release的方式、常常会遇上外界编好的东西与系统上的函式库版本对不上的问题。另外就是小弟我非常仰赖gdb的TUI模式、可说是重度使用者,没有它我debug的能力会只剩下10%吧,而很多时候预编工具链的TUI mode常常是关闭的。此时,透过buildroot重新建置一套工具链便是必然的结果。
然而,手工调整buildroot的组态有点花时间,我们乾脆直接使用qemu virtual platform的组态来进行修改:
git clone https://github.com/buildroot/buildroot
cd buildroot
make qemu_riscv32_virt_defconfig
紧接着 make menuconfig
後,我们可以透过以下选单顺序开启gdb的建置 Toolchain
=> Build cross gdb for the host
=> TUI mode
关於buildroot的build target可以从其文件中得知,这边小弟只简单带过几个常用的与其规则:
在buildroot的世界观中,东西是以package的形式存在,就跟rpm/deb类似,常见的package有 zlib
、linux
(指kernel) ......等等,也有类似meta-package的概念,如toolchain
。 而这些package若是编译平台自身要用的,会加上前缀host-
。如果要重新编译某个package,则是加上後缀-remake
。
所以这边我们要建置gdb,其实就是进行 make host-gdb
。不过以我们的使用情境,我会建议直接make all
,原因会在以後的篇章解释。
在漫长的下载与编译後,我们获得了打开TUI模式、target为riscv32的host-gdb可以使用,他会放在 output/host/bin
里面。
好的,回到TUI mode下,我们发现format string的处理函数fmt_u这边被编译器优化成了一个无穷回圈:
这下子就奇怪了?合理怀疑是ULONG_MAX的定义出现了错误。
我们干掉musl build资料夹下的object code重编 obj/src/stdio/vfprintf.lo
看看compiler有没有报什麽讯息好了:
src/stdio/vfprintf.c: In function ‘fmt_u’:
src/stdio/vfprintf.c:168:16: warning: integer overflow in expression of type ‘long long int’ results in ‘-2’ [-Woverflow]
168 | for ( ; x>ULONG_MAX; x/=10) *--s = '0' + x%10;
| ^
结果还真的有。
以compiler的理解上,因为ilp32下被错误定义的 LONG_MAX*2+1
远超过 unsigned long可容纳的大小,最後一连串type promote被算成了-1
,而 x
是signed value,无论如何都大於 -1
,结果被直接优化成一个无穷回圈。
回头去检查 arch/riscv32/alltypes.h.in
,发现我们需要重新定义data types。要简单的话可以直接搬arm32或mips32的来用。
+#define _Addr int
+#define _Int64 long long
+#define _Reg int
+#define __BYTE_ORDER 1234
+#define __LONG_MAX 0x7fffffffL
+//#define __LONG_MAX 0x7fffffffffffffffL
详情可见commit:
https://github.com/Ruinland/musl-rv32port/commit/fc3b36c2aa7d65a6de34ad727ce3e41c6af4aaf0
在搬迁完成後,我们就可以正常获得一个印时间的结果了!
$ qemu-riscv32 ./test_time
now: 2021-09-14 19:52:34
现在在修正了基本的data type後,我们明天将会来跑跑看libc-test
来进行更深入的压力测试,来保障我们的porting品质。
<<: 案例:AWS MLOps Framework - AWS CloudFormation 模板,部署单帐号版本
宝塔windows版本自7.2开始需要绑定账户才能使用,删除“bind_path.pl”都没用,甚至...
什麽是 MVC 分别是 Model, View, Controller, 是一种软件架构, View...
设定transform属性可以使文字或图像有旋转(rotate)、缩放(scale)、倾斜(ske...
MyBatis 可以简单的使用注解或XML 的方式进行配置和对映,通过将引数对映到配置的SQL 形成...
首先来个永丰官方的文件图片作开场吧! (图一:由商户->永丰正向发动的所需参数) 而我们今天要...