ARM中跳转指令BL/BLX偏移值计算规则

ARM 284浏览

源文地址:http://www.cnblogs.com/Reyzal/p/4857948.html

1. 4字节对齐arm指令

    规则:偏移=( 跳转地址-(指令地址+8) )/4

原因:

指令地址 + 8:因为ARM的流水线使得指令执行到当前指令处时,PC实际的值是A+8。

跳转指令 - 上一步得到地址:得到跳转指令与当前PC处的差值。

÷4:因为ARM的指令是4对齐的,即最低两位为00,于是将这个值右移两位。

 

执行时:

取出偏移,左移两位,加入PC,这时PC的值刚好为目标处的地址值,即目标地址指令进入取值,流水线前两级被清空。

 

实例测试:

.text:0000126C 90 00 9F E5
LDR R0, =0x4D44

.text:00001270 00 70 8F E0 ADD R7, PC, R0 ;
_GLOBAL_OFFSET_TABLE_

.text:00001274 07 00 86 E0 ADD R0, R6, R7

.text:00001278 74 10 80 E2 ADD R1, R0, #0x74

.text:0000127C DC 20 80 E2 ADD R2, R0, #0xDC

.text:00001280 04 00 A0
E3 MOV R0, #4

.text:00001284 92 FF
FF EB BL __android_log_print

.text:00001288 00 00 95 E5
LDR R0, [R5]

 

 

.plt:000010D4 __android_log_print

.plt:000010D4 00 C6 8F E2
ADR R12, 0x10DC

(0010d4 - (001284 + 8))/4 = 00FFFF92。

对应机器码为 92 ff ff

2. thumb2指令

    (转自 http://bbs.pediy.com/showthread.php?t=199429 ))

1.向后跳转

0012 00F001F8 bl .Lhelo

.Lhelo:

0018 05F0D1F7 pld [r1, r5]

 

计算方式:

取高位 f000, 取后11位 => 000

取低位 f801, 取后11位 => 001

计算: (000 << 12) | (001 << 1) = 2

由于这个最高位符号位为0. 代表向后跳转, 只需要保留该值2即可

 

然后计算得到的目标地址为 : 0x0012 + 4 + 2 = 0x0018

向前跳转

00001164 FF F7 BE FF BL _Z4testv

_Z4testv

000010E4 07 B5 PUSH {R0-R2,LR}

 

计算方式:

取高位 f7ff, 取后11位 => 7ff

取低位 ffbe, 取后11位 => 7be

计算: (7ff << 12) | (7be << 1) = 7fff7c

由于这个最高位符号位为1 代表向前跳转, 需要-1然后取反 得到值为 ff800084。取84即可

 

然后计算得到的目标地址为 : 0x1164 + 4 - 0x84 = 0x10e4

 

逆向过程:

BL <label>
由BL指令得到机器码算法:

offset = dstAddr - srcAddr;

 

offset = (offset -4) & 0x007fffff;

 

high = offset >> 12;

low = (offset & 0x00000fff) >> 1;

 

machineCode = ((0xFF00 | low) << 16) | (0xF000 | high);

BLX <label>

与BL类似。

offset = dstAddr - srcAddr;

 

offset = (offset -4) & 0x007fffff;

 

high = offset >> 12;

low = (offset & 0x00000fff) >> 1;

 

if(low%2 != 0) {

low++;

}

 

machineCode = ((0xEF00 | low) << 16) | (0xF000 | high);