在移植Contiki的过程中,我们发现Contiki的进程无法正常启动,而后又发现所有已初始化的变量中的数据全都错位了,集体向后偏移了8个字节。因为在PC机中初始化程序的DATA段与BSS段的任务都是交由C库或是别的库函数来代劳的,所以从前从没遇到过这种问题。经过一天的调试使用readelf与IDA反汇编查看程序反汇编代码后发现原来是ld脚本中少考虑的一个段,直接导致初始化DATA段时从错误的地址拷贝数据,具体如下:
原先的LD脚本(部分):
MEMORY
{
CODE (rx) : ORIGIN = 0x8000000, LENGTH = 128K
DATA (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
}
/* Section Definitions */
SECTIONS
{
/* Make sure the vector table is at address 0 */
.vectrom :
{
KEEP(*(.isr_vector))
} >CODE =0
.text :
{
KEEP(*(.init))
*(.text .text.*)
KEEP(*(.fini))
} >CODE =0
. = ALIGN(4);
.rodata :
{
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
} >CODE
_etext = . ;
PROVIDE (etext = .);
.data :
{
_data = . ;
*(.data)
_edata = . ;
PROVIDE (edata = .);
} >DATA AT >CODE
. = ALIGN(4);
…
}
直接认为在rodata段后直接就跟着data段的初始化数据。注意,这里不能将_etext在data段中赋值,那样的话将使_etext指向ram区域。直接查看使用objcopy生成的.bin文件后发现_etext指向的区域与实际data区有8字节的偏移。进而使用readelf工具查看编译出的elf文件具有的段,发现还有一个.ARM.exidx段(位于rom中)没有考虑,其大小正好是8个字节。加上.ARM.exidx的定义后,data段初始化正常,Contiki进程启动成功。
/* ADD BY Kauffman Sun */
.ARM.exidx :
{
*(.ARM.exidx)
} >CODE
/* ADD END */