如何在gcc内联汇编中使用全局变量

时间:2012-01-10 20:55:06

标签: c linux gcc assembly inline-assembly

我正在尝试使用这样的内联汇编,用于全局变量,但是编译器通过对 saved_sp 进行未定义的引用来给出错误。

__asm__ __volatile__ (
        "movq saved_sp, %rsp\n\t" );

saved_sp 全局声明为static long saved_sp(对于文件而言)。我在这做什么错?

3 个答案:

答案 0 :(得分:6)

saved_spstatic时,如果失败并且“未定义引用`saved_sp'”(实际上是链接器错误,而不是编译器错误)如果不是,那么编译器似乎已经决定在源文件中没有使用saved_sp,因此决定从传递给汇编程序的已编译代码中完全省略它。

编译器不理解asm块内的汇编代码;它只是将其粘贴到它生成的汇编代码中。因此,它不知道asm块引用saved_sp,如果C代码中没有其他内容可以从中读取,则可以自由决定它是否完全未使用 - 特别是如果您有任何内容已启用优化选项。

您可以通过添加gcc属性告诉saved_sp used被无法看到的内容使用,从而阻止它选择将其丢弃(请参阅static long __attribute__((used)) saved_sp; documentation of variable attributes,大约是页面的一半),例如:

$ cat test.c
#ifdef FIXED
static long __attribute__((used)) saved_sp;
#else
static long saved_sp;
#endif

int main(void)
{
  __asm__ __volatile__ (
        "movq saved_sp, %rsp\n\t" );
}

$ gcc -m64 -o test test.c
$ gcc -m64 -O1 -o test test.c
/tmp/ccATLdiQ.o: In function `main':
test.c:(.text+0x4): undefined reference to `saved_sp'
collect2: ld returned 1 exit status
$ gcc -m64 -DFIXED -O1 -o test test.c
$ 

这是一个完全有效的例子:

-m64

(这是来自32位Debian挤压系统,带有gcc 4.4.5,这是我最接近的东西; {{1}}在您的系统上可能是不必要的。)

答案 1 :(得分:1)

正如我在评论中指出的那样,以下在64位Ubuntu上使用gcc 4.4.4编译(并生成正确的机器代码):

long saved_sp;

int main() {
  __asm__ __volatile__ (
        "movq saved_sp, %rsp\n\t" );
}

也许问题可能完全是其他问题(缺少#include,因此saved_sp实际上没有定义?编辑:现在您说它是static ,我想这不太可能。)

答案 2 :(得分:1)

最好使用输入和输出参数:

__asm__ __volatile__ ( 
    "movq %0, %%rsp\n\t"
    : : "r"(saved_sp) : "memory"
);

在组装阶段通常可能存在一些根本不是符号的变量(例如堆栈变量或寄存器。另外,你想要破坏整个内存,以确保没有堆栈变量保存在寄存器中saved_sp存储在RSP之后。