关于链接脚本和汇编导致的数据段初始化错误的问题



链接脚本分别如下:

  • 有错误的类型
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 = . );
  } >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 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 中搬运为什么就会运行出错?
    • 解决思路:
        1. 确认链接器会把data 段的数据放在哪里?
        2. 真正代码跑起来的时候,mcu 会去哪里取代码?这个是由谁决定的?连接器还是编译器?
        3. 目前问题的逻辑解释
      • 对于问题1:一般情况下不加AT 属性就会编译在哪个内存空间,就存放在哪个内存空间。
      • 对于问题2:真正代码跑起来的时候,mcu 会去ram 中取data段,这个是由连接器决定的(连接器会 为每个符号分配地址?),因为两个lds 文件都是把data 段放在了ram 的区域。
      • 原因解释,对应这个问题,有以下几点
          1. 符号的定义,结合上面的lds 源码,_data_lma 永远在 flash地址,_data永远在ram地址
          2. 汇编代码:结合汇编,永远是从_data_lma 搬运 到data 地址处
          3. 链接脚本:第一种错误的链接脚本,没有加At>flash,data 段存放和使用地址都在 ram区域(data 地址开始),这个时候汇编代码还将_data_lma_ 的数据搬运到 data 处就会导致将错误的数据覆盖了正确的数据。
          4. 第二种正确的链接脚本,加个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的区别
posted @ 2024-04-13 14:45  Satellite98  阅读(128)  评论(0)    收藏  举报