简体   繁体   English

编写Windows x86程序集

[英]Writing Assembly for Windows x86

I would like to write simple programs (console input/output) for Windows using x86 assembly, mainly because I am just curious. 我想用x86汇编为Windows编写简单的程序(控制台输入/输出),主要是因为我只是好奇。 It would be great if anybody could point me in the right direction. 如果有人能指出我正确的方向,那就太好了。 I already have a fairly good understanding of some of the more simple x86 instructions, the functions of the registers, etc. but it remains a mystery to me how programs interface with the operating system and use standard input and output. 我已经对一些更简单的x86指令,寄存器的功能等有了相当好的理解,但对于程序如何与操作系统连接并使用标准输入和输出仍然是一个谜。 I know that these things have to do with libraries such as advapi32.dll and kernel32.dll, and that there are associated static library .lib files which enable compilers to use these dynamically linked libraries, but other than that I have little idea how this happens. 我知道这些东西与advapi32.dll和kernel32.dll这样的库有关,并且有相关的静态库.lib文件,它们使编译器能够使用这些动态链接的库,但除此之外我不知道这是怎么回事发生。 I'm even fuzzy on how header files in languages like C use .lib files. 我甚至模糊C语言中的头文件如何使用.lib文件。

Perhaps it's easiest to give directions for building some simple programs, and let you extrapolate from there. 也许最简单的方法是建立一些简单的程序,让你从那里推断出来。 First you need some source code: 首先,您需要一些源代码:

.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

To build that, we'd invoke masm like: 要构建它,我们会调用masm

ml hello32.asm -link -subsystem:windows user32.lib

That's telling it the file to assemble, and when it links, telling it to link it as being for the Windows subsystem (the primary alternative would be -subsystem:console ) and to link with user32.lib . 这告诉它要汇编的文件,当它链接时,告诉它将其链接为Windows子系统(主要替代方案是-subsystem:console )并链接user32.lib The latter provides the definition of MessageBoxA for us. 后者为我们提供了MessageBoxA的定义。

A similar program that writes to the console is (oddly enough) a tiny bit more complex: 写入控制台的类似程序(奇怪的是)稍微复杂一点:

.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

Building is pretty much the same, except that this uses the console, so we specify the console subsystem, and the functions we're using are defined in the kernel: 构建几乎是相同的,除了它使用控制台,因此我们指定控制台子系统,我们正在使用的函数在内核中定义:

ml hello_console.asm -link -subsystem:console kernel32.lib

A header would include the equivalent of the declarations I've given above for MessageBoxA , GetStdHandle , WriteFile , etc. Each header would normally have a lot more of them though -- for example, all the functions in kernel32 might be in a single header. 标头将包含我在上面给出的MessageBoxAGetStdHandleWriteFile等的声明的等价物。每个标头通常会有更多的声明 - 例如,kernel32中的所有函数可能都在一个标题中。

As far as libraries go, the mechanism involved is somewhat involved, but mostly irrelevant. 对于图书馆来说,所涉及的机制有些牵连,但大多不相关。 To get the job done, you look at (for example) MSDN, and see what library says to link, and add that on your command line. 要完成工作,请查看(例如)MSDN,并查看要链接的库,并在命令行中添加它。

The more complex explanation is that at least when you link against a static library, it simply finds any functions you've called, and puts a copy of each into your executable/DLL. 更复杂的解释是,至少当您链接到静态库时,它只是找到您调用的任何函数,并将每个函数的副本放入您的可执行文件/ DLL中。 If (like above) you're using code that's in a DLL, it basically just puts a record into the executable that tells what function in what DLL it depends upon. 如果(如上所述)你正在使用DLL中的代码,它基本上只是将一条记录放入可执行文件中,该记录告诉它所依赖的DLL中的函数。 Then, when you load/run the program, the loader looks for all the DLLs your program depends upon, and loads them (recursively loading anything they depend upon as well, of course). 然后,当你加载/运行程序时,加载器会查找你的程序所依赖的所有DLL,并加载它们(当然也可以递归地加载它们所依赖的任何东西)。 Then the loader fixes up those references, so the reference to the function in the DLL gets filled in with whatever address has been assigned to that function in that DLL. 然后加载器修复这些引用,因此DLL中函数的引用将填入该DLL中为该函数分配的任何地址。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM