win32汇编基本结构

(1)Summary
win32汇编和8086或者单片机汇编,总体来说都是类似的,不同的汇编的主要差别无非就是指令区别,伪指令的区别等。

(2)模式定义

.386    
.model flat,stdcall    
option casemap:none

这些指令定义了程序使用的指令集、工作模式和格式。
1. 定义使用的指令集
.386是汇编语言的伪指令,类似的指令有.8086,.186,.286,.386/.386p,.486/.486p和 .586/.586p等,用于告诉编译器在本程序中使用的指令集。默认使用的是8086指令集,所以如果要写win32的汇编,使用32位寄存器,就必须使用.386指令。
另外,这些指令中,带p的伪指令表示程序中可以使用特权指令。
要使用80486或Pentiun处理器的指令,就需要使用.486或.586,另外,和指令集相关的伪指令还有.mmx伪指令,表明除了使用基本的.586指令外,还能使用扩展的MMX指令。如下:

.586  
.mmx  

2. .model指令
用于定义程序工作的模式,使用方法:

.model 内存模式[,语言模式][,其他模式]

 

对于win32的内存模式,只有一种内存模式为flat,即平坦模式,表明代码和数据段使用同一个4GB段。在Dos程序中,程序开始都会有mov ax,data;mov ds,as;用于把数据段寄存器指向data数据段,而win32的flat平坦模式带来的好处是,不需要使用ds或es等段寄存器,因为所有的4GB空间用32位寄存器都能访问到,这就是平坦内存模式的好处。
model还有一个是语言模式,定义子程序的调用方式,不同的高级语言在调用子程序的时候使用堆栈来传递参数,但是处理方法不完全相同,如果要和其他语言配合,就必须制定相应的语言模式。(windows API的调用使用的是stdcall格式)
3. option选项
option语句能定义的选项很多,对于win32汇编程序,只需要定义option casemap:none,定义程序的变量和子程序是否大小写敏感。

总结:这部分的一些指令更多的是一些说明信息,并不执行真正的指令。
(3)段定义
汇编代码是分段的,数据段、代码段、堆栈段等等。在win32汇编中,使用.stack,.data,.data?,.const和 .code等分段伪指令。win32中实际只有代码和数据段之分,.data,.data?和.const都是数据段,.code是代码段。win32汇编不需要考虑堆栈,系统会为程序分配一个向下扩展的、足够大的段作为堆栈段,所以win32中.stack被忽略。
另外,win32的分段和Dos的分段的概念是不一样的,或者说win32是不需要分段的。win32的分段指的是内存的分段,具体不展开了,总之,win32的分段实际上是把不同类型的数据或代码归类,放到不同的内存页中,不涉及使用不同的段寄存器。
1. 数据段
.data,.data?,.const定义数据段,对应不同方式的数据定义,在最后生成的可执行文件中也放在不同的section中。程序中的数据定义一般分为三类。
第一类是可读可写的已定义变量,这些数据在源程序中定义初始值,是可读可写的,这些数据只能定义在.data段中。.data段一般放在可执行文件的_DATA节(section)中。
第二类是可读可写的未定义变量。一般当作缓冲区或程序执行后才开始使用,可以定义到.data,也可以定义在.data?中(一般放在.data?中)。区别在于.data段中定义,会增大可执行文件大小,因为编译器认为这些数据在程序装入就必须有效,所以定义的数据多大,程序大小就会增加多大。而.data?段定义的时候编译器认为程序在开始执行后才会用到,所以在可执行文件中只会保留大小信息,.data?段在可执行文件中一般放到_BSS节中。
第三类数据是一些常量,在程序装入时已经有效,但是运行过程不能修改。可以放到.const段中,也可以放到.data段中(只是就成为可读可写了)。另外,常量数据也可以定义到.code中(代码段也是只读的),但是会降低程序可读性。
2. 代码段
.code段是代码段,所有的指令都是在代码段中,在可执行文件中,代码段一般是放在_TEXT节中。
3. 堆栈段
win32程序不用定义堆栈段,系统会自动分配堆栈空间。

说明:上面提到,在可执行文件中,有_DATA,_TEXT等节,其实,在vs生成的汇编中也会直接使用_DATA SEGMENT,_TEXT SEGMENT等,相信其含义就是.data和.code了。
如果使用.data,.code,那么两者之间就不能有其它内容了,所以,有时候,使用_DATA/_TEXT SEGMENT和ENDS配合使用更好的。
说明:发现,这些东西本来就都是8086汇编的东西,以前都学过了,只是有些伪指令以前没怎么知道,哎,不管这些概念了,什么8086汇编,win32汇编的,总之,我的目标不是自己去写汇编,而是看懂一些汇编代码就可以了。
(4)程序入口和出口
汇编程序需要指定入口和出口,当然,入口和出口属于代码的部分,所以首先它们是在.code段内部的。汇编程序可以从代码段中的任何一个地方开始执行,这个地方由最后一句的end语句来决定。

end label

其中,label是一个标号,可以为任意字符串.如下,通过PROC过程伪指令定义程序的开始:

_main PROC  
...  
END

 

说明:PROC不是用于定义”主函数“的,可以定义任何一个函数。END也不只是用于”主函数“的结束,而是任何的函数的结束。
(5)程序注释和换行
汇编使用分号为注释的开始,多行书写代码换行用”\”。

例子:
上面说明的不是很清楚,因为发现有些东西都是8086的内容,不想重复。下面就弄两个例子复习一下汇编的基本结构吧。

; file: 1.asm  
.686P               ; MUST  
.model  flat        ; MUST  
  
INCLUDELIB LIBCMT       ; MUST for ml.exe, startup  
  
.data  
    $TEXT   DB  'Hello, world', 0aH, 00H  
  
.code  
    _main PROC  
    ret 0  
    _main   ENDP  
      
END     ; END of source file

用命令:ml 1.asm编译可以成功。
说明一下:
(1) 其中INCLUDELIB LIBCMT,不是很清楚,但是知道是跟入口有关,可能是ml.exe汇编器会入口有一定的要求,需要包含这个库,而且,和上面说的不一样的是,这里必须是_main,命名不能任意,可能也是ml.exe的要求,总之,能看懂即可。
(2) 最后的一个END,是表示整个源文件的结束,必须要有。顺便说一下,汇编的指令是不分大小写的,所以可以写成end。
上面的代码和下面的是一样的效果:

; file: 1.asm  
.686P               ; MUST  
.model  flat        ; MUST  
  
INCLUDELIB LIBCMT       ; MUST for ml.exe, startup  
  
_DATA   segment  
    $TEXT   DB  'Hello, world', 0aH, 00H  
_DATA   ends  
      
;.code  
_TEXT segment  
    _main PROC  
    ret 0  
    _main   ENDP  
_TEXT ends  
  
end     ; END of source file

 

您可能还喜欢...

想说点什么吗?

您将是第一位评论人!

提醒
avatar