如何在没有扩展内联 asm 的情况下在 gcc 内联汇编中声明和初始化局部变量?
Posted
技术标签:
【中文标题】如何在没有扩展内联 asm 的情况下在 gcc 内联汇编中声明和初始化局部变量?【英文标题】:How to declare and initialize local variables in gcc inline assembly without extended inline asm? 【发布时间】:2013-01-04 10:09:57 【问题描述】:我知道这是一个非常基本的问题,但我真的坚持下去。事实上,我绝对是 GCC 语法的新手。
我想在不使用扩展内联汇编的情况下拥有局部变量(带标签的堆栈地址)。类似于 Intel 语法中的以下代码:
DATA1 DB 100
MOV AL, DATA1
这是我猜想可以在 GCC 中替代的代码:
int someFunction(int x)
__asm__ volatile(
"function1:"
".data;"
".2byte $4 data1 ;"
".text;"
"pushq %rbp;"
"movq %rsp , %rbp ;"
"movl var , %eax;" // this is source of error
"popq %rbp;"
"leaveq;"
"retq ; "
);
但是这段代码导致了这个错误:
未找到架构 x86_64 的符号
我可以在 x86 中使用全局变量,但在 x64 或 x86_x64 中会出现相同的结果。
设置:LLVM 4.1; Xcode 4 中使用的 Cocoa
正确的语法是什么?
【问题讨论】:
注意DATA1 DB 100
是静态存储。像static char DATA1 = 100;
非static
局部变量(自动存储类)存在于寄存器中,如果寄存器用完或需要获取它们的地址,则存在于堆栈中。所以同一个函数可以在多个线程中运行而不会踩到自己:它是可重入的。
【参考方案1】:
GCC 内联汇编器不支持局部变量,请使用GCC's extended syntax。
如果您对 AT&T 语法感到不舒服,可以使用 use Intel syntax on GCC 的方法。
这是一个很棒的how-to on GCC asm。
【讨论】:
但是你怎么知道变量在堆栈中的起始位置呢?你只是假设 gcc 在开始时创建一个新的堆栈帧并假设第一个局部变量就在它上面还是什么? @greatwolf:不,这个建议完全是垃圾。 不要尝试硬编码 gcc 如何进行堆栈布局。即使您确实知道它相对于堆栈指针的位置,编译器也会假定您没有修改它。您必须使用带有输入/输出操作数的扩展内联汇编来安全地读取、写入或读取+写入局部变量。除非您喜欢编写仅适用于具有特定 gcc 版本的未优化调试版本的代码,并且在您更改周围代码时仍会中断。 @PeterCordes 谢谢,我可能在那里大声思考,我会从答案中删除那一点 也相关:gcc.gnu.org/wiki/ConvertBasicAsmToExtended - 你应该永远在函数中使用 Basic asm。仅在全局范围内,或在不能使用 C 语句或扩展 asm 的__attribute__((naked))
函数中,您编写包括 ret
在内的整个函数体,并自己处理调用约定。做asm("lfence")
或不影响内存或寄存器的操作在技术上是安全的,但通常你想知道它是按wrt 排序的。内存访问和周围 C 中的东西。
顺便说一句,asm("movl $123, global_var")
并不安全:它不会告诉编译器您修改了该内存。它将无错误地编译和组装,但它仍然不安全并且会中断。 How can I indicate that the memory *pointed* to by an inline ASM argument may be used?以上是关于如何在没有扩展内联 asm 的情况下在 gcc 内联汇编中声明和初始化局部变量?的主要内容,如果未能解决你的问题,请参考以下文章