打印

ALIGN的烦恼和传说中的秘技

[复制链接]
4160|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wolver|  楼主 | 2007-12-5 23:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
TI, se, TE, ST, IO
ALIGN的烦恼和传说中的秘技

风起

一个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以库形式提供,有没有其它
简便的解决办法呢?有!传说中的秘技:“不要给定义在程序函数外的
全局变量赋初值,而是用单独的初始化函数来在程序内部赋值...”
我想当初第一个说这话的人一定有他的道理,但经过这番折腾后,我
明白了其中大部分的含意,我的境界也许没他高,但对这个问题的看法,
我相信我们的境界大致是一样的...

感谢大家一起分享...

2007-12-5
wolver@21com.com

相关帖子

沙发
twentyone| | 2007-12-6 04:50 | 只看该作者

顶一个。。。

使用特权

评论回复
板凳
mytempid| | 2007-12-6 12:03 | 只看该作者

虽然不用adi的arm,但是非常佩服楼主

使用特权

评论回复
地板
阿南| | 2007-12-6 16:12 | 只看该作者

佩服,加酷

使用特权

评论回复
5
1dqmoon| | 2007-12-6 19:41 | 只看该作者

gcc在某些处理器上存在很多问题

我用的winavr,就出现过,当然不是对齐的问题

使用特权

评论回复
6
dragonyu| | 2007-12-7 22:40 | 只看该作者

佩服你的细节精神!!!

嵌入式开发中的字节对齐确实要小心,曾经遇到过面向mips的SDE工具链,定义某个全局变量为非0,结果make时候link错误。当时自己也没有深入研究。只是突然发现有时候编程规范可以帮我们规避和掩盖很多问题,如果定义的数据结构和变量注意4字节对齐filled,或者明确要求全局变量的统一初始化,可能我们就发现不到这些细节问题了,呵呵

使用特权

评论回复
7
pppking| | 2007-12-9 18:03 | 只看该作者

非常欣赏楼主的钻研精研,更欣赏楼主的分享精神

你为嵌入式的发展添砖加瓦了!

使用特权

评论回复
8
tombtomb| | 2007-12-9 22:37 | 只看该作者

帮顶--分享精神dn

与大家共享经验,可见楼主的善良与胸怀!

使用特权

评论回复
9
high| | 2007-12-10 00:58 | 只看该作者

碰到这样说法.

此(特定)编译器有时候处理ALIGN指令会出问题,在cache模式时候有时会有问题.

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

31

主题

401

帖子

0

粉丝