汇编语言学习笔记(三)

CH3Windows汇编基础

.386

.model flat,stdcall

option casemap:none

定义程序使用的指令集、工作模式

相应的还有:.8086,.486,.586,.586p

内存模式有很多,如:

tiny small medium compact large huge flat

汇编经常遇到这样的代码:

mov ax,DATA

mov ds,ax

作用是给DS赋值。参考前面描述CPU结构的知识,知道不能直接写成

mov ds,DATA

但对于.model flat模式,MASM自动做了下面的定义:

ASSUME CS:flat, DS:flat, ES:flat, SS:flat, FS:ERROR,GS:ERROR

flat是内存平坦模式,意思是段寻址4G空间。

因此,CSDSESSS可以在程序中平坦使用。使用FSGS则会报错。

.model 语句用于指定调用规则,即子程序的调用方式。就是说明了在调用API时的参数传递次序和堆栈平衡的方法。

option casemap:none 说明程序对大小写敏感。注意,Windows API是大小写敏感的,因此这里这么定义。

使用includelib 链接需要用到的lib库,如:

includelib user32.lib

对于所有要用到的库函数,在程序的开始部分必须预先声明。包括:

函数名称 PROTO[调用规则]:[第一个参数类型][,:后续参数类型]

全部声明所用到的Api函数显然很麻烦,因此可以使用include把声明包括进来,用法和C一样。

.data

数据段

.code

代码段,遇到end代码段结束。

.stack [堆栈大小]

定义堆栈段

有的变量一开始并不赋值,在程序运行过程中才赋值,因此放到:

.data?中。

如果定义一个缓冲区,则:

buffer byte 65536 dup(?)

定义固定变量,程序运行过程中不再修改:

.const

==========

一段Hello World例子代码

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

.386

.model flat,stdcall

option casemap:none

MessageBoxA PROTO :dword , :dword, :dword, :dword

MessageBox equ <MessageBoxA>

includelib user32.lib

NULL equ 0

MB_OK equ 0

.stack 4096

.data

szTitle byte 'Hi!',0

szMsg byte 'Hello world!',0

.code

start:

invoke MessageBox, NULL, offset szMsg, offset szTitle, MB_OK

ret

end start

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

编译指令:

ml /coff hello.asm /link /subsystem:windows

操作数的寻址方式:

1、 立即数寻址,操作数是常数

mov AL,0

mov EAX, 0fffffffH

2、 寄存器寻址,不和内存打交道。

MOV EAX, EBX

除了12两种外,其它寻址都要和内存打交道。

3、 直接寻址,给出操作数的内存地址。

定义变量dVar,寻址时

MOV EAX, dVar

MOV dVar, EBX

这相当于在C语言里用指针赋值一样

4、 寄存器间接寻址,地址在寄存器中。

MOV ESI, 00404011H

MOV EAX, [ESI]

5、 寄存器相对寻址,地址是寄存器和一个立即数相加得到的结果。

MOV ESI,00404011H

MOV EAX,[ESI + 4]

6、 基址变址寻址,地址是两个寄存器相加的结果。

MOV ESI, 0040200AH

MOV EBX,4

MOV EDI,[EBX + ESI]

7、 基址变址相对寻址,两个寄存器相加后再加一个立即数

MOV ESI, 0040200AH

MOV EBX,4

MOV EDI,[EBX + ESI 4]

8、 基址变址比例相对寻址,变址寄存器需要乘以一个比例数。

MOV ESI, 0040200AH

MOV EBX,4

MOV EDI,[EBX*2 + ESI 4]

段超越

为了确定内存中的地址,还需要借助段寄存器。

如果在基址寄存器中用了ESP(保存栈顶偏移)和EBP(栈数据访问),则段寄存器中的内存操作数在SS中,这是一种默认。

使用段超越前缀能够改变寻址方式中的默认使用的段寄存器。

MOV EAX, CS:[EDI] ;默认是DS

MOV EBX, ES:[ESP – 4] ;默认是SS

MOV DS: [EBP] ,ECX

CS段只能用来读取数据,因此只能作为源操作数的段前缀

MOV CS:[0040200AH] , EAX

Windows 32环境中,FS段保存系统使用的一些信息,如果要访问,必须明确指出段寄存器为FS。另外,Win32环境下,CSDSESSS在内存中指向同一个段,大小为4G,程序中一般不需要使用段超越前缀。

数据定义

二进制:后跟b/B0001b

八进制:后跟o33o

十进制:后跟D27d

十六进制:后跟H2Ah

程序中可以指明默认使用16进制数

.radix 16

简单数据类型

类型 助记符 简写 占用字节数 范围

字节 BYTE DB 1 0~255

WORD DW

双字 DWORD DD

远字 FWORD DF

四字 QWORD DQ

十字 TBYTE DT

有符号字节 SBYTE

有符号字 SWORD

有符号双字 SDWORD

定义变量:

[变量名] 助记符 表达式,[,表达式]

表达式是 则不进行初始化

数组定义

ch DWORD 50 DUP (0)

定义ch为数组,共50个元素,每个元素初始值为0

DUP是重复数据操作符。可以嵌套

ch DWORD 3 DUP (2 DUP (-1,-2))

相当于char ch[3][2], ch[0] = {-1,-2}ch[1] = {-1,-2} 。。。。

伪操作符,不真正生成数据。

PTR ,作用有二,

一是临时改变变量类型:

dVar DWORD 01020304H

MOV AX , WORD PTR dVar

MOV DX, WORD PTR dVar + 2

如果不用PTR就会报错,因为AX16位,而dVar是双字类型。

MOV BYTE PTR dVar + 1 , 0FFH

MOV BYTE PTR dVar + 3 , 12H

dVar的第一字节设置成0ffH,第三字节设置成12H

作用二,指明操作传递的数据类型

有些语句能够知道传递的类型,比如

MOV AL , 0 ;传一个字节

MOV AX , [EBX] ;传一个字

但下面的语句就不知道了:

MOV [EBX] , 0

需要这样写:

MOV BYTE PTR [EBX] , 0

EQU,相当于C语言的#define

比如:

NULL EQU 0

MB_OK EQU 0

等于符号

为一个变量或者表达式定义一个等价符号名。

I = 100

DwFirst DWORD I

I = I + 1

DwSecond DWORD I

$ 当前地址计数器值

MOV EAX , $

EAX中是该指令所在的地址。

注意,程序中的每一行都有一个地址。

ORG 为程序的地址计数器赋值

aVar BYTE 01h

ORG $ + 10

bVar BYTE 02h

计数器当前值的基础上增加了10

Offset 取地址

下面两条语句是等价的

dVar3 DWORD wVar2

dVar3 DWORD offset wVAr2

下面语句不等价

MOV EBX , dVar2

MOV EBX , offset dVar2

Type 返回变量占用字节数

Length 返回变量用DUP重复的数目,无重复返回1

Size 返回type * length的值

操作符

算术操作符

× / MOD

MOV EAX , 4 * 5

MOV EAX , OFFSET dVar2 – 10

Mov eax , 30 / 8

Mov eax , 30 mod 8

逻辑操作符

AND OR XOR NOT

关系操作符

EQ(等于) NE(不等于) LT(小于) LE(小于等于) GT(大于) GE(大于等于)

关系成立,结果为真,关系不成立,结果为假。

寻址问题

在实际寻址时,操作数类型很关键,比如:

MOV AL , -1

MOV AX , -1

MOV EAX , -1

同样是-1,但第一个-1 = 0FFH,第二个-1 = 0FFFFH,第三个-1 = 0FFFFFFFFH

数组元素的访问

可以这样定义变量

bVar byte 01h , 02h , 03h , 04h

wVar word 0101h , 0102h , 0103h , 0104h

dVar dword 01010101h , 01010102h , 01010103h , 01010104h

访问时

mov ebx , 2

mov al , bVar[ebx] ; al 中为03h

mov ax , wVar[ebx * 2] ; 加入比例因子,ax 中为0103h

mov eax , dVar[ebx * 4] ;

你可能感兴趣的:(数据结构,C++,c,windows,D语言)