韦东山嵌入式第一期学习笔记DAY_11——13_5_代码重定位与位置无关码(绝对地址与相对地址)

作者:GWD 时间:2019.7.12

一、课程内容:
摘要:本节课讲解了整体的代码重定位与位置无关码,其中重点和难点是位置无关码。
实现第二种方法的代码重定位:在第二节课讲的第一个代码实现的功能,是分段重定位的,本节讲的是整体形式的链接脚本。
1、问:位置无关码怎么理解?(很关键,一开始没理解!!!!)
答:位置无关码说白了就是相对跳转指令与绝对跳转指令的关系。譬如bl 0x30000478的意思并不是跳到0x30000478,实际意义是由当前的PC值跳到一个偏移地址。若当前指令PC值是0,则跳到0x00000478了。在程序中写这个值只是为了方便看代码。
注:在汇编文件中B/BL只是方便查看作用,不是跳到这个地址。
例:
在这里插入图片描述
这里bl 300001d0的意思相当于一个“标号”只是方便程序员到0x300001d0这个“标号”位置去查看代码,真实情况中这个代码在哪个位置中运行是与PC指针的位置有关系的。理解这点很重要,我们看下一点就知道这个知识点的重要性了。
2、问、1与2的汇编代码一样但是区别在哪里?
在这里插入图片描述
答:首先看实验现象,当烧写1语句时,串口打印的速度明显没有语句2速度快,由此可知代码1的时候程序还是在nor中运行。
其次分析代码:语句1就是相对跳转指令,此时PC指针并不是真正的0x300005b0只相当于标号,代码只是偏移了0x5b0还在nor中运行,执行语句2是绝对跳转指令,是真的把0x30000640给了PC指针,程序在sdram中运行了。
3、问:那么什么时候用相对跳转(位置无关),什么时候用绝对跳转(位置相关)呢?
答:
在这里插入图片描述
这张图展示了启动的流程,bin文件包含段和地址的信息,烧写进nor_flash中,在nor中运行,然后重定位到SDRAM,所以可知,在重定位之前的代码应该是位置无关的(相对跳转在nor中执行),重定位之后的代码要位置相关(在SDRAM中运行);
4、问:说了这么多怎么写位置无关的程序呢?
答:
a. 调用程序时使用B/BL相对跳转指令
b. 重定位之前, 不可使用绝对地址,比如:
不可访问全局变量/静态变量
不可访问有初始值的数组(因为初始值放在rodata里,使用绝对地址来访问)
c. 重定位之后, 使用绝对跳转命令跳到Runtime Addr,比如: ldr pc, =main

5、问:相对地址与绝对地址怎么理解区分呢?
答:相对地址就是跳转,所有的跳转都是以当前为基准的。相对于当前的地址;绝对地址是直接去了。绝对唯一的地址,在汇编的过程中,会根据跳转的距离自动形成。相对地址的范围一般比较短。在中国说故宫大家都知道,要是在美国说故宫就要说中国北京故宫。所以要是需要绝对地址的时候为了保险不让编译器自己做主就要用ldr pc,=XXX避免程序没跳出nor。
二、代码编写过程
1、写一个新的链接脚本,首先参考u-boot

在这里插入图片描述
在这里插入图片描述
这种整体的链接脚本,要比之前的分体的好,用的也多,分体的适合单片机,单片机内部有可以运行程序的flash,这样可以节省内存,但是对于嵌入式系统内存很庞大,不用省这一点内存。还有一个原因是,JTAG一般只支持这种整体的链接脚本

2、在START.S中修改重定位前后的代码,重定位前用位置无关码(相对地址),重定位后用绝对跳转指令(绝对地址)
在这里插入图片描述
三、代码
链接脚本

SECTIONS
{ 
    . = 0x30000000;
	. = ALIGN(4);
  .text		: 
  	{ 
		*(.text)
	}
  . = ALIGN(4);
  .rodata	: { *(.rodata) }
  . = ALIGN(4);
  .data	 :
  { 
  	*(.data)
  }
  . = ALIGN(4);
  bss_start = .;
  .bss	: { *(.bss) *(.COMMON) }
  end =.;
  }


START.S

.text
.global _start

_start:

	/* 关闭看门狗 */
	ldr r0, =0x53000000
	ldr r1, =0
	str r1, [r0]

	/* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */
	/* LOCKTIME(0x4C000000) = 0xFFFFFFFF */
	ldr r0, =0x4C000000
	ldr r1, =0xFFFFFFFF
	str r1, [r0]

	/* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8  */
	ldr r0, =0x4C000014
	ldr r1, =0x5
	str r1, [r0]

	/* 设置CPU工作于异步模式 */
	mrc p15,0,r0,c1,c0,0
	orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA
	mcr p15,0,r0,c1,c0,0

	/* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0) 
	 *  m = MDIV+8 = 92+8=100
	 *  p = PDIV+2 = 1+2 = 3
	 *  s = SDIV = 1
	 *  FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M
	 */
	ldr r0, =0x4C000004
	ldr r1, =(92<<12)|(1<<4)|(1<<0)
	str r1, [r0]

	/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定
	 * 然后CPU工作于新的频率FCLK
	 */
	
	/* 设置内存: sp 栈 */
	/* 分辨是nor/nand启动
	 * 写0到0地址, 再读出来
	 * 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
	 * 否则就是nor启动
	 */
	mov r1, #0
	ldr r0, [r1] /* 读出原来的值备份 */
	str r1, [r1] /* 0->[0] */ 
	ldr r2, [r1] /* r2=[0] */
	cmp r1, r2   /* r1==r2? 如果相等表示是NAND启动 */
	ldr sp, =0x40000000+4096 /* 先假设是nor启动 */
	moveq sp, #4096  /* nand启动 */
	streq r0, [r1]   /* 恢复原来的值 */

	bl sdram_init
	
	/*重定位data段*/
	mov r1,#0
	ldr r2, = _start
	ldr r3, = bss_start
cpy:
	ldr r4,[r1]
	str r4,[r2]
	add r1,r1,#4
	add r2,r2,#4
	cmp r2,r3
	bne cpy
	
	/*清除bss段*/
	ldr r1,= bss_start
	ldr r2,= end
	mov r3,#0
clean:
	str r3,[r1]
	add r1,r1,#4
	cmp r1,r2
	bne clean

	//bl main
	ldr pc,=main
halt:
	b halt


  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值