6

假设我们有以下 c++ 代码:

int var1;

__asm {
    mov var1, 2;
}

现在,我想知道的是,如果我不想在 __asm 指令之外定义 var1,我需要做什么才能将其放入其中。甚至可能吗?

谢谢

4

3 回答 3

14

为此,您需要使用 _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)并向上。

于 2009-09-08T21:05:55.847 回答
4

在汇编程序中创建 C 变量是不可能的:C 编译器必须知道变量(即它的类型和地址),这意味着它必须在 C 代码中声明。

可以做的是通过externC 中的声明访问在汇编程序中定义的符号。但这不适用于具有自动存储持续时间的变量,因为这些变量没有固定地址,而是相对于基指针引用。

如果您不想访问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

如果您不希望在操作堆栈时更改局部变量的相对地址(即使用pushor pop),则必须建立堆栈框架(即,将堆栈的基址保存在其中ebp并相对于该值的地址局部变量)如cedrou 的回答中所述。

于 2009-09-08T21:00:45.157 回答
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
}
于 2009-09-08T21:07:08.310 回答