原创

: 32位汇编语言复习文档

32位汇编语言复习文档

汇编使用C语言的参数
printf的参数从右向左push,最后再 call crt_printf 和 call crt_scanf;
调用伪指令 CALL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.686
.model flat, stdcall
.stack 4096
INCLUDE Irvine32.inc
INCLUDELIB Irvine32.lib
include F:\masm32\include\msvcrt.inc
includelib F:\masm32\lib\msvcrt.lib
.data
me_str db 'hello world! %x\n',0
me_input_int db '%d'
int32_val dd 123
ExitProcess proto,dwExitCode:dword
.code
main proc
push offset int32_val
push offset me_input_int
call crt_scanf;
push int32_val
push offset me_str
call crt_printf
invoke ExitProcess,0
main endp
end main

CF是无符号数溢出标志,OF是有符号数溢出标志

db定义字节类型变量,一个字节数据占1个字节单元,读完一个,偏移量加1 AL 8位
Define byte

dw定义字类型变量,一个字数据占2个字节单元,读完一个,偏移量加2 AX 16位
Define word

dd定义双字类型变量,一个双字数据占4个字节单元,读完一个,偏移量加4 EAX 32位 define dword

Dq 存放64位的双精度数据 8个字节 一般使用FPU寄存器来计算,但是也可以使用强制类型转换赋值给通用寄存器

使用
DD 最多存放2个WORD,4个字符 ,也就是Dword的大小,DD就是DWORD ,DOUBLE WORD
是伪指令的写法
两个字符为一个byte,
2个字节为DWORD,
也就是32位,4个BYTE

int32_val2 dd ‘1234’
定义dd ,目标内存为 倒序
int32_val2 dd ‘12345’ 报错,定义的字符串过大,超出32位的存放大小

0X 39 30
57 48
57=316+9
48=3
16

0X 3039 =3163+9*162+316 = 12345

通过小端对齐,把高字节的39放在内存高位,所以为

39 30

理论上,DD 类型的数据可以存放为2^32次方的数据

DW 16位 2个字节 1个WORD 初始值可能为 00 00 首先存放在低字节处,好歹大小也可以有2^16

0x:d2 4d
D:19922

实际存储为4DD2 还是小段对齐,优先放在低位 ,在存放到高位 的内存

12*16+7=199

7*16+11=123

00C7

007B

7B(0X) =7*16+11=123

1
2
MOV AH,7B

EAX:00EA 7B 01

AX AH AL

MOV AL ,7B

移动到AL 寄存器的位置

9*16+1=145

255+22 =============15 CF=1 OF=0
CF表示无符号数 ,OF表示有符号数
由此,若将两数字看作有符号数,则没有溢出,以往255为1111 1111 它的补码是-1,表示-1 ;22为 0000 0016 表示22本身。所以,正数和负数相加,结果为正数,不可能溢出
若,将两数字看作无符号数字,则溢出,因为BYTE的界限是255,明显就是溢出了

16进制储存数组元素

在DWORD PTR 后 ,类型被强制转换后,默认存放;若是WORD PTR 的转换,则存放到AX中,此时,可以使用位运算的操作,将其他的位置零。

1
2
3
4
	MOV ecx,10
L5: dec int32_val
LOOP L5

LOOP指令很容易出现错误,需要在使用前确定,尽量少使用MOV CX,10 之类的形式, 或是应该先将ECX 置零 XOR ECX,ECX 比较好。

FFFF FF FF 不能使用
应该使用0FFFFFFFFH
0和H 都是必须要有的,涉及到汇编识别16进制数字的规范

在16进制数,的开头是1的情况下(也就是说,在A-F开头的情况下在16进制前添加0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.DATA
stri dword 31h,2,3,4,5,6,37h,8,9,0AH,0BH,0CH,0DH,0EH,0FH,0FFH
count =lengthof stri
.CODE
main proc
MOV ECX,count
dec ecx
outlp: mov edx,ecx
mov ebx,offset stri
inlp: mov eax,[ebx]
cmp eax,[ebx+4]
jng next
xchg eax,[ebx+4]
mov [ebx],eax

next: add ebx,4
dec edx
jnz inlp
loop outlp
main endp
end main

冒泡排序结构,edx控制内循环,ecx控制外循环,dword 4个字节,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Mov ecx,count
Dec ecx
Outlp: mov edx,ecx
Mov ebx,offset stri
Inlp: MOV EAX,[EBX]
CMP EAX,[EBX+4]
JNG NEST
XCHG eax,[ebx+4]
MOv [ebx],eax
Netx: add ebx,4
Dec edx
Jnz inlp
Loop outlp

对应的C语言形式

1
2
3
4
5
6
For(i): 						[  OUTLLP  ]
For(j): [ INLP ]
If (x[]>x[]):
Echg:
[NEXT]

Dword 占4个字节 32位 00 00 00 00 置零的情况, 31h (31 00 00 00)

mov eax,31323334h 极限是32位

地址大小为8位的16进制 ,32位2进制

这是将’A’传递到EAX寄存器,A必须带’’否则会解释为A名称的数组。
‘A’表示 十进制的65,既是16进制的41h。等价

1234和’1234’是不一样的,在内存中的存储
‘1234’表示字符串,也可以表示31323334h的16进制数字。
‘1234’在内存中实际上是34333231的存储
还有 1,2,3,4 和’1’,’2’,’3’,’4’是不一样的。这两个表示dd数组,每个占32位,是01000000,02000000,03000000,04000000;和31000000,32000000,33000000,34000000
很有意思

1234表示1234d 的10进制,16进制为4D2

1
2
3
4
5
6
7
8
9
10
11
.if x < 0
mov eax,-1
mov y,eax
.elseif x > 0
mov eax,1
mov y,eax
.else
mov eax,0
mov y,eax
.endif

汇编If结构

1
2
3
4
5
6
7
8
.if 

.elseif

.else

.endif

DWORD类型数组,每个元素占4个字节
这个和连起来是不一样的

esi 的取值到最后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
	.WHILE   esi<count*4+offset stri
cmp byte ptr [esi],20h
je next
mov ebx,[esi]
mov [edi],ebx
mov eax,[edi]
mov eax ,sizeof(dword)
#sizeof(dword)=4;sizeof(word)=2;sizeof(byte)=1
add edi,eax
next:
mov eax ,sizeof(dword)
add esi,eax
.ENDW

遇到空格,则跳到NEXT 位置;若不是空格,则把[esi]的数值传送到[edi]。

While 循环语句
.while 持续条件

.endw

汇编表示16进制必须加后缀 H

1
2
3
4
5
.DATA
stri byte 31h,2,3,4,5,6,37h,8,9,0AH,0BH,0CH,0DH,0EH,0FH
strj db 4 dup('123',' ','abc')
dis byte sizeof stri dup(?)

#一般而言,是要除以定义类型的大小的,但是此处是byte,单位byte的大小是1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.CODE
main proc
mov eax,offset strj 此时eax指向了strj的首地址
mov esi,offset stri
mov edi ,offset dis
add esi ,lengthof stri-1 此时指向的是strj的最后一个元素的位置
add edi ,lengthof dis-1
mov ecx,lengthof stri
std
rep movsb


main endp
end main

· db 4 dup(‘123’,‘abc’) #可以重复4个’123abc’,
Str db n dup(‘string’)可以在str作为首位置中重复 n个string

1
2
3
Std     		
rep movsb

cld,清方向标志,即(DF)=0,地址从低到高
std,置方向标志1,DF=1,地址从高到低,
也就是从数组的末尾到数组的头的方向

Rep 串指令
movsb指令用于把字节从ds:si 搬到es:di;
rep是repeat的意思,rep movsb 就是多次搬运。
搬运前先把字符串的长度存在cx寄存器中,
然后重复的次数就是cx寄存器所存数据的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
.386
.model flat,stdcall
.stack 4096
INCLUDE Irvine32.inc
INCLUDELIB Irvine32.lib
include F:\masm32\include\msvcrt.inc
includelib F:\masm32\lib\msvcrt.lib

.DATA
x byte 8,1,8,1,8,1,16,8,3,2,1,1,1,1
n =lengthof x
count dword 0
.CODE
main proc
xor ebx, ebx
xor eax, eax
xor ecx, ecx
mov esi,offset x
mov ecx, n-1
mov ebx,n-1
add esi,ebx
lp:
mov ax,[esi]
and ax,0fh
mov bl,4
dec esi
DIV bl
CMP AH, 0
JNE next
add count, 1
next:
mov eax,count
cmp esi,offset x-1
je break
loop lp
break:
mov eax,count
main endp
end main

判定整除4 的数量

将整除2的数字转储

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.DATA

BUF Db 12H, 32H, 0BH, 1, 3, 90, 33H, 128, 2, 9
EDATA Db 10 DUP(0)

.CODE
main proc
LEA ESI,BUF
MOV ECX,10
lea di,EDATA
NEXT:
LODSB
#存放[ESI]的一个字节到AL中,(根据DF=1或0来判断,若为0,自增1;若为1,自减1)并ESI+1
SHR AL, 1
SHL AL, 1
mov ebx,[esi-1]
CMP AL,byte ptr [ESI-1]
JnZ ODDDATA
STOSB

ODDDATA: LOOP NEXT

invoke ExitProcess,0
main endp
end main

处理字符串数组时候比较有用,是一连串指令的简易表示
把esi位置的内存数据
Lodsb 存放byte 到ah
Lodsw 存放word 到ax
Lodsd 存放dword 到eax

LODSB,LODSW,LODSD把esi的内存数据存放到ah,ax,eax
与之对应的是stosb,stosw,stosd; 一般需要一同使用
意为把ah,ax,eax 存放到edi

使用FPU堆栈寄存器,堆栈溢出的表示。

1#IND

1
2
lea eax,[1+5*56]

汇编邪道流计算四则运算的方法
程序截图

计算得出的数字是16进制,可以很容易的使用,而不必使用寄存器来运算