混合c和组件cortex-m0

混合c和组件cortex-m0,c,assembly,arm,cortex-m,C,Assembly,Arm,Cortex M,我想在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 register

我想在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"
        );
}
    .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
但不幸的是,我有问题:

  • 我的程序因此崩溃
  • 编译器声明我的“伪”例程没有返回值
编辑,工作代码:我将代码移动到单独的.s文件中,最终的解决方案如下所示

__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"
        );
}
    .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,在r0中返回,您不接触r4、r5、r6、r7、lr,因此无需推送它们


丑陋但是你可以用gcc来组装它,gnu汇编程序是首选的(arm不管是什么)

裸函数的末尾掉下来实际上不是一个错误。在这种情况下,警告是一个GCC错误,它在GCC 5.4之前的某个地方被修复。(但CodeGen是相同的;警告的旧GCC版本不会破坏您的代码。)

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

  • 如果您有可以为任一模式编译的代码,则让编译器发出thumb vs.ARM指令。(Cortex-M0仅适用于拇指,因此对您的情况没有好处。)
  • 调试信息、动态库函数大小以及其他类似的元数据
  • <> LI>让编译器为您做C++名称的修改,而不是声明它“代码>外部”C”/代码>,如果您正在编写C++。
  • 您可以在与之交互的实际C代码旁边维护它
否则,您最好只编写一个单独的asm文件。它仍然不能像GNU C扩展asm语句周围的非裸包装函数那样内联

我不是ARM专家,但您使用内嵌asm/
裸版
函数的方式没有问题。
裸版
的主体基本上是GNU C“基本”asm的唯一合理使用案例(无约束)

如果您使用正确的GCC选项编译此命令,GCC应该发出与您在备用asm中使用的相同的指令。(虽然不是
。但如果有必要,可以展开
。)


gcc5.4.1-O2-Wall-mcpu=cortex-m0-mthumb-fverbose asm
编译干净(无警告)。这是asm输出,未过滤指令,但一些手动编辑以删除指令和标签,我认为这些都是杂乱无章的(包括调试信息):

由于您使用的是thumb-only CPU,您不需要通过
bx-lr
进行thumb互通,但正如@old-timer所指出的:如果您可以在运行过程中保持lr未被触动,那么您只需返回
bx-lr
即可,而无需将其弹出到PC中

还要注意,第一个arg在R0中传递,因此读取R3就是读取一个寄存器,而您的原型表示该寄存器不是输入



将其移动到独立的asm文件完全可以,同样有效,而且可能是更好的选择。但是,由于您要求使用
裸体
函数进行此操作,因此也应该可以使用。

一般来说,避免使用内联汇编是一个好主意。把你的程序放到一个汇编文件中,然后自己把它汇编成一个对象文件。你应该知道,代码应该可以正常工作。它在我的机器上编译得很好。如果有问题,它可能在其他地方。另外,添加
gcc-v
的输出。您没有返回值,这就是它抱怨的原因,编译器无法识别包含返回的内联汇编功能,因此它看不到返回值(在C语言中)。添加任何返回值返回0;这应该会消失。可能需要一个
.type dummy,#function
来正确链接。我将代码移到了一个单独的.s文件中,现在它似乎可以工作了,谢谢你的回答,它对我非常有用。我问这个问题是因为我不知道如何调用约定,以及是否可以通过R0寄存器返回值。我在想这可能就是这次坠机的原因。在阅读答案时,我发现我的原始代码或多或少都很好,并且工作正常。然后我在代码的另一部分发现了问题。这段代码实际上是在做一些SPI比特攻击,它崩溃了,因为我违反了一些定时。