《Windows环境下32位汇编语言程序设计》 第三章笔记

  • Post author:
  • Post category:其他




模式定义

.386
.model flat,stdcall
option casemap:none
  • .386语句是汇编语言的伪指令,用于告诉编译器在本程序中使用的指令集。
  • .model语句用来定义程序工作的模式,它的用法是:

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



内存模式

模式 内存使用方式
tiny 用来建立 .com文件,所有的代码、数据和堆栈都在同一个64KB段内
small 建立代码和数据分别用一个64KB段的 .exe文件
medium 代码段可以有多个64KB段,数据段只有一个64KB段
compact 代码段只有一个64KB段,数据段可以有多个64KB段
large 代码段和数据段都可以有多个64KB段
huge 同large,并且数据段中的一个数组也可以超过64KB
flat Win32程序使用的模式,代码和数据段使用同一个4GB段
  • option语句定义的选项有很多,在win32汇编程序中,需要的只是定义option casemap:none,这个语句定义了程序中的变量和子程序名是否对大小写敏感,由于Win32 API名称是区分大小写的,所以必须指定这个选项,否则在调用API的时候会有问题



段的定义



数据段

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

    1. 可读可写的已定义变量。这些数据在源程序中已经被定义了初始值,而且在程序的执行中有可能被更改,如一些标志等,这些数据必须定义在.data段中,.data段一般存放在可执行文件的_DATA节区内。
    2. 可读可写的未定义变量。这些变量一般是当做缓冲区或者在程序执行后才开始使用的。这些数据可以定义在.data段中,也可以定义在.data?段中,但一般把它放到.data?段中。虽然定义在这两种段中都可以正常使用,但定义在.data?段中不会增大.exe文件的大小。

      3.可读不可写的常量。如一些要显示的字符串信息,他们在程序装入的时候已经有效,在整个执行过程中不需要修改,这些数据可以放在 .const段中, .const段是常量段,它是可读不可写的



代码段

  • .code段是代码段,所有的指令都必须写在代码段中,在可执行文件中,代码段一般是放在_TEXT节区中的,Win32环境中的数据段是不可执行的,只有代码段的属性。对于工作在特权级3的应用程序来说,.code段是不可写的。



堆栈段

  • 在程序中不必定义堆栈段,系统会自动分配堆栈空间。堆栈段的内存属性是可读可写可执行的。



调用API



使用invoke语句


invoke 函数名 [,参数1] [,参数2]......



函数的声明

在调用API函数的时候,函数原型也必须预先声明,否则,编译器会不认这个函数。invoke伪指令也无法检查参数个数。声明函数的格式是:


函数名 proto [距离] [语言] [参数1]:数据类型, [参数2]:数据类型,......

  • proto是函数声明的伪指令
  • 距离 可以是NEAR,FAR,NEAR16,NEAR32,FAR16或FAR32,Win32只有一个平坦的段,无所谓距离,所以在定义时是忽略的
  • 语言类型就是 .model那些类型,如果忽略,则使用.model定义的默认值
  • 参数,由于Win32 API仅仅使用了dword类型的参数,所以绝大多数的数据类型都是doword。



include语句

  • 在Win32汇编中使用API函数,程序必须知道调用的API函数存在于哪个DLL中,否则操作系统必须搜索系统中存在的所有DLL,并且无法处理不同DLL中的同名函数,所以必须有个文件包括DLL库正确的定位信息,这个任务是由导入库来实现的。


includelib 库文件名



includelib <库文件名>



全局变量



全局变量的定义

Win32汇编的全局变量定义在.data或.data?段内,可以同时定义变量的类型和长度:


变量名 类型 初始值1,初始值2,......



变量名 类型 重复数量 dup (初始值1,初始值2,......)



变量的类型

名称 表示方式 缩写 长度(字节)
字节 byte db 1
word dw 2
双字 dword dd 4
三字 fword df 6
四字 qword dq 8
十字节BCD码 tbyte dt 10
有符号字节 sbyte 1
有符号字 sword 2
有符号双字 sdword 4
单精度浮点数 real4 4
双精度浮点数 real8 8
10字节浮点数 real10 10



局部变量的定义


local 变量1[[重复数量]] [:类型],变量2[[重复数量]] [:类型]......

  • local伪指令必须紧接在子程序定义的伪指令proc后,数据类型不能缩写,默认的类型是dword。局部变量的作用域是当前的子程序。



子程序的定义

子程序名 proc [距离] [语言类型] [可视区域] [USES 寄存器列表] [,参数:类型] ......[VARARG]
        local 局部变量列表
        
        程序

子程序名 endp
  • 距离——可以是NEAR,FAR等,win32中只有一个平坦的段,所以对距离的定义忽略
  • 语言类型——表示参数的使用方式和堆栈平衡的方式,如果忽略,则使用程序头部.mode定义的值
  • 可视区域——可以是PRIVATE,PUBLIC和EXPORT。PRIVATE表示子程序只对本模块可见;PUBLIC表示对所有的模块可见(在最后编译链接完成的.exe文件中);EXPORT表示是导出函数,当编写DLL的时候要将某个函数导出的时候可以这样使用。默认的设置是PUBLIC。
  • USES寄存器列表——表示由编译器在子程序指令开始前自动安排push这些寄存器指令,并且在ret前自动安排pop指令,用于保存执行环境。
  • 参数——参数指参数的名称,在定义参数名的时候不能跟全局变量和子程序中的局部变量重名。
  • 类型——由于win32中的参数类型只有32位(dword)一种类型,所以可以忽略。
  • VARARG——表示在已确定的参数后还可以跟多个数量不确定的参数,在Win32汇编中唯一使用VARARG的API就是wsprintf。



不同语言调用方式的差别

C SysCall StdCall BASIC FORTRAN PASCAL
最先入栈参数
清除堆栈者 调用者 子程序 子程序 子程序 子程序 子程序
最先入栈参数



分支语句

.if 条件表达式1
 	表达式1为“真”时执行的指令
[.elseif 条件表达式2]
 	表达式2为“真”时执行的指令
[.elseif 条件表达式3]
 	表达式3为“真”时执行的指令
.....
[.else]
	所有表达式为“否”时执行的指令
.endif



循环语句

.while 条件测试表达式
	指令
	[.break [.if 退出条件]]
	[.continue]
.endw
或
.repeat
	指令
	[.break [.if 退出条件]]
	[.continue]
	.until 条件测试表达式 (或.untilcxz [条件测试表达式1]



使用标号@@

  • 当@@做标号时,可以用@F和@B来引用它,@F表示本指令后的第一个@@标号,@B表示本指令前的第一个@@标号,程序中可以有多个@@标号,但是@B和@F只寻找匹配最近的一个。



版权声明:本文为qq_17111397原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。