【问题标题】:What exactly are the variables in assembly?汇编中的变量到底是什么?
【发布时间】:2020-09-07 19:17:01
【问题描述】:

我是 x86 汇编的新手,最近一直在使用 nasm 进行一些实验,并在 Windows 10 机器上运行该程序。

我有这个代码:

global _start
extern  _GetStdHandle@4
extern  _WriteFile@20
extern  _ExitProcess@4
section .data
    message db "1234"
section .text
_start:
    call print
    call _ExitProcess@4
print:
    ; DWORD  bytes;    
    mov     ebp, esp
    sub     esp, 4

    ; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
    push    -11
    call    _GetStdHandle@4
    mov     ebx, eax

    ; WriteFile( hstdOut, message, length(message), &bytes, 0);
    push    0
    lea     eax, [ebp-4]
    push    eax
    push    4
    push    message
    push    ebx
    call    _WriteFile@20
    mov     esp, ebp
    ret

    ; ExitProcess(0)

我使用以下命令组装它:

nasm -f win32 out.asm
link out.obj /entry:start /subsystem:console "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.18362.0\um\x86\kernel32.lib"

在 cmd 上运行时,它会按预期输出“1234”

现在在组装和运行以下代码时,程序直接推送“1234”而不是推送消息

global _start
extern  _GetStdHandle@4
extern  _WriteFile@20
extern  _ExitProcess@4
section .data
    message db "1234"
section .text
_start:
    call print
    call _ExitProcess@4
print:
    ; DWORD  bytes;    
    mov     ebp, esp
    sub     esp, 4

    ; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
    push    -11
    call    _GetStdHandle@4
    mov     ebx, eax

    ; WriteFile( hstdOut, message, length(message), &bytes, 0);
    push    0
    lea     eax, [ebp-4]
    push    eax
    push    4
    push    "1234"
    push    ebx
    call    _WriteFile@20
    mov     esp, ebp
    ret

什么都不输出

为什么? message 有哪些“1234”没有的信息?推送消息时,程序是否只是推送存储“1234”的内存地址?如果是这样,我可以将“1234”存储在其他地方,而不是在不创建变量的情况下推送其地址吗?

【问题讨论】:

  • 是的,你需要传递地址。是的,您可以将其存放在任何您喜欢的地方。至于你是否认为变量并不重要。
  • 在汇编中考虑变量的另一种方式是它们只是特定内存地址的标签。 (例如,message db "1234"message"1234" 的起始字节所在的地址)当您想要存储在该地址的内容时,您可以通过将变量括在 [...] 中来取消引用该变量,例如[message].
  • 好的,尝试在“push o”行之前推“1234”,而不是将 esp 移动到 edi,然后推 edi,而不是“1234”,它似乎正在工作

标签: windows assembly windows-10 nasm


【解决方案1】:

变量是一种逻辑结构——变量有生命周期,有的短,有的长。它们可以产生和消失。

相比之下,寄存器和内存是物理构造——在某种意义上,它们一直都在那里。

在汇编编程中,由人工或编译器生成,我们将 C 代码、算法和伪代码所需的逻辑变量映射到处理器中可用的物理存储。当变量的生命周期结束时,我们可以将其用于其他目的(另一个变量)的物理存储重用。

Assembly 语言支持全局变量(整个进程生命周期)和局部变量——它们可以在堆栈的内存中,也可以在 CPU 寄存器中。 CPU 寄存器当然没有地址,因此不能通过(内存)引用传递。 CPU 寄存器也不能被索引,因此索引数组需要内存。

【讨论】:

  • 这似乎是正确和有用的,但它并没有回答我的问题。现在,您能否进一步详细说明逻辑构造和物理构造之间的区别?例如,堆栈和全局变量是否位于内存中?如果是这样,我是否可以完全访问内存,或者只是其中的一部分?(假设操作系统不会阻止我的程序)
  • 操作系统和CPU合力虚拟化内存,让每个进程看起来都有自己的地址空间,地址相似。 CPU 知道(由操作系统编程)知道它在执行指令的任何时候正在工作的地址空间。堆栈和全局内存只是地址空间的一部分,因此它们具有不同的内存地址。正如我所提到的,局部变量在某些条件下必须在 RAM 中(您希望通过引用传递它们,或索引到它们中),否则它们是 CPU 寄存器的潜在候选者。全局变量也需要 RAM。
  • 感谢您的回答
【解决方案2】:

我会在堆栈上创建一个局部变量,如下所示:

print:
    ; DWORD  bytes;    
    mov     ebp, esp
    sub     esp, 12

    ; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
    push    -11
    call    _GetStdHandle@4
    mov     ebx, eax

    lea     ecx, [ebp-12]
    mov     dword ptr [ecx], “1234”

    ; WriteFile( hstdOut, message, length(message), &bytes, 0);
    push    0
    lea     eax, [ebp-4]
    push    eax
    push    4
    push    ecx
    push    ebx
    call    _WriteFile@20
    mov     esp, ebp
    ret

注意:语法mov ..., “1234” 可能会也可能不会做你想做的事,这取决于汇编程序。我不记得 Microsoft 汇编程序是如何处理它的。如果它不能转换为 0x34333231,则使用该常量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-28
    • 1970-01-01
    • 1970-01-01
    • 2015-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多