链接地址和运行地址.docx
《链接地址和运行地址.docx》由会员分享,可在线阅读,更多相关《链接地址和运行地址.docx(11页珍藏版)》请在冰豆网上搜索。
链接地址和运行地址
1、运行地址<--->链接地址:
他们两个是等价的,只是两种不同的说法。
2、加载地址<--->存储地址:
他们两个是等价的,也是两种不同的说法。
运行地址:
程序在SRAM、SDRAM中执行时的地址。
就是执行这条指令时,PC应该等于这个地址,换句话说,PC等于这个地址时,这条指令应该保存在这个地址内。
加载地址:
程序保存在Nandflash中的地址。
位置无关码:
B、BL、MOV都是位置位置无关码。
位置有关码:
LDRPC,=LABEL等类似的代码都是位置有关码。
下面我们来看看一个Makefile文件
sdram.bin:
head.S leds.c
arm-linux-gcc -c-ohead.ohead.S
arm-linux-gcc-c-oleds.oleds.c
arm-linux-ld-Ttext0x30000000head.oleds.o-osdram_elf
arm-linux-objcopy-Obinary-Ssdram_elfsdram.bin
arm-linux-objdump-D-marm sdram_elf>sdram.dis
clean:
rm-f sdram.dissdram.binsdram_elf*.o
我们可以看到sdram_elf的代码段是从0x30000000地址开始存放,这个地址我们称之为运行地址。
为什么从这个地址开始存放,因为SDRAM的起始地址是0x30000000.
下面来看看一个启动代码@*************************************************************************
@File:
head.S
@功能:
设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行
@*************************************************************************
.equ MEM_CTL_BASE, 0x48000000
.equ SDRAM_BASE, 0x30000000
.text
.global_start
_start:
bl disable_watch_dog @关闭WATCHDOG,否则CPU会不断重启
bl memsetup @设置存储控制器
bl copy_steppingstone_to_sdram @复制代码到SDRAM中
ldrpc,=on_sdram @跳到SDRAM中继续执行
on_sdram:
ldrsp,=0x34000000 @设置堆栈
bl main
halt_loop:
b halt_loop
disable_watch_dog:
@往WATCHDOG寄存器写0即可
movr1, #0x53000000
movr2, #0x0
strr2, [r1]
movpc, lr @返回
copy_steppingstone_to_sdram:
@将Steppingstone的4K数据全部复制到SDRAM中去
@Steppingstone起始地址为0x00000000,SDRAM中起始地址为0x30000000
movr1,#0
ldrr2,=SDRAM_BASE
movr3,#4*1024
1:
ldrr4,[r1],#4 @从Steppingstone读取4字节的数据,并让源地址加4
strr4,[r2],#4 @将此4字节的数据复制到SDRAM中,并让目地地址加4
cmpr1,r3 @判断是否完成:
源地址等于Steppingstone的未地址?
bne1b @若没有复制完,继续
movpc, lr @返回
memsetup:
@设置存储控制器以便使用SDRAM等外设
movr1, #MEM_CTL_BASE @存储控制器的13个寄存器的开始地址
adrl r2,mem_cfg_val @这13个值的起始存储地址
addr3, r1,#52 @13*4=54
1:
ldrr4, [r2],#4 @读取设置值,并让r2加4
strr4, [r1],#4 @将此值写入寄存器,并让r1加4
cmpr1, r3 @判断是否设置完所有13个寄存器
bne1b @若没有写成,继续
movpc, lr @返回
.align4
mem_cfg_val:
@存储控制器13个寄存器的设置值
.long 0x22011110 @BWSCON
.long 0x00000700 @BANKCON0
.long 0x00000700 @BANKCON1
.long 0x00000700 @BANKCON2
.long 0x00000700 @BANKCON3
.long 0x00000700 @BANKCON4
.long 0x00000700 @BANKCON5
.long 0x00018005 @BANKCON6
.long 0x00018005 @BANKCON7
.long 0x008C07A3 @REFRESH
.long 0x000000B1 @BANKSIZE
.long 0x00000030 @MRSRB6
.long 0x00000030 @MRSRB7
下面来看看反汇编代码
sdram_elf:
fileformatelf32-littlearm
Disassemblyofsection.text:
30000000<_start>:
30000000:
eb000005 bl 3000001c
30000004:
eb000010 bl 3000004c
30000008:
eb000007 bl 3000002c
3000000c:
e59ff090 ldr pc,[pc,#144] ;300000a4
30000010:
30000010:
e3a0d30d mov sp,#872415232 ;0x34000000
30000014:
eb000033 bl 300000e8
30000018:
30000018:
eafffffe b 30000018
3000001c:
3000001c:
e3a01453 mov r1,#1392508928 ;0x53000000
30000020:
e3a02000 mov r2,#0
30000024:
e5812000 str r2,[r1]
30000028:
e1a0f00e mov pc,lr
3000002c:
3000002c:
e3a01000 mov r1,#0
30000030:
e3a02203 mov r2,#805306368 ;0x30000000
30000034:
e3a03a01 mov r3,#4096 ;0x1000
30000038:
e4914004 ldr r4,[r1],#4
3000003c:
e4824004 str r4,[r2],#4
30000040:
e1510003 cmp r1,r3
30000044:
1afffffb bne 30000038
30000048:
e1a0f00e mov pc,lr
3000004c:
3000004c:
e3a01312 mov r1,#1207959552 ;0x48000000
30000050:
e28f2018 add r2,pc,#24
30000054:
e1a00000 nop ;(movr0,r0)
30000058:
e2813034 add r3,r1,#52 ;0x34
3000005c:
e4924004 ldr r4,[r2],#4
30000060:
e4814004 str r4,[r1],#4
30000064:
e1510003 cmp r1,r3
30000068:
1afffffb bne 3000005c
3000006c:
e1a0f00e mov pc,lr
30000070:
30000070:
22011110 andcs r1,r1,#4
30000074:
00000700 andeq r0,r0,r0,lsl#14
30000078:
00000700 andeq r0,r0,r0,lsl#14
3000007c:
00000700 andeq r0,r0,r0,lsl#14
30000080:
00000700 andeq r0,r0,r0,lsl#14
30000084:
00000700 andeq r0,r0,r0,lsl#14
30000088:
00000700 andeq r0,r0,r0,lsl#14
3000008c:
00018005 andeq r8,r1,r5
30000090:
00018005 andeq r8,r1,r5
30000094:
008c07a3 addeq r0,ip,r3,lsr#15
30000098:
000000b1 strheq r0,[r0],-r1
3000009c:
00000030 andeq r0,r0,r0,lsrr0
300000a0:
00000030 andeq r0,r0,r0,lsrr0
300000a4:
30000010 andcc r0,r0,r0,lslr0
300000a8:
e1a00000 nop ;(movr0,r0)
300000ac:
e1a00000 nop ;(movr0,r0)
300000b0:
300000b0:
e52db004 push {fp} ;(strfp,[sp,#-4]!
)
300000b4:
e28db000 add fp,sp,#0
300000b8:
e24dd00c sub sp,sp,#12
300000bc:
e50b0008 str r0,[fp,#-8]
300000c0:
ea000002 b 300000d0
300000c4:
e51b3008 ldr r3,[fp,#-8]
300000c8:
e2433001 sub r3,r3,#1
300000cc:
e50b3008 str r3,[fp,#-8]
300000d0:
e51b3008 ldr r3,[fp,#-8]
300000d4:
e3530000 cmp r3,#0
300000d8:
1afffff9 bne 300000c4
300000dc:
e28bd000 add sp,fp,#0
300000e0:
e8bd0800 pop {fp}
300000e4:
e12fff1e bx lr
300000e8:
300000e8:
e92d4800 push {fp,lr}
300000ec:
e28db004 add fp,sp,#4
300000f0:
e24dd008 sub sp,sp,#8
300000f4:
e3a03000 mov r3,#0
300000f8:
e50b3008 str r3,[fp,#-8]
300000fc:
e59f3030 ldr r3,[pc,#48] ;30000134
30000100:
e3a02b55 mov r2,#87040 ;0x15400
30000104:
e5832000 str r2,[r3]
30000108:
e59f0028 ldr r0,[pc,#40] ;30000138
3000010c:
ebffffe7 bl 300000b0
30000110:
e59f3024 ldr r3,[pc,#36] ;3000013c
30000114:
e3a02000 mov r2,#0
30000118:
e5832000 str r2,[r3]
3000011c:
e59f0014 ldr r0,[pc,#20] ;30000138
30000120:
ebffffe2 bl 300000b0
30000124:
e59f3010 ldr r3,[pc,#16] ;3000013c
30000128:
e3a02e1e mov r2,#480 ;0x1e0
3000012c:
e5832000 str r2,[r3]
30000130:
eafffff4 b 30000108
30000134:
56000010 undefinedinstruction0x56000010
30000138:
00007530 andeq r7,r0,r0,lsrr5
3000013c:
56000014 undefinedinstruction0x56000014
Disassemblyofsection.ARM.attributes:
00000000<.ARM.attributes>:
0:
00002541 andeq r2,r0,r1,asr#10
4:
61656100 cmnvs r5,r0,lsl#2
8:
01006962 tsteq r0,r2,ror#18
c:
0000001b andeq r0,r0,fp,lslr0
10:
00543405 subseq r3,r4,r5,lsl#8
14:
01080206 tsteq r8,r6,lsl#4
18:
04120109 ldreq r0,[r2],#-265 ;0x109
1c:
01150114 tsteq r5,r4,lslr1
20:
01180317 tsteq r8,r7,lslr3
24:
Address0x00000024isoutofbounds.
Disassemblyofsection.comment:
00000000<.comment>:
0:
3a434347 bcc 10d0d24
4:
74632820 strbtvc r2,[r3],#-2080 ;0x820
8:
312d676e teqcc sp,lr,ror#14
c:
312e362e teqcc lr,lr,lsr#12
10:
2e342029 cdpcs 0,3,cr2,cr4,cr9,{1}
14:
00332e34 eorseq r2,r3,r4,lsrlr
当我们从Nandflash启动时,硬件会自动将Nandflash前4kB代码拷贝到片内SRAM中,然后CPU从SRAM的0x00000000地址处开始执行程序。
在这里我想纠正一个错误的观点,网上很多人都说是CPU自动把Nandflash前4kB代码拷贝到片内SRAM中,其实不然,是Nandflash控制器完成的,这个过程中CPU根本就没有参与。
通过上面的Makefile文件,我们可以知道bl disable_watch_dog 这条指令的运行地址是0x30000000,但是它现在保存在SRAM的0x00000000的地址处,那么这条指令能够正确执行吗?
ofcourse,why?
因为这条指令 bl disable_watch_dog 是位置无关码,虽然它的运行地址是在SDRAM中的0x30000000,但是它可以在Steppingstone中执行。
这条指令的功能是跳转到标号disable_watch_dog处执行,它是一个相对跳转,PC=当前PC的值+偏移量OFFSET。
其中当前PC的值等于下两条指令的地址,通过反汇编可以看到下两条指令的地址为0x00000008,而不是0x30000008.因为现在指令是保存在SRAM中。
这条指令的机器码为eb000005,将机器码低24位按符号位扩展成32位得到0x000000005.然后将0x00000005左移2位得到0x00000014。
这个值就是偏移量OFFSET=0X00000014。
所以PC=0X00000008+0X00000014=0X0000001c.那么CPU就会到SRAM中的0x0000001c地址处执行程序。
可以发现bl指令依赖当前PC的值,这个特性使得bl指令不依赖指令的运行地址。
所以接下来的blmensetup,blcope_steppingstone_to_sdram都能够执行。
接下来的ldrpc,=on_sdram是一条位置有关码,经过反汇编可以看到,它是当前pc的值+偏移量,得到一个地址Addr,然后从内存中的这个地址去取数据Data赋给pc。
现在我们计算一下Addr这个地址。
Addr=当前PC的值+144。
当前PC的值等于下两条指令的地址0x00000014,而不是0x30000014,因为现在程序是保存在SRAM中。
所以Addr=0x00000014+144=0x00000014+0x00000090=0x000000a4.那么这个地址0x000000a4中保存了什么数据。
通过反汇编可以看到SRAM中的0x000000a4这个地址保存的机器码为30000010,所以cpu会跳转到0x30000010这个地址处执行程序。
这个地址0x30000010
是在SDRAM中,这样程序就跳到SDRAM中去了。
因为我们前面的指令blcope_stepping_to_sdram已经把SRAM中4kB的程序拷贝到了SDRAM中,所以现在SDRAM中有程序了。
但是如果在程序的开头放置一条这样的指令:
ldrpc,=disable_watch_dog,那么整个程序就不能够正确执行了。
why?
我们先来看看启动代码
@*************************************************************************
@File:
head.S
@功能:
设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行
@**