首先,ARM7TDMI 不支持 thumb2 扩展,而是基本上定义了原始的 thumb 指令集。
那么为什么不试试呢?
.thumb
@.syntax unified
b 0x50
运行这些命令
arm-whatever-whatever-as b.s -o b.o
arm-whatever-whatever-objdump -D b.o
得到这个输出
0: e7fe b.n 50 <*ABS*0x50>
所以这是一种 T2 编码,正如较新的文档所示,对于 ARMv4T、ARMv5T*、ARMv6*、ARMv7 支持的这条指令,ARM7TDMI 是 ARMv4t
所以我们看到 E7 与该指令定义的 11100 开始匹配,因此 imm11 是 0x7FE。这基本上是分支到地址 0x000 的编码,因为它没有与任何东西链接。我怎么知道?
.thumb
b skip
nop
nop
nop
nop
nop
skip:
00000000 <skip-0xc>:
0: e004 b.n c <skip>
2: 46c0 nop ; (mov r8, r8)
4: 46c0 nop ; (mov r8, r8)
6: 46c0 nop ; (mov r8, r8)
8: 46c0 nop ; (mov r8, r8)
a: 46c0 nop ; (mov r8, r8)
0xe004 以 11100 开头,所以这是一个分支编码 T2。imm11 是 4
我们需要从 0 到 0xC。应用偏移量时,pc 提前两条指令。文档说
Encoding T2 Even numbers in the range –2048 to 2046
和
PC, the program counter
- When executing an ARM instruction, PC reads as the address of the current instruction plus 8. • When executing a
- Thumb instruction, PC reads as the address of the current instruction
plus 4.
所以这一切都是有道理的。0xC-0x4 = 8。我们只能做偶数,无论如何分支到指令的中间是没有意义的,所以除以 2,因为拇指指令是两个字节(偏移量是指令而不是字节)。所以给出了 4
0xE004
这是生成 t4 编码的一种方法
.thumb
.syntax unified
b skip
nop
nop
nop
nop
nop
skip:
00000000 <skip-0xe>:
0: f000 b805 b.w e <skip>
4: 46c0 nop ; (mov r8, r8)
6: 46c0 nop ; (mov r8, r8)
8: 46c0 nop ; (mov r8, r8)
a: 46c0 nop ; (mov r8, r8)
c: 46c0 nop ; (mov r8, r8)
分支的 T4 编码是第一个半字顶部的 11110,表示这是一条未定义的指令(不是 ARMv6T2、ARMv7 的任何指令)或 ARMv6T2、ARMv7 的 thumb2 扩展
第二个半字 10x1,我们看到一个 B,所以看起来不错,这是一个 thumb2 扩展分支。
S 是 0 imm10 是 0 j1 是 1 j2 是 1 而 imm11 是 5
I1 = NOT(J1 EOR S); I2 = NOT(J2 EOR S); imm32 = SignExtend(S:I1:I2:imm10:imm11:’0’, 32);
1 EOR 0 是 1 对吗?不是你得到 0。所以 I1 和 I2 都是零,s 是零 imm10 是零。所以我们基本上在这个上只看 imm11 作为一个正数
执行时 pc 领先四位,所以 0xE - 0x4 = 0xA。
0xA / 2 = 0x5 那就是我们的分支偏移偏移 pc + (5*2)
.syntax unified
.thumb
b.w skip
nop
here:
nop
nop
nop
nop
skip:
b.w here
00000000 <here-0x6>:
0: f000 b805 b.w e <skip>
4: 46c0 nop ; (mov r8, r8)
00000006 <here>:
6: 46c0 nop ; (mov r8, r8)
8: 46c0 nop ; (mov r8, r8)
a: 46c0 nop ; (mov r8, r8)
c: 46c0 nop ; (mov r8, r8)
0000000e <skip>:
e: f7ff bffa b.w 6 <here>
s 是 1,imm10 是 0x3FF j1 是 1 j2 是 1 imm1 是 0x7FA
1 eor 1 是 0 不是你得到 1 的 i1 和相同的 i2
imm32 = SignExtend(S:I1:I2:imm10:imm11:’0’, 32);
s 是 1,所以这将符号扩展 1,除了最后几位之外都是 1,因此 imm32 是 0xFFFFFFFA 或 -6 指令或 -12 字节
所以我们的偏移量也是 ((0xE + 4) - 6)/2 = 6。或者从指令编码 PC - (6*2) = (0xE + 4) - 12 = 6 分支到 0x6 的另一种方式来看。
所以如果你想分支到 0x70 并且指令的地址是 0x12 那么你的偏移量是 0x70-(0x12+4) = 0x62 或 0x31 指令,我们从跳过中知道诀窍是让 s 0 和 j1 和 j2一个 1
0x12: 0xF000 0xB831 branch to 0x70
所以现在知道我们可以回到这个:
0: e7fe b.n 50 <*ABS*0x50>
偏移量是符号扩展 0x7FE 或 0xFFFFFFFE。0xFFFFFFFE*2 + 4 = 0xFFFFFFFC + 4 = 0x00000000。分支到 0
添加一个 nop
.thumb
nop
b 0x50
00000000 <.text>:
0: 46c0 nop ; (mov r8, r8)
2: e7fe b.n 50 <*ABS*0x50>
相同的编码
所以反汇编意味着绝对值 0x50 但没有对其进行编码,链接并没有帮助它只是抱怨
(.text+0x0): relocation truncated to fit: R_ARM_THM_JUMP11 against `*ABS*0x50'
这个
.thumb
nop
b 0x51
给出相同的编码。
所以基本上这种语法有问题和/或它正在寻找一个名为 0x50 的标签?
我希望您的示例是您想知道某个地址的分支编码,而不是确切的语法。
arm 不像其他一些指令集,分支总是相对的。因此,如果您可以根据编码到达目的地,那么您将获得一个分支,否则,您必须使用 bx 或 pop 或其他方式之一来修改 pc(具有绝对值)。
知道文档中的 T2 编码只能提前达到 2048,然后在分支与其目的地之间放置超过 2048 个 nop
b.s: Assembler messages:
b.s:5: Error: branch out of range
也许这就是你想要做的?
.thumb
mov r0,#0x51
bx r0
00000000 <.text>:
0: 2051 movs r0, #81 ; 0x51
2: 4700 bx r0
跳转到绝对地址 0x50。对于该特定地址,无需 thumb2 扩展。
.thumb
ldr r0,=0x12345679
bx r0
00000000 <.text>:
0: 4800 ldr r0, [pc, #0] ; (4 <.text+0x4>)
2: 4700 bx r0
4: 12345679 eorsne r5, r4, #126877696 ; 0x7900000
分支到地址 0x12345678 或任何其他可能的地址。