intel 汇编

注:此处使用 masm 编译器,以 8086 CPU 为主。

1. 基础

  • 8086 CPU 的所有寄存器都是16位的。

  • 源操作数在后,目的操作数在前。

  • 通用寄存器ax, bx, cx, dx;为了兼容上一代 CPU,每个通用寄存器都可以分为两个8位的寄存器来使用,如,ax 可分为 ah, alahax 的高8位,alax 的低8位,其他寄存器类似。

  • 段寄存器cs, ds, ss, es,分别表示代码段、数据段、栈段和附加段。

  • 8086 CPU 有20位的地址总线,可寻址1MB的内存。

  • 物理地址 = 段地址左移4位 + 偏移地址;物理地址为20位,其他均为16位。

  • CPU 的执行过程:

    • cs:ip 指向的物理地址(即,cs << 4 + ip)中读取一条指令,并放入指令缓冲器中;
    • ip += 所读指令长度,以指向下一条指令;
    • 执行指令;
    • 返回第一步。

2. 标志寄存器

  • mov, push, pop 指令的执行结果对标志寄存器没有影响。

  • ZF 标志:如果指令执行后结果为0,则 ZF=1,否则 ZF=0

  • PF 标志:如果指令执行后结果中1的个数为偶数,则 PF=1,否则 PF=0

  • SF 标志:如果指令执行后结果为负数,则 SF=1,否则 SF=0

  • CF 标志:如果有向最高位进位或借位,则 CF=1,否则 CF=0

  • OF 标志:如果结果溢出,则 OF=1,否则 OF=0

  • DF 标志:方向标志位。

  • TF 标志:CPU 在执行完一条指令之后,如果检测到 TF==1,则产生单步中断。

  • IF 标志:当 CPU 检测到可屏蔽中断时,如果 IF==1,则 CPU 在执行完当前指令后响应中断,否则不响应可屏蔽中断。

pushf	; 将标志寄存器压入栈
popf	; 弹出栈顶元素至标志寄存器中
cld	; DF = 0
std	; DF = 1

cli	; IF = 0
sti	; IF = 1

3. 寻址

  • [...] 中指定偏移地址。
  • 如果偏移地址是立即数,则需要显式地指定段地址。
  • bx 对应的默认段地址为 dsbp 对应的默认段地址为 ss
  • si, di 寄存器功能与 bx 类似。
  • 只有 bx, bp, si, di 这四个寄存器才可以出现在 [...] 中。
; 直接寻址
mov al, ds:[0]
; 寄存器间接寻址 [bx], [bp], [si], [di]
mov al, [bx]
; 寄存器相对寻址 [bx+10], [bp+10], [si+10], [di+10]
mov ax, [bx+200]
; 基址变址寻址 [bx+si], [bx+di], [bp+si], [bp+di]
mov ax, [bx+si]
; 相对基址变址寻址 [bx+si+10], [bx+di+10], [bp+si+10], [bp+di+10]
mov ax, [bx+si+200]

4. 栈

  • 8086 CPU 的入栈和出栈操作都是以为单位进行的。
  • ss:sp 指向栈顶。
  • 栈空间是从高地址到低地址的:栈底在高地址,栈顶在低地址。
push ax	; sp -= 2,然后将 ax 中的内容存到 ss:sp 指向的内存单元
pop ax	; 将 ss:sp 指向的内存单元中的数据存入 ax,然后 sp += 2

5. 中断

在接收到中断之后,CPU 执行:

  • 取得中断类型码 N
  • 标志寄存器入栈:pushf
  • 设置标志寄存器 TF=0, IF=0
  • push cs
  • push ip
  • 执行中断处理程序:ip = N*4, cs = N*4+2

中断处理程序的一般步骤包括:

  • 保存用到的寄存器;
  • 处理中断;
  • 恢复用到的寄存器;
  • 使用 iret 指令返回。
; iret 的功能等价于
pop ip
pop cs
popf

触发中断:

int 0	; 触发一个 0 号中断

6. 端口

对于 0~255 以内的端口号进行读写时:

in al, 60h	; 从 60h 号端口读取一个字节到 al
out 20h, al	; 将 al 中的数据写到 20h 号端口

对于 256~65535 以内的端口号进行读写时,端口号放在 dx 寄存器中:

mov dx, 3f8h
in al, dx
ins byte ptr [di], dx	; 从 dx 指定的端口中读取一个字节到 es:[di] 中

insb, dx	; 从 dx 指定的端口中读取一个字节到 es:[di] 中
insw, dx	; 从 dx 指定的端口中读取一个字到 es:[di] 中
outs dx, byte ptr [si]	; 将 ds:[si] 中的一个字节写到 dx 指定的端口中

outsb	; 将 es:[di] 中的一个字节写到 dx 指定的端口中
outsw	; 将 es:[di] 中的一个字写到 dx 指定的端口中

7. 数据长度

在没有寄存器的情况下,可以使用 X ptr 来指明内存单元的长度,X 可以为 dword, word, byte,表示双字、字、字节。

mov word ptr ds:[0], 1

8. 程序

assume cs:code, ds:data, ss:stack	; 将段寄存器与段相关联

data segment	; 定义一个段,段名为 data,这个段从此开始,标号 data 将被编译为一个段地址
	dw 0123H, 0456H, 0789H, 0abcH	; 定义字
data ends	; data 段到此结束

stack segment
	dw 0, 0, 0, 0, 0, 0, 0, 0
stack segment

code segment	
start:	mov ax, stack
		mov ss, ax
		mov sp, 10H
		
		mov ax, data
		mov ds, ax
		; ...
		; 程序返回
		mov ax, 4c00H
		int 21H
code ends

end	start	; 程序到此结束,且程序入口在标号 start 处
  • 伪指令 db, dw, dd:定义(define)字节、字、双字。

  • 伪指令 dup:与 db, dw, dd 结合使用,用来重复定义数据。

    db 3 dup (0)	; 重复 db 0 三次
    db 3 dup (0,1,2)	; 重复 db 0,1,2 三次
    
  • 伪指令 offset 用于获得标号的偏移地址。

    code segment
    	start:	mov ax, offset start	; mov ax, 0
    	s:		mov bx, offset s	; mov bx, 3
    code ends
    

9. 字符

实际保存的是 ASCII 码。

db 'unix'
mov al, 'a'

10. mov,movzx,movsx,cmovX

mov ax, 18	; ax = 18
mov ah, 48	; ah = 48
; 使用 0 扩展
mov bl, 9Bh
movzx dx, bl	; dx = 009Bh
; 使用符号位扩展
mov bl, 10001111b
movsx dx, bl	; dx = 1111111110001111b

条件移动:

; 如果条件成立(查看标志寄存器)则移动数据
; e 表示 equal
; n 表示 not
; g 表示 greater(有符号数)
; l 表示 less(有符号数)
; a 表示 above(无符号数)
; b 表示 below(无符号数)

cmove dx, ax
cmovne dx, ax

cmova dx, ax
cmovae dx, ax
cmovna dx, ax

cmovb dx, ax
cmovbe dx, ax
cmovnb dx, ax

cmovg dx, ax
cmovge dx, ax
cmovng dx, ax

cmovl dx, ax
cmovle dx, ax
cmovnl dx, ax

11. cbw,cwd

将字节转换为字、将字转换为双字,并使用符号位进行扩展。

; 将 al 的符号位扩展到 ah
cbw
; 将 ax 的符号位扩展到 dx
cwd

12. inc,dec,neg,add,sub,mul,div,imul,idiv

inc ax	; ax += 1
dec ax	; ax -= 1
neg ax	; ax = -ax
add ax, 8	; ax += 8
add ax, bx	; ax += bx
sub ax, 8	; ax -= 8

无符号乘法:

; 8位乘法
mul bl	; ax = al * bl

; 16位乘法
mul bx	; ax * bx,结果的高16位放在 dx 中,低16位放在 ax 中

无符号除法:

; 8位除数
div bl	; ax/bl,然后将商存到 al 中,将余数存到 ah 中

; 16位除数
div bx	; (dx<<16 + ax)/bx,然后将商存到 ax 中,将余数存到 dx 中

有符号乘法(符号位扩展):

; 8位乘法
mov al, -4
mov bl, 4
imul bl	 ; ax = al * bl, aX = FFF0h

; 16位乘法
mov ax, 48
mov bx, 4
imul bx	; ax * bx,结果的高16位放在 dx 中,低16位放在 ax 中; DX:AX = 000000C0h

; 两操作数:结果放到目的寄存器中
mov ax, -16 	; ax = -16
mov bx, 2		; bx = 2
imul bx, ax		; bx *= ax, bx = -32

; 三操作数:结果放到目的寄存器中
imul bx, 4, -16             ; bx = 4 * -16

有符号除法(在执行除法之前,必须对被除数进行符号扩展):

; 8位除数
mov al, -48
cbw
mov bl, +5
idiv bl	; ax/bl,然后将商存到 al 中,将余数存到 ah 中; al = -9, al = -3

; 16位除数
mov ax, -5000
cwd
mov bx, +256
idiv bx	; (dx<<16 + ax)/bx,然后将商存到 ax 中,将余数存到 dx 中; ax=-19, dx=-136

13. and,or,xor,not

and al, 00111011B	; al &= 00111011B
or al, 00111011B	; al |= 00111011B
xor al, 00111011B	; al ^= 00111011B
not al	; al = ~al

14. shl,shr,sal,sar

shl al, 1	; al 逻辑左移1位,低位用0填充,最后移出的一位写入 CF 中
shr al, cl	; al 逻辑右移 cl 位,高位用0填充,最后移出的一位写入 CF 中
sal al, 1	; al 算术左移1位,低位用0填充,最后移出的一位写入 CF 中
sar al, cl	; al 算术右移 cl 位,高位用符号位填充,最后移出的一位写入 CF 中

15. cmp,test

cmp	ax, bx	; 执行 ax-bx,但不保存结果,只是影响标志寄存器
test al, 00001001b	; 执行 al & 00001001b,并设置标志寄存器,但不包含执行结果

16. jmp

段内跳转分为短转移和近转移:

  • 短转移 ip 的修改范围是 -128~127
  • 近转移 ip 的修改范围是 -32768~32767

段间跳转又称为远转移。

; 短转移
; 跳转到标号 s 处
; short 指定此处的位移是8位位移
; 8位位移 = 标号 s 处的地址 - jmp 指令后的第一个字节的地址
; ip += 8位位移
jmp short s
; 近转移
; 跳转到标号 s 处
; near ptr 指定此处的位移是16位位移
; 16位位移 = 标号 s 处的地址 - jmp 指令后的第一个字节的地址
; ip += 16位位移
jmp near ptr s
; 远转移
; 跳转到标号 s 处
; cs=标号 s 处的段地址
; ip=标号 s 处的段内偏移地址
jmp far ptr s

也可以直接指跳转地址:

; 段内跳转
jmp bx	; ip = bx
jmp word ptr ds:[0]	; ip = ds:[0]

; 段间跳转
jmp dword ptr ds:[0]	; 高地址的字指定段地址,低地址的字指定偏移地址

17. 条件跳转

所有的条件转移都是短转移。

; 如果 cx == 0,则跳转到 s 处;否则继续往下执行
; 8位位移 = 标号 s 处的地址 - jcxz 指令后的第一个字节的地址
; ip += 8位位移
jcxz s

根据无符号数的比较结果进行跳转,需要配合标志寄存器使用。

; e 表示 equal
; n 表示 not
; b 表示 below
; a 表示 above

je label
jne label

jb label
jbe label
jnb label

ja label
jae label	
jna label

根据有符号数的比较结果进行跳转,需要配合标志寄存器使用。

; g 表示 greater
; l 表示 less
; e 表示 equal
; n 表示 not

jg label
jge label
jng label

jl label
jle lable
jnl label

18. loop

所有的循环指令都是短转移,ip 的修改范围是 -128~127

cx 中保存循环次数。

具体操作包括:

  • cx -= 1
  • 如果 cx != 0,则跳转到标号处,否则继续往下执行。
	mov ax, 2
	mov cx, 10
s:	add ax, ax
	loop s
	; 8位位移 = 标号 s 处的地址 - loop 指令后的第一个字节的地址
	; ip += 8位位移

19. call

也用于实现跳转。

; 将当前 ip 压入栈
; 16位位移 = 标号 s 处的地址 - call 指令后的第一个字节的地址
; ip += 16位位移
call s
; 将当前 cs 压入栈,接着将当前 ip 压入栈
; cs=标号 s 处的段地址
; ip=标号 s 处的段内偏移地址
call far ptr s
; 将当前 ip 压入栈
; ip = bx
call bx
; 将当前 ip 压入栈
; ip = ds:[0]
call word ptr ds:[0]
; 将当前 cs 压入栈,接着将当前 ip 压入栈
; cs = 高地址的字
; ip = 低地址的字
call dword ptr ds:[0]

20. ret,retf

分别用于实现近转移和远转移。

; 弹出栈顶元素至 ip 中
; 相当于 pop ip
ret
; 弹出栈顶元素至 ip 中,然后再次弹出栈顶元素至 cs 中
; 相当于
; pop ip
; pop cs
retf

21. movs,movsb,movsw

; 传送一个字节
; 从 ds:si 传送到 es:di
; 如果 DF==0,则 si+=1, di+=1;否则 si-=1, di-=1
movs byte ptr [di], byte ptr [si]
; 传送一个字节
; 从 ds:si 传送到 es:di
; 如果 DF==0,则 si+=1, di+=1;否则 si-=1, di-=1
movsb
; 传送一个字
; 从 ds:si 传送到 es:di
; 如果 DF==0,则 si+=2, di+=2;否则 si-=2, di-=2
movsw

22. cmpsb,cmpsw

; 比较一个字节
; 将 ds:si 寻址的内容 - es:di 寻址的内容,影响标志寄存器,但不保存结果
; 如果 DF==0,则 si+=1, di+=1;否则 si-=1, di-=1
cmpsb
; 比较一个字
; 将 ds:si 寻址的内容 - es:di 寻址的内容,影响标志寄存器,但不保存结果
; 如果 DF==0,则 si+=2, di+=2;否则 si-=2, di-=2
cmpsw

23. scasb,scasw

; 比较一个字节
; 将 al 中的内容 - es:di 寻址的内容,影响标志寄存器,但不保存结果
; 如果 DF==0,则 si+=1, di+=1;否则 si-=1, di-=1
scasb
; 比较一个字
; 将 ax 中的内容 - es:di 寻址的内容,影响标志寄存器,但不保存结果
; 如果 DF==0,则 si+=2, di+=2;否则 si-=2, di-=2
scasw

24. stosb,stosw

; 存储一个字节
; 将 al 中的内容存储到 es:di
; 如果 DF==0,则 si+=1, di+=1;否则 si-=1, di-=1
stosb
; 存储一个字
; 将 ax 中的内容存储到 es:di
; 如果 DF==0,则 si+=2, di+=2;否则 si-=2, di-=2
stosw

25. lodsb,lodsw

; 加载一个字节
; 将 ds:si 寻址的内容加载到 al
; 如果 DF==0,则 si+=1, di+=1;否则 si-=1, di-=1
lodsb
; 加载一个字
; 将 ds:si 寻址的内容加载到 ax
; 如果 DF==0,则 si+=2, di+=2;否则 si-=2, di-=2
lodsw

26. rep,repe,repne

rep movsb	; 重复执行 movsb 指令 cx 次;每次将 cx 减一
repe scasb	; 只要结果相等(查看标志寄存器)且 cx > 0 就继续执行 scasb 指令
repne scasb	; 只要结果不相等(查看标志寄存器)且 cx > 0 就继续执行 scasb 指令

27. lea

加载内存单元的有效地址,即偏移地址。

lea ax, [bx+100]	; ax = bx+100

28. xchg

xchg ax, bx	; 交换 ax 和 bx 的内容

29. setX

; 条件成立时(查看标志寄存器)将 al 设置为 1
; e 表示 equal
; n 表示 not
; s 表示 SF 是否被置位
; g 表示 greater(有符号数)
; l 表示 less(有符号数)
; a 表示 above(无符号数)
; b 表示 below(无符号数)

sete al
setne al
sets al
setns al
setg al
setge al
setl al
setle al
seta al
setb al
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值