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

近期将之前学习嵌入式的笔记进行了整理,内容涉及到基础知识以及嵌入式开发过程中比较重要的模块开发知识,文章中有我在学习过程中的标注,非常详细,可以让入门学习事半功倍。

获取链接    提取码:qk7t 

 

【正文】

① 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);
	}

编译烧写:

成功。

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值