位置无关码、链接地址与加载地址

来源:互联网 发布:欧洲卡车模拟2mac联机 编辑:程序博客网 时间:2024/05/16 15:42

从Nand Flash 启动CPU的时候,内部硬件自动将Nand Flash 开始的4KB 数据复制到4KB的内部RAM

“Steppingstore”(起始地址为0)中,cpu是从pc寄存器指向的地址取指令执行的,pc指向的地址应该存

放有对应的指令才能正确执行。刚开始的时候pc寄存器是指向0地址的,CPU从0地址取指令开始执行。


链接地址是我们写Makefile的时候指定了程序运行的时候应该保存在什么位置,但运行时程序具体存储
在哪里由硬件或我们写程序的时候把程序本身加载在哪里来决定。可能分段存储,可能重复存储在多处。
如nand启动,不管链接地址是哪里,硬件上自动把nand前4kb 加载到steppingstore,后面又可能把程序
从nand复制到其他地方去,往往复制到程序的链接地址那里去,这样那些位置相关码才可以正确执行。

不管链接地址,加载地址是哪里,总之cpu是从pc寄存器指向的地址取指令执行的,只要pc指向的地址存
放有对应的指令就能正确执行。这句话很重要。

位置无关码与位置相关码对pc寄存器的值的影响:
位置无关:pc = 当前 pc值(当前指令实际存储地址或加载地址) + 相对偏移量
位置相关:pc = 链接地址 + 绝对偏移量

名词解释:
1、相对偏移量:下一条要执行的指令的实际存储地址(即加载地址) - 当前指令的实际存储地址(即加载地址) 
或者:下一条要执行的指令的链接地址 - 当前指令的链接地址 
2、绝对偏移量:下一条要执行的指令的实际存储地址(即加载地址) - 程序的实际存储地址(即加载地址)
或者:下一条要指向的执行的指令的链接地址 - 程序的链接地址
一句话,无论是实际存储地址(即加载地址),还是链接地址,相对偏移是 指令与指令之间的偏移,
绝对偏移 是指令相对于程序起始位置的偏移。
 
当程序的实际存储地址(即加载地址)为0的时候,对于位置无关码有:
pc = 当前 pc值(当前指令实际存储地址或加载地址) + 相对偏移量
   = 当前 pc值(当前指令实际存储地址或加载地址) + 
     下一条要执行的指令的实际存储地址(即加载地址) - 当前指令的实际存储地址(即加载地址)
   = 下一条要执行的指令的实际存储地址(即加载地址)

即此时pc与链接地址无关,这就是为什么程序加载到steppingstore(0地址)的时候,即使程序的链接地址

不为0,位置无关码仍可以在这里正常执行的原因。



实例分析:

@*************************************************************************@ 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中    ldr pc, =on_sdram                   @ 跳到SDRAM中继续执行on_sdram:    ldr sp, =0x34000000                 @ 设置堆栈    bl  mainhalt_loop:    b   halt_loopdisable_watch_dog:    @ 往WATCHDOG寄存器写0即可    mov r1,     #0x53000000    mov r2,     #0x0    str r2,     [r1]    mov pc,     lr      @ 返回    ............

其Makefile:

sdram.bin : head.S  leds.carm-linux-gcc  -c -o head.o head.Sarm-linux-gcc -c -o leds.o leds.carm-linux-ld -Ttext 0x30000000 head.o leds.o -o sdram_elfarm-linux-objcopy -O binary -S sdram_elf sdram.binarm-linux-objdump -D -m arm  sdram_elf > sdram.disclean:rm -f   sdram.dis sdram.bin sdram_elf *.o
其sdram.dis文件部分内容:

30000000 <_start>:30000000:eb000005 bl3000001c <disable_watch_dog>30000004:eb000010 bl3000004c <memsetup>30000008:eb000007 bl3000002c <copy_steppingstone_to_sdram>3000000c:e59ff090 ldrpc, [pc, #144]; 300000a4 <mem_cfg_val+0x34>30000010 <on_sdram>:30000010:e3a0d30d movsp, #872415232; 0x3400000030000014:eb000032 bl300000e4 <main>

Makefile 中arm-linux-ld -Ttext 0x30000000 head.o leds.o -o sdram_elf指明了:
程序的链接地址是0x30000000,是sdram的起始地址,程序运行时本应在地址0x3000000处开始存放着

这个程序,但是程序被烧到nand,从nand启动,被加载到steppingstore,对于刚开始的几条位置无关码,

由于此时实际加载地址为0,则 pc = 下一条要执行的指令的实际存储地址(即加载地址),cpu根据pc值能

找到对应的指令,能正确执行。


执行bl  copy_steppingstone_to_sdram之后,0x30000000处已经存放有程序了,接着要到

“bl  copy_steppingstone_to_sdram”的下一条指令“ldr pc, =on_sdram”,执行这条指令的时候,cpu是

从0xc( 0+3*0x4,一条指令的大小是0x4)处取这条指令执行的,并不是在

0x30000000+ 3* 0x4 = 0x3000000c处取指令,执行完“ldr pc, =on_sdram”之后pc就指向标号“On_sdram"

指向的地址了,这个"on_sdram"指向的地址是位置相关地址,与链接地址有关,是绝对地址,

=链接地址+绝对偏移量,具体是0x30000000+ 4* 0x4 = 0x30000010,
(反汇编文件中可以看到这个,确实是=链接地址+绝对偏移量
30000010 <on_sdram>:
30000010: e3a0d30d mov sp, #872415232 ; 0x34000000 
//对应第五条指令ldr sp, =0x34000000      @ 设置堆栈
 )
 pc指向了0x30000010,对应的指令也由copy_steppingstone_to_sdram复制到了这里了,后面CPU

就从这里取指令执行。

阅读全文
1 0
原创粉丝点击