二、8086汇编命令大全

8086汇编命令大全

    • 1、基础指令
      • 1.1、`MOV` 指令
      • 1.2、使用 `idata`
      • 1.3、操作符 `PTR`
      • 1.4、操作符 `OFFSET`
    • 2、计算指令
      • 2.1、`ADD` 加法
      • 2.2、 `SUB` 减法
      • 2.2、`INC` 自增& `DEC` 自减
      • 2.3、`AND` 与运算
      • 2.4、`OR` 或运算
      • 2.5、 `MUL` 乘法
      • 2.6、 `DIV` 除法
    • 3、转移指令
      • 3.1、循环 `LOOP`
        • 3.1.1、单循环
        • 3.1.2、多层循环
      • 3.2、 `JUMP` 无条件转移指令
        • 3.2.1、偏移距离转移
        • 3.2.2、段地址偏移地址转移
        • 3.2.3、使用寄存器和内存中的地址转移
      • 3.3、 `JCXZ` 条件转移指令
    • 4、栈段指令
      • 4.1、入栈 `PUSH`
      • 4.2、出栈 `POP`
    • 5、伪指令
      • 5.1、变量定义
        • 5.1.1、 `db` 指令
        • 5.1.2、 `dw` 指令
        • 5.1.3、 `dd` 指令
      • 5.2、 `DUP` 定义多个变量
    • 6、寄存器
      • 6.1、寄存器
      • 6.2、段寄存器
    • 7、函数调用
      • 7.1、 `CALL` 指令
      • 7.2、 `RET` 和 `RETF` 指令
      • 7.3、将 `CALL` 和 `RET` 配合使用
    • 8、标志寄存器指令
      • 8.1、 `ADC` 指令
      • 8.2、 `SBB` 指令
      • 8.3、 `CMP` 指令
      • 8.4、条件转移指令
      • 8.5、串传送指令
        • 8.5.1、 `MOVSB` 字节传送
        • 8.5.2、 `MOVSW` 字传送
      • 8.6、修改 `DF` 标志位
      • 8.7、 `PUSHF` & `POPF`

1、基础指令

1.1、MOV 指令

将逗号前的寄存器中的值修改为逗号后寄存器的值、内存的值或指定的值

语法:

mov [寄存器], [需要放入的值]

示例:

mov ax, 100

将 100 赋值到 ax 寄存器

也可以将一个寄存器中的值赋值到另一个寄存器

mov bx, 100 ; 将100赋值到bx
mov ax, bx ; 将bx中的值赋值到ax中

也可以将内存中的值赋值到寄存器中

mov ax, 2000H ; 将段地址先储存到ax中
mov ds, ax ; 设置段地址
mov bx, 1000H ; 将偏移地址储存到bx中,以便引用

mov ax, [bx] ; 将段地址为2000,偏移地址为1000的内存中的值赋值到ax中
mov ax, ds:[bx] ; 效果同上
mov ax, ds:[1000H] ; 效果同上

在源码中,不可以直接使用 [0] 来表示偏移地址,必须引用其他寄存器中的值,或者使用 ds:[0] 这种格式。

1.2、使用 idata

可以在程序中使用 idata 更方便的定位到指定的偏移地址

示例:

mov ax, [bx+10]
mov ax, [bx+si+10]

可以在设置偏移地址的方括号中使用运算

1.3、操作符 PTR

一般在执行计算时,指令后的寄存器会默认指定计算的值是字数据还是字节数据。例如:add al, sp:[0]add ax, sp:[0] ,但是在一些特殊情况下,编译器无从得知需要计算的数是字数据还是字节数据,此时,就需要操作符 ptr 来指定数据类型。

语法:

[指令] [word/byte] ptr [操作]

示例:

inc word ptr sp:[0] ; 以字为单位将指定内存中的数据自加

1.4、操作符 OFFSET

取得对应标号的偏移地址

示例:

s:mov ax, offset s ; 将标号s所处的偏移地址复制到ax寄存器中

2、计算指令

2.1、ADD 加法

将第二个值和第一个寄存器中的值相加,并放入第一个寄存器中,用法同 mov

语法:

add [寄存器], [需要相加的值]

2.2、 SUB 减法

减法运算,用法同 add 指令

示例:

sub ax, 10

2.2、INC 自增& DEC 自减

自增,将指定的值加一。

语法:

inc [寄存器]
inc [内存地址]

自减,将指定的值减一

语法:

dec [寄存器]
dec [内存地址]

2.3、AND 与运算

逻辑与指令,将两个值进行逻辑与计算

1 and 1 = 1
0 and 1 = 0
1 and 0 = 0
0 and 0 = 0

语法:

and [寄存器、内存地址], [寄存器、内存地址]

示例:

and ax, bx

2.4、OR 或运算

逻辑或云端,将两个值进行逻辑或计算

1 or 1 = 1
0 or 1 = 1
1 or 0 = 1
0 or 0 = 0

语法:

or [寄存器、内存地址], [寄存器、内存地址]

示例:

or ax, bx

2.5、 MUL 乘法

对指定数值进行乘法计算

  • 8位的值进行相乘时结果在 ax 中,乘数默认在 al
  • 16位的值进行相乘时 dx 中为高位 ax 中为低位,乘数默认在 ax

2.6、 DIV 除法

除法指令 division 对寄存器的值进行除法运算。

  • 当除数为字节型数据时,执行 div 指令后
    • ax 寄存器中的值会被作为被除数
    • 结果:
      • al 中为结果的商
      • ah 中为余数
  • 当除数为字型数据时
    • dxax 中的值会拼接到一起作为一个双字型数据作为被除数,即 (dx)*10000h+(ax)
    • 结果:
      • ax 中为商
      • dx 中为余数

示例:

assume cs:code

code segment
start:mov ax, 4d00h
	mov dx, 25h ; 设置被除数为 254d00
	mov bx, 7d0h ; 设置除数为 7d0
	div bx
	
	mov ax, 4c00h
	int 21h
code ends
end start

在这里插入图片描述

3、转移指令

3.1、循环 LOOP

3.1.1、单循环

使用此指令可以跳转到指定的代码开始循环,若寄存器 cx 的值为0时则继续执行,若不为0时则会跳转到指定的代码进行循环,循环一次完成后会将 cx 中的值减一。

语法:

s:[代码段]
[代码...]
loop s ; 跳转到标号为 s 的代码上继续执行

loop 是否执行是判断 cx 中值,所以在使用 loop 时一定要将 cx 中的值保存处理。

3.1.2、多层循环

在多层循环的情况下,所有的 loop 指令使用的都是 cx 的值,所以在执行内层循环时需要将 cx 的值进行保存复原操作。

此操作可以使用寄存器和内存来实现,寄存器由于数量有限而且易被覆盖,而独立的内存地址在多个循环嵌套的情况下容易混淆,故使用栈来暂存复原 cx 的值。

格式:

assume cs:code, ss:stack

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

code segment
start:mov ax, stack
	mov ss, ax
	mov sp, 10h
	mov cx, 10 ; 设置外层循环次数
	s0:[...do something...]
	push cx ; 保存外层循环次数
	mov cx, 20 ; 设置内层循环次数
	s1:[...do something...]
	loop s1
	pop cx ; 复原外层循环次数
	loop s0
	
	mov ax, 4c00h
	int 21h
code ends

3.2、 JUMP 无条件转移指令

jump 为无条件转移,可以只修改 ip ,也可以同时修改 csip

跳转需要的两种信息

  • 转移的目的地址
  • 转移的距离
    • 段间转移
    • 段内短转移
    • 段内近转移
3.2.1、偏移距离转移

语法:

jmp [标号]

示例:

assume cs:code

code segment
start:mov ax, 1111h
	jmp s
	mov ax, 2222h
	s:mov ax, 3333h
	
	mov ax, 4c00h
	int 21h
code ends
end start

此指令使用的数据位为8位,所以跳转的极限位置为 -128~127 超出此区域会发生错误。

使用位移的方式确定跳转的地址时,无论这段代码放置在内存的任何位置,都可以正常执行。

3.2.2、段地址偏移地址转移

语法:

jmp far ptr [标号]

示例:

assume cs:code

code segment
start:mov ax, 0
	mov ax, 11h
	jmp far ptr s ; 此跳转指令编译后为 JMP 076E:010B
	db 256 dup (0)
	s:add ax, 1
	
	mov ax, 4c00h
	int 21h
code ends
end start

这种格式的跳转指令是直接改变 csip 寄存器中的值,从而实现远距离跳转。

3.2.3、使用寄存器和内存中的地址转移

直接使用寄存器或内存中储存的内容作为 ip 寄存器的值进行跳转

语法:

  • 寄存器
mov ax, 0123h
jmp ax
  • 内存
jmp word ptr ds:[12]
  • 实现段间跳转
jmp dword ptr ds:[12]

段间跳转使用的的是双字型数据,指定 内存单元地址ip 的值, 内存单元地址+2 的数据为 cs 寄存器的值。

3.3、 JCXZ 条件转移指令

根据条件:若寄存器 cx 的值为0,则跳转到指定标号的代码段,若 cx 不为0则继续向下执行。

格式:

jcxz short [标号]

4、栈段指令

4.1、入栈 PUSH

将指定的数据压入栈底,sp 寄存器中储存的内容是栈底的指针,值为栈底的偏移地址。

语法:

push [寄存器、内存地址、数据]

示例:

push ds:[bx]

4.2、出栈 POP

将栈顶的数据出栈到指定的寄存器或内存中

语法:

pop [寄存器、内存地址]

示例:

pop ds:[bx]

在使用栈段进行入栈出栈操作时,一定要先设置好 sp 寄存器的值。

5、伪指令

指令语句在源程序汇编时会产生可供计算机执行的指令代码,即目标代码。汇编程序除指令语句外,还需要提供一些指令,用于辅助源程序的汇编。比如指定程序或数据存放的起始地址,为数据分配一段连续的内存单元等。这些指令在汇编时并不生成目标代码,不影响程序执行,因此称之为伪指令。

5.1、变量定义

5.1.1、 db 指令

定义一个字节长度的数据

db 10,20
5.1.2、 dw 指令

定义两个字节长度的数据,也称为字型变量

dw 0123h,0234h
5.1.3、 dd 指令

定义四个字节长度的数据,也称为双字型变量

dd 123,234

5.2、 DUP 定义多个变量

使用 dup 伪指令可以同时定义多个变量

格式:

[db/dw/dp] [需要生成的数量] dup ([值],..)

示例:

dw 3 dup (0) ; 同 dw 0,0,0
dw 3 dup (0,1) ; 同 dw 0,1,0,1,0,1

6、寄存器

6.1、寄存器

  • AX,BX,CX,DX 数据寄存器:

    • AX (Accumulator):累加寄存器,也称之为累加器

    • BX (Base):基地址寄存器

    • CX (Count):计数器寄存器

    • DX (Data):数据寄存器

    • 以上四个寄存器都可以分为两个8位的寄存器,例如 ax 可以分为 alah

  • SP 和 BP 指针寄存器:

    • SP (Stack Pointer):堆栈指针寄存器
    • BP (Base Pointer):基指针寄存器
  • SI 和 DI 变址寄存器:

    • SI (Source Index):源变址寄存器
    • DI (Destination Index):目的变址寄存器
  • 只有 bx,bp,si,di 可以放在 [] 中进行寻址操作。并且只可以存在四种组合 bx,si bx,di bp,si bp,di
  • [] 寻址时使用 bp 并且没有显式给出段地址,段地址默认在 ss

6.2、段寄存器

  • CS (Code Segment):代码段寄存器;

  • DS (Data Segment):数据段寄存器;

  • SS (Stack Segment):堆栈段寄存器;

  • ES (Extra Segment):附加段寄存器;

7、函数调用

7.1、 CALL 指令

用于和 ret 指令配合时间函数调用和返回,用法与 jmp 指令类似实现代码的跳转,但在跳转前会将 csip 中的值 push 到栈中以用于程序返回。

语法:

call [标志位]
call [word/dword] ptr [内存地址] 

7.2、 RETRETF 指令

用于将 csip 寄存器返回到原来的地址,ret 命令会执行 pop ipretf 命令则会执行 pop cspop ip 两条命令。

语法:

ret
;-------
retf

7.3、将 CALLRET 配合使用

示例:

assume cs:code, ss:stack

stack segment
	db 16 dup(0) ; 用来存储 cs 和 ip 的值
stack ends

code segment
start:mov ax, stack
	mov ss, ax
	mov sp, 16
	call s ; 调用 s 代码段,实现函数调用
	
	mov ax, 4c00h
	int 21h
	
	s:mov ax, 0
	add ax, 10h
	ret ; 返回到 call 命令后,实现函数返回
code ends
end start

8、标志寄存器指令

8.1、 ADC 指令

adc 指令用于在计算时将 CF 标志寄存器的值也进行带入运算,可以用来实现更多位数的数据运算,使用格式与 add 相同。

格式:

adc [寄存器], [数值/寄存器/内存]

示例:

adc ax, 10

公式 (ax)+10+(cf)

使用 adc 指令计算 1EF000H201000H 的值:

assume cs:code

code segment
start:
	mov ax, 001eh ; 第一个数的高位
	mov bx, 0f000h ; 第一个数的低位
	add bx, 1000h ; 将低位相加,进位保存到CF中
	adc ax, 20h ; 两数高位和CF中的进位相加
	; 结果 ax 中为高位 bx 中为低位
	
	mov ax, 4c00h
	int 21h
code ends
end start

8.2、 SBB 指令

sbb 指令用法与 adc 指令相同,此指令用户两数相减再减去 cf 标记寄存器中的值。

示例:

sbb ax, bx

公式: (ax)-(bx)-(cf)

8.3、 CMP 指令

此指令功能相当于减法指令,但是不保存结果只会影响标志寄存器的值。其他指令通过识别被影响的标志寄存器来得知比较结果。

格式:

cmp [操作对象1], [操作对象2]

示例:

mov ax, 8
mov bx, 3
cmp ax, bx

执行后:

ax不变
ZF=0
PF=1
SF=0
CF=0
OF=0

通过此指令可以判断标志寄存器的值来确定两个数的大小关系

a 为值1,b 为值2

  • ZF 若为1则表示两个数相等
  • ZF 若为0则表示两个数不相等
    • OF 若为0,没有溢出
      • SF 为1,表示 a
      • SF 为0,表示 a>b
    • OF 为1,有溢出
      • SF 的含义正好和表达的相反

8.4、条件转移指令

指令 含义 检测内容
je 等于转移 ZF=1
jne 不等于转移 ZF=0
jb 低于转移 CF=1
jnb 不低于转移 CF=0
ja 高于转移 CF=0&ZF=0
jna 不高于转移 CF=1orZF=1

8.5、串传送指令

每次执行指令 SI,DI 寄存器都会根据 DF 标志位进行相应的增减。

  • ((es)*16+di)=((es)*16+si)
  • 如果 DF=0
    • 增加 SI,DI
  • 如果 DF=1
    • 减少 SI,DI

串传送指令和 rep 指令进行配合可以实现循环多次复制,循环条件和 loop 指令相同。

8.5.1、 MOVSB 字节传送

每次 SI,DI 加一,实现正向复制。

示例:

assume cs:code,ds:data

data segment
	db 'hello world'
	db 11 dup (0)
data ends

code segment
start:
	mov ax, data
	mov ds, ax
	mov si, 0
	mov es, ax
	mov di, 11
	mov cx, 11
	
	cld
	rep movsb
	
	mov ax,4c00h
	int 21h
code ends
end start

结果:

在这里插入图片描述

8.5.2、 MOVSW 字传送

效果同 movsb 指令,movsw 传送的为字型数据。

8.6、修改 DF 标志位

设置 DF 标志:

cld ; 将DF设置为0
std ; 将DF设置为1

8.7、 PUSHF & POPF

将标志寄存器中的数据进行入栈和出栈,用法同 pushpop 指令。

你可能感兴趣的:(汇编,编程语言,汇编,8086)