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