×
单片机 > 单片机程序设计 > 详情

嵌入式Linux学习笔记之——代码重定位002_链接脚本的引入

发布时间:2024-05-20 发布时间:
|

① NOR启动:

② nand 启动:

上次讲到的g_char不能按照程序正确输出的原因是nor启动的时候g_char在nor flash中,其不可写的特性决定了输出结果。


现在能否修改Makefile让nor启动时讲代码拷贝到SDRAM中,这样就可以实现全局变量的可读可写了。

现在想在nor flash启动的时候将其中的代码段拷贝至SDRAM中0地址起始的空间,将全局变量g_char拷贝至0x30000000起始的空间。

编译之后发现.bin文件变成了800M,805306369-->0x30000001,符合程序中的g_char所占1字节的设置。


但是nor flash一共才2M,不可实现。


解决方法有两种:


第1种: 只是重定位了全局变量


① 在,bin文件中让g_char和代码段靠在一起


② 烧写至nor flash中


③ 运行时让前面的代码段将g_char复制到SDRAM起始的0x30000000地址空间中,即重定位。


第2种:重定位了整个代码+全局变量


让代码段和g_char之间没有那么大的空洞。

我们怎么将位于0x30000000的数据data段跟位于0地址的代码段拼在一起呢?


因为这些复杂的操作通过简单的参数设置已经无法实现,因此需要引入链接脚本来完成相应的操作。


链接脚本:

通过链接脚本的方式实现:

SECTIONS {

.test 0 : { *(.test) }

.rodata : { *(.rodata) }

.data 0x30000000 : AT(0X800) { *(.data) }

.bss : { *(.bss) *(.COMMON)}

}


编译

烧写至开发板的nor flash之后发现输出是乱码,烧写至nand flash之后依然是乱码。


在链接脚本中,我们将data段定位到了0x800(2048)的位置上,但是在main函数中访问g_char时的地址是0x30000000。

下面查看main函数的反汇编码:

从反汇编码可以看出,寄存器r3确实在0x30000000地址中得到了其中的值,但是我们在程序中并没有将g_char的值放到0x3000000的地址空间去,因此缺少了重定位的一个步骤。

修改代码:现在需要将g_char的值从0x800的地方复制到0x30000000的地址空间去。


在start.S文件中加入重定位的代码即可:


/* 重定位data段 */

mov r1, #0x800

mov r0, [r1]

mov r1, #0x30000000

str r0, [r1]

之后编译代码下载至开发板,发现还是乱码。。。“RP值低预警”。。。


查找问题后发现,原因竟然是。。。在start.S中没有初始化SDRAM!!

之后再次编译代码下载至开发板(注意设置开发板启动模式为nor启动):

成功!!


接下来的问题是,刚刚的重定位代码并不通用。在重定位的时候我们是在知道原地址和重定位地址的情况下从0x800仅仅复制了一个字节到0x30000000地址中去的,如果我们要复制多个字节又该怎么做呢?


首先修改链接脚本:


SECTIONS {

.text 0 : { *(.text) }

.rodata : { *(.rodata) }

.data 0x30000000 : AT(0X800)

{

data_load_addr = LOADADDR(.data);

data_start = . ;

*(.data)

data_end = . ;

}

.bss : { *(.bss) *(.COMMON)}

}

注意:链接脚本中的“.”代表当前地址,这里的当前地址指的是前面各种段地址的顺延。

然后修改start.S文件:


/* 重定位data段 */

ldr r1, =data_load_addr /* data段在bin文件中的地址,加载地址 */、

ldr r2, =data_start /* data段的重定位(从nor或者nand flash中定位至SDRAM中)开始地址,运行时的地址 */

ldr r3, =data_end /* data段重定位的结束地址 */


/* 接下来将r1所指地址中的值拷贝至r2所指的地址空间 */

cpy:

ldrb r4, [r1] //从r1地址处拷贝一个字节到r4

strb r4, [r2]

add r1, r1, #1

add r2, r2, #1

cmp r2, r3

bne cpy

在main函数中加入一个全局变量:


char g_char = 'A';

char g_char3 = 'a';


const char g_char2 = 'B';

int g_A = 0;

int g_B;


int main(void)

{

uart0_init();


while(1)

{

putchar(g_char);

g_char++; /* nor启动时,此代码无效 */

putchar(g_char3);

g_char3++; /* nor启动时,此代码无效 */

delay(100000);

}


编译烧写:

成功。


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
单片机制作超级流水灯