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

thumb长跳转指令(BL)机器码详解

2018年02月11日 ⁄ 综合 ⁄ 共 1236字 ⁄ 字号 评论关闭
最近因为工作的原因,经常接触到长跳转指令,但是总是弄不明白,跳转的目标地址怎么得来的
经过多方面的资料查找,和自己的反复推算,现在总算弄明白了
先上例子:
下面是几个实际遇到的机器码机器对应的反汇编
示例一 3950a4: f13d feaa =>bl 4d2dfc
示例二 395082: f13d fe40 =>bl 4d2d06
示例三 395044: F7FF FFAc =>bl 394fa0

大家是不是也奇怪为什么16位的thumb指令里面,会出现32位的指令。
开始我也是这么认为的
这其实是一个误解,因为长跳转是由两条跳转指令组成的。
其实际机器码和和含义如下:
1 1 1 1  0 +11位地址偏移高位(off0)
0xF             13D
1 1 1 1  1 +11位地址偏移低位(off1)
0xF             EAA
还是以上述三个例子做示范,
其偏移如下:(偏移是将指令去除高五bit得来的,f13d->13d 高五bit是1111 0【001】||| feaa->6aa高五bit是1111 1【110】)
示例一 off0=0x13d off1=0x6aa
示例二 off0=0x13d off1=0x640
示例三 off0=0x7FF  off1=0x7AC
首先要做的事情是将两个11位合并为一个22位数(注意由于off1是11位,意味着其最高位为off0的最低位,off0的值要除2)
即 offmid = ((off0/2)<<12)|((off0%2)<<11)|(off1)
按照这样计算,几个示例的偏移中间量为:
offmid = 0x9eeaa
offmid = 0x9ee40
offmid = 0x3fffac
接着将这个值乘2,得到一个23位数
offmid1 = 0x13dd54
offmid1 = 0x13dc80
offmid1 = 0x7fff58
对于前面两个这是一个正数,最高位为0,所以不必取反保留原来的值
对于最后一个,最高位为1,是负数,要减1后取反
处理后,如下:
offmid2 = 0x13dd54
offmid2 = 0x13dc80
offmid2 = 0x8000a8
最高位为1,则表示向前跳转,最高位为0表示向后跳转
跳转的基址是当前指令的末尾,需要再追加4个字节
所以实际跳转值就是:
off = 0x3950a4+4+0x13dd54 = 0x4d2dfc
off = 0x395082+4+0x13dc80 = 0x4d2d06
off = 0x395044+4- 0x0000a8 = 0x394fa0
反过来再看一看,其实长跳转的偏移是这么来的
首先取当前位置和目标位置的偏移差
地址因为内存对齐的原因,必然是偶数(即最低位必然为0),所以偏移值只有23位有意义,最低位永远为0
又由于最高位为符号位,所以,只有22位存储了真正的值
然后取补码(正数的补码是源码,负数的补码是符号位不变,剩余数取反加1),这样可以去除符号位对值的影响,将结果变为一个真正的22位值
最后再将其拆分为两个11位数,分成两个跳转指令执行

这么一想,顺着看,结果一目了然;但是反汇编的时候,难度就大大增加了,呵呵

抱歉!评论已关闭.