gcc arm - 使用内联asm语句内联函数时,保留args

时间:2012-11-12 04:17:39

标签: gcc arm inline

我有一系列最终用SVC调用实现的函数。例如:

void func(int arg) {
    asm volatile ("svc #123");
}

正如您可能想象的那样,SVC在'arg'上运行,可能是在寄存器中。如果我明确地在定义中添加了“noinline”属性,那么一切都会按照您的预期进行。

但是,如果函数在更高的优化级别内联,则将'arg'加载到寄存器中的代码将被省略 - 因为显然没有对'arg'的引用。

我尝试在'arg'本身的声明中添加'used'属性 - 但是在这种情况下gcc显然会产生警告。

我也尝试添加“虚拟”asm语句,例如

asm ("" : "=r"(arg));

但这似乎不起作用。 (也许我还需要在这里说挥发性的???)

无论如何,对一个例程进行显式函数调用似乎很不幸,该例程的主体基本上由一个asm语句组成。

2 个答案:

答案 0 :(得分:4)

相关配方位于Assembler Instructions with C Expression Operands部分的GCC手册中,该手册使用sysintsvc指令相同的角色。我们的想法是使用指定的寄存器定义本地寄存器变量,然后使用扩展的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