第一个链接脚本存在data 段初始化失败的问题,第二个link 脚本增加了At>flash就可以正常的运行了,是为什么?如果只是链接错误的话,那么汇编从ram 向同地址的ram 中搬运为什么就会运行出错?
链接脚本分别如下:
- 有错误的类型
MEMORY
{
flash (rxai!w) : ORIGIN = 0x20000000, LENGTH = 256k
ram (wxa!ri) : ORIGIN = 0x20040000, LENGTH = 384k
}
.lalign :
{
. = ALIGN(4);
PROVIDE( _data_lma = . );
} > flash
.dalign :
{
. = ALIGN(4);
PROVIDE( _data = . );
} > ram
.data :
{
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} > ram
- 没有错误的类型
.lalign :
{
. = ALIGN(4);
PROVIDE( _data_lma = . );
} >rom AT>flash :flash
.dalign :
{
. = ALIGN(4);
PROVIDE( _data = . );
} >ram AT>flash :ram_init
.data :
{
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} >ram AT>flash :ram_init
- 汇编语言搬运data段的操作
la a0, _data_lma
la a1, _data
la a2, _edata
bgeu a1, a2, 2f
1:
lw t0, (a0)
sw t0, (a1)
addi a0, a0, 4
addi a1, a1, 4
bltu a1, a2, 1b
2:
分析如下:
-
原来存在的问题和分析思路
- 问题:上诉所说第一个链接脚本存在data 段初始化失败的问题,第二个link 脚本增加了At>flash就可以正常的运行了,是为什么?如果只是链接错误的话,那么汇编从ram 向同地址的ram 中搬运为什么就会运行出错?
- 解决思路:
-
- 确认链接器会把data 段的数据放在哪里?
- 真正代码跑起来的时候,mcu 会去哪里取代码?这个是由谁决定的?连接器还是编译器?
- 目前问题的逻辑解释
- 对于问题1:一般情况下不加AT 属性就会编译在哪个内存空间,就存放在哪个内存空间。
- 对于问题2:真正代码跑起来的时候,mcu 会去ram 中取data段,这个是由连接器决定的(连接器会 为每个符号分配地址?),因为两个lds 文件都是把data 段放在了ram 的区域。
- 原因解释,对应这个问题,有以下几点
-
- 符号的定义,结合上面的lds 源码,_data_lma 永远在 flash地址,_data永远在ram地址
- 汇编代码:结合汇编,永远是从_data_lma 搬运 到data 地址处
- 链接脚本:第一种错误的链接脚本,没有加
At>flash
,data 段存放和使用地址都在 ram区域(data 地址开始),这个时候汇编代码还将_data_lma_ 的数据搬运到 data 处就会导致将错误的数据覆盖了正确的数据。 - 第二种正确的链接脚本,加个
At>flash
,data 段存放地址在_data_lma_ 开始的地址和使用地址在_data_开始的地址,这个时候利用汇编代码将_data_lma_ 的数据搬运到 data 处,就是将数据搬运到了改在的位置,程序能正常运行。
-
-
-
对于符号的数值定义很重要
MEMORY { flash (rxai!w) : ORIGIN = 0x20000000, LENGTH = 256k ram (wxa!ri) : ORIGIN = 0x20040000, LENGTH = 384k } .lalign : { . = ALIGN(4); PROVIDE( _data_lma = . ); /* 这里的_data_lma 可以看到就是flash 中的地址 */ } > flash .dalign : { . = ALIGN(4); PROVIDE( _data = . ); /* 这里的 _data 地址是ram中的地址*/ } > ram
-
由于链接的时候选择了将.data 段编译到了ram 中,所以实际的时候取数会去ram的地址取值。
.data : { 、、、、、、 } >ram
待后续补充
- 用readelf 查看两种编译方式编译出来的section的区别