win32汇编快速入门

汇编可以开发WINDOWS程序?答案是肯定的,用WIN32汇编语言开发出来的WINDOWS程序具有执行效率高、占用空间小等特点。

一、开发工具下载与安装  在众多WIN32汇编开发工具中,MASM32笔者比较偏爱,它具有很多代码示例和丰富的开发资源,在下列下载地址中选择一个地址下载 MASM32。
http://www.pediy.com/tools/Compilers.htm二、知识预备  1、寄存器   为了提高运算速度和数据的存取速度,在计算机的CPU内,有一组硬件装置,第一个装置内存放CPU运算需要的 数,这些数值可供CPU直接存取,这组装置叫寄存器。寄存器分为通用寄存器、段寄存器、程序指针寄存器、标志寄存器。   编程最常用就是通用寄存器,常用的通用寄存器有eax,ebx,ecx,edx,esi,edi等等,现代计算机的CPU一般是以32位 为单位进行运算,因此一个寄存器最大能存放32位的二进制数。每个寄存器通常都有它默认的用法,所谓默认只是一种编程的习惯,你可以不遵守这些用法,但是 有些情况下必须遵守,因为我们开发的是WINDOWS程序,要遵守WINDOWS操作系统的规定和汇编语法本身的约束,比如调用一个WINDOWSAPI 函数,返回值放在EAX,堆栈的栈顶地址在esp,在汇编语言的循环中,ECX内存放循环的次数。具体寄存器的使用会在以后介绍。  2、堆栈   堆栈是个非常古老的概念,在DOS时代就有了,也是个非常重要的东西,程序没了它就活不了,堆栈就是在内存里分 配一个区域,使用这个区域必须遵守一个规定:后进先出,后进来的先出去,可以把它想像成一个空木箱,首先往里面放棉衣,然后往里面放书,最后放上运动服。 如果要取出书,必须得把最后放上的运动服取出,放的顺序是棉衣->书->运动服,取的顺序是运动服->书->棉衣,堆栈也是如 此。   先解释一下什么是地址,内存价格的便宜和内存容量的扩大,WINDOWS虚拟内存早已出现,内存中放着众多的数据,必须要有方法表示内存 某个地点,这个地点就用地址来表示。把内存以字节为单位划分,某个地址表示某个字节的地址,如左下图是一个内有4个成员的堆栈,堆栈里的成员以一个字节为 单位(数的右边标明了以十六进制表示的地址,如1001)+--+|AF|   地址:AF21+--+|03|   地址:AF20+--+|30|   地址:AF19+--+|F1|   地址:AF18+--+   堆栈是向下增长的,每增加一个成员,栈顶(堆栈顶部的地址)的地址减1,对于这个堆栈,栈顶地址是AF18,如果 再往这个堆栈里增加一个成员的话,它的地址是:AF18-1=AF17。如果往这个堆栈里增加一个32位的数,栈顶的地址是多少呢,32位的数占4个成员 的位置,栈顶的地址为:AF18-4=AF14。  在这个堆栈中增加一个32位数DAB0CD90,新的堆栈如下:+--+|AF|   地址:AF21+--+|03|   地址:AF20+--+|30|   地址:AF19+--+|F1|   地址:AF18+--+ |DA|   地址:AF17+--+|B0|   地址:AF16+--+|CD|   地址:AF15+--+|90|   地址:AF14+--+    如果从堆栈里拿走一个32位数,则栈顶的地址为:AF14+4=AF18三、WIN32汇编语言的语法   为了方便大家理解和入门,下面尽量使用宏汇编和伪指令地方进行描述,也正因为有了宏汇编和伪指令的帮助,WIN32汇编才具有很多高级语言的特性,很多 语法和C差不多。  1、WIN32汇编程序基本结构   .386   .MODEL Flat,STDCALL   .DATA     初始化值的全局变量定义   .DATA?     未初始化值的全局变量定义   .CONST     常量定义   .CODE    ..............    ...............        程序入口LABEL     ............     ............    end程序入口LABEL2、变量定义   (1)定义全局变量   全局变量定义在.data和.data?内,   初始化变量的定义方式如下:   .data   变量名  类型  初始值1,初始值2,.......   变量名  类型  重复次数dup(初始值1,初始值2,....)       注意:如果用?表示初始值的话,则表示0      未初始化变量的定义方式是   .data?    变量名  类型 ?    (2)条件测试语句   (A)基本结构    .IF条件       程序代码    [.ELSEIF]条件比较      程序代码      .......   [.ELSE]       程序代码    .ENDIF   (3)操作符   (A)比较操作符    == 相等   !=  不等于   >   大于    >=  大于或等于   <   小于    <=  小于或等于   &   位测试    !  逻辑非   &&  逻辑与   ||  逻辑或   (B)位操作符    AND按位与   OR  按位或   XOR 异或    SHL逻辑左移    SHR逻辑右移   (C)标志寄存器操作符    CARRY?是否进位   OVERFLOW? 是否溢出   PARITY?  奇偶位是否置位   SIGN?   符号位标志位是否被置位   ZERO?   零位标志位是否置位   (4)循环语句  (A)while语句  while 条件    ..........    ..........   [.break[.if 退出条件]]   [.contine[.if 退出条件]]]  .end(B)repeat语句.repeat.....................[.break[.if 退出条件]][.contine[.if 退出条件]]].until 条件(或.untilcxz [条件])(5)子程序定义1、定义子程序名 proc [距离][语言类型][可视区域][USERS 寄存器列表][,参数:类型]...[VARARG]local 局部变量列表............................................子程序名 endp2、如果在未定义前使用,要声明、函数名 proto [距离][语言][参数1]:数据类型,[参数2]:数据类型,...............(6)数据结构(A)声明wndclass struct...............wndclass ends(B)定义mystruct wndclass<1,1,...,1>mystruct wndclass <>(C)使用mov eax,mystruct.lpfnwndproc mov esi,offset mystructassume esi: ptr WNDCLASSmov eax,[esi].lpfnwndproc .......assume esi:nothing四、在WIN32汇编中的使用WINDOWS API  WIN32汇编如果没有API的帮助无法实现很多功能,笔者没见过在WIN32汇编程序不调用API的。  调用API实际上是靠堆栈来完成参数传递的,既然是堆栈,那就要遵守后进先出的原则,这意味API的第一个参数是最后一个放入堆栈的,最后 一个参数是第一个放入堆栈的。     调用方式如下:push 参数n..........  push 参数2p ush 参数1call API函数名  为了简化代码,也可以使用以下这种方式调用APIinvoke API函数名,参数1,参数2,.....,参数n