我尝试像这样使用内联汇编来操作全局变量,但编译器报错,显示saved_sp未定义。
__asm__ __volatile__ (
"movq saved_sp, %rsp\n\t" );
saved_sp 是全局声明为 static long saved_sp
的(针对一个文件)。我在这里犯了什么错误?
我尝试像这样使用内联汇编来操作全局变量,但编译器报错,显示saved_sp未定义。
__asm__ __volatile__ (
"movq saved_sp, %rsp\n\t" );
saved_sp 是全局声明为 static long saved_sp
的(针对一个文件)。我在这里犯了什么错误?
static
修饰符时出现“undefined reference to `saved_sp'”(这实际上是一个链接器错误,而不是编译器错误),但是当没有使用static
修饰符时运行良好,那么很可能编译器已经决定你的源文件中未使用saved_sp
,因此决定完全从传递给汇编程序的已编译代码中省略它。asm
块内部的汇编代码;它只是将其粘贴到生成的汇编代码中。因此,它不知道asm
块引用saved_sp
,如果C代码中没有其他内容读取它,那么编译器就有权决定它完全未被使用 - 尤其是如果启用了任何优化选项。used
属性(请参阅gcc
变量属性文档,该文档在页面中部,例如:documentation of variable attributes)告诉gcc
,saved_sp
被某些无法看到的东西使用,因此防止它选择放弃它。static long __attribute__((used)) saved_sp;
$ 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
$
这是来自一个使用gcc 4.4.5的32位Debian squeeze系统,这是我手头最接近的系统;-m64
在你的系统上可能是不必要的。
最好使用输入和输出参数:
__asm__ __volatile__ (
"movq %0, %%rsp\n\t"
: : "r"(saved_sp) : "memory"
);
在汇编阶段,有时会存在一些不是符号的变量(例如堆栈变量或寄存器)。此外,您需要清空整个内存,以确保在将saved_sp
存储在RSP之后,没有堆栈变量保留在寄存器中。
正如我在评论中所指出的,以下代码可以在64位Ubuntu上使用gcc 4.4.4
编译(并生成正确的机器码):
long saved_sp;
int main() {
__asm__ __volatile__ (
"movq saved_sp, %rsp\n\t" );
}
也许问题完全可能是其他原因(例如缺少#include
,导致saved_sp
实际上未定义?编辑:既然你说它是static
,那么这不太可能。)
static
均如此。 - NPEsaved_sp(%rip)
这样进行引用,而不是使用32位绝对地址寻址模式。此外,在这里缺少一个 "memory"
污点或 "m"
源操作数来告诉编译器该全局变量在此处被读取。 (在这种情况下,Antti 是正确的,因为我们正在修改 RSP 本身,尽管地址未逃逸的本地变量不必考虑内存污点。) - Peter Cordes
gcc
版本。在我的Ubuntu上,gcc 4.4.4
对您的代码很满意。 - NPE