branch - 在 Cortex-M3 中使用 B 指令(拇指)

标签 branch cortex-m thumb

我读到,在仅使用拇指模式的 Cortex-M3 中,每当我们写入 PC 时,我们必须确保目标地址 LSB 为“1”,以确保处理器保持在拇指模式。

此外,当我们使用“BX reg”时,reg 值必须具有 LSB = 1 才能启用拇指模式。

当我们在 cortex-m3 中使用“B 标签”时,情况怎么样?该“标签”的值 LSB = 0,因为 16 位/32 位指令与偶地址对齐。 'B label' 不等于 'PC := label' 吗?

‘B label’和‘BL label’是异常(exception)情况,PC的写入不会影响处理器模式吗?

谢谢。

最佳答案

对于bx(和blx)指令,目标地址的lsbit需要为1,当它进入pc时,1被去除。 b 指令是相对于 pc 的,arm 文档中显示的数学表明它是偶数。

通常,如果您让这些工具完成其工作,那么您在任何情况下都不必担心这一点。

拇指

.thumb

.globl _start
_start:
    b reset
    nop
    nop
.thumb_func
reset:
    nop
    nop
    nop
    nop
    ldr r0,=reset
    bx r0

然后

arm-none-eabi-as thumb.s -o thumb.o
arm-none-eabi-ld -Ttext=0x1000 thumb.o -o thumb.elf
arm-none-eabi-objdump -D thumb.elf 

这给出了

thumb.elf:     file format elf32-littlearm


Disassembly of section .text:

00001000 <_start>:
    1000:   e001        b.n 1006 <reset>
    1002:   46c0        nop         ; (mov r8, r8)
    1004:   46c0        nop         ; (mov r8, r8)

00001006 <reset>:
    1006:   46c0        nop         ; (mov r8, r8)
    1008:   46c0        nop         ; (mov r8, r8)
    100a:   46c0        nop         ; (mov r8, r8)
    100c:   46c0        nop         ; (mov r8, r8)
    100e:   4801        ldr r0, [pc, #4]    ; (1014 <reset+0xe>)
    1010:   4700        bx  r0
    1012:   10070000    andne   r0, r7, r0
    ...

分支会照顾自己

    1000:   e001        b.n 1006 <reset>
...    
00001006 <reset>:

分支中的编码以 16 位数量为单位,而不是以字节为单位,然后将其乘以 2(移位)以获得始终为偶数的字节地址。 pc 从来都不是奇数,奇数是您输入 bx 或 blx 的值。

现在因为我在重置之前使用了 .thumb_func ,它告诉汇编器这是一个拇指标签而不是 ARM 标签。因此,当我说请将复位地址加载到 r0 中时,汇编器然后为值 0x00001007 分配了一些数据,该值在反汇编中显示得很奇怪,但它确实存在。他们已经为我们设置了 lsbit

00001006 <reset>:
 ...
    100e:   4801        ldr r0, [pc, #4]    ; (1014 <reset+0xe>)
    1010:   4700        bx  r0
    1012:   10070000    andne   r0, r7, r0

现在如果您要删除 .thumb_func

100c:   46c0        nop         ; (mov r8, r8)
100e:   4801        ldr r0, [pc, #4]    ; (1014 <reset+0xe>)
1010:   4700        bx  r0
1012:   10060000    andne   r0, r6, r0

汇编器认为它是一个arm地址并且没有设置lsbit,并且此代码会崩溃。现在,如果您担心它,您可以随时添加额外的 orr r0,#1 但这实际上只是一个 hack。了解您使用的任何汇编器如何将标签声明为拇指标签而不是 ARM 。是的,gnu 汇编器知道这个代码段是拇指似乎很愚蠢,因为我们告诉它,但它无法弄清楚拇指代码中的标签是……拇指标签。非常愚蠢的工具。

而且我假设还有其他更详细的 gnu 汇编器指令,它们也允许您将其声明为函数或拇指标签或其他内容。当然,每个汇编器都是不同的,因此不要假设 gnu 汇编器指令适用于其他汇编器指令。

如果你混合 C 和 asm,C 编译器并不愚蠢,它知道 -mthumb 使所有函数和全局变量(标签)成为拇指,并且根据你在代码中使用它们的方式和位置,链接器放置正确的值。它甚至可以为您正确切换模式,bl main 在拇指代码中,其中 main 是arm代码,并且它在代码中为您放置了一个蹦床来切换模式。反之亦然,至少我已经看到该工具执行此操作(并在堆栈溢出答案中多次演示)。我不记得让它工作是否很棘手,您应该始终定期反汇编并确保链接器为您执行此操作,否则让它执行此操作,或者您始终可以自己执行此操作。

所以

请记住,只有 bx 和 blx 需要为拇指设置 lsbit,并为分支到 arm 重置两个 lsbit。 blx 和 bx 指令将删除该 lsbit 并在 pc 中留下偶数编号的 pc(非常简单,执行 mov r0,pc 然后在拇指代码中查看它)。

理想情况下,无条件和条件分支(不是 bx)永远不应该切换 ARM 到 ARM 和拇指到拇指的模式。 bl 也是如此,但我已经看到 gnu 工具可以帮助解决这个问题,如果您希望代码纯净,则将地址加载到寄存器中,工具必须正确执行该操作,否则整个工具链都会失败,而 blx 而不是 bl该标签而不是依赖工具链为您做蹦床。

关于branch - 在 Cortex-M3 中使用 B 指令(拇指),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21965365/

相关文章:

git - 从本地分支推送到不同的远程分支

django - 将 Django South 与多个代码分支结合使用的工作流程

assembly - ARM汇编中的函数地址有一个字节的偏移量?

linux - ARM汇编分支段错误

git - 清理提交日志质量较差的 git 分支

assembly - 软件卡在反汇编程序的 B.N 指令上——不知道是什么意思

rust - 找不到目标 thumbv7em-none-eabihf 的 sin()、cos()、log10()( float )

c - 查找哪条指令在 Cortex M3 上导致了陷阱

assembly - ARM 汇编不能同时使用立即数和 ADDS/ADCS

assembly - 我可以强制 Cortex-M4 ARM 处理器在 IT block 之外使用条件指令吗?