在c ++内联汇编中定义变量

时间:2009-09-08 20:50:19

标签: c++ c assembly

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

int var1;

__asm {
    mov var1, 2;
}

现在,我想知道的是,如果我不想在__asm指令之外定义var1,我需要做些什么才能把它放在里面。它甚至可能吗?

由于

3 个答案:

答案 0 :(得分:12)

要做到这一点,你需要用_declspec(裸)创建一个“裸”方法,并自己编写通常由编译器创建的prolog和epilog。

序言的目的是:

  • 设置EBP和ESP
  • 在堆栈上为局部变量保留空间
  • 保存应在函数体中修改的寄存器

一个结语必须:

  • 恢复已保存的寄存器值
  • 清理本地变量的保留空间

这是一个标准的序言

push        ebp                ; Save ebp
mov         ebp, esp           ; Set stack frame pointer
sub         esp, localbytes    ; Allocate space for locals
push        <registers>        ; Save registers

和标准的epilog:

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)开始向上。

答案 1 :(得分:3)

无法在汇编程序中创建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

如果您不想在操作堆栈时更改局部变量的相对地址(即使用pushpop),则必须建立堆栈帧(即保存ebp中堆栈的基础,并且相对于此值的地址位置),如cedrou's answer中所述。

答案 2 :(得分: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
}