混合 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"
);
}
但不幸的是我遇到了问题:
- 我的程序因此而崩溃。
- 编译器声称我的 "dummy" 例程没有 return 值
编辑,工作 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 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 不变,那么你可以 return 和 bx lr
而不是将它弹出回 PC。
另请注意,第一个 arg 是在 R0 中传递的,因此读取 R3 是在读取您的原型所说的不是输入的寄存器。
将其移至独立的 asm 文件完全没问题,同样有效,而且可能是更好的选择。但是既然你问的是用 naked
函数来做,那应该也可以。
我想在 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"
);
}
但不幸的是我遇到了问题:
- 我的程序因此而崩溃。
- 编译器声称我的 "dummy" 例程没有 return 值
编辑,工作 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 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 不变,那么你可以 return 和 bx lr
而不是将它弹出回 PC。
另请注意,第一个 arg 是在 R0 中传递的,因此读取 R3 是在读取您的原型所说的不是输入的寄存器。
将其移至独立的 asm 文件完全没问题,同样有效,而且可能是更好的选择。但是既然你问的是用 naked
函数来做,那应该也可以。