程序运行地址和加载地址

在嵌入式编程中,我们经常讲程序保存在 nand flash中。但是我们知道,nand flash的接口设计和 RAM 的接口设计是不一样的。
他的 数据线通常都是复用的,所以通常存取都是以块为单位(nor flash带有RAM接口,有足够的地址线来寻址,
所以可以访问内存中每一个字节)  这导致了,nand flash不可以片内执行程序(nor flash可以,因为他能存取内存每一个字节)

对于 s3c2440 来说,当使用 nand flash 启动时,为了解决 nand flash 不能片内执行程序的问题(片内不能执行,那么程序烧进去不是不能运行嘛)
 于是 s3c2440 在内部有一个 叫 Stepping Stone(垫脚石?)的东西,其实他就是一块 4KB 的RAM,当我们以 nand flash启动想运行烧写在上面
 的程序是,s3c2440会自动将 nand flash 前面 4KB 的内容拷贝到 这个叫Stepping Stone的片内内存中。
 然后 pc指针为0 从这个片内内存0地址开始运行。

但是这个 片内内存只有 4Kb 大小,如果我们烧到 nand falsh中的程序大于 4KB 那么只有一部分被考到了片内内存中去执行。剩下的就不能执行了。
 
但是我们不是可以接外设吗, s3c2440的BANK6 和 BANK7都可以接最大 128M的SDRAM。SDRAM是一个RAM(内存)
 
那么当程序大于 4k 的时候,当我们以 nand flash启动后,前面的4Kb 被拷贝到 片内RAM中去执行(自动完成)。
我们在这前4K的程序中初始化SDRAM(SDRAM 使用前需要初始化) ,然后将剩下的程序拷贝到 SDRAM中(不是只有4kb 被拷贝到片内RAM中执行了嘛)然后跳转到 SDRAM中去执行剩下的程序。
 
那么也就是说 通常当程序大于 4kb的 时候,我们就需要把程序拷贝到SDRAM中去运行。(程序小于4KB 那么也就可以不用拷贝了,以nand flash方式 启动后,程序全被拷贝到 片内4kb的 RAM中去运行。)。
 
那么,既然程序大于4kb的时候需要从nand flash中拷贝到 SDRAM中去运行。自然可以想到 烧到nand flash中的程序前面一部分代码应该是初始化SDRAM(程序最终需要拷贝到SDRAM中去运行)和 将NAND flash中的剩余的程序拷贝到SDRAM中去(全考过去也行,方便点),然后跳转到SDRAM中执行。
 
下面我们就要详细说明,前面这一段跳转到 SDRAM去执行前在片内内存中运行的初始化代码的要点和细节。也就是 关于程序运行地址和加载地址以及位置无关指令的 一些注意点和细节

先来看下程序运行地址和加载地址

看个 随便写的简单的示例,这是一个连接脚本中的一段 first 0x30000000 : AT(0){main.o}

我们只注意 0x30000000 和 AT(4096) 这两处。

如果程序是烧到nand flash中。这句话里面的意思就是  a.o烧到nand flash 中从0地址(当然也可以是其他数)开始的地方,但他的运行地址是在从0x30000000地址开始的地方。(为什么是0x30000000,应为 s3c2440的 bank6 和bank7 可以接sdram,bank6从地址0x30000000开始,我们的程序最终是要在SDRAM中运行的)烧到 nand flash中从地址0 开始的地方应该比较好理解,就是说我程序是存储在nand flash中最开始的地方。那么运行地址呢怎么理解呢
 
 看一下断汇编
  1 .text
  2 .global _start
  3 _start:
  4        mov    r0, #2
  5 loop:
  6        ldr    pc,=loop

上面这段汇编,我们将 他的运行地址分别设为 0x0 和0x30000000来看看反汇编后的情况

先将运行地址设为0x0
  all: test.c head.s
  2        arm-linux-gcc -c -Wall -o head.o head.s
  3        arm-linux-ld -Ttext 0x0 -o main_elf  head.o
  4        arm-linux-objdump -D -m arm main_elf > main.dis
  5
  6 clean:
  7        rm -rf *.o main.dis main_elf

反汇编 main.dis如下:
 6 00000000 <_start>:
  7    0:  e3a00002        mov    r0, #2  ; 0x2
  8
  9 00000004 :
 10    4:  e51ff004        ldr    pc, [pc, #-4]  ; 8 <.text+0x8>
 11    8:  00000004        andeq  r0, r0, r4

将    arm-linux-ld -Ttext 0x0 -o main_elf  head.o
 改为    arm-linux-ld -Ttext 0x30000000 -o main_elf  head.o
 也就是将运行地址设定为0x30000000 再看看它的反汇编
  6 30000000 <_start>:
  7 30000000:      e3a00002        mov    r0, #2  ; 0x2
  8
  9 30000004 :
 10 30000004:      e51ff004        ldr    pc, [pc, #-4]  ; 30000008 <.text+0x8>
 11 30000008:      30000004        andcc  r0, r0, r4

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/bf03c36549f4617861426569451f601f.html