这是我从Stackoverflow.com's Question复制的代码:
global _main
extern _GetStdHandle@4
extern _WriteFile@20
extern _ExitProcess@4
section .text
_main:
; 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 (message_end - message)
push message
push ebx
call _WriteFile@20
; ExitProcess(0)
push 0
call _ExitProcess@4
; never here
hlt
message:
db 'Hello, World', 10
message_end:
此代码正常运行,无需清除任何错误,但有一些行无法理解它们的作用,请向下滚动:
MOV ebp, esp
好的,任何人都可以告诉这份副本esp
到ebp
寄存器的内容,但是如何将未初始化的寄存器值复制到寄存器呢?它会加载ebp
0
(零)吗?
SUB esp, 4
此处esp
被4
减去,所以0-4= -4
,是吗?但为什么这两行代码呢?相反,如果结果是我给出"-4"
的结果,我会让Normaly做MOV esp, -4
MOV ebx, eax
eax
,我认为必须由_GetstdHandle
函数填充?
和最后一个,hlt
?
答案 0 :(得分:2)
esp永远不会“未初始化”。它始终指向堆栈的顶部 - 您推送和弹出的东西。例如,当您按下32位寄存器时,esp会自动减少4。
“sub esp,4”在堆栈上分配四个字节 - 用于“bytes”变量。之后你可以看到“lea ax,[ebp-4]”,它对应于评论中的“& bytes”。
非常正确,从_GetStdHandle返回了eax。
“hlt”停止处理器 - 这是一件坏事。但正如评论所说 - 因为_ExitProcess不会返回,所以不会被执行。想法可能是如果 _ExitProcess应该返回,最好暂停,而不是开始执行随机代码。
答案 1 :(得分:2)
总结一下,这个程序用一个局部变量创建一个堆栈框架,然后从上面的&上面导入的kernel32.lib调用Win32 API函数,然后退出SUCCESS(0)。
mov ebp, esp
使用SS:ESP的当前值设置基址指针寄存器。这样做是为了访问用
保留的本地DWORD变量(4个字节)sub esp, 4
堆栈向下增长,例如:如果ESP在程序启动时由OS设置为0FFFF0000h,则EBP将设置为此值,减法将减少为0FFFEFFFCh,为本地4字节var @ this地址提供空间,
将在稍后引用lea eax, [ebp-4] ; &bytes
该行
mov ebx, eax
将句柄保存在EBX的EAX中(在这种情况下不是必需的),因为
Registers EBP, EBX, ESI, and EDI are preserved during Win32 API calls.
最后的HLT是无法访问的代码,因此永远不应该执行。无论如何,它会停止进一步执行,请参见此处:http://www.felixcloutier.com/x86/HLT.html