【问题标题】:mix c and assembly cortex-m0混合 c 和组装 cortex-m0
【发布时间】:2020-05-07 14:46:32
【问题描述】:

我想在 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"
        );
}

但不幸的是我有问题:

  • 我的程序因此而崩溃。
  • 编译器声称我的“虚拟”例程没有返回值

编辑,工作代码:我将代码移动到单独的 .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

【问题讨论】:

  • 避免内联汇编通常是个好主意。将您的例程放入汇编文件中,然后自行将其汇编为目标文件。
  • 对于你应该做的代码应该可以正常工作。它在我的机器上编译得很好。如果有问题,它可能在其他地方。
  • 另外,添加gcc -v的输出。
  • 您没有返回值,这就是它抱怨的原因,编译器无法识别包括返回在内的内联汇编功能,因此它看不到返回值(在 C 语言中)。添加任何返回值 return 0;这应该会消失

标签: c assembly arm cortex-m


【解决方案1】:

使用真正的汇编

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

调用约定允许修改 r0-r3,在 r0 中返回,你没有触及 r4,r5,r6,r7,lr 所以不需要推送这些。

很丑但是你可以用gcc、gnu汇编器来组装它,因为是首选(arm-whatever-as)

【讨论】:

  • 可能需要.type dummy, #function 才能正确链接。
  • 我将代码移到了一个单独的 .s 文件中,现在它似乎可以工作了,谢谢
【解决方案2】:

naked 函数的末尾脱落实际上并不是一个错误。在这种情况下,警告是在 GCC 5.4 之前的某个地方修复的 GCC 错误。 (但 code-gen 是相同的;警告的旧 GCC 版本不会破坏您的代码。)

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

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

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

我不是 ARM 专家,但您使用内联 asm / naked 函数的方式并没有错。 naked 的主体基本上是唯一理智的用途 - GNU C "Basic" asm 的案例(无限制)。

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


From Godbolt, gcc5.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 不变,那么您可以直接返回 bx lr 而不是将其弹回 PC。

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


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

【讨论】:

  • 谢谢你的回答,对我很有用。我问这个问题是因为我不知道调用约定,以及是否可以通过 R0 寄存器返回值。我在想这可能是坠机的原因。阅读答案,我发现我的原始代码或多或少都很好并且可以正常工作。然后我在代码的另一部分发现了问题。代码实际上是在做一些 SPI bitbanging,它崩溃了,因为我违反了一些时间。
猜你喜欢
  • 2020-03-22
  • 2016-06-19
  • 1970-01-01
  • 2017-12-22
  • 2021-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多