请查看http://github.com/dwelch67/yagbat qemu目录。
下面是从arm调用arm或thumb的几个示例:
start_vector:
mov sp,#0x20000
bl notmain
ldr r0,=0xAABBAABB
bl hexstring_trampoline
ldr r0,=0x12341234
ldr r1,hexstring_addr
mov lr,pc
bx r1
ldr r0,=0x12312344
bl hexstring_trampoline
hang:
b hang
hexstring_trampoline:
ldr r1,hexstring_addr
bx r1
hexstring_addr: .word hexstring
如果您查看指令集参考,您会发现需要使用BX或BLX在ARM和Thumb状态之间切换。BLX不如BX得到广泛支持。
从定义的角度来看,程序计数器PC在执行指令时比指令提前两个指令。对于Thumb来说是4个字节,对于ARM来说是8个字节。无论哪种情况都是两条指令。为了模拟不能用于更改状态的bl,您需要将链接寄存器加载返回地址,并使用bx跳转到函数,根据地址的lsbit更改状态。
mov lr,pc
bx r1
here:
mov指令将here的地址(即返回地址)加载到寄存器lr中,bx r1以与状态无关的方式调用函数。lr地址的最低有效位表示要返回的模式,必须始终使用bx返回。
pre_thumb:
ldr pc,lr
thumb_capable:
bx lr
编译器为调用函数分配了一个 bl 指令,链接器稍后填充其余部分,如果距离太远,则需要一个跳板函数,链接器自己添加。同样,如果需要更改模式,则 bl 调用调用执行该操作的跳板函数。我在上面的代码中对其进行了建模,您可以看到它有些浪费。希望我对编译器只为 bl 分配空间的解释更加清晰。浪费是为大多数代码中的函数调用始终计划模式更改并必须插入 nops。
代码还包括从汇编语言中的 thumb 调用 arm 的调用:
.thumb
.thumb_func
.globl XPUT32
XPUT32:
push {lr}
ldr r2,=PUT32
mov lr,pc
bx r2
pop {r2}
bx r2
除了在Thumb模式下无法弹出到LR以外,大部分都相同。可以弹出到PC,但我认为这不会切换模式,因此不能使用它,您需要一个多余的寄存器。当然,您需要知道调用约定才能知道可以使用哪些寄存器,或者您可以包装另一组推和弹操作来保留除了LR以外的所有内容。
push {r2,lr}
ldr r2,=PUT32
mov lr,pc
bx r2
pop {r2}
mov lr,r2
pop {r2}
bx lr
无论是手指与手指相触还是手臂与手臂相接,你只需使用一个 bl 指令(如果你可以到达的话),如果不能到达,则需要使用 ldr pc,address 指令。这些指令涉及到 IT 技术领域。