友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
读书室 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

windows环境下32位汇编语言程序设计-第2部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!

。386

。model flat;stdcall

option casemap:none

  

。stack '堆栈段的大小'

。data

  

。data?

  

nst

  

de

  

  

     

end 开始标号

。stack,。data,。data?,nst和 de是分段伪指令,Win32中实际上只有代码和数据之分,。data,。data?和 nst是数据段,de是代码段,和DOS汇编不同,Win32汇编不必考虑堆栈,系统会为程序分配一个向下扩展的、足够大的段作为堆栈段,所以 。stack段定义常常被忽略。

   前面不是说过Win32环境下不用段了吗?是的,这些“段”实际上并不是DOS汇编中那种意义的段,而是内存的“分段”。上一个段的结束就是下一个段的开始,所有的“分段”合起来,包括系统使用的地址空间,就组成了整个可以寻址的4 GB空间。Win32环境的内存管理使用了80386处理器的分页机制,每个页(4 KB大小)可以自由指定属性,所以上一个4 KB可能是代码,属性是可执行但不可写,下一个4 KB就有可能是既可读也可写但不可执行的数据,再下面呢?有可能是可读不可写也不可执行的数据。Win32汇编源程序中“分段”的概念实际上是把不同类型的数据或代码归类,再放到不同属性的内存页(也就是不同的“分段”)中,这中间不涉及使用不同的段选择器。虽然使用和DOS汇编同样的 de和 。data语句来定义,意思可是完全不同了!为了简单起见,在本书中还是简称“段”,读者应该注意到其中不同的含义。



 
来源:电子工业出版社 作者:罗云彬 上一页         回书目         下一页          
上一页         回书目         下一页          
  


第3章 使用MASM


3。1 Win32汇编源程序的结构(3)

    
2。 数据段

。data,。data?和 nst定义的是数据段,分别对应不同方式的数据定义,在最后生成的可执行文件中也分别放在不同的节区(Section)中。程序中的数据定义一般可以归纳为3类:

第一类是可读可写的已定义变量。这些数据在源程序中已经被定义了初始值,而且在程序的执行中有可能被更改,如一些标志等,这些数据必须定义在 。data段中,。data段是已初始化数据段,其中定义的数据是可读可写的,在程序装入完成的时候,这些值就已经在内存中了,。data段存放在可执行文件的_DATA节区内。

第二类是可读可写的未定义变量。这些变量一般是当做缓冲区或者在程序执行后才开始使用的,这些数据可以定义在 。data段中,也可以定义在 。data?段中,但一般把它放到 。data?段中。虽然定义在这两种段中都可以正常使用,但定义在 。data?段中不会增大 。exe文件的大小。举例说明,如果要用到一个100 KB的缓冲区,可以在数据段中定义:

szBuffer            db      100 * 1024 dup (?)

如果放在 。data段中,编译器认为这些数据在程序装入时就必须有效,所以它在生成可执行文件的时候保留了所有的100 KB的内容,即使它们是全零!如果程序其他部分的大小是50 KB,那么最后的 。exe文件就会是150 KB大小,如果缓冲区定义为1 MB,那么 。exe文件会增大到1 050 KB。。data?段则不同,其中的内容编译器会认为程序在开始执行后才会用到,所以在生成可执行文件的时候只保留了大小信息,不会为它浪费磁盘空间。和上面同样的情况下,即使缓冲区定义为1 MB,可执行文件同样只有50 KB!总之,。data?段是未初始化数据段,其中的数据也是可读可写的,但在可执行文件中不占空间,。data?段在可执行文件中存放在_BSS节区中。

第三类数据是一些常量。如一些要显示的字符串信息,它们在程序装入的时候也已经有效,但在整个执行过程中不需要修改,这些数据可以放在 nst段中,nst段是常量段,它是可读不可写的。一般为了方便起见,在小程序中常常把常量一起定义到 。data段中,而不另外定义一个 nst段。在程序中如果不小心写了对 nst段中的数据做写操作的指令,会引起保护错误,Windows会显示一个如图3。2所示的提示框并结束程序。


图3。2  对 nst段写操作引起的非法操作

如果不怕程序可读性不佳的话,把 nst段中定义的东西混到 de段中去也可以正常使用,因为 de段也是可以读的。

3。 代码段

de段是代码段,所有的指令都必须写在代码段中,在可执行文件中,代码段是放在_TEXT节区中的。Win32环境中的数据段是不可执行的,只有代码段有可执行的属性。对于工作在特权级3的应用程序来说,de段是不可写的,在编DOS汇编程序的时候,好事的程序员往往有个习惯,就是靠改动代码段中的代码来做一些反跟踪的事情,如果企图在Win32汇编下做同样的事情,结果就是和上面同样的“非法操作”。

当然事物总有两面性,在Windows 95下,在特权级0下运行的程序对所有的段都有读写的权利,包括代码段。另外,在优先级3下运行的程序也不是一定不能写代码段,代码段的属性是由可执行文件PE头部中的属性位决定的,通过编辑磁盘上的 。exe文件,把代码段属性位改成可写,那么在程序中就允许修改自己的代码段。一个典型的应用就是一些针对可执行文件的压缩软件和加壳软件,如Upx和Pepact等,这些软件靠把代码段进行变换来达到解压缩或解密的目的,被处理过的可执行文件在执行时需要由解压代码来将代码段解压缩,这就需要写代码段,所以这些软件对可执行文件代码段的属性预先做了修改。

3。1。3  程序结束和程序入口

在C语言源程序中,程序不必显式地指定程序由哪里开始执行,编译器已经约定好从main()函数开始执行了。而在汇编源程序中,并没有一个main函数,程序员可以指定从代码段的任何一个地方开始执行,这个地方由程序最后一句的end语句来指定:

end     '开始地址'

这句语句同时表示源程序结束,所有的代码必须在end语句之前。

end start

上述语句指定程序从start这个标号开始执行。当然,start标号必须在程序的代码段中有所定义。

但是,一个源程序不必非要指定入口标号,这时候可以把开始地址忽略不写,这种情况发生在编写多模块程序的单个模块的时候。当分开写多个程序模块时,每个模块的源程序中也可以包括 。data,。data?,nst和 de段,结构就和上面的Win32 Hello World一样,只是其他模块最后的end语句必须不带开始地址。当最后把多个模块链接在一起的时候,只能有一个主模块指定入口地址,在多个模块中指定入口地址或者没有一个模块指定了入口地址,链接程序都会报错。

3。1。4  注释和换行

注释是源程序中不可忽略的一部分,汇编源程序的注释以分号(;)开始,注释既可以在一行的头部,也可以在一行的中间,一行中所有在分号之后的字符全部当做注释处理,但在字符串的定义中包含在引号内的分号不当做是注释的开始。

举例如下:

;这里是注释

call    _PrintChar      ;这里是注释

szChar  db 'Hello; world;';0dh;0ah   ;world后面的分号不是注释,后面的才是

当源程序的某一行过长,不利于阅读的时候,可以分行书写,分行的办法是在一行的最后用反斜杠()做换行符,如:

        invoke  MessageBox;NULL;offset szText;offset szCaption;MB_OK

可以写为:

    invoke  MessageBox;

        Null;              ;父窗口句柄

        offset szText;     ;消息框中的文字

        offset szCaption;  ;标题文字

        MB_OK

“一行的最后”指的是最后一个有用的字符,反斜杠后面多几个空格或加上注释并不影响换行符的使用,如上例所示,这一点和makefile文件中换行符的规定有所不同。



 
来源:电子工业出版社 作者:罗云彬 上一页         回书目         下一页          
上一页         回书目         下一页          
  


第3章 使用MASM


3。2 调用API(1)

    
3。2。1  API是什么

Win32程序是构筑在Win32 API基础上的。在Win32 API中,包括了大量的函数、结构和消息等,它不仅为应用程序所调用,也是Windows自身的一部分,Windows自身的运行也调用这些API函数。

在DOS下,操作系统的功能是通过各种软中断来实现的,如大家都知道int 21h是DOS中断,int 13h和int 10h是BIOS中的磁盘中断和视频中断。当应用程序要引用系统功能时,要把相应的参数放在各个寄存器中再调用相应的中断,程序控制权转到中断中去执行,完成以后会通过iret中断返回指令回到应用程序中。如DOS汇编下的Hello World程序中有下列语句:

    mov     ah;9

    mov     dx;offset szHello

    int     21h

这3条语句调用DOS系统模块中的屏幕显示功能,功能号放在ah中,9号功能表示屏幕显示,要输出到屏幕上的内容的地址放在dx中,然后去调用int 21h,字符串就会显示到屏幕上。

这个例子说明了应用程序调用系统功能的一般过程。首先,系统提供功能模块并约定参数的定义方法,同时约定调用的方式,应用程序按照这个约定来调用系统功能。在这里,ah中放功能号9,dx中放字符串地址就是约定的参数,int 21h是约定的调用方式。

下面来看看这种方法的不便之处。首先,所有的功能号定义是冷冰冰的数字,int 21h的说明文档是这样的:

Int 21 Functions:

 

00——Program termination

01——Keyboard input

02——Display output

03——AUX input

04——AUX output

05——Printer output

06——Direct console I/O

07——Direct STDIN input; no echo

08——Keyboard input; no echo

09——Print string

0A——Buffered keyboard input

0B——Check standard input status

再进入09号功能看使用方法:

Print string (Func 09)

    AH = 09h

    DS:DX …》 string terminated by 〃〃

这就是DOS时代汇编程序员都有一厚本《中断大全》的原因,因为所有的功能编号包括使用的参数定义仅从字面上看,是看不出一点头绪来的。

另外,80x86系列处理器能处理的中断最多只能有256个,不同的系统服务程序使用了不同的中断号,这少得可怜的中断数量就显得太少了,结果到最后是中断挂中断,大家抢来抢去的,把好好的一个系统搞得像接力赛跑一样。

对于这些弱点,程序员们都有个愿望:系统功能如果能以功能名称作为子程序名直接调用就好了,参数也最好定义的有意义一点,这样一来写程序就会方便得多,编系统扩展模块也就不必老是担心往哪个中断上面挂了,最好能把上面int 21h/ah=9的调用写成下面这副样子:

call    PrintString;addr szHello

终于,好消息出来了,Win32环境中的编程接口就是这个样子,这就是API,它实际上是以一种新的方法代替了DOS中用软中断的方式。和DOS的结构相比,Win32的系统功能模块放在Windows的动态链接库(DLL)中,DLL是一种Windows的可执行文件,采用的是和 。exe文件同样的PE格式,在PE格式文件头的导出表中,以字符串形式指出了这个DLL能提供的函数列表。应用程序使用字符串类型的函数名指定要调用的函数。

应用程序在使用的时候由Windows自动装入DLL程序并调用相应的函数。

实际上,Win32的基础就是由DLL组成的。Win32 API的核心由3个DLL提供,它们是:

●   KERNEL32。DLL——系统服务功能。包括内存管理、任务管理和动态链接等。

●   GDI32。DLL——图形设备接口。利用VGA与DRV之类的显示设备驱动程序完成显示文本和矩形等功能。

●   USER32。DLL——用户接口服务。建立窗口和传送消息等。

当然,Win32 API还包括其他很多函数,这些也是由DLL提供的,不同的DLL提供了不同的系统功能。如使用TCP/IP协议进行网络通信的DLL是Wsock32。dll,它所提供的API称为Socket API;
返回目录 上一页 下一页 回到顶部 1 4
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!