ALIGN的烦恼和传说中的秘技<br /><br />风起<br /><br />一个ADuC702x(ARM7TDMI)的系统,编译后运行发现这样的问题:<br /><br />// Begin main.c<br />// Some code here...<br />unsigned char bcd[14] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13};<br /><br />void pro_init(void) {<br /> // Some code here...<br />}<br /><br />int main(void) {<br /> // Some code here...<br />}<br />// End main.c<br /><br />gcc下编译汇报...<br />-------- begin (mode: ROM_RUN) --------<br />arm-elf-gcc (GCC) 4.1.2 (WinARM 4/2007)<br />Copyright (C) 2006 Free Software Foundation, Inc.<br />This is free software; see the source for copying conditions. There is NO<br />warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.<br /><br />Size before:<br />main.elf :<br />section size addr<br />.text 436 524288<br />.data 14 65536<br />.comment 34 0<br />Total 484<br /><br />Errors: none<br />-------- end --------<br /><br />云涌<br /><br />结果main()中测试发现:bcd_buf[0]~bcd_buf[11]有对应初值,而bcd[12]和bcd[13]的值<br />为0。显然,编译结果有BUG! 经过多次实验,发现改定义为bcd[16],那么bcd[0]至bcd[15]<br />都有对应初值。gcc编译结果如下:<br />Size before:<br />main.elf :<br />section size addr<br />.text 436 524288<br />.data 16 65536<br />.comment 34 0<br />Total 484<br />可以看到.data变为16....也就说这是ALIGN(ARM7的RAM是4byte对齐的)方面的BUG.虽然有<br />这个暂时的回避办法,但这个滥竽充数的招数严重影响我们境界的提升,我们需要更深探索<br />本源...<br /><br /><br />惊涛<br /><br />1)下载gcc使用文档....没找到解法...<br />2)看startup.S的汇编启动文件...<br />#ifdef ROM_RUN<br /># Relocate .data section (Copy from ROM to RAM) <br /> LDR R1, =_etext <br /> LDR R2, =_data <br /> LDR R3, =_edata <br /> CMP R2, R3<br /> BEQ DataIsEmpty<br />LoopRel: CMP R2, R3 <br /> LDRLO R0, [R1], #4 <br /> STRLO R0, [R2], #4 <br /> BLO LoopRel <br />DataIsEmpty:<br />#else<br />#warning RAM_RUN - .data will not be copied<br />#endif<br /> <br /># Clear .bss section (Zero init) <br /> MOV R0, #0 <br /> LDR R1, =__bss_start__ <br /> LDR R2, =__bss_end__ <br />LoopZI: CMP R1, R2 <br /> STRLO R0, [R1], #4 <br /> BLO LoopZI <br />我们从代码中可以猜出有初值的全局变量被定位在flash,然后拷贝到ram,紧跟着把没有<br />初值的全局变量(.bss段)全清0...,那么可以断定没有ALIGN的bcd[12]和bcd[13]应该<br />是被砍头(ALIGN)后清0了...<br />3)天啊,又要学汇编...<br />这些定义(_etext,_edata...)在哪里呢?终于找到了,在ADuC7021-ROM.ld<br />4)我倒!还要学LD Script...来看看ADuC7021-ROM.ld...<br />SECTIONS<br />{<br /><br /> /* first section is .text which is used for code */<br /><br /> .text :<br /> {<br /> *startup.o (.text) /* Startup code */<br /> *(.text) /* remaining code */<br /> *(.glue_7t) *(.glue_7)<br /> } >IntFLASH <br /> . = ALIGN(4);<br /><br /> /* .rodata section which is used for read-only data (constants) */<br /><br /> .rodata :<br /> {<br /> *(.rodata)<br /> } >IntFLASH<br /> . = ALIGN(4);<br /><br /> _etext = . ;<br /> PROVIDE (etext = .);<br /><br /> /* .data section which is used for initialized data */<br /><br /> .data : AT (_etext)<br /> {<br /> _data = . ;<br /> *(.data)<br /> SORT(CONSTRUCTORS)<br /> } >IntRAM<br /> . = ALIGN(4);<br /><br /> /* take empty data section into account: */<br /> <br /> _edata = . ;<br /> PROVIDE (edata = .);<br /> <br /> /* .bss section which is used for uninitialized data */<br /><br /> .bss :<br /> {<br /> __bss_start = . ;<br /> __bss_start__ = . ;<br /> *(.bss)<br /> *(COMMON)<br /> } >IntRAM<br /> . = ALIGN(4);<br /> __bss_end = . ;<br /> __bss_end__ = . ;<br /><br /> <br /> _end = .;<br /> PROVIDE (end = .);<br /><br /> /* Stabs debugging sections. */<br />/* 省略n字 */<br />}<br />显然,ALIGN(4)没有起作用,否则,gcc编译应该看到.data不是14而是16...<br />我请教了n个gcc的高手(至少我认为是)了,可其中90%的都没自己改过<br />ld script文件...看来我要做剩下的10%...我改...我改...我改改改...<br /><br />SECTIONS<br />{<br /><br /> /* first section is .text which is used for code */<br /><br /> .text :<br /> {<br /> *startup.o (.text) /* Startup code */<br /> *(.text) /* remaining code */<br /> *(.glue_7t) *(.glue_7)<br /> . = ALIGN(4)<br /> } >IntFLASH <br /><br /> /* .rodata section which is used for read-only data (constants) */<br /><br /> .rodata :<br /> {<br /> *(.rodata)<br /> . = ALIGN(4)<br /> } >IntFLASH<br /><br /><br /> _etext = . ;<br /> PROVIDE (etext = .);<br /><br /> /* .data section which is used for initialized data */<br /><br /> .data : AT (_etext)<br /> {<br /> _data = . ;<br /> *(.data)<br /> SORT(CONSTRUCTORS)<br /> . = ALIGN(4)<br /> } >IntRAM<br /><br /> /* take empty data section into account: */<br /> <br /> _edata = . ;<br /> PROVIDE (edata = .);<br /> <br /><br /> /* .bss section which is used for uninitialized data */<br /><br /> .bss :<br /> {<br /> __bss_start = . ;<br /> __bss_start__ = . ;<br /> *(.bss)<br /> *(COMMON)<br /> . = ALIGN(4)<br /> } >IntRAM<br /> __bss_end= . ;<br /> __bss_end__ = . ;<br /><br /> <br /> _end = .;<br /> PROVIDE (end = .);<br /><br /> /* Stabs debugging sections. */<br />/* 省略n字 */<br />}<br />变换ALIGN(4)位置后,将bcd[16]定义改回bcd[14],看看gcc编译结果...<br /><br /><br />彩虹<br /><br />Size before:<br />main.elf :<br />section size addr<br />.text 436 524288<br />.data 16 65536 // 注意这里<br />.comment 34 0<br />Total 484<br /><br />下载文件,观察bcd[12]和bcd[13],果然有我们对应的初值了...<br />兴奋之余,默然回首,发现学了n多东东...<br />gcc的编译参数和Makefile、 arm汇编语言、ld script、obj定位.....<br /><br /><br />花絮<br /><br />回头看WinARM的example下所有ld script文件都存在类似的问题...<br />再想想,如果没有ld script文件,又或startup.S以库形式提供,有没有其它<br />简便的解决办法呢?有!传说中的秘技:“不要给定义在程序函数外的<br />全局变量赋初值,而是用单独的初始化函数来在程序内部赋值...”<br />我想当初第一个说这话的人一定有他的道理,但经过这番折腾后,我<br />明白了其中大部分的含意,我的境界也许没他高,但对这个问题的看法,<br />我相信我们的境界大致是一样的...<br /><br />感谢大家一起分享...<br /><br />2007-12-5<br />wolver@21com.com<br /> |
|