对链接地址的理解

本文解释了在编写链接器脚本时设置代码段起始链接地址的重要性,并通过实例说明了链接地址如何帮助实现ARM处理器上的代码执行,尤其是在从NAND闪存加载到内存的过程中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  

  当我们写链接器脚本的时候,我们会设置代码段的起始链接地址为0x30008000(S3C2440)。如果对链接地址理解错误的话,可能会出现像我这样的问题。

  Q:gboot的链接器脚本里写的其实链接地址是内存中的0x30008000,再用交叉工具反汇编得到的start.S前几行代码地址都变成了0x30008000+,不太对啊。ARM启动流程里面讲处理器将NAND中的代码复制了4K到垫脚石中,垫脚石的地址是0x0,也正是因为这样,我们设置的异常向量表才有意义,处理器才能准确的找到处理异常的标号。但是把链接地址改成了0x30008000还怎么找?

  A:首先要理解链接地址。我认为,链接地址就是为程序假想了一个起点,之后的代码都是在这个假想的起点基础上展开的。我们只有根据这个链接地址,才能找到后续的一些指令并执行。但是这个链接地址不是实际的指令的地址,我们先对gboot.elf进行反汇编看看

复制代码
30008000 <_start>:
30008000:    ea000014     b    30008058 <reset>
30008004:    e59ff014     ldr    pc, [pc, #20]    ; 30008020 <_undefined_instruction>
30008008:    e59ff014     ldr    pc, [pc, #20]    ; 30008024 <_software_intrrupt>
3000800c:    e59ff014     ldr    pc, [pc, #20]    ; 30008028 <_prefetch_abort>
30008010:    e59ff014     ldr    pc, [pc, #20]    ; 3000802c <_data_abort>
30008014:    e59ff014     ldr    pc, [pc, #20]    ; 30008030 <_not_used>
30008018:    e59ff014     ldr    pc, [pc, #20]    ; 30008034 <_irq>
3000801c:    e59ff014     ldr    pc, [pc, #20]    ; 30008038 <_fiq>
复制代码

用b reset举例,虽然reset标号的地址已经到了0x30008000,但是我们的代码此时实际上是在垫脚石中运行的,也就是说PC指针还是指在0x0的位置。这样0x0和0x30008000就形成了一个映射的关系,即0x4相当于0x30008004,0x8相当于0x30008008......,都是因为我们将链接起始地址设成了0x30008000,这也就是我们所说的相对跳转。

  Q:为什么链接起始地址要写成0x30008000?

  A:照理说这个地址是随意的,只要在S3C2440的寻址空间内都可以。但是后期我们要执行C语言程序,而对堆栈等的初始化都是对SDRAM进行的,即在0x30000000之后的64M空间中。所以为了C语言能够成功运行,直接将代码的链接地址设到内存中,这样方面之后的绝对跳转,即

ldr pc, =main



一定要注意寄存器可用的位数,若少于32位的,必须用移位来赋值,或者定义时就确定位数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值