欢迎光临散文网 会员登陆 & 注册

13.2代码重定位_链接脚本的引入与简单测试

2020-08-20 19:17 作者:韦东山  | 我要投稿

前面程序运行,发现从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启动:

Chapter13 lesson2 002.jpg

上电后,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,代码段和数据段直接有间隔,称之为黑洞。

Chapter13 lesson2 003.jpg

解决黑洞有两个办法:

第一个方法

  1. 把数据段的g_Char和代码段靠在一起;

  2. 烧写在Nor Flash上面;

  3. 运行时把g_char(全局变量)复制到SDRAM,即0x3000000位置(重定位);

第二个方法

  1. 让文件直接从0x30000000开始,全局变量在0x3......;

  2. 烧写Nor Flash上 0地址处;

  3. 运行会把整个代码段数据段(整个程序)从0地址复制到SDRAM的0x30000000(重定位);

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

第一种办法如何实现 修改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

链接脚本的语法: 

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

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

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

上面的这种方法,只能复制0x700处的一位数据,不太通用,下面写一个更加通用的复制方法:

链接脚本修改如下:

修改start.S 


13.2代码重定位_链接脚本的引入与简单测试的评论 (共 条)

分享到微博请遵守国家法律