您的位置 首页 传感器

arm汇编中的跳转指令

ARM汇编中,常有两种跳转方法:b跳转指令、ldr指令向PC赋值。我自己经过归纳如下:(1)blabel该指令完成的操作是pc-label,将label处…

ARM汇编中,常有两种跳转办法:b跳转指令、ldr指令向PC赋值。

我自己经过归纳如下:
(1)b label
该 指令完结的操作是pc<-label,将label处的地址传给pc。b跳转指令是相对跳转,依靠当时PC的值,偏移量是经过该指令自身的 bit[23:0]算出来的,这使得运用b指令的程序不依靠于要跳到的代码的方位,只看指令自身。即该分支指令的二进制码的后24位的实践的值是相对当时 的 R15 的值的一个偏移量;而不是一个肯定地址。它的值由汇编器来核算,它是 24 位有符号数,左移两位后有符号扩展为 32 位,一共的有用偏移为 26 位(+/- 32 M)。
(2)ldr pc, =label
该指令是一条伪指令,将内存中的某个数据的方位(label处)赋给PC,相同依靠当时PC的值,可是偏移量是那个方位(label)的衔接地址(运行时的地址),所以能够用它完结从Flash到RAM的程序跳转,说白了,pc是个地址数值。
伪指令LDR 常用于加载芯片外围功用部件的寄存器地址(32 位当即数),以完结各种
操控操作。
如:ldr r0,=5e000000 ;将外围某IO端口寄存器的地址赋给r0,留意该当即数前面没有#。
—————————————————————————
这儿讲一下为什么会有ldr 伪指令

典范demo.s:


.equSTACK_BASE,0x0c002000

.equSTACK_SIZE,0x00001000

.text
ldrsp,=STACK_BASE
ldrsl,=STACK_BASE-STACK_SIZE
ldrpc,=entry

这是一个合法的汇编文件,它把仓库基址设为0x0c002000,栈限设为0x0c001000,然后跳到entry所标识的C程序中碑文。

下面咱们假定符号“entry”的地址为0x0c000000。

咱们如果把上面代码写成:

.text
movsp,#0x0c002000
movsl,#0x0c001000
movpc,#0x0c000000

汇编器会报错:
demo.s: Assembler messages:
demo.s:2: Error: invalid constant — `mov sp,#0x0c002000
demo.s:3: Error: invalid constant — `mov sl,#0x0c001000

说起这个过错的原因可就话长了,简而言之是我们RISC有一个重要的概念便是一切指令等长。在ARM指令拘押,一切指令长度为4字节(Thumb指令是2 字节)。那问题就来了,4字节是不可能一起存的下指令操控码和32位当即数的,那么我要把一个32位当即数(比方一个32位地址值)传送给寄存器该怎样 办?
RISC CPU供给一个通用的办法便是把地址值作为数据而不是代码,从存储器中相应的方位读入到寄存器中。像在代码一中,将一切读取的32位数据放到label标 注的内存地址中,运用ldr伪指令,从该内存处读出该数据。因而label适当于一个内存地址。如下,给出了代码一的反汇编代码:让咱们在Linux环境下碑文下面的指令:
arm-elf-as -o demo.o demo.s
arm-elf-objdump -D demo.o

成果:

demo.o:fileformatelf32-littlearm

Disassemblyofsection.text:

00000000<.text>:
0: e59fd004 ldrsp,[pc,#4];c<.text+0xc>
4: e59fa004 ldrsl,[pc,#4];10<.text+0x10>
8: e59ff004 ldrpc,[pc,#4];14<.text+0x14>
c: 0c002000 stceq0,cr2,[r0]
10: 0c001000 stceq0,cr1,[r0]
14:00000000 andeqr0,r0,r0
Disassemblyofsection.data:

0、4、8三行适当所以代码段,C,10,14适当所以数据段,伪指令的变量界说存储在这儿。咱们entry还没连上方针地 址,objdump反汇编会认为是0,咱们先不管它。别的两条LDR伪指令变成了实践的LDR指令!但方针很古怪,都是[pc, #4]。那好咱们看看[pc, #4]是什么。
咱们知道pc中寄存的是当时指令的下下条指令的方位,也便是.+8。那么上面的第一条指令ldrsp,[pc,#4]中的pc便是0x8,pc+4便是0xc,而[0xc]的内容正是0x0c002000;同理,第二条ldr指令也是如此。明显这儿LDR伪指令选用的是RISC通用的办法。
别的从反汇编的代码能够看出ldr伪指令中存储的是一个相对偏移量,该偏移量是相对当时pc值的一个偏移量。
——————————————————————————

(3)此外,有必要回味一下adr伪指令,U-boot中那段relocate代码便是经过adr完结当时程序是在RAM中仍是flash中。
ADR指令为小规模的地址读取伪指令.ADR指令将根据PC相对偏移的地址值读取到寄存器中.在汇编编译源程序时,ADR伪指令被编译器替换成一条适宜的 指令.一般,编译器用一条ADD指令或SUB指令来完结该ADR伪指令的功用,若不能用一条指令完结,则发生过错,编译失利.
ADR 伪指令格局如下
ADR{cond} register,exper 其间
register 加载的方针寄存器
exper 地址表达式.当地址值对错字地齐时,取值规模-255~255 字节之间;当地址是字对齐时,取值规模-1020~1020 字节之间.关于根据PC 相对偏移的地址 值时,给定规模是相对当时指令地址后两个字处(我们ARM7TDMI 为三级流水线).
ADR 伪指令举例如下;
LOOP MOV R1,#0xF0

ADR R2,LOOP ;将LOOP 的地址放入R2
ADR R3,LOOP+4
能够用ADR 加载地址,完结查表:

ADR R0,DISP_TAB ;加载转化表地址
LDRB R1,[R0,R2] ;运用R2 作为参数,进行查表

DISP_TAB
DCB 0Xc0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90

4 ldr pc,_label
_label .word label
一般ldr pc,=label就被解说成上面这两条指令,可是从反汇编程序中能够看出咱们偏移量仅为4k,_label的界说方位要和ldr指令相距在4k以内。借此能够完结大规模地址的跳转,完结从flash到sdram的跳转。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/yingyong/chuanganqi/264061.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部