【汇编】汇编考前总结

本文是对汇编语言基础知识点的总结,主要包括以下内容

进制转换

10进制->16进制:除16取余法.

16进制->10进制:按权展开相加法

10进制->2进制:除2取余法

2进制->10进制:按权相加展开法

2进制->16进制:每4位转换一位

16进制->2进制:每一位转换4位

补码

已知x的补码,要求-x的补码:x的补码取反加1

x可以为正,也可以为负

类型

类型2进制位字节寄存器
db81al
dw162ax
dd324eax
0h(一个16进制位)40.5

地址转换

段地址*10+偏移地址=物理地址

1234:5678h=12340h+5678h=179B8h

寄存器

数据寄存器

名称用途
ax数据处理
bx基址寄存器,存放基址
cx用来循环中计数
dx辅助ax

变址寄存器

名称用途
si源变址寄存器
di目的变址寄存器

地址指针寄存器

名称用途
sp栈顶的偏移地址
bp基址指针寄存器

段寄存器

名称用途
cs代码段的段地址
ss堆栈段的段地址
ds数据段的段地址
es附加数据段的段地址

控制寄存器

名称用途
ip指向下一条指令的首字节(相当于cs:ip作为下一条指令的地址)用户不能访问,对其更改
fl标志寄存器

fl 标志位

名称用途
cf(进位标志)非符号数是否溢出标志,最高位有向上进位或者借位,cf=1,否则cf=0
zf(零标志位)结果为0时zf=1,否则zf=0
of(溢出标志)符号数是否溢出的标志,正+正=负,正-负=负,负-正=正,溢出of=1,不溢出of=0
sf(符号标志)符号数,为正时sf=0,为负时sf=1(就是首位的值)
df(方向标志)df=1, si和di减1(高到低),df=0,si和di加1(低到高)
if(中断标志)if=1允许中断,if=0禁止中断
tf(跟踪标志)tf=1每条指令结束后中断,tf=0,正常工作,不产生中断
af(辅助进位标志)记录第三位进位借位,af=1,否则af=0
pf(奇偶标志)低8位1的个数为偶数,pf=1,否则为pf=0

程序格式

;.386如果需要用到eax,必须加这一句
data segment
	a db 100 dup(0)	;定义了一个名叫a的数组,共一百位,全部为0
	b db 'ABC',0Dh,0Ah,'$'	;字符串用db格式,0Dh:回车,0Ah换行
							;'$'结束符,如果用21h输出整个字符串,必须使用
data ends
code segment
	assume ds:data, cs:code	;这句话必写,并且不能放在main之后
main:
....
code ends
end main	;程序从main开始

寻址

	;引用12345h
	mov dx, 1000h
	mov ds, dx
	mov al, ds:[2345h]
	;段地址和偏移地址都是16位,可以表示20位物理地址

	mov ax, 1000h:[bx]	;错,段地址必须是段寄存器
	mov ds, 1000h	;错,段地址只能用寄存器赋值
	
	mov al, [12h] 	
	;直接寻址,偏移地址用常数表示
	
	mov al, [si]	
	;间接寻址,偏移地址用寄存器表示
	;基址寄存器:bp,bx,变址寄存器:si,di
	;间接寻找的格式,基址+变址+8位或16位符号数
	ds:[bx+si]	;ds可以省略,bx的段地址默认是ds,bp段地址默认是ss
	ds:[bx+bp]	;错,bx和bp只能出现一个,si和di只能出现一个
	ds:[bx-si]	;错,只能出现加法
	ds:abc[2]	;对	
	ds:[abc+2]	;对
	
	
	;间接寻址中,寄存器必须用括号括起来,常数可括可不括
	;如果常数在寄存器之后且没有括号一定要带加号,若在寄存器之前则可以省加号
	
	mov bx, offset abc
	mov si, 1
	mov al, [bx+si] ;引用abc[1]的另一种方式

指令

;xchg---------------------------------------------------------------
	xchg ax, bx	;交换两个寄存器或变量的值
	xchg ax, es:[bx]	;对
	xchg ax, cs	;错,不能有段寄存器
	xchg byte ptr es:[bx], byte ptr ds:[bp]	;错,不能交换两个变量

;push---------------------------------------------------------------
	push ax	;把ax压入堆栈,导致sp=sp-2
	push word ptr ds:s[bx]	;对
	push ds:s[bx]	;对
	push al	;错,必须是16位变量或寄存器

;pop----------------------------------------------------------------
	pop ax	;弹出到ax中
	pop [bx]	;对
	pop byte ptr [bx]	;错,不是16位的
	pop cs	;错,不能更该cs的值

;pushf--------------------------------------------------------------
	pushf	;后面不跟操作数,表示标志寄存器fl入栈
	;用来对fl的标志位赋值
	push ax
	popf	;把ax的值赋给fl
	pushf
	pop ax	;获取fl的值
;popf---------------------------------------------------------------
	popf	;表示弹出一个字到标志寄存器fl

;cbw----------------------------------------------------------------
	cbw	;convert byte to word,把al中8位符号数扩充为ax
	;如果al中最高位是1(16进制最高位是F),则ah填充0FFh,否则填充00h
	mov al, 7Fh
	cbw	;结果是ax=00 7Fh
	mov al, 0FCh
	cbw	;结果是ax=FF FCh

;cwd----------------------------------------------------------------
	cwd	;convert word to double word,把ax中16位符号数扩充为dx:ax
	;如果ax最高位是1(16进制最高位是F),则dx为0FFFFh,否则为0000h
	mov ax, 0FFFEh
	cwd	;dx:ax=0FFFF FFFEh
	mov ax, 7FFFh
	cwd	;dx:ax=0000 7FFFh
	
;lea----------------------------------------------------------------
	lea ax, es:[bx]	;结果是ax=bx
    ;lea表示把右侧的内存偏移地址放入左侧的寄存器中

;add----------------------------------------------------------------
	add ax, bx
	add ax, 1234h
	add ax, ds:[si]
	add word ptr ds:[si], 1234h	
	add s[bx], ax
;adc----------------------------------------------------------------
	;用于非符号数加法,和add的用法相同,但是结果加上cf
	;用在数据存放在多个寄存器里的情况,比如放在dx:ax和cx:bx中
	add ax, bx
	adc dx, cx	;最后结果dx:ax=dx:ax+cx:bx
;inc----------------------------------------------------------------
	inc ax	;ax++
	inc ds:[bx]	;ds:[bx]++
	;inc不影响标志位

;sub----------------------------------------------------------------
	sub ax, bx
	sub ax, 12h
	sub ax, s[si]
	sub s[si], ax
	sub word ptr s[si], 12h
;sbb----------------------------------------------------------------
	;和sub相同,但是会减去cf
	;比如数据存放在dx:ax和cx:bx中
	sub ax, bx
	sbb dx, cx	;注意加减都是从低位先算
;dec----------------------------------------------------------------
	dec ax	;ax--
	dec ds:[bx]	;ds:[bx]--
	;dec不影响标志位

;mul----------------------------------------------------------------	
	mov al, 12h
	mov bl, 0FCh
	mul bl ;8位乘法(乘数为8位),al默认为一个乘数,ax = bl * al
	
	mov ax, 1234h
	mov bx, 5678h
	mul bx	;16位乘法(乘数数为16位),ax默认为一个乘数,dx:ax = ax * bx
	
	mov eax, 12345678h
	mov ebx, 0FFFFFFFFh
	mul ebx	;32位乘法(乘数为32位),eax默认为一个乘数,edx:eax = eax * ebx
	
	mul 12h	;错,因为无法判断是几位乘法
	mul word ptr [bx]	;对
;imul---------------------------------------------------------------
	;看作是符号数进行乘法
;div----------------------------------------------------------------	
	mov ax, 32h
	mov bl, 12h
	div bl
	;8位除法(除数是8位),ax默认是被除数,ax/bl = al....ah 商放在低位
	
	mov dx, 1234h
	mov ax, 3456h
	mov bx, 5678h
	div bx	
	;16位除法(除数是16位),dx:ax默认被除数,dx:ax/bx = ax...dx 

	mov eax, 12345678h
	mov edx, 23456789h
	mov ebx, 3456789Ah
	div ebxh 
	;32位除法(被除数是32位),edx:eax默认为被除数,edx:eax/12h = eax...edx
	
	div 12h	;错
	div [bx]	;错
	div byte ptr [bx]	;对
;idiv---------------------------------------------------------------
	;符号数除法
;xlat---------------------------------------------------------------	
	xlat	;换码指令
	;将ds:[bx]指向的表作为一个数组,把al替换为以al为下标的内容
	;如果ds:[bx]指向"0123456789ABCDEF"
	mov al, 10
	xlat	;al='A'
;in-----------------------------------------------------------------
	in al, 12h	;表示读端口为12h位置的内容到al
	in ax, 12h	;表示读端口为12h位置到al,13h位置到ah
	;只能读到al或ax中,后面跟dx或立即数。
	;立即数00-FFh之间,dx在0000-FFFFh之间
	mov dx, 1234h
	in ax, dx	;表示al=[1234h], ah=[1235h]
;out----------------------------------------------------------------
	out 12h, ax
	out dx, al
	;与in类似
;and----------------------------------------------------------------
	and ax, bx
	and ax, 01h
	and ax, [bx]
	and [bx], 01h
	and [bx], ax
	;有0为0,全1为1
;or-----------------------------------------------------------------
	;与and类似,有1为1,全0为0
;xor----------------------------------------------------------------
	;相同为0,不同为1
;not----------------------------------------------------------------
	not ax
	not ds:s[bx]
	;取反
;neg----------------------------------------------------------------
	;求补,即取反加1
;test---------------------------------------------------------------
	test ax, bx
	test ax, [bx]
	test ax, 12h
	test [bx], ax
	test [bx], 12h
	;test和and运算相同,但是丢弃结果,只影响zf标志位
	
;shl----------------------------------------------------------------
	;逻辑左移 shift left
	shl ax, 1
	shl ax, cl
	shl [bx], cl
	;超过1位必须用Cl
	;左移后右边补0,最后一次移出的数放入cf中
	mov al, 1110h
	shl al, 1	;则cf=1,al=1100h
;shr----------------------------------------------------------------
	;逻辑右移 shift right
	;右移后左边补0,最后一次移出的数放入cf中
;sal----------------------------------------------------------------
	;算术左移 shift arithmetic left
	;与shl完全相同
;sar----------------------------------------------------------------
	;算术右移 shift artithmetic right
	;如果左侧最高位是1,则左侧补1,否则补0,其他和shr指令相同
;rol----------------------------------------------------------------
	;循环左移 rotate left
	;每一位向左移,移出的放入右边空位,移出的同时放入cf中,重复若干回
	;注意循环左移指的是每一位数字先向左移动,移出的向右移动到最右边
;ror----------------------------------------------------------------
	;循环右移 rotate right
	;每一位向右移,移出的放入左边空位,移出的同时放入cf中,重复若干回
;rcl----------------------------------------------------------------
	;带位循环左移,rotate through carry left
	;最左侧的一位移动到cf中,同时cf移动到最右边一位
	;用于两个寄存器表示的数据高位的移动
	;注意移动后的结果一定也能用两个寄存器表示
	;移动内存变量,需要写明类型
	;左移dx:ax
	rhl ax, 1
	rcl dx, 1	;此时cx本来是dx移出的那位
				;但是循环后执行第一步,cf的值又被ax移出的覆盖了
				;循环多次可以实现左移若干次
;rcr----------------------------------------------------------------
	;带位循环右移,rotate through carry right
	;与带位循环左移类似
;cmp----------------------------------------------------------------
	;和sub相同,但是只影响标志位,丢弃结果
	;如果符号数溢出,of=1,非符号数溢出,sf=1,如果是0,zf=1
;loop---------------------------------------------------------------
again:
	....
	loop again	;如果cx=0则跳出,否则跳到指定的位置
				;属于短跳,必须在距离00~FFh中(-128~127)
;call(近调用)------------------------------------------------------
	call 1000h	;1000h指的是本段的偏移地址为1000h的位置
	call ax	;必须是16位寄存器,ax,bx,cx,dx,bp,bx,si,di
	call word ptr [bp-2]	;跳到偏移地址放在ds:[bp-2]中的地方
;call(远调用)------------------------------------------------------
	call 1234h:5678h	;跳到该位
	call dword ptr ds:[bx]	;跳到ds:[bx]存放的内容所在的位置
	;call 将会push ip,然后使ip变到操作数的位置
;ret----------------------------------------------------------------
	;返回到上一次call的下一个位置
	;pop ip
	;或者返回到指定的位置
	ret 
	ret 1000h
;retf---------------------------------------------------------------
	;远调用的返回
	;pop ip
	;pop cs
	retf
	retf 1000h
	;与ret最大的不同就是恢复了cs,可以用于不同段间的call返回
;int----------------------------------------------------------------
	;请求中断
	int 21h
	;首先压入ip和cs,然后将cs:ip赋值为函数的地址
	;中断向量(入口程序的地址)存放在中断表中。中断表的地址是0000h:n*4h
	;比如21h的中断表地址为0000:0084h
	;中断向量的值:dword ptr 0000h:[n*4h]
;iret---------------------------------------------------------------
	;返回到int的下一条指令上,对应
	;pop ip
	;pop cs
	;popf

;mov----------------------------------------------------------------
	mov ax, bx
	mov ax, 21h
	mov ax, ds:t[si]
	mov ds:t[si], ax
	mov word ptr ds:t[si], 21h
	;注意mov的左侧必须是可变的对象,即寄存器或者内存变量。一共3中类型,但是变量之间不能直接mov,故只有3+
	;add,sub都一样
    mov cs, ax	;错,不能对cs赋值
    mov ax, ip	;错,不能访问ip
    mov ax, fl	;错,不能访问fl
	mov bx, al	;错,mov后面必须等宽
	mov ds, es	;错,段地址不能赋给段地址
	mov [bx], 12h 	;错,mov变量,数字组合必须写出变量的类型,
	mov [bx], ax	;对,mov寄存器或数字,变量都不需要
	mov ds, 1200h	;错,段地址只能用寄存器赋值
;jmp----------------------------------------------------------------
	jmp 0108h	;短跳,距离不能超过-128~127
	jmp ax	;近跳,距离不能超过32768
	jmp 0120h	;近跳
	jmp word ptr [bx]
	jmp 1234h:5678h	;远跳,跨段跳
	jmp dword ptr ds:[10F0h]
;movsb--------------------------------------------------------------
	;move string byte 以字节传送字符串
	;byte ptr es:[di] = byete ptr ds:[si]
	;df=0,si++,di++
	;df=1,si--,di--
	rep movsb
	;若cx=0则停止,否则重复每一次cx--,一共重复cx次
	mov ax, 1000h
	mov es, ax
	mov ax, 2000h
	mov ds, ax
	mov si, 10F0h
	mov di, 20F0h
	cld
	mov cx, 5
	rep movsb
;lodsb-------------------------------------------------------------
	;从字符串中取字节
	;al=ds:[si]
	;用于和stosb一起,取字符串时只取符合要求的
	;把ds:[si]指向源字符串,es:[di]指向目标内存
	mov cx, 15h	;字符串长度
	cld	;字符串的方向,存取方向是一致的
again:
	lodsb	;取出字符到al
	cmp al, ' '
	je next
	stosb	;如果不是空格则存入
next:
	dec cx
	jnz again
;stosb--------------------------------------------------------------	
	;存入字节到字符串,重复cx次
	;es:[di] = al,df=0为正方向,df=1为负方向
	mov cx, 100h
	mov al, 0h
	rep stosb
	
;scasb--------------------------------------------------------------	
	;在es:[di]中查找al中字符cx次
	mov es, 1000h
	mov ds, 10F0h
	mov cx, 6
	mov al, '0'
	cld
	repne scasb
	jne not_find
	dec di
	;正方向查找'0'6次
	;zf=0没找到,zf=1找到了
	;找到后需要反向操作一次
;cmpsb--------------------------------------------------------------
	;cmpare string by byte
	;byte ds:[si]-byte es:[di],导致标志位的变化
	;df=0, si++,di++
	;df=1, si--,di--
	;判断是否继续的时候会恢复做差时的fl,所以cx变为0时的zf=1被覆盖
	repe cmpsb
	je equal
	;最多比较cx次,如果相等会继续比较
	;循环结束后,如果不相等,zf=0,相等zf=1
unequal:
	dec di
	dec si
	;不相等di,si会再重复一次才退出,所以正方向df=0,di,si减1,负方向di,si加1
	repne cmpsb
	jne totally_unequal
	je equal
equal:
	dec di
	dec si
	;最多比较cx次,如果不相同,继续比较
	;退出循环是因为相同,zf=1,否则是因为比较完了,zf=0
	;di,si会多做一次,为了找到相同的下标需要反向操作di,si
字符串操作指令意义
repne scasbes:[di]中查找al,若找到就退出
repe scasbes:[di]中查找al,若有不同就退出
repe cmpsb比较es:[di]ds:[si]字节是否相同,若有不同就退出
repne cmpsb比较es:[di]ds:[si]字节是否相同,若有相同就退出
rep movsb把字ds:[si]赋给es:[di]
rep lodsb把字ds:[si]赋给al
rep stosbal赋给es:[di]

前面四个如果找到就退出,没找到最多重复cx次

后面三个重复cx次

方向均由df控制

df的值指令方向下标
0cld正(低地址到高地址)si++,di++​
1std负(高地址到低地址)si--,di--
跳转指令意义判断
ja非符号数大于cf=0且zf=0
jae非符号数大于等于cf=0
jb非符号数小于cf=1
jbe非符号数小于等于cf=1或zf=1
jg符号数大于of=sf且zf=0
jge符号数大于等于of=sf
jl符号数小于of ≠ \ne =sf
jle符号数小于等于of ≠ \ne =sf或zf=1
je等于zf=1
jne不等于zf=0

注意非符号数判断大小看有没有借位,即cf的值,符号数看of=sf为大于,然后判断zf

跳转指令判断
jc/jnccf=1/cf=0
jo/jnooc=1/of=0
js/jnssf=1/sf=0
jz/jnzzf=1/zf=0
jcxzcx=0跳
杂类指令作用
clc (clear cf)cf=0
stc (set cf)cf=1
cliif=0(禁止中断)
stiif=1(允许中断)
clddf=0
stddf=1

小端规则

内存中按字节存放,如果有多个字节,会倒着存放。

比如1234h

偏移地址内容
1000h34h
1001h12h

堆栈对参数调用

_CDECL(c语言方式,堆栈由调用者清理,压入的顺序是从左往右)

f:
	push bp
	mov bp, sp
	mov ax, [bp+6]	;参数1
	mov bx, [bp+4]	;参数2
	...
	pop bp
	ret
;程序从这里开始
	mov ax, 3	;参数1
    push ax
    mov ax, 4	;参数2
    push ax
    call f
	add sp, 4	

堆栈结构(堆栈是从下面开始压入参数的)

地址堆栈内容压入顺序
0FFFh:FFF8hbp高8位<-sp4
0FFFh:0009hbp低8位4
1000h:0000hip高8位3
1000h:0001hip低8位3
1000h:0002h参数2高8位2
1000h:0003h参数2低8位2
1000h:0004h参数1高8位1
1000h:0005h参数1低8位1

只需要注意:

  1. 压入的参数放在堆顶
  2. 地址参数均为16位,一个内存单位只能放8位,所以要两个内存单位存放一个地址
  3. 结束调用:恢复bp时弹出bp->ret时弹出ip->参数由调用者清理

_PASCAL堆栈布局

唯一的不同是,由被清理者清理堆栈,ret n n是需要清理的大小,上面的例子是ret 4

_STDCALL

参数从右往左的顺序压入,f(a1,a2,…,an)则an首先压入


祝大家学习愉快!

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值