现在的位置: 首页 > 综合 > 正文

arm跳转指令

2013年10月28日 ⁄ 综合 ⁄ 共 1679字 ⁄ 字号 评论关闭

编写了一段汇编,理论上是拷贝到sdram上面运行的,移植在思考这样的一个问题,板子的外接ram在没有初始化之前是不能使用的,jlink是不能帮我们拷贝程序到sdram的,同时自己写的只是一个小小的程序,没有必要大动干戈用uboot,这样的引导程序拷贝我们的小程序到sdram上面去,因而自己实现的拷贝,因为我的板子外部ram的地址是0x30000000,这个地址必须要初始化之后才能使用。

大概的思路是这样的,写一个小程序,包含了拷贝动作的代码,和需要拷贝的程序,一起烧写到我们的nand flash(nand flash)启动,注意要小于4K,然后我们的把需要执行的小程序拷贝到sdram上面去。

代码如下。

 

.equ MEM_CTL_BASE,0x48000000
.equ SDRAM_BASE,0x30000000

.text
.global _start

_start:

    bl disable_watch_dog   @关闭watchdog
    bl memsetup            @设置储存控制器
    bl copy_steppingstone_to_sdrame @复制代码到sdram
    ldr pc,=on_sdram
   
on_sdram:
    ldr sp,=0x34000000   @设置栈
    bl main
   
halt_loop:
    b halt_loop

……………………(后面的省略)

 

注意我们的拷贝是拷贝从0x00开始的4k的片内ram,就是自己把自己拷贝到SDRAM上面去,然后跳转到SDRAM上面运行。

 

也就是说,同样的程序,放在4k ram执行了一次,然后放在0x30000000又执行了一次,我对执行的正确度表示怀疑,因为,最起码,放的地方不同,跳转的地方也不同,程序还能正常运行吗?

 

注意,在ARM指令中,一般的子函数的调用都是相对的跳转,也就是说,我们的所有的代码就是一大块,这一块无论你放在什么地方,只要你的PC只想程序的开始地方,他就会一条一条的执行,碰到跳转的时候,自动的找到当前位置的子函数的位置,这是怎么实现的呢?——相对跳转。

例如:

bl disable_watch_dog

在编译的时候

错误的理解:首先编译器计算出disable_watch_dog的地址,然后跳转到上面运行,这样显然,我的程序编译之后就不会再去编译,当时程序放在不同的地址上面就不能运行了。

正确的理解:bl disable_watch_dog,编译器计算当前的PC值,然后计算处当前的PC值和disable_watch_dog之间的距离,然后跳转的位置是pc+offset,这个offset偏移量,不管你的程序放在哪里都是不会变的,因而程序可以到处搬运。只是要注意,这个offset只是在正负32M范围之内的。

 

所以说,即使我的程序最开始是准备到0x30000000上运行的,只要里面使用相对跳转的指令,我把程序拷贝到0x0000照样能够运行。

然后在看一下绝对的跳转,绝对的跳转就是直接给pc赋值,例如:

 

ldr pc,=0x34000000

也许,如果考虑的比较深入,有的人会问,既然这样我们编译之后连接还要指明一个-Ttext有什么用,反正放在什么地方执行都是一样的,真的要用到绝对跳转,注意一下就可以了。

 

使用-T,就是给每一条指令添加一个属性,就是运行的地址,这个可以在elf文件中看出来,这个运行的地址在相对跳转的时候没有什么大用,但是在绝对跳转的时候,你不可能记住或者运算某一个函数的地址,必须要借助lable,然后

 

ldr pc,=on_sdram

 

说的简单一点,相对跳转,要使用lable,然后计算lable与当前pc的差距,就可跳转。

绝对跳转的时候,首先可以直接指明一个值,其次,我如果想用lable呢,这个lable不是想放在什么地方都可以的,于是就必须知道程序运行的地方,程序运行的地方并不是程序只能在那里运行,而是程序最终还是要到那里去的,添加这个地址,便于我们的编译器知道绝对跳转的时候该如何跳转。

 

 

不知道说的清楚不,个人理解,仅供参考。

 

 

抱歉!评论已关闭.