混合c和组件cortex-m0
我想在GCC C中为cortex-m0编写一个例程,其中混合了C和汇编代码。我正在尝试这样的东西混合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
__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
但不幸的是,我有问题:
- 我的程序因此崩溃李>
- 编译器声明我的“伪”例程没有返回值
__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比特攻击,它崩溃了,因为我违反了一些定时。