指令操作码
数据传输指令
MOV
MOV 指令。将第二个操作数(寄存器的内容、内存中的内容或常数值)复制到第一个操作数(寄存器或内存)。
其语法如下,注意第一个操作数不能是立即数:
mov <reg>, <reg> ; 复制寄存器值
mov <reg>, <mem> ; 从内存加载数据到寄存器
mov <mem>, <reg> ; 把寄存器值存入内存
mov <reg>, <con> ; 立即数赋值给寄存器
mov <mem>, <con> ; 立即数赋值给内存
示例:
mov eax, ebx ; 把 ebx 复制到 eax
mov eax, [var] ; 把变量 var 的值存入 eax
mov [var], eax ; 把 eax 的值存入变量 var
mov ecx, 100 ; 将 100 赋值给 ecx
mov byte ptr [var], 5 ; 只修改 var 指向的 1 字节
PUSH
、POP
PUSH
将数据压入堆栈,POP
则从堆栈取出数据。
堆栈 指的是程序的运行栈,从高地址向低地址增长。
PUSH
指令将数据压入栈顶,POP
指令从栈顶取出数据,并存入寄存器或者内存单元。
语法:
push <reg> ; 将寄存器值压入堆栈
push <mem> ; 将内存值压入堆栈
push <con> ; 将立即数压入堆栈
pop <reg> ; 从堆栈弹出值存入寄存器
pop <mem> ; 从堆栈弹出值存入内存
示例:
push eax ; 将 eax 压入栈
push 10 ; 将 10 压入栈
pop ebx ; 弹出栈顶的值存入 ebx
算术和逻辑运算指令
ADD
、SUB
加法和减法运算,结果存入第一个操作数。
示例:
add eax, ebx ; eax = eax + ebx
sub eax, 10 ; eax = eax - 10
MUL
、DIV
无符号乘法和除法运算,MUL
默认用 EAX
作为被乘数,结果存放在 EDX:EAX
中。
示例:
mov eax, 5
mov ebx, 3
mul ebx ; EAX = 5 * 3
AND
、OR
、XOR
、NOT
位运算操作,AND
是与操作,OR
是或操作,XOR
是异或操作,NOT
是非操作。
示例:
and eax, 0xF0 ; 只保留 eax 的高 4 位
or eax, 0x0F ; 低 4 位置 1
xor eax, eax ; eax 清零
not eax ; 取反 eax
INC
、DEC
递增和递减,等同于 ADD 1
和 SUB 1
。
示例:
inc eax ; eax = eax + 1
dec ebx ; ebx = ebx - 1
CMP
比较两个值,结果影响标志位(ZF、SF、CF)。
CMP
常常与 JXX
混合使用,从而实现条件跳转。
示例:
cmp eax, ebx
je equal_label ; 如果 eax == ebx,跳转到 equal_label
控制转移指令
JMP
无条件跳转到某个标签(label)。
标签是一个可识别的标识符,标签通常是一个有意义的名字,后跟一个冒号,用于标记程序中的某个位置或地址。
示例:
jmp label
Jxx
条件跳转指令
在 CMP
指令后尝尝跟一个条件跳转指令,条件跳转指令会检查标志寄存器(FLAGS)的标志,从而决定是否跳转到某个标签(条件成立时),如果选择不跳转的话,则继续向后执行。
指令 | 全称 | 跳转条件 |
---|---|---|
JE/JZ | jump equal/zero(相等/零) | ZF=1 |
JNE/JNZ | not equal/zero(不等/非零) | ZF=0 |
JG (大于) | greater (大于) | ZF=0 且 SF=OF |
JL (小于) | less(小于) | SF≠OF |
JGE (大于等于) | greater equal(大于等于) | SF=OF |
JLE (小于等于) | less equal(小于等于) | ZF=1 或 SF≠OF |
示例:
cmp eax, ebx
je equal_label
jl less_label
CALL
、RET
调用子程序和返回。
CALL
指令用于调用子程序,涉及以下步骤:
- 保存返回地址:将当前指令的下一个地址(即返回地址)压入栈中,这样子程序返回时才知道从哪一条指令继续执行。
- 跳转到子程序:将程序计数器设置为子程序的入口地址,开始执行子程序的代码。
RET
指令用于从子程序返回到调用函数,涉及以下步骤:
- 从栈中弹出返回地址:从栈顶弹出一个值,并将这个值作为返回地址。这是之前
CALL
指令压入栈的地址。 - 跳转到返回地址:将程序计数器设置为返回地址,继续执行从调用子程序的指令的下一条指令。
示例:
call subroutine
...
subroutine:
; 执行一些操作
ret
陷阱指令
陷阱指令(Trap Instruction)是一种特殊的指令,用于从用户模式切换到内核模式,以便执行特权操作,例如操作系统的系统调用等。
陷阱指令与中断类似,但通常是由程序主动发起的,而不是由硬件事件触发的。
INT
INT
指令用于产生一个软件中断,它后面跟着一个中断向量号(通常是一个字节大小的立即数),用于指定要调用的中断或服务例程。
系统通过中断向量号去中断向量表中查找中断服务程序并执行。
示例:
mov eax, 1 ; 系统调用:exit
mov ebx, 0 ; 退出代码
int 0x80 ; 触发中断
协处理器指令
CLI
和 STI
CLI
和 STI
用于控制 CPU 的中断响应能力。具体来说,这两条指令用于修改处理器的中断标志(IF,Interrupt Flag),从而控制外部硬件中断的使能和禁止。
中断标志 (IF) 状态寄存器中的一个标志位。如果 IF 位被设置(即为 1),处理器将响应外部硬件中断。如果 IF 位被清除(即为 0),处理器将忽略外部硬件中断请求。
CLI
:清除中断标志位,将 IF 位设置为 0,从而禁止处理器响应外部硬件中断。STI
:设置中断标志位,将 IF 位设置为 1,从而允许处理器响应外部硬件中断。
示例:
cli ; 关闭中断
sti ; 开启中断
输入/输出指令
IN
、OUT
IN
和 OUT
指令用于处理与外部设备的输入/输出(I/O)操作。这些指令让 CPU 可以直接与硬件端口通信,从而读取或发送数据。I/O 端口是设备与 CPU 进行通信的一种方式,每个设备通常分配有一组特定的 I/O 端口。
IN
:从指定的 I/O 端口读取数据到寄存器。通过IN
指令,可以从硬件设备读取状态信息或数据。OUT
:将寄存器中的数据写入到指定的 I/O 端口。通过OUT
指令,CPU 可以向设备发送控制命令或数据。
示例:
in al, 0x60 ; 从端口 0x60 读取数据
out 0x60, al ; 将 al 的值输出到端口 0x60
字符串操作指令
字符串操作指令基本不考察,这里简单了解即可。
MOVS
复制字符串(ES:EDI
← DS:ESI
)。
示例:
movs byte ptr es:[edi], byte ptr ds:[esi] ; 复制 1 字节
movs dword ptr es:[edi], dword ptr ds:[esi] ; 复制 4 字节
LODS
从 DS:ESI
加载数据到 AL/AX/EAX
。
示例:
lodsb ; 读取 1 字节
lodsd ; 读取 4 字节
STOS
将 AL/AX/EAX
存储到 ES:EDI
。
示例:
stosb ; 存储 1 字节
stosd ; 存储 4 字节
CMPS
比较两个字符串。
示例:
cmpsb ; 比较字节
cmpsd ; 比较 4 字节
总结
指令类别 | 说明 |
---|---|
MOV | 数据传输 |
PUSH /POP | 堆栈操作 |
ADD /SUB | 加减运算 |
MUL /DIV | 乘除运算 |
AND /OR /XOR /NOT | 逻辑运算 |
CMP | 比较 |
JMP | 无条件跳转 |
Jxx | 条件跳转 |
CALL /RET | 子程序调用 |
IN /OUT | 输入/输出 |
MOVS /LODS /STOS | 字符串操作 |
INT | 触发中断 |
CLI /STI | 控制中断 |