Jack's第一个Win32汇编程序HelloWorld

    技术2022-05-11  74

    本文已被更新,请看新版文章Jack整理的Win32汇编基础知识 http://blog.csdn.net/magus_yang/archive/2007/04/05/1552930.aspx

    标 题: Jack's第一个Win32汇编程序HelloWorld

    作 者: Jack Yang 时 间: 2007-02-26 1:02 链 接: http://blog.csdn.net/magus_yang/archive/2007/02/26/1514439.aspx Hello.asm文件的内容如下: ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 第一部分:模式和源程序格式的定义语句               .386                                    ; 指令集               .model flat,stdcall                 ; 工作模式               option casemap:none             ; 格式 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; Include 文件定义 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> include            windows.inc include            user32.inc includelib        user32.lib include            kernel32.inc includelib        kernel32.lib ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 数据段 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>               .data szCaption        db    'A MessageBox !',0 szText             db    'Hello, World !',0 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 代码段 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>               .code start:               invoke     MessageBox,NULL,offset szText,offset szCaption,MB_OK               invoke     ExitProcess,NULL ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>               end start        ; 指定程序的入口   1.         第一部分 模式和源程序格式的定义语句 第一行 指定使用的指令集(编译器使用) Win32环境工作在80386及以上的处理器中,所以必须定义.386。如果程序(VxD等驱动程序)中要用到特权指令,那么必须定义.386p。 第二行 定义程序工作的模式(包括内存模式、语言模式、其它模式) 对Win32程序来说,只有一种内存模式,即flat(平坦)模式。 Win32 API调用使用的是stdcall格式,所以Win32汇编中必须在.model中加上stdcall参数。 第三行 option语句        由于Win32 API中的API名称区分大小写,所以必须定义option casemap:none,来表明程序中的变量和子程序名对大小写敏感。   2.         包含全部段的源程序结构: .386 .model flat,stdcall option casemap:none <一些include语句> .stack [堆栈段的大小] .data <一些初始化过的变量定义> .data? <一些没有初始化过的变量定义> .const <一些常量定义> .code <代码> <开始标记> <其他语句> end 开始标记   3.         段的定义 数据段        .data               已初始化数据段,可读可写的已定义变量; 当程序装入完成时,这些值就已经在内存中;               数据定义在.data段中会增加可执行文件的大小;               .data段一般存放在可执行文件的_DATA节区(Section)内;        .data?               未初始化数据段,可读可写的未定义变量,在可执行文件中不占空间;               这些变量一般作为缓冲区或者在程序执行后才开始使用。               数据定义在.data?数据段中不会增加可执行文件的大小;               .data?段一般存放在可执行文件的_BSS节区内;        .const               常量,可读不可写的变量;   代码段        .code               所有的指令都必须写在代码段中;               Win32中,数据段是不可执行的,只有代码段有可执行的属性;               对于运行在特权级3的应用程序,.code段不可写。除非把可执行文件PE头部中的属性位改成可写;               对于运行在特权级0的程序,所有的段都有读写权限,包括代码段;               .code代码段一般存放在可执行文件的_TEXT节区内;   堆栈段        .stack               与DOS汇编不同,Win32汇编不必考虑堆栈。系统会自动分配堆栈空间;               堆栈段的内存属性是可读写并且可执行;               靠动态修改代码的反跟踪模块可以拷贝到堆栈中去边修改边执行;               缓冲区溢出技术也会用到这个特性;   4.         调用操作系统功能的方法: DOS下 操作系统的功能通过各种软中断来实现。        应用程序调用操作系统功能将经历如下三个过程:               把相应的参数放在各个寄存器中再调用相应的中断;               程序控制权转到中断中去执行;               完成以后通过iret中断返回指令回到应用程序中;        DOS下调用系统功能方法的缺点:               所有的功能号定义是难以记忆的数字;               80x86系列处理器能处理的中断最多只能有256个;               通过寄存器来传递参数,对于参数较多的函数很不方便; Win32下        系统功能模块放在Windows的动态链接库(DLL)中        作为Win32 API核心的3个DLL:               KERNEL32.DLL    系统服务功能。               GDI32.DLL           图形设备接口。               USER32.DLL         用户接口服务。   常用API的参数和函数声明,查看文档《Microsoft Win32 Programmer's Reference》   5.         Win32 API 的函数原型声明 函数原型声明的汇编格式如下: 函数名 proto [距离] [语言] [参数1]:数据类型, [参数2]:数据类型,...... proto是函数声明的伪指令 距离可以设置为NEAR、FAR、NEAR16、NEAR32、FAR16或FAR32,由于Win32中只有一个平坦的段,无所谓距离,所以在定义时可以忽略距离。 语言类型可是使用.model所定义的默认值。   以消息对话框函数MessageBox为例 C格式如下: int MessageBox(        HWND hWnd,              // Handle to owner window        LPCTSTR lpText,         // text in message box        LPCTSTR lpCaption,     // message box title        UINT uType                 // message box style        );   汇编格式如下: MessageBox Proto hWnd:dword,lpText:dword,lpCaption:dword,uType:dword 或者写为 MessageBox Proto :dword,:dword,:dword,:dword 编译器只对参数的数量和类型感兴趣,参数的名称只是增加可读性,所以可以省略。 对于汇编语言来说,Win32环境中的参数实际上只有一种类型,就是一个32位的整数(dword,double word),双字,四字节。     6.         调用Win32 API 调用API有如下两种方法: 1)        invoke               MASM提供的伪指令;               invoke伪指令的好处就是能够提高代码的可读性,减少错误;               invoke做了下面三件事:                      在编译的时候,由编译器把invoke伪指令展开成相应的push指令和call指令;                      进行参数数量的检查工作;                      如果带的参数数量和声明时的数量不符,编译器会报错; 2)        push和call的组合 80386处理器的指令   invoke      MessageBox,NULL,offset szText,offset szCaption,MB_OK 也可写为 push NULL push offset szText push offset szCaption push MB_OK call MessageBox   7.         Win32 API 函数返回值的处理方法 对于汇编语言来说,Win32 API函数返回值的类型只有dword一种类型,它永远放在eax中。 如果要返回的内容在一个eax中放不下,Win32 API采用如下方法来解决: a)         一般是eax中返回一个指向返回数据的指针; b)        在调用参数中提供一个缓冲区地址,数据直接返回到这个缓冲区中去。类似变参的概念;   8.         与字符串相关Win32 API 的分类 在Win32环境中,根据两个不同的字符集(ANSI字符集和Unicode字符集),可以把和字符串相关的API分成两类: a)         处理ANSI字符集的Win32 API函数 函数名称的尾部带一个“A”字符; ANSI字符串是以NULL结尾的一串字符数组,每一个ANSI字符占一个字节的宽度; MessageBoxA Proto hWnd:dword,lpText:dword,lpCaption:dword,uType:dword b)        处理Unicode字符集的Win32 API函数 函数名称的尾部带一个“W”字符;               每一个Unicode字符占两个字节的宽度,所以可以同时定义65536个不同的字符;               MessageBoxW Proto hWnd:dword,lpText:dword,lpCaption:dword,uType:dword   Windows 9x系列不支持Unicode版本的API,绝大多数的API只有ANSI版本。 只有Windows NT系列才完全支持Unicode版本的API。 为了编写在几个平台中都能通用的程序,一般应用程序都使用ANSI版本的API函数集。   提高程序可移植性的一个方法: 一般在源程序中不直接指明使用Unicode还是ANSI版本,而是使用宏汇编中的条件汇编功能来统一替换。 比如,在头文件中做如下定义: if UNICODE        MessageBox equ <MessageBoxW> else        MessageBox equ <MessageBoxA> endif 然后在源程序的头部指定UNICODE=1或UNICODE=0,重新编译后就能产生不同的版本。   未完,待续。。。     参考资料: 罗云彬的《Windows环境下32位汇编语言程序设计》(第二版)第三章  

    最新回复(0)