在堆栈中创建命名变量

Creating named variables in the stack

有没有办法在堆栈中创建命名变量而不是通过偏移量引用它们:

sub esp, 0x10 ; 4 variables of 4 bytes

mov DWORD [ebp-4], 0xf ; 1st var
mov DWORD [ebp-8], 0xff  ; 2nd var
; and so on

FASM

FASM 通过 ad-hoc FASM 自带的特制宏来支持局部变量。

include 'win32ax.inc' 

.code

  start:
        mov ax, 1

        call foo


  proc foo

      ;Local variables

      locals
        var1 dd ?
        var2 dw ?
      endl


      ;Use them as expected
      mov eax, [var1]
      lea ebx, [var2]

   ret
  endp 

也就是编译1

:00401000 66B80100                mov ax, 0001
:00401004 E800000000              call 00401009
:00401009 55                      push ebp
:0040100A 89E5                    mov ebp, esp
:0040100C 83EC08                  sub esp, 00000008
:0040100F 8B45F8                  mov eax, dword ptr [ebp-08]
:00401012 8D5DFC                  lea ebx, dword ptr [ebp-04]
:00401015 C9                      leave
:00401016 C3                      ret

NASM

NASM 使用 %local 指令也支持局部变量。

引自手册:

silly_swap: 
    %push mycontext             ; save the current context 
    %stacksize small            ; tell NASM to use bp 
    %assign %$localsize 0       ; see text for explanation 
    %local old_ax:word, old_dx:word 

    enter   %$localsize,0   ; see text for explanation 
    mov     [old_ax],ax     ; swap ax & bx 
    mov     [old_dx],dx     ; and swap dx & cx 
    mov     ax,bx 
    mov     dx,cx 
    mov     bx,[old_ax] 
    mov     cx,[old_dx] 
    leave                   ; restore old bp 
    ret                     ; 

    %pop                        ; restore original context

The %$localsize variable is used internally by the %local directive and must be defined within the current context before the %local directive may be used.

其他草率的方法

可以

%define SUPER_VAR ebp-4
%define MEGA_VAR ebp-8

mov DWORD [SUPER_VAR], 0xf
mov DWORD [MEGA_VAR], 0xff

然而,这隐藏了变量在堆栈中并假定正确设置帧指针的事实。

稍微好一点的方法:

%define SUPER_VAR 4
%define MEGA_VAR 8

mov DWORD [ebp-SUPER_VAR], 0xf
mov DWORD [ebp-MEGA_VAR], 0xff

汇编程序员之道

真正的汇编程序员使用注释[citation needed]来陈述他们代码的意图。
并且只在vi写代码。或者是 emacs?

mov DWORD [ebp-4], 0xf           ;SUPER_VAR
mov DWORD [ebp-8], 0xff          ;MEGA_VAR

汇编语言的主要优势在于其简单的语法和完整的信息方法(没有任何隐藏,程序员控制一切)。

虽然使用 high-level 宏 2 没有任何问题,但混合高级和低级方法会导致源文件更难被专家解析。

此外,从本体论的角度来看,它没有什么意义:如果你想使用 high-level 特性,那么像 C 这样的语言更适合,必须重新考虑使用汇编。相反,如果您想学习如何进行 low-level 编程,那么此类宏会阻碍学习过程。

最后,宏不是魔法。虽然非常灵活,但程序员迟早会遇到他们的限制。
例如,我没有深入研究 FASM 和 NASM 对 aligned 局部变量的支持。


1 此时这不再是汇编了...
2 High-level 宏让你轻松重构代码,这一点非常重要。不过,人们应该暂停片刻,质疑自己在重要重构 expected/needed.

时使用汇编的选择

FASM 执行此类操作的本机方法是通过 virtual 指令:

参数:

virtual at ebp + 8
  .arg1 dd ?
  .arg2 dq ?
end virtual

对于局部变量:

virtual at ebp - 10h  ; the offset is the size of the local variables area.
  .var1        dd ?
  .local_array rb 12
end virtual

不同种类的 proc 宏在内部使用 virtual