CPU 最常做的指令,就是设定数值,例如设定某个缓存器、某个地址的内存的数值。以下例子示范如何把缓存器 AX 的值设为 9:
首先执行 DEBUG,在地址 100h 处输入组语 MOV AX, 9 的指令:
C:/>debug
-A100
1358:0100 MOV AX,9
1358:0103
-
用 DEBUG 的 R 指令,显示「缓存器」(Register) 的值:
-R
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0100 NV UP EI PL NZ NA PO NC
1358:0100 B80900 MOV AX,0009
留意一下 IP 的值,如果您在执行指令之前发现它不是 100 ,就要打 RIP ,然后打 100 ,把 IP 设为 100。
用 T 指令,执行在地址 100h 那里的一个 CPU 指令:
-T
AX=0009 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0103 NV UP EI PL NZ NA PO NC
1358:0103 0000 ADD [BX+SI],AL DS:0000=CD
-
执行 MOV AX, 9 指令之后,缓存器 AX 的值变成 0009 了。
跳到
CPU 执行指令时,是一个接一个地执行的,其实,CPU 也有一些「跳到」(Jump) 的指令,可以跳到某个内存地址,执行那处的指令。
-A100
1358:0100 JMP 105
1358:0102 MOV AX, 9
1358:0105 MOV AX, 1
1358:0108
-
JMP 就是「跳到」的指令,JMP 105 表示跳到内存地址 105 那里,而在那里的指令是 MOV AX, 1。
-R
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0100 NV UP EI PL NZ NA PO NC
1358:0100 EB03 JMP 0105
-T
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0105 NV UP EI PL NZ NA PO NC
1358:0105 B80100 MOV AX,0001
-
结果跳过了地址 102 那个 MOV AX, 9 指令了。
留意一下 JMP 105 的机械码,您会发觉是 EB 03,这里的 03 是怎样来的?为什么要跳到地址 105 ,机械码郄是 03,两者好像没有关系的呢?
其实 105 与 03 是有关系的,这里的 03 其实等于 105 减 102,而 102 刚好就是 JMP 105 的下一个指令的地址。简单来说,EB 03 可以想象成「跳前 3 个地址」,当您打 JMP 105 指令,DEBUG 会计算一下地址 105 与 JMP 105 那个指令的地址相差多少 ,然后把 JMP 105 译成 EB 03 机械码。
条件
之前的「跳到」指令,是无条件地跳的,即是总之一执行那个指令就会跳。而本节会介绍一些「条件性跳到」(Conditional Jump),即是要符合某个条件才会跳,不符合的话就不会跳,继续执行下一个指令。
-A100
1358:0100 MOV AX, 9
1358:0103 CMP AX, 9
1358:0106 JZ 100
1358:0108 MOV AX, 1
1358:010B
-
在地址 103 那个 CMP AX, 9 指令,意思是「把 AX 的值与 9 比较」,而 JZ 100 表示 「如果等于零,就跳到 100 」"Jump to 100 if zero" ,为什么明明与 9 比较,它郄要与零扯上关系呢?其实您可以想象为「把 AX 的值减去 9,如果等于零就跳」。所以,这两个指令的意思其实是「如果 AX 等于 9 就跳,否则就继续执行下一个指令」。
-R
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0100 NV UP EI PL NZ NA PO NC
1358:0100 B80900 MOV AX,0009
-T
AX=0009 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0103 NV UP EI PL NZ NA PO NC
1358:0103 3D0900 CMP AX,0009
-T
AX=0009 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0106 NV UP EI PL ZR NA PE NC
1358:0106 74F8 JZ 0100
-T
AX=0009 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0100 NV UP EI PL ZR NA PE NC
1358:0100 B80900 MOV AX,0009
-
执行了 JZ 100 后,结果跳到 100。
除了 JZ 之外,还有其它的 Conditional Jump 的指令,使用方法也差不多:
1. JZ - 如果等于零就跳 (Jump if zero/equal)
2. JNZ - 如果不等于零就跳 (Jump if not zero/equal)
3. JG - 如果大于零就跳 (Jump if greater than)
4. JL - 如果小于零就跳 (Jump if less than)
5. JGE - 如果大于或等于零就跳 (Jump if greater than or equal to)
6. JLE - 如果小于或等于零就跳 (Jump if less than or equal to)
循环
假设您要重复执行某段指令 10 次,您可以使用 LOOP 指令,而不必把该段指令重复写 10 次。
-A100
1358:0100 MOV CX, 2
1358:0103 MOV AX, 9
1358:0106 LOOP 103
1358:0108 MOV AX, 1
1358:010B
-
这个 LOOP 指令很特别,因为它要配合 CX 缓存器来用的,您只须把重复的次数放到 CX 缓存器,这里把 CX 设为 2 ,表示要重复 2 次,而 LOOP 103 表示要跳到地址 103。以下示范 LOOP 指令是如何做到重复的效果:
-R
AX=0009 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0100 NV UP EI PL NZ NA PO NC
1358:0100 B90200 MOV CX,0002
-T
AX=0009 BX=0000 CX=0002 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0103 NV UP EI PL NZ NA PO NC
1358:0103 B80900 MOV AX,0009
-T
AX=0009 BX=0000 CX=0002 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0106 NV UP EI PL NZ NA PO NC
1358:0106 E2FB LOOP 0103
-T
AX=0009 BX=0000 CX=0001 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0103 NV UP EI PL NZ NA PO NC
1358:0103 B80900 MOV AX,0009
AX=0009 BX=0000 CX=0001 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0106 NV UP EI PL NZ NA PO NC
1358:0106 E2FB LOOP 0103
-T
AX=0009 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0108 NV UP EI PL NZ NA PO NC
1358:0108 B80100 MOV AX,0001
留意一下每次执行 LOOP 103 之后,CX 的值都会减1,直至当 CX 等于1时,LOOP 103 就不再跳到地址 103了,继续执行下一个指令。 所以,这个 LOOP 103 的意思就好像「如果 CX 减了1之后不等于零,就跳到 103 ,否则继续下一个指令」。
呼叫子程序
有时候,您会需要在不同的时候,都执行同一段指令,这时您可以用 CALL 指令,总之在需要该段指令时就 CALL 它,这样就不用重复写这段指令了。
-A100
1358:0100 MOV AX, 9
1358:0103 CALL 109
1358:0106 MOV AX, 1
1358:0109 MOV AX, 3
1358:010C RET
1358:010D
-
CALL 109 表示「呼叫地址 109」,其实它好像 JMP 109 会跳到地址 109,RET 表示「返回」(Return),执行 RET 指令后,就会跳回之前作出呼叫的指令 CALL 109 的下一个地址,即是 106。
-R
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0100 NV UP EI PL NZ NA PO NC
1358:0100 B80900 MOV AX,0009
-T
AX=0009 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0103 NV UP EI PL NZ NA PO NC
1358:0103 E80300 CALL 0109
-T
AX=0009 BX=0000 CX=0000 DX=0000 SP=FFEC BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0109 NV UP EI PL NZ NA PO NC
1358:0109 B80300 MOV AX,0003
-T
AX=0003 BX=0000 CX=0000 DX=0000 SP=FFEC BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=010C NV UP EI PL NZ NA PO NC
1358:010C C3 RET
-T
AX=0003 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0106 NV UP EI PL NZ NA PO NC
1358:0106 B80100 MOV AX,0001
-
这种效果是 JMP 指令不能做到的,因为 CPU 会记着 CALL 的身处地址,所以 RET 会返回之前 CALL 的地址。
数学运算
计算机其中一个主要用途就是计数,以下逐一示范计算加减乘除数:
计算 1+2=3:
-A100
1358:0100 MOV AX, 1
1358:0103 MOV BX, 2
1358:0106 ADD AX, BX
1358:0108
-R
AX=0003 BX=0002 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0100 NV UP EI PL NZ NA PE NC
1358:0100 B80100 MOV AX,0001
-T
AX=0001 BX=0002 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0103 NV UP EI PL NZ NA PE NC
1358:0103 BB0200 MOV BX,0002
-T
AX=0001 BX=0002 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0106 NV UP EI PL NZ NA PE NC
1358:0106 01D8 ADD AX,BX
-T
AX=0003 BX=0002 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0108 NV UP EI PL NZ NA PE NC
1358:0108 0000 ADD [BX+SI],AL DS:0002=FF
ADD AX, BX 表示把 AX 加上 BX,然后把结果放到 AX,结果 AX 等于 3 。
计算 3-2=1:
-A100
1358:0100 MOV AX, 3
1358:0103 MOV BX, 2
1358:0106 SUB AX, BX
1358:0108
-R
AX=FFFF BX=0002 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0100 NV UP EI NG NZ AC PE CY
1358:0100 B80300 MOV AX,0003
-T
AX=0003 BX=0002 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0103 NV UP EI NG NZ AC PE CY
1358:0103 BB0200 MOV BX,0002
-T
AX=0003 BX=0002 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0106 NV UP EI NG NZ AC PE CY
1358:0106 29D8 SUB AX,BX
-T
AX=0001 BX=0002 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0108 NV UP EI PL NZ NA PO NC
1358:0108 0000 ADD [BX+SI],AL DS:0002=FF
-
SUB AX, BX 表示把 AX 减去 BX,然后把结果放到 AX,结果 AX 等于 1 。
计算 2*3=6:
-A100
1358:0100 MOV AX, 2
1358:0103 MOV BX, 3
1358:0106 MUL BX
1358:0108
-R
AX=0006 BX=0003 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0100 NV UP EI PL NZ NA PO NC
1358:0100 B80200 MOV AX,0002
-T
AX=0002 BX=0003 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0103 NV UP EI PL NZ NA PO NC
1358:0103 BB0300 MOV BX,0003
-T
AX=0002 BX=0003 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0106 NV UP EI PL NZ NA PO NC
1358:0106 F7E3 MUL BX
-T
AX=0006 BX=0003 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0108 NV UP EI PL NZ NA PO NC
1358:0108 0000 ADD [BX+SI],AL DS:0003=9F
-
MUL BX 表示把 AX 乘以 BX,然后把结果放到 AX,结果 AX 等于 6。
计算 7 除以 2,商数是 3,余数是 1:
-A100
1358:0100 MOV AX, 7
1358:0103 MOV BX, 2
1358:0106 DIV BX
1358:0108
-R
AX=0006 BX=0003 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0100 NV UP EI PL NZ NA PO NC
1358:0100 B80700 MOV AX,0007
-T
AX=0007 BX=0003 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0103 NV UP EI PL NZ NA PO NC
1358:0103 BB0200 MOV BX,0002
-T
AX=0007 BX=0002 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0106 NV UP EI PL NZ NA PO NC
1358:0106 F7F3 DIV BX
-T
AX=0003 BX=0002 CX=0000 DX=0001 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1358 ES=1358 SS=1358 CS=1358 IP=0108 NV UP EI PL NZ NA PO NC
1358:0108 0000 ADD [BX+SI],AL DS:0002=FF
-
DIV BX 表示把 AX 除以 BX,然后把商数放到 AX,余数放到 DX,结果 AX 等于 3,DX 等于 1。