ImageVerifierCode 换一换
格式:DOCX , 页数:103 ,大小:77.51KB ,
资源ID:6390630      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/6390630.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(罗云彬的Win32汇编教程.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

罗云彬的Win32汇编教程.docx

1、罗云彬的Win32汇编教程罗云彬的Win32汇编教程之一Win32汇编的环境和基础 1.32位环境简介 在Dos下编汇编程序,我们可以管理系统的所有资源,我们可以改动系统中所有的内存,如自己改动内存控制块来分配内存,自己修改中断向量表来截获中断等,对其他操作也是如此,如我们对键盘端口直接操作就可以把键盘屏蔽掉,可以这样来描述Dos系统:系统只有一个特权级别,在编程上讲,任何程序和操作系统都是同级的,所以在Dos下,一个编得不好的程序会影响其他所有的程序,如一个程序把键盘口中断关掉了,所有程序就都不能从键盘获得键入的数据,直到任何一个程序重新打开键盘为止,一个程序陷入死循环,也没有其他程序可以把

2、它终止掉。Dos下的编程思路是“单任务”的,你只要认为你的程序会按照你的流程一步步的执行下去,不必考虑先后问题(当然程序可能会被中断打断,但你可以认为它们会把环境恢复,如果中断程序没有把环境恢复,那是他们的错)。 在内存管理方式上,Dos汇编和Win32汇编也有很多的不同:Dos工作在实模式下,我们可以寻址1M的内存,寻址时通过段寄存器来制定段的初始地址,每个段的大小为64K,超过1M的部分,就只能把他作为XMS使用,也就是说,只能用作数据存放使用而无法在其中执行程序。 而Windows在保护模式下执行,这里所有的资源对应用程序来说都是被“保护”的:程序在执行中有级别之分,只有操作系统工作在最

3、高级-0级中,所有应用程序都工作在3级中(Ring3), 在Ring3中,你无法直接访问IO端口,无法访问其他程序运行的内存,连向程序自己的代码段写入数据都是非法的,会在Windows的屏幕上冒出一个熟悉的蓝屏幕来。只有对Ring0的程序来说,系统才是全开放的。 在内存方面,Windows使用了处理器的分页机制,使得对应用程序来说,所有的内存都是“平坦”的,你不必用一个段寄存器去指定段的地址,因为在保护模式下,段寄存器的含义是不同的(可以参见80386手册方面的书籍),你可以直接指定一个32位的地址来寻址4GB的内存。 在程序结构方面,Windows程序也有很大的不同,它是“基于消息”的,你可

4、以想象这样一个常见的Windows窗口,上面有几个按钮,如果你用Dos编程的思路去考虑,你会发现实现它很困难:鼠标移动到窗口边缘时拖动会改变窗口大小,鼠标点击按钮时再做要做的事,你会发现,你的程序自开始执行后就在等待,你不知道鼠标先会点什么地方,实际上你是在等待所有可能的事情的发生。而在Dos下,你可以只顾自己先执行,需要用户输入时,再停下来,你不输入我就不再执行,而且,我让你输入数据A你就不能输入数据B。 好了,言归正传,因为以上是Win32编程的基础,无论对Win32汇编还是VC+,它们都是一样的,下面我们来看看有关Win32汇编的内容。2.Win32ASM编译器Win32ASM的编译器最

5、常用的有两种:Borland公司的Tasm5.0和Microsoft的Masm6.11以上版本,两种编译器各有自己的优缺点,Tasm带了一个不大不小的Import库,而Masm没有带,但Masm在代码的优化上面好象比Tasm做得好,但它却不带Import库。看来使用哪一种编译器还是比较难选择的,但Steve Hutchesson给了我们一个答案,他为Masm建立了一个很全的Import库,基本上包括了Windows绝大部分的Api函数,这些库、include文件和其他工具还有Masm6.14版本一起做成了一个 Masm32编译器 - Masm32V5。这样一来,我们用汇编编程就象用C一样方便。

6、因为有了Masm32V5,所以就我个人而言,我推荐使用Masm作为Win32ASM的编译工具,但Masm和Tasm的宏语法有很多的不同,我的这个教程是以Masm格式写的。3.Masm32的环境设置在Win32编程中,由于Windows有很多的数据结构和定义,这些都放在include文件中,还有连接时要用到Import库(通俗的讲就是Windows提供的DLL文件中的函数列表,也就是告诉程序到哪里去调用API函数),这些都放在include 和lib目录中。我们在编译时要指定以下的系统环境:set include=Masm32v5Includeset lib=Masmv5libset path=

7、Masmv5Bin这样编译器就会到正确的路径中去找 include 文件和 lib 文件。你可以自己在 autoexec.bat 文件中加上以上语句,为了产生Windows的PE格式的执行文件,在编译和连接中要指定相应的参数:编译: Ml /c /coff 文件名.asm连接: Link /SUBSYSTEM:WINDOWS OBJ文件名.obj 资源文件名.res为了不在每次编译时都要打这么多的参数,我们可以用 nmake 文件来代为执行,nmake 是代码维护程序,他会检查 .asm .obj .exe .res 等文件的时间,如果你更新了源程序,他会自动执行编译程序或连接程序产生相应的文

8、件。你可以在文件名为 makefile 的文件中指定使用的编译器和连接程序以及相应的参数,下面是一个 makefile 文件的例子:NAME = ClockOBJS = $(NAME).objRES = $(NAME).res$(NAME).exe: $(OBJS) $(RES)Link /DEBUG /SUBSYSTEM:WINDOWS $(OBJS) $(RES) $(RES): $(NAME).rc Rc $(NAME).rc .asm.obj:Ml /c /coff $(NAME).asm文件告诉 nmake程序,程序名为 clock,产生 clock.exe 文件需要 clock.o

9、bj和 clock.res 文件,而产生 clock.res 文件需要 clock.rc 文件,产生 clock.obj 文件要用到 clock.asm 文件,至于是否需要执行 ml, link 和 rc,程序会根据文件的时间自动判断。Win32汇编教程二Win32汇编程序的结构和语法在这儿下载本节的所有源程序。Win32ASM程序的结构和语法让我们先来看看一个最简单的Win32汇编程序: .386 .model flat, stdcall option casemap :none ; case sensitiveinclude windows.incinclude kernel32.inci

10、ncludelib kernel32.lib .dataszCaption db Win32汇编例子,0szText db Win32汇编,Simple and powerful!,0 .codestart: invoke MessageBox,NULL,addr szText,addr szCaption,MB_OK invoke ExitProcess,NULL end start这就是一个能执行的最简单的Win32汇编程序,下面我简单地介绍一下各部分的作用:.386这条语句和Dos下汇编是一样的,是告诉编译器我们要用到80386的指令集,因为32位汇编程序要用到32位的寄存器如eax,e

11、bx等,所以这一句是必须的,当然,你也可以用.486,.586等,当用到特权指令时,还可以用 .386p,.486p等等。.model flat,stdcall.model告诉编译器程序的模式,编过Dos汇编的人可能知道在Dos程序的模式有tiny,small,.huge 等,它指定了程序内存寻址模式,在huge等模式下,内存寻址和子程序调用将用Far的格式,但在Win32汇编中,你只能使用一个模式即 flat 模式,因为对Win32程序来说,内存是连续的一个4GB的段,无所谓小或大的模式。而stdcall 告诉编译器参数的传递方式,在调用子程序时,参数是通过堆栈传递的,参数的传递方式有三种,

12、stdcall,c 和 pascal,stdcall 指定了参数是从右到左压入堆栈的,比如说对一个Windows API 如 MessageBox,在手册中是如此定义的:int MessageBox( HWND hWnd, / handle of owner window LPCTSTR lpText, / address of text in message box LPCTSTR lpCaption, / address of title of message box UINT uType / style of message box );那么在汇编中我们就可以这样调用它: push uT

13、ype push lpCaption push lpText push hWnd call MessageBox大家要注意最右面的参数是最后一个进堆栈的,当然,我们不必这样麻烦的调用一个 API,因为Masm中的一个宏语句不但帮助我们完成了所有的压栈操作,还帮我们检查参数的个数是否正确,那就是 invoke 语句,我们可以把上面的语句换成 invoke MessageBox,hWnd,lpText,lpCaption,uType 就行了。如本程序中代入实际参数就成了 invoke MessageBox,NULL,addr szText,addr szCaption,MB_OK。include

14、语句include 语句包含了一些系统的定义和API函说明,其中所有的Windows 数据结构定义和常量定义包含在 windows.inc 中,而其他 API函数的说明包含在 xxx.inc 中, 如查 Microsoft Win32 Programmers Reference 知道 ExitProcess包含在kernel32.dll 中,那么我们就要在程序中包括 include kernel32.inc 和 includelib kernel32.lib语句,否则在编译时会出现 API 函数未定义的错误。而 MessageBox 在 user32.dll 中,那么我们就要在程序中包括 in

15、clude user32.inc 和 includelib user32.lib语句.data 或 .data?指明了接下来是数据段,.data 定义了预定义的变量,.data?定义了未初始化的变量,两者的不同之处是 .data? 定义的变量并不占用 .exe 文件的大小,而是在程序执行时动态分配,所以开始是不指定初始值的数据可以放在 .data? 段中,如一个1K大小的缓冲区,放在 .data?中,程序将不会增加一个字节。.code指明了接下来是代码段,我们的所有代码都放在这里。最后的一句 start 语句指定了程序开始执行的语句。程序中的 ExitProcess 是一个标准的 Win32

16、API,对应 Dos汇编中的 int 20h 或 mov ah,4ch/int 21h,也就是程序退出。而 MessageBox 也是一个标准的 API,功能是在屏幕上显示一个消息框,具体的参数上面已经解释过了还有要注意的是 invoke MessageBox,NULL,addr szText,addr szCaption,MB_OK 语句中, MB_OK 和 NULL 已经预定义在 Windows.inc 中。Win32汇编教程三一个简单的对话框 - 兼谈资源文件的使用在这儿下载本节的所有源程序。Windows 的资源文件不管在Dos下编程还是在Windows下编程,我们总是要用到除了可执行

17、文件外的很多其他数据,如声音数据,图形数据,文本等等,在Dos下编程,我们可以自己定义这些文件的格式,但这样一来就造成了很多资源共享的问题,大家可能还记的Dos下的很多游戏,它们的图形都是按自己的格式存放的,你无法用标准的看图软件来看。也无法把它另存为其他格式。虽然在Win32编程中,我们仍然可以这样做,但Win32编程给了我们一个方案 - 就是格式统一的资源文件,把字符串、图形、对话框包括上面的按钮,文本等定义到一个资源文件中,就可以方便的在不同的文件中使用它,最重要的是,如果我们用自己的文件格式,使用时就要涉及到这些文件的读写操作,比较复杂,但使用资源文件时,Windows提供了一系列的A

18、PI来装入资源。非常方便。现在,让我们来看一个很简单的资源文件的源文件,它的扩展名是 .rc,当它用资源编译器编译以后产生 .res 文件就可以在 link的时候连入.exe 文件中:#include #define DLG_MAIN 1DLG_MAIN DIALOGEX 0, 0, 236, 185STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENUCAPTION 对话框模板FONT 9, 宋体BEGIN DEFPUSHBUTTON 退出,IDOK,177,163,50,14 CONTROL ,-1,Sta

19、tic,SS_ETCHEDHORZ,7,155,222,1END现在我简单解释一下 .rc文件的语法:#include - resource.h文件包括资源文件的一些常量定义,如下面的 WS_POPUP,WS_VISIBLE 等窗口的风格等等#define DLG_MAIN 1 - 类似于 .asm 文件的 equ 语句,和汇编源程序一样,这些定义是为了程序的可读性。DLG_MAIN DIALOGEX 0,0,236,185Windows的.rc文件可以定义 BITMAP(位图),CURSOR(光标),ICON(图标),ACCELERATORS(加速键),DIALOG(对话框),MENU(菜单

20、),STRINGTABLE(字符串表),RCDATA(自定义资源)等8种资源,详细的描述可以参考有关MFC的书籍,在Win32ASM中的资源编译器的语法中,一般格式是这些资源的定义方法是:位图定义: nameID BITMAP load-mem filename光标定义: nameID CURSOR load-mem filename 图标定义: nameID ICON load-mem filename 加速键定义:acctablename ACCELERATORS optional-statementsBEGIN event, idvalue, type options. . .END 等

21、等,具体的定义和参数可以参考 Masm32v5 中的 Rc.hlp 帮助文件。(可以在编程工具中下载),我们可以用资源编辑器来所见即所得地编辑资源,也可以在文本编辑器中用上面这些语句自己定义资源。在程序中使用资源在程序中,要使用资源之前必须先装如内存,Windows定义了一系列的API来装入资源,如 LoadMenu,LoadString,LoadBitmap 等等,如 LoadBitmap 的定义: HBITMAP LoadBitmap( HINSTANCE hInstance, / handle of application instance LPCTSTR lpBitmapName /

22、address of bitmap resource name ); 这些Load函数的返回值是一个句柄,调用参数中一般至少为两项: hInstance 和 ResouceName,这个 ResouceName(如BitmapName,MenuName)就是在资源文件中的 #define 指定的值,如果你用 #define MY_ICON 10/ MY_ICON ICON Main.ico 定义了一个图标,那么在程序中要使用 Main.ico 图标就可以用 LoadIcon(hInstance,10) 来装入已经定义为10号的图标文件。另一个参数 hInstance 是执行文件的句柄,它对应资

23、源所在的文件名,你可以在程序开始执行时用 invoke GetModuleHandle,NULL 获得 hInstance。另外一些资源并不是显式地装入的,如对话框资源,它是在建立对话框的函数中由Windows自己装入的,如下面例子中的 invoke DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,0 ,是在屏幕上显示一个资源文件中已经定义好了的对话框,就并不存在 LoadDialogBox 之类的API来先装入对话框。Win32ASM - 显示一个对话框介绍了这么多相关的东西,现在让我们来看看如何显示一个对话框,源程序如下

24、: ; Programmed by 罗云彬, bigluo; Website: ; LuoYunBins Win32 ASM page (罗云彬的编程乐园); .386 .model flat, stdcall option casemap :none ; case sensitiveinclude windows.incinclude user32.incinclude kernel32.incinclude comctl32.incinclude comdlg32.incincludelib user32.libincludelib kernel32.libincludelib comct

25、l32.libincludelib comdlg32.libDLG_MAIN equ 1 .data?hInstance dd ?szBuffer db 256 dup (?)_ProcDlgMain PROTO :DWORD,:DWORD,:DWORD,:DWORD .data .code;*_ProcDlgMain proc uses ebx edi esi, hWnd:DWORD,wMsg:DWORD,wParam:DWORD,lParam:DWORD mov eax,wMsg .if eax = WM_CLOSE invoke EndDialog,hWnd,NULL .elseif e

26、ax = WM_INITDIALOG .elseif eax = WM_COMMAND mov eax,wParam .if eax = IDOK invoke EndDialog,hWnd,NULL .elseif eax = IDCANCEL invoke EndDialog,hWnd,NULL .endif .else mov eax,FALSE ret .endif mov eax,TRUE ret _ProcDlgMain endp;*start: invoke InitCommonControls invoke GetModuleHandle,NULL mov hInstance,

27、eax invoke DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,0 invoke ExitProcess,NULL end start看了前面几篇文章以后,这儿的大部分语句应该是很熟悉了,我来讲解几句新的语句:_ProcDlgMain PROTO :DWORD,:DWORD,:DWORD,:DWORDPROTO 语句类似于C语言中的函数定义,在Win32汇编中,如果子程序的定义在引用以后,你就必须先定义,当然,这个定义是针对 invoke 语句和其他带参数的调用的,如果你的子程序没有参数,你就可以用 call 指令去调

28、用它而不是用宏指令 invoke,这时候你就不必声明这个函数。_ProcDlgMain proc uses ebx edi esi, hWnd:DWORD,wMsg:DWORD,wParam:DWORD,lParam:DWORD这个定义 proc 的语句应该是不陌生的,要重复讲解一下的是 uses 和 下面的参数,uses 下的寄存器表示要编译器自动插入保存及恢复这些寄存器的指令, 是在 Masm32 中接下一行的符号,表示下一行是本行的继续内容,以避免一行中的内容过长。下面的 hWnd:DWORD 等语句定义了调用这个子程序的参数,如果有以下定义 MyProc proc dwPara1:DW

29、ORD,dwPara2:DWORD,dwPara3:DWORD,然后你用 invoke MyProc 1,2,3 来调用它,那么,1,2,3 将分别被赋值给 dwPara1,dwPara2,dwPara3,你可以在子程序中使用这些传递过来的参数。如果参数的类型是双字,那么:DWORD 可以省略。.if/.else/.elseif/.endif这些语句是宏指令,实际上不说你也知道它们的意思,有了这些宏指令,我们就可以把汇编编得象C一样结构清晰,而不必老是看到 jmp 指令了,当然,这只不过编译器帮你做了这些事情而已,如果你去反汇编一下,你开始会看到一大堆 jmp 指令,.if 的格式如下.if

30、eax = 1 如果eax等于1.if eax != 1 如果eax不等于1.if eax != 1 & ebx != 2 如果eax不等于1且ebx不等于2.if eax = 1 | ebx = 2 如果eax等于1或者ebx等于2其他的宏指令还有 .while/.endw .break 等等,可以参考 Masm32V5 的帮助文件 Masm32.hlp最后要讲到的就是 DialogBoxParam 这个API了,在Windows中,所有的窗口都要指定一个子程序,当Windows检测到鼠标、定时器等和这个窗口有关的动作时,它回调用这个子程序,这就是Windows基于消息的体系的最基本的概念,换句话说,在Dos下,我们通过INT指令调用系统,而在Windows 下,有很多时候是你指定子程序地址让Windows来调用你。 invoke DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1