我想使用x86程序集为Windows编写简单程序(控制台输入/输出),主要是因为我只是好奇。如果有人能指出我正确的方向,那就太好了。我已经对一些更简单的x86指令,寄存器的功能等有了相当好的理解,但对于程序如何与操作系统连接并使用标准输入和输出仍然是一个谜。我知道这些东西与advapi32.dll和kernel32.dll这样的库有关,并且有相关的静态库.lib文件,它们使编译器能够使用这些动态链接的库,但除此之外我不知道这是怎么回事发生。我甚至模糊C语言中的头文件如何使用.lib文件。
答案 0 :(得分:3)
也许最简单的方法是建立一些简单的程序,并让你从那里推断出来。首先,您需要一些源代码:
.386
.MODEL flat, stdcall
; This is what would come from a header -- a declaration of a the Windows function:
MessageBoxA PROTO near32 stdcall, window:dword, text:near32,
windowtitle:near32, style:dword
.stack 8192
.data
message db "Hello World!", 0
windowtitle db "Win32 Hello World.", 0
.code
main proc
invoke MessageBoxA, 0, near32 ptr message, near32 ptr windowtitle, 0
ret
main endp
end main
要构建它,我们会调用masm
,如:
ml hello32.asm -link -subsystem:windows user32.lib
告诉它要汇编的文件,当它链接时,告诉它将其链接为Windows子系统(主要替代方案是-subsystem:console
)并链接到user32.lib
。后者为我们提供了MessageBoxA
的定义。
写入控制台的类似程序(奇怪的是)稍微复杂一点:
.386
.MODEL flat, stdcall
getstdout = -11
WriteFile PROTO NEAR32 stdcall, \
handle:dword, \
buffer:ptr byte, \
bytes:dword, \
written: ptr dword, \
overlapped: ptr byte
GetStdHandle PROTO NEAR32, device:dword
ExitProcess PROTO NEAR32, exitcode:dword
.data
message db "Hello World!", 13, 10
msg_size dd $ - offset message
.data?
written dd ?
.code
main proc
invoke GetStdHandle, getstdout
invoke WriteFile, \
eax, \
offset message, \
msg_size, \
offset written, \
0
invoke ExitProcess, 0
main endp
end main
构建几乎是一样的,除了它使用控制台,所以我们指定控制台子系统,我们正在使用的函数在内核中定义:
ml hello_console.asm -link -subsystem:console kernel32.lib
标题将包含我在MessageBoxA
,GetStdHandle
,WriteFile
等上面给出的声明的等效内容。每个标题通常会包含更多的声明 - - 例如,kernel32中的所有函数可能都在一个标题中。
就图书馆而言,所涉及的机制有些牵连,但大多不相关。要完成工作,请查看(例如)MSDN,并查看要链接的库,并在命令行中添加它。
更复杂的解释是,至少当您链接到静态库时,它只是找到您调用的任何函数,并将每个函数的副本放入您的可执行文件/ DLL中。如果(如上所述)你正在使用DLL中的代码,它基本上只是将一条记录放入可执行文件中,该记录告诉它所依赖的DLL中的函数。然后,当你加载/运行程序时,加载器会查找你的程序所依赖的所有DLL,并加载它们(当然也可以递归地加载它们所依赖的任何东西)。然后加载器修复了这些引用,因此DLL中对函数的引用将被填充到该DLL中为该函数分配的任何地址。