jz2440裸机开发与分析:S3c2440代码重定位详解2---链接脚本的引入与简单测试

前面程序运行,发现从Nand Flash启动和从Nor Flash启动表现是不一样的。

设置成Nand Flash启动没有问题 显示ABCDE…

设置成NOor Flash启动则显示AAA…

这是什么原因呢?

Nor启动

在这里插入图片描述
Nor Flash就被认为是0地址,g_Char被放在0x700后面。CPU上电后从0地址开始执行,它能读取Nor Flash上的代码,打印出A,当进行g_Char++的时候,写操作操作无效,下次读取的数据仍然是A。

NAND启动

在这里插入图片描述
上电后,Nand Flash前4K代码就被自动的复制到SRAM里面,SRAM是CPU认为的0地址。CPU上电后从0地址开始执行,它读取SRAM上的代码,并g_Char++修改变量,下次读取的数据就依次增加了

为了解决Nor Flash里面的变量不能写的问题,我们把变量所在的数据段放在SDRAM里面,看行不行。
修改Makefile 指定数据段为0x30000000 -Tdata 0x30000000:

 arm-linux-ld -Ttext 0 -Tdata 0x30000000  start.o led.o uart.o init.o main.o -o sdram.elf

这样的话编译出来的bin文件 从0地址 到 0x30000000地址 文件大小有700多MB,代码段和数据段直接有间隔,称之为黑洞
在这里插入图片描述
解决黑洞有两个办法:
第一个方法:
①把数据段的g_Char和代码段靠在一起
②烧写在Nor Flash上面
③运行时把g_char(全局变量)复制到SDRAM,即0x3000000位置(重定位);
第一种办法如何实现
修改Makefile的代码段地址,使用链接脚本sdram.lds指定。

注释:#arm-linux-ld -Ttext 0 -Tdata 0x30000000  start.o led.o uart.o init.o main.o -o sdram.elf
修改为: arm-linux-ld -T sdram.lds start.o led.o uart.o init.o main.o -o sdram.elf

链接脚本的语法:

SECTIONS {
...
secname start BLOCK(align) (NOLOAD) : AT ( ldadr )
  { contents } >region :phdr =fill
...
}

我们需要依次排列 代码段、只读数据段、数据段、.bss段、.common。

其中数据段放在0x800,但运行时在0x3000000:

SECTIONS {
   .text   0  : { *(.text) }//所有文件的.text
   .rodata  : { *(.rodata) } //只读数据段
   .data 0x30000000 : AT(0x800) { *(.data) } //放在0x700,但运行时在0x3000000
   .bss  : { *(.bss) *(.COMMON) }//所有文件的bss段,所有文件的.COMMON段
}

重新编译后烧写bin文件,发现启动后显示乱码。原因是我们从0x30000000处获取g_Char,但在这之前,并没有在0x30000000处准备好数据。因此需要重定位数据段,将0x700的数据移动到0x30000000处,在start.S加入:

 bl sdram_init

 /* 重定位data段 */
 mov r1, #0x700 
 ldr r0, [r1]
 mov r1, #0x30000000
 str r0, [r1]

 bl main

上面的这种方法,只能复制0x800处的一位数据,不太通用,下面写一个更加通用的复制方法:
链接脚本修改如下:

SECTIONS {
   .text   0  : { *(.text) }
   .rodata  : { *(.rodata) }
   .data 0x30000000 : AT(0x700) 
   { 
      data_load_addr = LOADADDR(.data);
      data_start = . ;//等于当前位置
      *(.data)  //等于数据段的大小
      data_end = . ;//等于当前位置
   }
   .bss  : { *(.bss) *(.COMMON) }
}

修改start.S

    bl sdram_init   

    /* 重定位data段 */
    ldr r1, =data_load_addr  /* data段在bin文件中的地址, 加载地址 */
    ldr r2, =data_start      /* data段在重定位地址, 运行时的地址 */
    ldr r3, =data_end        /* data段结束地址 */

cpy:
    ldrb r4, [r1] //从r1读到r4
    strb r4, [r2] //r4存放到r2
    add r1, r1, #1 //r1+1
    add r2, r2, #1 //r2+1
    cmp r2, r3 //r2 r3比较
    bne cpy //如果不等则继续拷贝

    bl main

第二个方法
①让文件直接从0x30000000开始,全局变量在0x3……;
②烧写Nor Flash上 0地址处;
③运行会把整个代码段数据段(整个程序)从0地址复制到SDRAM的0x30000000(重定位);

这两个方法的区别是前者只重定位了数据段,后者重定位了数据段和代码段。

参考文档
[http://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_mono/ld.html Using LD, the GNU linker]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值