Windows 汇编语言编程教程_第1页
Windows 汇编语言编程教程_第2页
Windows 汇编语言编程教程_第3页
Windows 汇编语言编程教程_第4页
Windows 汇编语言编程教程_第5页
已阅读5页,还剩16页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Windows 汇编语言编程教程Version 1.02Copyright2005,Jeff Huang.All rights reserved Translator:fqh 2005.7.10JEFF HUANG 作,fqh 译目录介 绍 2为什么选用汇编语言 2为什么选择Windows系统2开始学习之旅 .3编译器 3编辑器 3第一个程序 4控制台程序 4窗体程序 6ADDR 与 OFFSET6汇编基础7cpu 寄存器 7指令集基础 8Push 和 Pop8Invoke 9程序例子 9IV. 窗体程序基础10预备知识10变量10一个简单的窗体程序11IV. 深入汇编和系统13控制15附加资

2、源 16MASM3216MSDN16IRC 16介 绍“Thisisforallyoufolksoutthere,whowanttolearnthemagicartofAssembly programming”-MAD介 绍我最近才开始学习windowsIRC 通讯工具请问他人,本侧重于X86知识。为什么选用汇编语言?汇编语言具有若干的特色,使得在某此情况下,汇编语言是一种很好的选择。序是用汇编语言编写的。在实现某些特定的要求时变得困难。是非常有用的。为什么选择Windows 系统?人在使用基于x86 处理器的Windows序。第 一 章 胜任这些工作的运行于Windows编译器Windows

3、.exe 为后缀的。下面给出一些流行的编译器:1 MASM先由微软公司开发,现在被包括在MASM32v8MASM32v8 程序包还包括了其他的工具。你可以从这个网址得到它: HYPERLINK / /.注意:教程中有一些指令和宏指令,只有在MASM 编译器才是有效的,所以强烈建议您从开始学习时选用MASM。TASM 这是另一个受欢迎的编译器。由Borland所以你不能免费地获取到它。NASM址获取到 HYPERLINK /projects/nasm/ /projects/nasm/记住编辑器器,你可以试用一下它们并选择一种你喜欢的。Notepad 记事本,WindowsVisual Studi

4、o易于阅读。Ultraedit (我个人最喜欢的e) HYPERLINK / /Textpad HYPERLINK / /VIM HYPERLINK / /Emacs HYPERLINK /software/emacs/emacs.html /software/emacs/emacs.htmljEdit HYPERLINK / /第 二 章 现在我们有了自己的工具,打开你的文本编辑器,跟着下面的介绍,开始学习编程吧。这是世上最普通的程序,“Hello World”程序。控制台程序控制台程序是运行在系统控制台的(也就大家所知的命令行.386.model flat, option casemap

5、include masm32includewindows.inc include masm32includekernel32.inc include masm32includemasm32.inc includelib masm32libkernel32.lib includelib masm32libmasm32.lib.dataHelloWorld db Hello World!, 0.code start:invoke StdOut, addr HelloWorld invoke ExitProcess, 0end start到cmdhello.asmasm32binml/c/Zd/co

6、ff hello.asmmasm32binLink /SUBSYSTEM:CONSOLE Hello.exeHello World!Hello World!,我们只要编写很少的代码就可以了。这些代码都起了什么作用呢?让我们一行一行地看下去。.386这条指令的作用是告知编译器使用.386 指令集。当前,几乎没有处理器使用比.386 更老的指明令集了。我们还可以选择使用.486.或 586,但是.386 是兼容性最好的指令集。.model flat, stdcall.MODEL 是一条指定你程序的内存模式的汇编指令。Flat(far(farStdcall 是一种系统函数传递参数的方法,它意味着你得

7、以从右到左的顺序传递你的参数。option casemap :noneHellohello语言同样是大小写敏感的,所以这是个编程的良好习惯。include masm32includewindows.inc include masm32includekernel32.inc include masm32includemasm32.incwindows.incWin32 kernel32.inc 包含了我们所使用的ExitProcessmasm32.incStdOutStdOutWin32MASM32v8includelib masm32libkernel32.libincludelib masm

8、32libmasm32.lib函数依赖库,基于这个目的,这些库得包含进去。.data.data? 和.const World序中并没有用到它们。HelloWorld db Hello World!, 0db 代表“字节”,并声明HelloWorldHello World!NULL”字母,这是因为ANSINULL.code这代表程序代码段的开始。start:你程序的代码位于这个标号的后面,但位于” end startinvoke StdOut, addr HelloWorldInvoke HelloWorld World!的地址和调用StdOut。注意StdOut 函数只是在MASM32个调用其

9、它函数来输出文件的宏。在别的编译器里,你得使用更多的代码并要用到win32 WriteConsole.。invoke ExitProcess, 00ExitProcess窗体程序 Worldhellow.asm.386.model flat, option casemap include masm32includewindows.inc include masm32includekernel32.inc include masm32includeuser32.inc includelib masm32libkernel32.lib includelib masm32libuser32.lib.

10、dataHelloWorld db Hello World!, 0.code start:invoke MessageBox, NULL, addr HelloWorld, addr HelloWorld, MB_OK invoke ExitProcess, 0end starthellow.asmmasm32binml /c /Zd /coff hellow.asmmasm32binLink /SUBSYSTEM:WINDOWS hellow.obj注意,subsystem 是WINDOWS 不再是CONSOLEHello World!的信息框。与控制台版相比,窗体版本的代码只有3 行是不同

11、的。其中有两行把masm32 包含文件和库文件更换为user32MessageBox不是使用StdOut3 个不同的行是用MessageBox 函数代替了StdOut就这么多而已!ADDR 与 OFFSETHello addr 来获取字符串Hello World! offsetaddr 第三章汇编基础cpu 寄存器32 位通用寄存器有8168 存取eax168ah916地址名称描述EAX*累加寄存器进行计算操作和保存数据结果EBX基址寄存器指向数据寄存器中的数据ECX*计数寄存器字符串以及循环的计数EDX*数据寄存器输入/输出的指针ESI源变址寄存器字符串操作中的源指针EDI目的变址寄存器字符

12、串操作中的目的指针ESP堆栈指针寄存器堆栈指针,不能人为使用它EBP堆栈基址寄存器 注意:虽然它们被称为通用寄存器,但是只有那些标有*号的才能在窗体程序编程中使用。616地址CS代码段寄存器保存要运行的指令DS,ES,FS,GS数据段寄存器数据段SS堆栈段寄存器 232地址名 称 描述EFLAGE标志寄存器状态,控制,系统标志EIP指令指针寄存器下一个要执行的指针的偏移指令集基础x86 指令集非常宏大,但是我们通常并没全都使用到了它们。下面介绍一些我们应该掌握的指令。指令描述ADD* reg/memory, reg/memory/constant把两个操作数相加并把结果保存进第一个操作数。如果

13、有进位的话,它会设置CF 标志位SUB* reg/memory, reg/memory/constant第一个操作数减去第二个操作数,并把结果保存到第一个操作数里AND* reg/memory, reg/memory/constant两个操作数逻辑与,并把结果存到第一个操作数里OR* reg/memory, reg/memory/constant两个操作数逻辑或,并把结果存到第一个操作数里XOR* reg/memory, reg/memory/constant两者异或,并把结果存到第一个操作数里。注意你不能对两个存储器操作数进行异或操作MUL reg/memory操作数与累加器寄存器相乘,而后

14、把结果存进累加器寄存器DIV reg/memory累加器寄存器被操作数除并把结果存到累加器INC reg/memory1DEC reg/memory1NEG reg/memory操作数的值取补并把结果存进操作数NOT reg/memory操作数的值取反并把结果存进操作数PUSH reg/memory/constant把操作数压进堆栈顶端POP reg/memory弹出堆栈顶端的值并保存到操作数MOV* reg/memory, reg/memory/constant把第二个操作数的值保存到第一个操作数里面CMP* reg/memory, reg/memory/constant第一个操作数减第二个

15、操作数,并设置相应当的标志位。通常与 JMP,REP 等指令一起使用JMP* label跳转到标号处LEA reg, memory取第二个操作数的地址偏移,并把结果保存进第一个操作数CALL subroutine调用另一个过程直到程序返回RET程序返回到调用者INT constant调用操作数指定的中断*指令不能有两个存储器操作数*CF=0 这一条件下才会跳转。最新的全部指令集参考可以从下面这个网址得到 HYPERLINK /design/pentium4/manuals/index.htm /design/pentium4/manuals/index.htm.Push 和 PopPushpo

16、pPushPop(LIFO议你先掌握这一知识。InvokeInvoke 是 MASM 特有的一个伪指令。它使得在调用函数前不必先传递参数。这让我们省略了很多的代码。举个例子说明如下invoke SendMessage, hWnd, WM_CLOSE, 0, 0等效于:push 0push 0push WM_CLOSE push hWndcall SendMessage程序例子下面是一个完整的程序。它说明了如何去使用指令和寄存器。看看是否全部弄懂了它。.386.model flat, option casemap include masm32includewindows.inc include

17、masm32includekernel32.incinclude masm32includemasm32.inc includelib masm32libkernel32.lib includelib masm32libmasm32.lib.dataProgramText db Hello World!, 0BadText db Error: Sum is incorrect value, GoodText db Excellent! Sum is 6, 0Sum sdword 0.code start:; eaxmov ecx, 6 ; set the counter to 6 xor ea

18、x, eax ; set eax to 0 0_label: add eax, ecx ; add the numbers ? dec ecx ; from 0 to 6 ?jnz _label ; mov edx, 7 ; mul edx ; multiply by 7 147push eax ; pushes eax into the stack pop Sum ; pops eax and places it in cmp Sum, 147 ; compares Sum to 147jz _good ; if they are equal, go to _good_bad: invoke

19、 StdOut, addr BadText jmp _quit_good: invoke StdOut, addr GoodText_quit: invoke ExitProcess, 0 end start注意:“;”符号表示注释。所有跟在它后面的字符都不会被编译。把提示和注意点放在注释中是个好主意,它能让你的代码易读。第四章IV. 窗体程序基础窗体程序通常由一个或几个窗体组成。因此,做为 windows 程序员至少要懂得怎么创建一个简单的窗体。很不幸,它不是那么容易的事,但是本教程会指导你怎么去做。预备知识在编写窗体程序前我们还要讨论几个主题。让我们花点时间复习一下预备知识。宏MASM 有

20、几个让汇编编程变得非常容易的宏。我们已经接触到invoke,它简单地调用一个函数。下面列出其他几种,之前在你用高级语言编程时它们的用法是很明显的。.if, .else, .endif.while, .break, .endw过程与高级语言类似,MASM 让你定义各种过程使得你的代码易于阅读。它们的格式如下所示: proc :, :, . ret endp返回值保存在eax 寄存器里,这个过程用下面格式来调用invoke , param1, param2, .返回值可以用下面指令来获取mov RetVal, eax变量.data.data.const 化。格式如下:local : (4 byte

21、s)。还有更多,但是它们常常与这三种类型中的一种是相同的,只不过名称不同。一个简单的窗体程序窗体程序有两个主要的部分。第一部分是WinMainWndProc,它是接收消息的,这部分处理你的鼠标事件及刷新窗口等。.386.model flat, option casemap include masm32includewindows.inc include masm32includeuser32.inc include masm32includekernel32.inc includelib masm32libuser32.lib includelib masm32libkernel32.lib

22、以上是我们通常必需的WinMain proto :DWORD, :DWORD, :DWORD, :DWORDThis is a function prototype. It lets us call the WinMain function later in the program.It can be compared to a C/C+ function declaration.这是函数原型。在稍后的程序里我们称它为WinMain 函数。.dataClassName db WinClass, 0 AppName db Simple Window, 0 我们声明我们的字符变量.data?hIn

23、stance HINSTANCE ?变量hInstance 保存模块实例的句柄,以便与窗体相关联。稍后我们将把它传递到CreateWindow 函数中。.code start:invoke GetModuleHandle, NULL mov hInstance, eaxinvoke WinMain, hInstance, NULL, NULL, 0invoke ExitProcess, eax获取模块句柄并把它保存到变量hInstanceWinMainWinMain是这个程序的核心,所以我们将深入研究它。注意:从这点来看,我们假设你能够从MSDN 中查找windows 函数。它有函数参数,返回

24、值,还有其它你必须了解的信息。你可以在附加资源这个章节里获取关于MSDN 的信息。WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR,CmdShow:DWORDlocal local msg:MSGlocal hwnd:HWND这是WinMainhwnd。Wc Msg保存我们窗本的句柄。mov wc.cbSize, SIZEOF WNDCLASSEXmov wc.style, CS_HREDRAW or CS_VREDRAW mov wc.lpfnWndProc, offset WndProcmov wc.cbCls

25、Extra, mov wc.cbWndExtra, 注意:在窗体程序中,or操作运算符常常用来联合参数中的标志。push hInstance pop mov wc.hbrBackground, COLOR_WINDOW+1 mov wc.lpszMenuName, NULLmov wc.lpszClassName, offset ClassName invoke LoadIcon, NULL, IDI_APPLICATION mov wc.hIcon, eaxmov wc.hIconSm, eaxinvoke LoadCursor, NULL, IDC_ARROW mov wc.hCursor

26、, eaxinvoke RegisterClassEx, addr wc这些是填充我们先前声明的wc 结构。然后以wc 为参数调用RegisterClassEx。至于更多关于wc 的每个成员的信息,请在MSDN 中查找WNDCLASSEX 结构的资料。invoke CreateWindowEx, 0, addr ClassName, addr AppName, WS_OVERLAPPEDWINDOW or WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,NULL,NULL, hInst, NULLmo

27、v hwnd, eax调用CreateWindowEx 函数创建窗体。其中有很多参数被传递进去来表明怎么创建窗体。窗体的句柄会返回并保存到变量hwnd 中。.while TRUEinvoke GetMessage, addr msg, NULL, 0, 0.break .if (!eax)invoke TranslateMessage, addr invoke DispatchMessage, addr msg.endw这个whileGetMessage 取回这些消息并保存进msgTranslateMessage些消息发送到WndProcWndProcmov eax, msg.wParam r

28、etWinMain endp返回值保存进msg.wParam,WinMain 函数结束。WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM.if uMsg = WM_DESTROY invoke PostQuitMessage, .elseinvoke DefWindowProc, hWnd, uMsg, wParam, lParam ret.endifxor eax, eax retWndProc endpWndProc PostQuitMessageWM_CREATE(当创建窗体时),WM_PAINT (当窗体必须

29、重画时), 还有WM_CLOSE (关闭窗体时)。其它没有处理的消息被传递给DefWindowProcend start就这些了。你已经了解了怎么去创建一个窗体! 第五章IV. 深入汇编和系统下面有一些资料来扩展你关于汇编以及系统编程方面的知识:字符串操作,文件处理, 还有系统窗体的控制。字符串操作 中的方向控制标志。方向控制标志是指定移动字符串时的方向。一些常见的字符串操作指令是movsb, cmpsb, stasb, and stosb.为了操作字符串,你可以在字符串控制指令中使用某些rep?的形式。下面是在串操 作指令中可以使用到rep?前缀前缀描述rep movsb复制字符串repe

30、cmpsbrepne scasb扫描字符串中一个字符rep stosb保存一个字符到字符串中下面给个复制字符串的例子cld ; sets the direction flag to forwardmov esi, source ; move the source address in to esi mov edi, dest ; move the destination address in to mov ecx, length ; move the length to copy in to ecx rep movsb ; copy length bytes from esi to edi文件

31、管理在旧的DOSwindows过使用系统函数访问文件。其中可供我们使用的4CreateFile 创建或打开一个文件,并返回它的句柄ReadFile 从文件中读取数据WriteFile 写数据到文件里CloseHandle 关闭你用CreateFile 函数得到的句柄存储为了读取文件内容,我们必须分配一些内存来存储数据。内存可以如你所愿地被分配, 锁定,但是最后记得解锁和释放。做这些工作的函数是GlobalAlloc, GlobalLock,GlobalUnlock, 还有GlobalFree程序例子这个程序读取c:test.txt的内容,并通过一个消息框输出。.386.model flat,

32、option casemap include masm32includewindows.inc include masm32includeuser32.inc include masm32includekernel32.inc includelib masm32libuser32.lib includelib masm32libkernel32.lib 一些通常的包含文件.dataFileName db c:test.txt, 0.data?hFile HANDLE ?hMemory HANDLE pMemory DWORD ? ReadSize DWORD 我们定义字符串,还声明了四个将会用

33、到的变量.constMEMORYSIZE equ 65535这是说明分配多大的内存,这样有足够的空间保存我们的文件.code start:invoke CreateFile, addr FileName, GENERIC_READ, FILE_SHARE_READ,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULLmov hFile, eax调用CreateFile 函数并保存文件句柄到hFile 变量。通常,放置一个h在句柄之前, 而放置p在指针之前invoke GlobalAlloc, GMEM_MOVEABLE or GMEM_ZEROINI

34、T, MEMORYSIZE mov hMemory, eaxinvoke GlobalLock, mov pMemory, eax分配并锁定我们的内存invoke ReadFile, hFile, pMemory, MEMORYSIZE-1, addr ReadSize, invoke MessageBox, NULL, pMemory, addr FileName, MB_OKinvoke GlobalUnlock, pMemory invoke GlobalFree, hMemoryinvoke CloseHandle, hFile invoke ExitProcess, NULL end

35、 start可别忘清除工作啊控制这是容易的事!它的语法非常类似于创建一个窗体,除此外,我们不必调用RegisterClassEx,因为我们的类将为我们预先定义了。为了做到这些,从第4 章内容那里编辑 WndProc 函数来响应WM_CREATE 消息.elseif uMsg = WM_CREATEinvoke CreateWindowEx, NULL, addr ButtonClassName, addr ButtonText, WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON, 10, 50, 80, 30, hWnd, ButtonID, hInstance,NULLmov hButton, eaxinvoke CreateWindowEx, WS_EX_CLIENTEDGE, addr EditClassName, NULL, WS_CHILD or W

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论