的ARM / Thumb:在拇指$ ​​C $ c。使用BX,调用Thumb函数,或跳转到Thumb指令在另一个函数 [英] Arm/Thumb: using BX in Thumb code, to call a Thumb function, or to jump to a Thumb instruction in another function

查看:184
本文介绍了的ARM / Thumb:在拇指$ ​​C $ c。使用BX,调用Thumb函数,或跳转到Thumb指令在另一个函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想学习固件改装有用的技能(对此我没有源$ C ​​$ C)
从拇指code这些问题涉及使用BX的跳或调用其他现有的拇指code。

I'm trying to learn skills useful in firmware modding (for which i don't have source code) These questions concern use of BX from thumb code to jump or call other existing thumb code.


  1. 我如何使用BX跳转到现有固件拇指code,从我的拇指code。

  2. 我如何使用BX调用现有的Thumb函数(必须先设置LR),从我的拇指code。

我的理解是,CPU着眼于LSB位(0),我必须确保这样做是为了保持CPU状态为拇指状态设置为 1
所以我想我要补充1,位为LSB为1。

My understanding is that cpu looks at lsb bit (bit 0) and i have to make sure this is set to 1 in order to keep cpu state to "thumb state". So I guess i have to ADD 1, to set lsb bit to 1.

所以...说我想只是跳转到0×24000(在一些现有的拇指code的中间)

So ...say i want to just JUMP to 0x24000 ( in the middle of some existing THUMB code)

LDR R6, =0x24000
ADD R6, #1       @ (set lsb to 1)
BX R6

我认为这是正确的?

I think this is correct ?

现在说我要调用现有的拇指功能,采用BX,我希望它退还给我,所以我需要LR设置到我希望它回来。

Now say i want to CALL an existing thumb function, using BX, and i want it to return to me, so i need to set LR to where i want it to return.

可以说,我要调用的函数是0×24000
这是<一个href=\"http://stackoverflow.com/questions/9348709/arm-thumb-$c$c-for-firmware-patches-how-to-tell-gcc-assembler-linker-to-bl-t\">suggested我的使用方法:

Lets say the function i want to call is at 0x24000 It was suggested to me to use:

ldr r2, =0x24000
mov lr, pc
bx r2

下面来什么,我不明白:

Here comes what i don't understand:


  1. 在R2中的地址不必LSB位设置......所以不会 BX R2 开关模式,以ARM模式??

  1. the address in R2 doesn't have lsb bit set... so won't bx r2 switch mode to ARM mode??

的LR ..
PC有(当前指令开始时,+ 4)的地址,有人告诉我。
在这两个拇指和手臂,任何指令的地址必须对齐(16位或32位),所以它不会有LSB位设置为1。只有奇数已LSB位设置为1。

The LR.. The PC has the address of (begining of current instruction, + 4), i was told. In both Thumb and Arm, any instruction address has to be aligned (16 bit or 32 bit), so it won't have the LSB bit set to 1. Only odd numbers have lsb bit set to 1.

因此​​在上面的code,我设置为LR(PC),不具有LSB位1设置或者一个地址。因此,当我调用该函数来它的尾声,并执行 BX LR ,... .. uhmmm怎么能这项工作回到我的拇指code?我必须失去了一些东西...

So in the code above, i'm setting LR to (PC), an address that DOESN'T have lsb bit 1 set either. So when the function i called comes to it's epilogue, and does BX LR, ... uhmmm.. how can that work to return to my THUMB code ? I must be missing something...

通常BL用于调用函数。手册上说BL指令将LR为code的下一行...
那么,这是否意味着一个(正常使用) BL Thumb指令,设置LR为返回地址+ 1 自动?

Normally BL is used to call functions. The manual says BL instruction sets the LR to the next line of code... So does this mean that a (normally used) BL THUMB instruction, sets the LR to return addr + 1 automatically?

推荐答案

哇,谢谢你给我打电话了这一点。我知道我试着QEMU code在 http://github.com/dwelch67/yagbat 并认为XPUT32这就要求PUT32在路上你描述,和它的工作。但它似乎没有工作。我创建了大量的实验和我非常惊讶,这不是我所期待的。现在我明白为什么GNU链接做它做什么。很抱歉,这是一个长期的反应,但我觉得它非常有价值的。这是一个令人困惑的话题,我知道我已经错了多年想在PC周围拖动模式位,但它不。

Wow, thanks for calling me out on this one. I know I tried the qemu code in http://github.com/dwelch67/yagbat and thought XPUT32 which calls PUT32 in the way you describe, and it worked. But it DOES NOT appear to work. I created a number of experiments and am quite surprised, this is not what I was expecting. Now I see why the gnu linker does what it does. Sorry this is a long response but I think it very valuable. It is a confusing topic, I know I have had it wrong for years thinking the pc drags the mode bit around, but it doesnt.

在我开始与下面的实验中,如果你要做到这一点:

Before I start with the experiments below, if you are going to do this:

LDR R6, =0x24000
ADD R6, #1       @ (set lsb to 1)
BX R6

因为你碰巧知道0×24000是拇指code,只是这样做,而不是:

because you happen to know that 0x24000 is thumb code, just do this instead:

LDR R6, =0x24001
BX R6

是的,这是你如何从手臂或拇指跳转到拇指code,如果你碰巧知道这很难codeD地址0×24000是你用包含地址加上一个寄存器BX Thumb指令。

And yes, that is how you branch to thumb code from arm or thumb if you happen to know that that hardcoded address 0x24000 is a thumb instruction you bx with a register containing the address plus one.

如果您不知道地址,但知道地址的名称

if you dont know the address but know the name of the address

ldr r6,=something
bx r6

有关的好处是的东西可以是ARM或Thumb地址和上面的code只是工作。那么它的工作原理,如果正确地连接知道什么标签的类型是手臂或拇指,如果被搞砸它不会工作的权利,你可以在这里看到。

The nice thing about that is that something can be an arm or thumb address and the above code just works. Well it works if the linker properly knows what type of label that is arm or thumb, if that gets messed up it wont work right as you can see here

.thumb
ping:
    ldr r0,=pong
    bx r0
.code 32
pong:
    ldr r0,=ping
    bx r0


d6008148 <ping>:
d6008148:   4803        ldr r0, [pc, #12]   ; (d6008158 <pong+0xc>)
d600814a:   4700        bx  r0

d600814c <pong>:
d600814c:   e59f0008    ldr r0, [pc, #8]    ; d600815c <pong+0x10>
d6008150:   e12fff10    bx  r0

d6008158:   d600814c    strle   r8, [r0], -ip, asr #2
d600815c:   d6008148    strle   r8, [r0], -r8, asr #2

这是没有工作的乒乓球想拉离0xD600815C拇指地址,但有一个手臂的地址。

that didnt work pong wanted to pull a thumb address from 0xD600815C but got an arm address.

这是所有的GNU汇编的东西顺便说一句,对于其他工具,你可能不得不做别的事情。对于气体你需要你想声明为拇指标签(术语FUNC暗示功能被误导,不约.thumb_func意味着什么,它只是是一个汇编器/连接器游戏忧虑)。

this is all gnu assembler stuff btw, for other tools you may have to do something else. For gas you need to put .thumb_func before a label that you want declared as a thumb label (the term func implying function is misleading, dont worry about what .thumb_func means it just is an assembler/linker game).

.thumb
.thumb_func
ping:
    ldr r0,=pong
    bx r0
.code 32
pong:
    ldr r0,=ping
    bx r0

,现在我们得到了我们想要的东西。

and now we get what we wanted

d6008148 <ping>:
d6008148:   4803        ldr r0, [pc, #12]   ; (d6008158 <pong+0xc>)
d600814a:   4700        bx  r0

d600814c <pong>:
d600814c:   e59f0008    ldr r0, [pc, #8]    ; d600815c <pong+0x10>
d6008150:   e12fff10    bx  r0

d6008158:   d600814c    strle   r8, [r0], -ip, asr #2
d600815c:   d6008149    strle   r8, [r0], -r9, asr #2

0xD600815C都有一套,所以LSb让你没有做任何工作。编译器通吃的这种照顾,当你正在做的C函数,例如调用。对于汇编虽然必须使用该.thumb_func(或其他一些指令,如果有一个),以获得气体知道这是一个拇指标签,并设置为,所以LSb你。

0xD600815C has that lsbit set so that you dont have to do any work. The compiler takes care of all of this when you are doing calls to C functions for example. For assembler though you have to use that .thumb_func (or some other directive if there is one) to get gas to know this is a thumb label and set the lsbit for you.

所以下面的实验是在一个MPCore的其是ARM11完成,但我还试图testthumb功能1至4上的ARM7TDMI和QEMU具有相同的结果。

So the experiment below was done on an mpcore which is an ARM11 but I also tried testthumb functions 1 through 4 on an ARM7TDMI and qemu with the same results.

.globl testarm
testarm:
    mov r0,pc
    bx lr

armbounce:
    mov r0,lr
    bx lr

.thumb
.thumb_func
.globl testthumb1
testthumb1:
    mov r0,pc
    bx lr
    nop
    nop
    nop
bounce:
    bx lr
.thumb_func
.globl testthumb2
testthumb2:
    mov r2,lr
    mov r0,pc
    bl bounce
    bx r2
    nop
    nop
    nop
.thumb_func
.globl testthumb3
testthumb3:
    mov r2,lr
    mov lr,pc
    mov r0,lr
    bx r2
    nop
    nop
    nop
.thumb_func
.globl testthumb4
testthumb4:
    push {lr}
    ldr r2,=armbounce
    mov r1,pc  ;@ -4
    add r1,#5  ;@ -2
    mov lr,r1  ;@ +0
    bx r2      ;@ +2
    pop {r2}   ;@ +4
    bx r2
.thumb_func
.globl testthumb5
testthumb5:
    push {lr}
    ldr r2,=armbounce
    mov lr,pc
    bx r2
    pop {r2}
    bx r2
.thumb_func
.globl testthumb6
testthumb6:
    push {lr}
    bl testthumb6a
.thumb_func
testthumb6a:
    mov r0,lr
    pop {r2}
    bx r2

.thumb_func
.globl testthumb7
testthumb7:
    push {lr}
    bl armbounce_thumb
    pop {r2}
    bx r2

.thumb_func
.globl testthumb8
testthumb8:
    push {lr}
    bl armbounce_thumb_two
    pop {r2}
    bx r2

.align 4
armbounce_thumb:
    ldr r1,[pc]
    bx r1
.word armbounce

nop
.align 4
armbounce_thumb_two:
    bx pc
    nop
.code 32
    b armbounce

变成

d60080b4 <testarm>:
d60080b4:   e1a0000f    mov r0, pc
d60080b8:   e12fff1e    bx  lr

d60080bc <armbounce>:
d60080bc:   e1a0000e    mov r0, lr
d60080c0:   e12fff1e    bx  lr

d60080c4 <testthumb1>:
d60080c4:   4678        mov r0, pc
d60080c6:   4770        bx  lr
d60080c8:   46c0        nop         ; (mov r8, r8)
d60080ca:   46c0        nop         ; (mov r8, r8)
d60080cc:   46c0        nop         ; (mov r8, r8)

d60080ce <bounce>:
d60080ce:   4770        bx  lr

d60080d0 <testthumb2>:
d60080d0:   4672        mov r2, lr
d60080d2:   4678        mov r0, pc
d60080d4:   f7ff fffb   bl  d60080ce <bounce>
d60080d8:   4710        bx  r2
d60080da:   46c0        nop         ; (mov r8, r8)
d60080dc:   46c0        nop         ; (mov r8, r8)
d60080de:   46c0        nop         ; (mov r8, r8)

d60080e0 <testthumb3>:
d60080e0:   4672        mov r2, lr
d60080e2:   46fe        mov lr, pc
d60080e4:   4670        mov r0, lr
d60080e6:   4710        bx  r2
d60080e8:   46c0        nop         ; (mov r8, r8)
d60080ea:   46c0        nop         ; (mov r8, r8)
d60080ec:   46c0        nop         ; (mov r8, r8)

d60080ee <testthumb4>:
d60080ee:   b500        push    {lr}
d60080f0:   4a15        ldr r2, [pc, #84]   ; (d6008148 <armbounce_thumb_two+0x8>)
d60080f2:   4679        mov r1, pc
d60080f4:   3105        adds    r1, #5
d60080f6:   468e        mov lr, r1
d60080f8:   4710        bx  r2
d60080fa:   bc04        pop {r2}
d60080fc:   4710        bx  r2

d60080fe <testthumb5>:
d60080fe:   b500        push    {lr}
d6008100:   4a11        ldr r2, [pc, #68]   ; (d6008148 <armbounce_thumb_two+0x8>)
d6008102:   46fe        mov lr, pc
d6008104:   4710        bx  r2
d6008106:   bc04        pop {r2}
d6008108:   4710        bx  r2

d600810a <testthumb6>:
d600810a:   b500        push    {lr}
d600810c:   f000 f800   bl  d6008110 <testthumb6a>

d6008110 <testthumb6a>:
d6008110:   4670        mov r0, lr
d6008112:   bc04        pop {r2}
d6008114:   4710        bx  r2

d6008116 <testthumb7>:
d6008116:   b500        push    {lr}
d6008118:   f000 f80a   bl  d6008130 <armbounce_thumb>
d600811c:   bc04        pop {r2}
d600811e:   4710        bx  r2

d6008120 <testthumb8>:
d6008120:   b500        push    {lr}
d6008122:   f000 f80d   bl  d6008140 <armbounce_thumb_two>
d6008126:   bc04        pop {r2}
d6008128:   4710        bx  r2
d600812a:   46c0        nop         ; (mov r8, r8)
d600812c:   46c0        nop         ; (mov r8, r8)
d600812e:   46c0        nop         ; (mov r8, r8)

d6008130 <armbounce_thumb>:
d6008130:   4900        ldr r1, [pc, #0]    ; (d6008134 <armbounce_thumb+0x4>)
d6008132:   4708        bx  r1
d6008134:   d60080bc            ; <UNDEFINED> instruction: 0xd60080bc
d6008138:   46c0        nop         ; (mov r8, r8)
d600813a:   46c0        nop         ; (mov r8, r8)
d600813c:   46c0        nop         ; (mov r8, r8)
d600813e:   46c0        nop         ; (mov r8, r8)

d6008140 <armbounce_thumb_two>:
d6008140:   4778        bx  pc
d6008142:   46c0        nop         ; (mov r8, r8)
d6008144:   eaffffdc    b   d60080bc <armbounce>
d6008148:   d60080bc            ; <UNDEFINED> instruction: 0xd60080bc
d600814c:   e1a00000    nop         ; (mov r0, r0)

和调用并打印所有这些功能的结果。

And the results of calling and printing all of these functions

D60080BC testarm
D60080C8 testthumb1
D60080D6 testthumb2
D60080E6 testthumb3
D60080FB testthumb4
         testthumb5 crashes
D6008111 testthumb6
D600811D testthumb7
D6008127 testthumb8

那么,什么是这一切的做着?它与你的问题做。这与混合模式从拇指模式调用(以及从手臂是简单)

So what is all of this doing and what does it have to do with your question. This has to do with mixed mode calling from thumb mode (and also from arm which is simpler)

我一直在这个级别多年编程ARM和Thumb模式,并以某种方式都错一直有这个。我想程序计数器始终保持在了,所以LSb模式,我知道你也知道,你想拥有它的设置与否,当你做一个BX指令集。

I have been programming ARM and thumb mode at this level for many years, and somehow have had this wrong all along. I thought the program counter always held the mode in that lsbit, I know as you know that you want to have it set or not set when you do a bx instruction.

在ARM体系结构参考手册中的ARM处理器的CPU描述(如果你正在写汇编程序,你应该已经有这个,如果没有,也许大部分的问题将迎刃而解)。很早就

Very early in the CPU description of the ARM processor in the ARM Architectural Reference Manual (if you are writing assembler you should already have this, if not maybe most of your questions will be answered).

Program counter Register 15 is the Program Counter (PC). It can be used in most
      instructions as a pointer to the instruction which is two instructions after 
      the instruction being executed...

所以让我们检查,看看是什么真正的意思,并在ARM模式意味着未来两个指令,8个字节?并在拇指模式下,两个指令进取,或4个字节的前景如何?

So lets check and see what that really means, does that mean in arm mode two instructions, 8 bytes ahead? and in thumb mode, two instructions ahead, or 4 bytes ahead?

所以testarm验证程序计数器超前8个字节。这也是两个指令

So testarm verifies that the program counter is 8 bytes ahead. which is also two instructions.

testthumb1验证该节目是4字节前方,在这种情况下也是两个指令

testthumb1 verifies that the program is 4 bytes ahead, which in this case is also two instructions.

testthumb2

testthumb2

d60080d2:   4678        mov r0, pc
d60080d4:   f7ff fffb   bl  d60080ce <bounce>
d60080d8:   4710        bx  r2

如果程序计数器是两个指令的头,我们会得到0xD60080D8但我们反而得到0xD60080D6这是未来四个字节,这使得很多更有意义。单臂模式8个字节进取,Thumb模式提前4个字节,没有与那些领先于code被执行的解码指令(或数据)搞乱,只需添加4个或8。

if the program counter was two "instructions" head we would get 0xD60080D8 but we instead get 0xD60080D6 which is four bytes ahead, and that makes a lot more sense. Arm mode 8 bytes ahead, thumb mode 4 bytes ahead, no messing with decoding instructions (or data) that are ahead of the code being executed, just add 4 or 8.

testthumb3是一个希望,MOV LR,PC是特殊的,它不是。

testthumb3 was a hope that mov lr,pc was special, it isnt.

如果你没有看到的格局还没有,程序计数器的LSb不设置,我想这是有道理的分支表为例。所以MOV LR,PC在Thumb模式下不建立链接寄存器适合回报。

if you dont see the pattern yet, the lsbit of the program counter is NOT set, and I guess this makes sense for branch tables for example. So mov lr,pc in thumb mode does NOT set up the link register right for a return.

在testthumb4一个很痛苦的样子的确需要程序计数器这个地方code恰巧
最终基于精心放置的指令,计算返回地址,如果你改变MOV R1,PC,你必须重新调整附加BX R2之间的指令序列。现在为什么想不出我们只是做这样的事:

testthumb4 in a very painful way does take the program counter wherever this code happens to end up and based on carefully placed instructions, computes the return address, if you change that instruction sequence between mov r1,pc and bx r2 you have to retune the add. Now why couldnt we just do something like this:

add r1,pc,#1
bx r2

与你不能Thumb指令,与thumb2你也许可以。而且似乎有一些处理器(ARMv7的),同时支持ARM指令和Thumb / thumb2所以你可能在一个情况下,你会想这样做,但你不会加#1,因为一个thumb2加指令,如果有一个允许上登记并有三个操作数是一个4字节的拇指2指令。 (您需要添加#3)。

with thumb instructions you cant, with thumb2 you probably could. And there appear to be some processors (armv7) that support both arm instructions and thumb/thumb2 so you might be in a situation where you would want to do that, but you wouldnt add #1 because a thumb2 add instruction, if there is one that allows upper registers and has three operands would be a 4 byte thumb 2 instruction. (you would need to add #3).

所以testthumb5是直接从code我给你,导致这个问题的一部分,它崩溃。这是不是它是如何工作的,对不起,我误导人我会尽量回去修补我用这个。在做题

So testthumb5 is directly from the code I showed you that lead to part of this question, and it crashes. this is not how it works, sorry I mislead folks I will try to go back and patch up the SO questions I used this with.

testthumb6是一个实验,以确保我们都没有疯。一切都很好链接寄存器确实得到设定,所以LSb,这样当你BX LR以后它知道从位模式。

testthumb6 is an experiment to make sure we are all not crazy. All is well the link register does indeed get the lsbit set so that when you bx lr later it knows the mode from that bit.

testthumb7,这是从ARM端蹦床,你看到单臂模式将拇指模式的时候,在这种情况下,虽然我从Thumb模式将ARM模式连接器做的。为什么不能连接器做这种方式?因为在Thumb模式,至少你必须使用一个低寄存器,在游戏这一点上,code之后编译链接器没有知道什么注册它可能会破坏方式。在ARM模式虽然ip寄存器,不知道那是什么,也许R12,可以得到丢弃,我想这是保留给编译器使用。我知道在这种情况下,R1可以得到丢弃,并用它,这可以作为理想的。在armbounce code被调用它抓住了链接寄存器,如果在那里返回,这是一个Thumb指令(设置,所以LSb)在testthumb7功能BL armbounce_thumb后,正是我们希望它是。

testthumb7, this is derived from the ARM side trampoline that you see the linker doing when going from arm mode to thumb mode, in this case though I am going from thumb mode to arm mode. why cant the linker do it this way? because in thumb mode at least you have to use a low register and at this point in the game, after the code is compiled the linker has no way of knowing what register it can trash. In arm mode though the ip register, not sure what that is maybe r12, can get trashed, I guess it is reserved for the compiler to use. I know in this case that r1 can get trashed and used it, and this works as desired. the armbounce code gets called which grabs the link register if where to return to, which is a thumb instruction (lsbit set) after the bl armbounce_thumb in the testthumb7 function, exactly where we wanted it to be.

testthumb8这是GNU链接如何做它时,它需要从拇指模式去ARM模式。 BL指令设置去蹦床。然后他们做一些非常非常棘手,并且疯狂的寻找。

testthumb8 this is how the gnu linker does it when it needs to get from thumb mode to arm mode. the bl instruction is set to go to a trampoline. then they do something very very tricky, and crazy looking.

d6008140 <armbounce_thumb_two>:
d6008140:   4778        bx  pc
d6008142:   46c0        nop         ; (mov r8, r8)
d6008144:   eaffffdc    b   d60080bc <armbounce>

一个BX PC。我们知道,从上面的实验,该电脑是未来四个字节,我们也知道,LSb不SET。所以,这是什么意思是跳转到ARM code,它是这个后四个字节。该NOP是两个字节的间隔,那么我们就必须提前四个字节产生ARM指令并对准在四字节边界,我们做出无条件转移到任何地方,我们都去,这可能是AB的东西或LDR PC ,这取决于你需要走多远=东西。非常棘手。

A bx pc. We know from the experiments above that the pc is four bytes ahead, we also know that the lsbit is NOT SET. So what this is saying is branch to the ARM CODE that is four bytes after this one. The nop is a two byte spacer, then we have to generate an ARM instruction four bytes ahead AND ALIGNED ON A FOUR BYTE BOUNDARY, and we make that an unconditional branch to whatever place we were going, this could be a b something or a ldr pc,=something depending on how far you need to go. Very tricky.

原始BL arm_bounce_thumb_two建立链路寄存器BL后,返回到指令。蹦床不会修改链接注册它简单地执行分支。

The original bl arm_bounce_thumb_two sets up the link register to return to the instruction after that bl. The trampoline does not modify the link register it simply performs branches.

如果你想从手臂的拇指模式,然后做链接器做什么:

if you want to get to thumb mode from arm then do what the linker does:

...
bl myfun_from_arm
...


myfun_from_arm:
  ldr ip,[pc]
  bx ip
.word myfun

它看起来像这样,当他们这样做(不0xD6008xxx但0x0001xxxx从不同的二进制抢下)。

which looks like this when they do it (grabbed from a different binary not at 0xD6008xxx but at 0x0001xxxx).

   101f8:   eb00003a    bl  102e8 <__testthumb1_from_arm>


000102e8 <__testthumb1_from_arm>:
   102e8:   e59fc000    ldr ip, [pc]    ; 102f0 <__testthumb1_from_arm+0x8>
   102ec:   e12fff1c    bx  ip
   102f0:   00010147    andeq   r0, r1, r7, asr #2

所以无论这个IP寄存器(R12?),他们不介意捣毁它,我想你,欢迎你自己垃圾了。

so whatever this ip register is (r12?) they dont mind trashing it and I assume you are welcome to trash it yourself.

这篇关于的ARM / Thumb:在拇指$ ​​C $ c。使用BX,调用Thumb函数,或跳转到Thumb指令在另一个函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆