arm跳转指令
2009-03-31 15:15
211 查看
编写了一段汇编,理论上是拷贝到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不是想放在什么地方都可以的,于是就必须知道程序运行的地方,程序运行的地方并不是程序只能在那里运行,而是程序最终还是要到那里去的,添加这个地址,便于我们的编译器知道绝对跳转的时候该如何跳转。
不知道说的清楚不,个人理解,仅供参考。
大概的思路是这样的,写一个小程序,包含了拷贝动作的代码,和需要拷贝的程序,一起烧写到我们的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不是想放在什么地方都可以的,于是就必须知道程序运行的地方,程序运行的地方并不是程序只能在那里运行,而是程序最终还是要到那里去的,添加这个地址,便于我们的编译器知道绝对跳转的时候该如何跳转。
不知道说的清楚不,个人理解,仅供参考。
相关文章推荐
- ARM的B,BL跳转指令偏移值计算
- 关于ARM的B,BL跳转指令
- ARM中跳转指令的范围
- 关于ARM跳转指令b跳转指令范围为什么为正负32M??
- 深入理解ARM跳转指令B以及在此基础上理解arm-linux中断向量表中
- 深入理解ARM跳转指令B以及在此基础上理解arm-linux中断向量表中的内容。
- ARM汇编跳转指令理解
- ARM 汇编中跳转指令
- 关于ARM的B,BL跳转指令
- ARM指令跳转范围
- ARM汇编中B跳转指令和LDR跳转的区别 【转】
- 深入理解ARM跳转指令B以及在此基础上理解arm
- arm跳转指令对应的机器码
- ARM 汇编中跳转指令
- ARM学习笔记2——分支跳转指令
- arm汇编的跳转指令
- ARM跳转指令B的反汇编分析
- ARM和Thumb的跳转指令B、BL、BX
- ARM的六大类指令集---跳转指令
- ARM的跳转指令