我有一系列最终用SVC调用实现的函数。例如:
void func(int arg) {
asm volatile ("svc #123");
}
正如您可能想象的那样,SVC在'arg'上运行,可能是在寄存器中。如果我明确地在定义中添加了“noinline”属性,那么一切都会按照您的预期进行。
但是,如果函数在更高的优化级别内联,则将'arg'加载到寄存器中的代码将被省略 - 因为显然没有对'arg'的引用。
我尝试在'arg'本身的声明中添加'used'属性 - 但是在这种情况下gcc显然会产生警告。
我也尝试添加“虚拟”asm语句,例如
asm ("" : "=r"(arg));
但这似乎不起作用。 (也许我还需要在这里说挥发性的???)
无论如何,对一个例程进行显式函数调用似乎很不幸,该例程的主体基本上由一个asm语句组成。
答案 0 :(得分:4)
相关配方位于Assembler Instructions with C Expression Operands部分的GCC手册中,该手册使用sysint
与svc
指令相同的角色。我们的想法是使用指定的寄存器定义本地寄存器变量,然后使用扩展的asm
语法将输入和输出添加到内联汇编块。
我尝试编译以下代码:
#include <stdint.h>
__attribute__((always_inline))
uint32_t func(uint32_t arg) {
register uint32_t r0 asm("r0") = arg;
register uint32_t result asm("r0");
asm volatile ("svc #123":"=r" (result) : "0" (r0));
return result;
}
uint32_t foo(void) {
return func(2);
}
这是已编译(带-O2标志)对象文件的反汇编:
00000000 <func>:
0: ef00007b svc 0x0000007b
4: e12fff1e bx lr
00000008 <foo>:
8: e3a00002 mov r0, #2
c: ef00007b svc 0x0000007b
10: e12fff1e bx lr
func
内联展开,参数正确放入r0
。我相信volatile
是必要的,因为如果你不使用服务调用的返回值,那么编译器可能会认为代码的汇编代码不是必需的。
答案 1 :(得分:1)
您应该有一个asm块,编译器仍可以单独处理两个asm块,直到另行指定。第二个asm块的含义要求对第一个没有任何影响。
由于调用约定,您假设寄存器位于正确的位置。
这样的事情怎么样? (没有测试)
void func(int arg) {
asm volatile (
"mov r0, %[code]\n\t"
"svc #123"
:
: [code]"r" (code)
);
}
有关详细信息,请参阅ARM GCC Inline Assembler Cookbook。