6.IA32指令
不需要记住,查手册
但是要理解手册在说什么
6.1 传送指令
6.1.1 常用传送指令
通用数据传送指令
MOV,等长的传送movb,movw,movl
MOVS,不等长的传送8->16,高8位用符号位扩展movsbw,movswl
MOVZ,0扩展(无符号扩展)高位补0,movzwl, movzbl
XCHG,数据交换,类似于两条MOV实现的功能
PUSH/POP,出入栈,如pushl, pushw, popl, popw
地址传送
LEA,加载有效地址
leal (%edx,%eax), %eax 实现的功能 R[eax] <- R[edx] + R[eax]
输入输出指令
标志传送指令
PUSHF,POPF,
用出入栈来研究指令
栈(Stack),不等于堆栈
pushw %ax
R[sp] <- R[sp] - 2
M[R[sp]] <- R[ax]
popw %ax
R[ax] <- M[R[sp]]
R[sp] <- R[sp] + 2
前面介绍过,程序由指令序列组成,一个简单的函数进行反汇编
理解了程序是指令序列。
函数从首地址开始执行,把函数地址送到EIP里面,就开始执行了。
根据EIP取指令,指令译码,一步一步往前走。
6.1.2 指令传送过程
第一条指令
执行函数的第一件事情去取指令,4这个地址,EIP寄存器接通到地址总线,并且CPU发出读命令,控制信号也送给存储器,存储器收到信号把制定的存储单元接通到数据总线上,此时数据总线在CPU一侧是接通到指令寄存器里的。
指令寄存器里的各个字段又分别送到不同的控制器,解析op的内容,产生很多控制信号控制对应的数字电路动作。比如说这个指令就是接通ebp到数据总线,然后把栈指针寄存器接通到地址总线,给出存储器写信号,就写进去了,然后栈指针加4。
更具体的,就要参考时序图了,纯数字电路分析一条指令的执行过程。
执行完操作后,EIP寄存器会自动+1,重复上述过程,所有指令完成了,那么这个函数也就运行完成了。
如果是寄存器到寄存器之间的传送,那么就是CPU内部电路的事情,如果是访问外部内存,那么就会有总线上的操作。
6.2 定点运算指令
6.2.1 常用定点运算指令
加减运算指令,影响标志位,不区分有无符号运算
ADD:加,addb, addw, addl
SUB:减,subb, subw, subl
加1 减1运算,影响CF之外的标志,不区分符号
INC,incb, incw, incl
DEC, decb, decw, decl
取负运算,影响标志
NEG,negb, negw, negl
比较运算,作减法得到标志,不区分符号
CMP,cmpb, cmpw, cmpl
乘除运算,不影响标志,区分符号
MUL/IMUL
DIV/IDIV
乘法指令格式有很多种,可以给出一个、两个、三个操作数。
给一个,另一个操作数隐含在AL/AX/EAX里,结果存放在AX或者DX-AX或者EDX-EAX里
两个操作数DST和SRC,则结果存放在DST里
三个操作数,REG,SRC,IMM,src*imm,结果放寄存器里
除法指令只明显指出除数,用EDX-EAX中的内容处以指定除数
8bit,16bit被除数在AX里,商AL,余数AH
16bit,32bit被除数在DX-AX里,商AX,余数DX
32bit,被除数在EDX-EAX里,商EAX,余数EDX
此外还有一个运算指令对标志位影响与否的表,对应的有C语言的运算符。
6.2.2 加法运算的底层实现
上面的例子,有一条指令
是做加法运算的,在看实现之前,先看看IA32的寄存器组织
000 a
001 c
010 d
011 b
机器里面执行指令,按照前面的思路,两个数据已经到了EAX和EDX寄存器里了,下一步就是取得这个指令
01 d0
00000001 11010000
两个寄存器里的数据要送到ALU里去运算,ALU的样子钱买年有过简单介绍,里面有补码加减器,可以对有无符号数进行加减运算,还有逻辑运算器。ALU里面没有乘法器,可以用加减移位来实现,当然为了快速实现乘法,也可以在ALU外面设计一个独立的乘法器。除法器也不在ALU里。
ALU像是一个多路选择器,两个输入端,一个输出端,控制信号选择输出的结果。
这里的可玩性就比较高了,可以用FPGA设计实现一个简单的CPU
6.2.3 加法指令和乘法指令举例
假设 R[ax]=FFFAH,R[bx]=FFF0H,执行指令 addw %bx,%ax
后,AX,BX中的内容?标志位?操作数作为无符号数和带符号数解释并验证。
R[ax] <- R[ax] + R[bx]
结果是FFEAH,进位位1
CF=1, OF=0, ZF=1, SF=1
无符号数来解释,那么必然溢出了。带符号数解释的话,结果正确OF=0
对于乘法,布斯乘法算法
6.3
6.3.1 逻辑运算
逻辑运算,仅NOT不影响标志,OF=CF=0
NOT,非 notb, notw, notl
AND,与 andb, andw, andl
OR,或 orb, orw, orl
XOR,异或 xorb, xorw, xorl
TEST,与测试,只影响标志
移位运算
SHL/SHR,逻辑左/右移
SAL/SAR,算术左右移
ROL/ROR,循环左/右移
6.3.2 运算举例
逆向工程,机器码,反汇编,从汇编程序语言推断高级语言代码。
可以看出,高级语言不区分算术移位和逻辑移位的指令
6.4 条件转移指令
6.4.1 常用指令
指令的执行一种是按顺序执行,还有一种是跳转到转移目标出执行
无条件转移指令
JMP DST,无条件转移
条件转移
Jcc DST,cc为条件码,满足才跳转到DST
条件设置
SETcc DST,按条件码cc判断的结果保存到DST
调用和返回指令,用于过程调用
CALL DST,返回地址入栈,转到DST执行
RET,栈内取出返回地址,继续返回点执行
中断指令,也是一种跳转
在这些指令里,有非常重要的一个寄存器:条件寄存器。
条件码是执行一条指令后生成的。
具体的转移指令特别多,查手册就好。
举个小例子
当参数为0时,会出错。
按照无符号数比时,i已经变成了一个巨大的值。
正确的做法是把len声明为int型,机器指令会使用带符号指令来比较。
6.4.2 条件设置指令举例
C表达式类型转换顺序。不同类型的参与运算,会向上做一转换处理。
6.5 x87 FPU
IA32浮点处理架构有两种,
x87 FPU 指令集 , gcc默认
SSE指令集,x86-64架构
6.5.1
早期的FPU作为一个外置的浮点处理器使用的,协处理器。现在的FPU和CPU做在一起。
x87 FPU 特指与 x86 处理器配套的浮点协处理器架构。
寄存器用栈结构
深度为8,位数为80,8个80bit寄存器
ST(0)-ST(7),栈顶为ST(0)-
所有浮点运算按80bit扩展精度进行
浮点数在浮点寄存器和内存之间传送
因此会有个bit扩展或者阶段的操作。
装入,转换为80bit扩展精度
FLG
FILD,int转换为浮点格式在装入
存储,转换为IEEE754单精度或者双精度
FSTx,sl精度格式
FSTPx,弹出栈顶
6.6 MMX 及 SSE 指令集
最后更新于