【问题标题】:Creating named variables in the stack在堆栈中创建命名变量
【发布时间】:2017-07-11 00:14:13
【问题描述】:

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

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

【问题讨论】:

  • 您可以为偏移量创建“equ”,但这不是非常可靠的解决方案,因为它们仅在基指针正确时才有效,因此仍然由程序员来完成所有类型/ptr 检查。另外,如果您在单个文件中有多个函数,则局部变量的名称可能会发生冲突。当我年轻且不太聪明的时候,我在 ASM 中做过大项目,我使用 r32 + equ_offsets 来模仿 OOP,这部分工作正常。如果你把几个变量组合成“对象”,创建函数来操作它们,比如lea ebx,[ebp-30] ; object "X" instancecall Xsomething...然后我终于学会了C++。

标签: assembly nasm fasm


【解决方案1】:

FASM

FASM 通过 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

%$localsize 变量由 %local 指令在内部使用,并且必须在当前上下文中定义,然后才能使用 %local 指令。

其他草率的方法

可以

%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

汇编程序员方式

真正的汇编程序员使用 cmets[citation needed] 来说明他们代码的意图。
并且只在vi 中编写代码。还是emacs

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

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

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

此外,从本体论的角度来看,这毫无意义:如果您想使用高级功能,那么像 C 这样的语言更适合,并且必须重新考虑汇编的使用。相反,如果你想学习如何进行低级编程,那么这样的宏是学习过程的障碍。

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


1 现在这不再是汇编了...
2 高级宏让您可以轻松地重构代码,这一点非常重要。不过,人们应该暂停片刻,质疑自己在预期/需要重要重构时使用汇编的选择。

【讨论】:

  • "真正的汇编程序员使用 cmets" ...阅读别人的代码时,我有时会觉得“我很难编码,所以你应该很难阅读”; -)
  • @Tommylee2k 加上那一刻,当您比作者更了解它时:/ ... ;) ... 我同意评论的事情,当您将程序集用于与性能相关的事情时完全有效,只重写大项目的几个瓶颈。我可以想象拥有更复杂的语言结构对大型 ASM 项目有何帮助,但根据我自己的经验(总共超过 500kB 的 ASM 文件)本地人的名字绝对不是大型 asm 项目的最大问题 :) )。 (即使我不是真正的程序员,我也同意,因为我不使用viemacs,只使用joe
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2011-04-28
    • 2022-10-05
    • 2015-12-22
    • 1970-01-01
    • 1970-01-01
    • 2017-10-21
    • 2019-01-20
    • 2018-05-04
    • 1970-01-01
    相关资源
    最近更新 更多