【问题标题】:Using B instructions in Cortex-M3 (thumb)在 Cortex-M3 中使用 B 指令(拇指)
【发布时间】:2014-02-23 07:20:07
【问题描述】:

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

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

我们在 cortex-m3 中使用“B 标签”的情况如何?由于 16 位/32 位指令与偶数地址对齐,因此该“标签”将具有 LSB = 0 的值。 'B label' 不等同于 'PC := label' 吗?

'B label'和'BL label'是不是PC写不会影响处理器模式的例外情况?

谢谢。

【问题讨论】:

    标签: branch cortex-m3 thumb


    【解决方案1】:

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

    一般来说,如果您让工具完成它们的工作,您在任何情况下都不必担心这一点。

    拇指.s

    .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,它告诉汇编器这是一个拇指标签而不是手臂标签。因此,当我说请将复位地址加载到 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。了解您使用的任何汇编程序如何将标签声明为拇指标签而不是手臂。是的,gnu 汇编器知道这个代码段是 thumb 似乎很愚蠢,因为我们告诉它但它无法弄清楚拇指代码中的标签是......拇指标签。非常愚蠢的工具。

    我会假设还有其他更详细的 gnu 汇编器指令也允许您将其声明为函数或拇指标签或其他任何东西。当然,每个汇编器都是不同的,所以不要假设 gnu 汇编器指令适用于其他汇编器指令。

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

    所以

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

    理想情况下,无条件和有条件分支(不是 bx)不应该切换模式 arm to arm 和 thumb to thumb。 bl 也一样,但我已经看到 gnu 工具可以帮助解决这个问题,如果你想要你的代码纯然后将地址加载到工具必须正确执行的寄存器中,否则整个工具链都会失败,并且 blx 而不是 bl该标签,而不是依赖工具链为您做蹦床。

    【讨论】:

      【解决方案2】:

      “B 标签”不等同于“PC := label”吗?

      它实际上是PC := PC + offset * 2,在指令中编码了偏移量。汇编器/链接器必须计算这个偏移量。

      有关指令编码的详细信息,请参阅 Armv7-M 的 ARM 架构参考手册。

      'B label'和'BL label'是不是PC写不会影响处理器模式的例外情况?

      是的。最后一位在B(L) label 指令中编码,因此无法更改拇指模式位。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-01-19
        • 1970-01-01
        • 1970-01-01
        • 2013-07-28
        • 1970-01-01
        • 1970-01-01
        • 2012-05-15
        • 2017-06-07
        相关资源
        最近更新 更多