【问题标题】:Defining a variable inside c++ inline assembly在 C++ 内联汇编中定义一个变量
【发布时间】:2010-11-26 15:29:19
【问题描述】:
假设我们有以下 c++ 代码:
int var1;
__asm {
mov var1, 2;
}
现在,我想知道的是,如果我不想在 __asm 指令之外定义 var1,我该怎么做才能将其放入其中。有可能吗?
谢谢
【问题讨论】:
-
只是添加authoritative source:虽然__asm 块可以引用C 或C++ 数据类型和对象,但它不能使用MASM 指令或运算符定义数据对象。具体来说,您不能使用定义指令 DB、DW、DD、DQ、DT 和 DF,或运算符 DUP 或 THIS。 将 cedrou 的答案作为解决方案。
标签:
c++
c
assembly
visual-c++
inline-assembly
【解决方案1】:
不可能在汇编程序中创建 C 变量:C 编译器必须知道变量(即它的类型和地址),这意味着它必须在 C 代码中声明。
可以做的是通过 C 中的 extern 声明访问在汇编器中定义的符号。但这不适用于具有自动存储持续时间的变量,因为这些变量没有固定地址,而是相对于基指针。
如果您不想访问asm 块之外的变量,您可以使用堆栈来存储汇编程序本地数据。请记住,在离开 asm 块时,您必须将堆栈指针恢复到之前的值,例如
sub esp, 12 ; space for 3 asm-local 32bit vars
mov [esp-8], 42 ; set value of local var
[...]
push 0xdeadbeaf ; use stack
[...] ; !!! 42 resides now in [esp-12] !!!
add esp, 16 ; restore esp
如果您不希望在操作堆栈时改变局部变量的相对地址(即使用push 或pop),则必须建立堆栈帧(即保存堆栈的基数)在ebp 和地址本地人相对于这个值)如cedrou's answer 中所述。
【解决方案2】:
为此,您需要使用 _declspec(naked) 创建一个“裸”方法,并自己编写通常由编译器创建的序言和结语。
序言的目的是:
- 设置 EBP 和 ESP
- 为局部变量保留堆栈空间
- 保存应该在函数体中修改的寄存器
结语必须:
这是一个标准的序言
push ebp ; Save ebp
mov ebp, esp ; Set stack frame pointer
sub esp, localbytes ; Allocate space for locals
push <registers> ; Save registers
和一个标准的结语:
pop <registers> ; Restore registers
mov esp, ebp ; Restore stack pointer
pop ebp ; Restore ebp
ret ; Return from function
然后,您的局部变量将从 (ebp - 4) 开始,向下到 (ebp - 4 - localbytes)。函数参数会从(ebp + 8)开始往上走。
【解决方案3】:
通过ESP寄存器操作调用栈上的可用空间来分配和释放局部变量,即:
__asm
{
add esp, 4
mov [esp], 2;
...
sub esp, 4
}
一般情况下,最好为调用函数建立一个“栈帧”,然后使用帧内的偏移量访问局部变量(和函数参数),而不是直接使用 ESP 寄存器,即:
__asm
{
push ebp
mov ebp, esp
add esp, 4
...
mov [ebp-4], 2;
...
mov esp, ebp
pop ebp
}