3

我有一系列最终通过 SVC 调用实现的功能。例如:

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

正如您可能想象的那样,SVC 对可能在寄存器中的“arg”进行操作。如果我明确地在定义中添加一个“noinline”属性,一切都会如你所愿。

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

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

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

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

但这似乎并不普遍。(也许我也需要在这里说 volatile ???)

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

4

2 回答 2

4

相关配方在 GCC 手册中,在带有 C 表达式操作数的汇编器指令部分中,它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

funcr0被内联扩展并且参数被正确地放入。我认为这volatile是必要的,因为如果您不使用服务调用的返回值,那么编译器可能会认为汇编代码是不必要的。

于 2012-11-14T19:18:25.827 回答
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

于 2012-11-12T08:41:38.350 回答