看本文请参考《都江堰操作系统与嵌入式系统设计》第15章,该书可在www.djyos.com下载。
djyos使用gcc作为编译器,已经5年多了,要抛弃它,实在是一个艰难的抉择,需要下很大的决心。在移植日志中,专门为gcc写一篇,以示纪念。
当初选择gcc做编译环境,是因为gcc支持的cpu种类繁多,可以简化djyos移植到其他cpu平台的工作,现在证明,这种想法大错特错!这次将djyos从ARM7移植到stm32的过程中,花了大量的时间折腾gcc后,仍未成功,而从0开始学习MDK到成功编译djyos,花费的时间竟然比花在gcc上的时间少得多。
所以说,企图通过gcc简化cpu间移植工作是不现实的,新的cpu应该去学习它的专业开发环境,才是王道。也许,在linux环境下编译linux应用程序,gcc是最合适的,但用来编译非linux程序,gcc真的不适合。5年多来,gcc把我折腾得够呛,让gcc再去折腾djyos的用户,让我于心何忍!
空口无凭,让事实说话,过去的就不说了,也没有留下什么记录,下面谈谈这次把djyos移植到stm32的过程中gcc给我的苦头。
牛头马嘴的出错信息
我们知道,要使用gcc编译,就必须编写makefile和ld文件,这两个文件的书写规矩还真多,有些地方要用[tab]键,有些地方要用空格,有些地方又不允许空格,有些地方可以空行,有些地方不允许空行。违反了这些规矩,如果能给出正确的错误信息也行,可惜的是,给出的信息和真正的错误根本牛头不对马嘴!略举几例:
1、makefile中可以使用shell的printf命令,如果被打印的字符串有分行的话,空行是绝对不允许的,如果任意地方出现空行,可能的出错信息是:
makefile:244: *** commands commence before first target. Stop. 注:244行是文件末行
也可能是:
/usr/bin/sh: -c: line 0: unexpected EOF while looking for matching `"'
你看着这些出错信息,是不是云里雾里?
2、在ld文件中,一个输出段描述如下:
sec1 :
{
sec_base = . ;
. = addr;
* (.text)
} > region1
上述代码中,但“sec_base=.”中的“.”代表的是绝对地址,“ .=addr ”中的“.”却是region1内的偏移地址。万幸的是,这个问题能够直接导致代码定位出错,调试的时候可以发现。
3、同样是ld文件中,地址必须升序排列,若有代码:
sec2 :
{
. = addr1;
. = addr2;
* (.text)
} > region2
如果addr2<addr1,出错信息是:
debug.ld: xx1 cannot move location counter backwards (from xx2 to xx3)
其中:
xx1:文件最后一行的行号,不是出错行的行号
xx2:addr1+region2段起始地址。
xx3:addr2+region2段起始地址
生成了错误的代码
如果说上述问题只是对你的考验的话——这么好的东西,不经九九八十一难,怎能轻易让你用!接下来的问题,就更严重了。
一直使用的是gnuarm,经过一番煎熬后,终于编译成功了,加载调试吧!却发现根本无法调试,0地址并不是ld文件中指定的向量表,于是把可执行文件objdump出来,一看其中的内容,简直让人哭笑不得,gcc居然在向量表前面,0地址处放了这些东西:
00000000 <____divdf3_from_thumb>:
0: 4778 bx pc
2: 46c0 nop (mov r8, r8)
4: ea00274a b 9d34 <__aeabi_ddiv>
00000008 <____asm_reset_switch_from_thumb>:
8: 4778 bx pc
a: 46c0 nop (mov r8, r8)
c: ea0003ed b fc8 <__asm_reset_switch>
这段代码有两个错误:
1、 这段代码是用来从thumb切换到arm状态的interwork代码段,在cm3中,企图切入arm状态,岂不是找死吗?fault伺候。
2、 它把这段代码放在0地址,谁都知道cm3中0地址应该是什么!
虽然这两个是不可饶恕的错误,但我还是企图通过调整编译参数来解决问题,花了大量时间阅读gcc文档,并且经过无数次失败的试验后,我最终还是投降了。
gnuarm不行,那换一个发行版本如何呢?于是安装了sourcery g++ lite,编译后,反汇编一看,OK,0地址正确地出现了向量表:
00000000 <_start>:
0: 2000c000 .word 0x2000c000
4: 00000012 .word 0x00000012
8: 00000010 .word 0x00000010
c: 00000010 .word 0x00000010
00000010 <rst_fault_handler>:
10: e7fe b.n 10 <rst_fault_handler>
大喜过望之余,马上加载调试,可一上来就陷入fault,通过跟踪调试,发现sourcery产生的代码,虽然没有在0地址添加interwork代码,但在所有的用C调用汇编函数的地方,用了比interwork稍微“聪明”点的blx:
13f8: f7ff ef64 blx 12c4 <__asm_reset_thread>
看官,指令中目的地址的最低位是0,摆明要切入arm状态,在只支持thumb-2的cm3中,是不折不扣的非法指令,怪不得陷入fault了。
我仍不死心,于是又安装了yagarto,结果一样令人失望。
连正确地使用指令集都保证不了,这样的编译器,还有什么留恋的呢?还是从MDK或IAR中选一个吧。 |