混合 c 和装配 cortex-m0

mix c and assembly cortex-m0

我想在 GCC C 中为 cortex-m0 编写一个例程,其中混合了 C 和汇编代码。我正在尝试这样的事情

__attribute__((naked)) uint8_t dummy(uint8_t value)
{
    asm volatile (
            "push   {r1-r7, lr}\n\t"
             // R0 contains input value
             //here i do some operation on registers r0..r7         
             //.....
             //I guess result will be in the R0 register
            "MOV R0, R3\n\t"

            "pop    {r1-r7, pc}\n\t"
        );
}

但不幸的是我遇到了问题:

编辑,工作 CODE:I 将代码移至单独的 .s 文件,最终解决方案如下所示

    .syntax unified
    .arch armv6-m
    .text
    .thumb
    .thumb_func
    .align 1
    .globl    dummymethod
    .type    dummymethod, %function
dummymethod:
    .fnstart
            PUSH    {r1-r7, lr}
            // here some operation on registers R0..R7

            MOV R0, R3 //result is in R0

            pop {r1-r7, pc}

    .pool
    .cantunwind
    .fnend
    .size   dummymethod,.-dummymethod

使用真正的汇编

.cpu cortex-m4
.thumb
.globl dummy
.thumb_func
dummy:
    mov r0,r3
    bx lr

调用约定允许修改 r0-r3,return 在 r0 中,您没有触及 r4、r5、r6、r7、lr,因此无需推送它们。

丑陋,但你可以 assemble 它与 gcc,gnu assembler 一样,是首选(arm-whatever-as)

naked 函数的末尾掉落实际上不是错误。在这种情况下,警告是 GCC 错误,已在 GCC 5.4 之前的某处修复。 (但代码生成是相同的;发出警告的旧 GCC 版本不会破坏您的代码。)

用 C + asm 编写 naked 函数只有几个小好处:

  • 如果您的代码可以为任一模式编译,则让编译器发出 thumb 与 ARM 指令。 (Cortex-M0 仅适用于拇指,因此对您的情况没有任何好处。)
  • 调试信息、动态库函数大小和其他类似的元数据。
  • 让编译器为您进行 C++ 名称修改,而不是声明它 extern "C",如果您正在编写 C++。
  • 您可以在与其交互的一些实际 C 代码旁边维护它。

否则你还不如单独写一个asm文件呢。它仍然不能像 GNU C Extended asm 语句周围的非 naked 包装函数那样内联。

我不是 ARM 专家,但是您使用内联 asm / naked 函数的方式没有任何问题。 [=11 的主体=] 基本上是 GNU C "Basic" asm(无限制)唯一合理的用例。

如果您使用正确的 GCC 选项编译它,GCC 应该发出您在独立 asm 中使用的相同指令。 (尽管不是 .cantunwind 以防万一。)


From Godboltgcc5.4.1 -O2 -Wall -mcpu=cortex-m0 -mthumb -fverbose-asm 编译得很干净(没有警告)。这是 asm 输出,指令未过滤,但一些手动编辑以删除指令和标签我认为只是混乱(包括调试信息):

        .syntax unified
        .cpu cortex-m0
        .fpu softvfp

        .text
        .global dummy
        .code   16
        .thumb_func
        .type   dummy, %function
dummy:
        .syntax divided
        push   {r1-r7, lr}
        MOV R0, R3
        pop    {r1-r7, pc}

        .thumb
        .syntax unified
        .cfi_endproc
        .size   dummy, .-dummy

因为你只使用拇指 CPU 你不需要 需要 通过 bx lr 拇指互通,但正如@old timer 指出的那样: 如果你可以在你的功能期间保持 LR 不变,那么你可以 return 和 bx lr 而不是将它弹出回 PC。

另请注意,第一个 arg 是在 R0 中传递的,因此读取 R3 是在读取您的原​​型所说的不是输入的寄存器。


将其移至独立的 asm 文件完全没问题,同样有效,而且可能是更好的选择。但是既然你问的是用 naked 函数来做,那应该也可以。