概述
计算机硬件只能识别和理解机器语言程序,用各种汇编语言或高级语言编写的源程序都要翻译(汇编,解释或编译)成以机器指令形式表示的机器语言才能在计算机中执行。
计算机的指令有微指令,机器指令和伪(宏)指令之分。微指令是微程序级命令,属于硬件范畴;伪指令是由若干机器指令组成的指令序列,属于软件范畴;机器指令介于二者之间,处于硬件和软件的交界面。
指令结构体系
在计算机系统的抽象层中,最重要的抽象层就是指令集体系结构(ISA),他作为计算机硬件之上的抽象层,对使用硬件的软件屏蔽了底层硬件的实现细节,将物理上的计算机硬件抽象成一个逻辑上的虚拟计算机,称为机器语言级虚拟机。
ISA 定义了机器语言级虚拟机的属性和功能特性,主要包括以下信息:
- 可执行的指令集合,包括指令格式,操作种类以及每种操作对应的操作数的相应规定;
- 指令可接收的操作数的类型;
- 操作数或其地址所能存放的寄存器组的结构,包括每个寄存器的名称,编号,长度和用途;
- 操作数所能存放的存储空间的大小和编制方式;
- 操作数在存储空间存放时按照大端方式还是小端方式存放;
- 指令获取操作数以及下一条指令的方式,即寻址方式;
- 指令执行过程的控制方式,包括程序计数器,条件码定义等。
生成机器代码的过程
通常,将一个 C 语言程序转换为可执行目标代码的过程分为 4 个步骤:
- 预处理:在预处理截断对带有
#
开头的语句进行处理,在源程序中插入所有用#include
命令指定的文件和用#define
声明指定的宏。 - 编译:将预处理后的源程序编译生成相应的汇编语言程序。
- 汇编:由汇编程序将汇编语言转换为可重定向的机器语言目标代码文件。
- 链接:由链接器将多个可重定位的机器语言目标文件以及库文件链接起来,生成最终的可执行文件。
源程序文件后缀名为 .c
,所包含的头文件后缀名为 .h
;预处理过的源文件后缀名为 .i
;汇编语言源程序后缀名为 .s
;编译后的可重定向文件后缀名为 .o
,最终生成的可执行代码文件没有后缀。
寄存器与寻址方式
寄存器
IA-32 中的定点寄存器中共有 8 个通用寄存器,2 个专用寄存器和 6 个段寄存器。
- 8 个通用寄存器的长度为 32 位,其中 EAX, EBX, ECX, EDX 主要用来存放
操作数
,可根据操作数长度是字节,字还是双子来确定存取寄存器的最低 8 位,16 位还是全部 32位。ESP, EBP, ESI, EDI 主要用来存放变址值或指针
。ESP 是栈顶指针,EBP 是栈底指针。 - 2 个专用寄存器分别是指令指针寄存器 EIP 和标志寄存器 EFLAGS。IP 与程序计数器 PC 是功能完全一样的寄存器,名称不同而已。EFLAGS 內有各种标志信息,用来记录操作数的状态。常见的标志信息有:
- OF:溢出标志,反映带符号数的运算结果是否超过相应数值范围。
- SF:符号标志,反映带符号数运算结果的符号。
- CF:进/借位标志,反映无符号整数加减运算后的进借位情况。
- DF:方向标志,用来确定串操作指令执行时编制寄存器 ESI 和 EDI 中的内容时自增还是自减。
- IF:中断允许标志。IF 对非屏蔽中断和内部异常不起作用,仅对外部可屏蔽中断起作用。
- TF:陷阱标志,用来控制单步执行操作。
寻址方式
根据指令给定的信息得到操作数或操作数地址的方式称为寻址方式。
立即寻址是指指令中直接给出操作数;寄存器寻址指指令中给出操作数所存放的寄存器的编号。除了立即寻址和寄存器寻址外,其他寻址方式下的操作数都在存储单元中,也称为存储器操作胡。
指令系统概述
数据类型
c 语言基本数据类型和 IA-32 操作数类型的对应关系:
c 语言声明 | Intel 操作数类型 | 汇编指令长度后缀 | 存储长度(字节) |
---|---|---|---|
(unsigned) char | 整数/字节 | b | 1b |
(unsigned) short | 整数/字 | w | 2b |
(unsigned) int | 整数/双字 | l | 4b |
(unsigned) long int | 整数/双字 | l | 4b |
(unsigned) long long int | – | – | 8b |
char * | 整数/双字 | l | 4b |
float | 单精度浮点数 | s | 4b |
double | 双精度浮点数 | l | 8b |
long double | 扩展精度浮点数 | t | 10b~12b |
在表中,可以看出双字整数和双精度浮点数的长度后缀都一样,因为已经通过指令操作码区分了是浮点数还是整数,所以长度后缀相同不会产生歧义。
C 语言程序的基本数据类型主要由以下几类:
- 指针或地址:用来表示字符串或其他数据区域的指针或存储地址,可声明为
char *
等类型,其宽度为 32 位,对应 IA-32 的双字。 - 序数,位串:用来表示序号,元素个数,元素总长度,位串等的无符号数。
- 带符号整数:是 C 语言应用最广泛的基本数据类型,可声明位 char,short,int,long 等。
- 浮点数:用来表示实数,可声明为 float,double 和 long double 等。
指令类型
1. 传送指令
传送指令用于寄存器,存储单元或 I/O 端口之间传送信息。
通用数据传送指令:
- MOV:一般的传送指令,包括 movb(字节传送),movw(单字传送),movl(双字传送);
- MOVS:符号扩展传送指令,将短的源数据按高位符号扩展后传送到目的地址,如
movzwl
表示把一个字节进行符号扩展后送到一个字地址中。 - MOVZ:零扩展传送指令,将短的源数据按高位零扩展后传送到目的地址。
- XCHG:数据交换指令,将两个寄存器内容互换。
- PUSH:压栈操作,先将栈下移一个单元,为新进成员让出空间,然后再把新进成员放进来。
- POP:出栈操作,先将栈顶成员算到目的寄存器中,再上移缩小栈空间。
地址传送指令:LEA 指令,主要是加载有效地址,用来将源操作数的存储地址送到目的寄存器中。
输入输出指令:专门用于累加器和 I/O 端口之间进行数据传送。例如:in 指令用于将 I/O 端口内容送至累加器,out 指令将累加器内容送至 I/O 端口。
标志传送指令:标志传送指令专门用于对标志寄存器进行操作。如 pushf 指令用于将标志寄存器的内容压栈,popf 指令将栈顶内容送至标志寄存器。
2. 定点算术运算指令
- 加/减运算指令:ADD/SUB。用于对给定长度的两个位串进行相加或相减,两个操作数中最多只有一个是存储器操作数,不区分是无符号数还是带符号整数,产生的和/差送到目的地址,生成的标志信息送到标志寄存器 EFLAGS。
- 增/减运算指令:INC/EDC。对给定长度的一个位串加一或减一,给定的操作数既是源操作数,也是目的操作数。
- 取负指令:NEG。用于求操作数的负数。
- 比较指令:CMP。用于两个寄存器操作数的比较,用目的操作数减去源操作数,结果不送回目的操作数,即两个操作数保持不变,只是标志位作相应改变,因而类似于 SUB 指令。
- 乘法指令:
- 无符号数乘:MUL。只能明显给出一个操作数。
- 带符号数乘:IMUL。可以明显给出一个,两个或三个操作数。
若指令只给出一个操作数,则另一个源操作数隐含再累加器 EAX 中。对于 MUL 指令,若乘积高 n 位为全 0,则标志 OF 和 CF 皆为 0,否则皆为 1。对于 IMUL 指令,若乘积的高 n 位为全 0 或全 1,并且等于低 n 位中的最高位,则 OF 和 CF 皆为 0,否则皆为 1。
- 除法指令:
- 无符号数除:DIV。
- 有符号数除:IDIV
指令中只能明显指出除数,用累加器 EAX,EDX 存放被除数。若源操作数(除数)是 32 位,则 64 位被除数隐含在 EDX-EAX 寄存器中,计算后的商在 EAX,余数在 EDX。
3. 按位运算指令
逻辑运算指令:
- NOT:单操作数取反指令,将操作数每一位取反,然后把结果送回对应位。
- AND:对双操作数进行按位逻辑“与”,主要用来实现“掩码”操作。
- OR:对双操作数进行按位逻辑“或”,常用于使目的操作时的特定位置为 1.
- XOR:对双操作数进行按位逻辑“异或”,常用于判断两个操作数中哪些位不同或用于改变指定位的值。
- TEST:根据两个操作数相“与”的结果来设置标志位,常用于检测某种条件但不能改变源操作数的场合。
移位指令:
- SHL:逻辑左移,每左移一次,最高位送入 CF,并在低位补 0。
- SHR:逻辑右移,每右移一次,最低位送入 CF,并在低位补 0。
- SAL:算术左移,操作与 SHL 类似,每次移位,最高位送入 CF,并在低位补 0.执行 SAL 指令使,如果移位前后符号位发生变化,则 OF=1,表示左移后结果溢出。这是 SAL 与 SHL 的不同之处。
- SAR:算术右移,每右移一次,操作数的最低位送入 CF,并在高位补符号位。
- ROL:循环左移,每左移一次,最高位移到最低位,并送入 CF。
- ROR:循环右移,每右移一次,最低位移到最高位,并送入 CF。
- RCL:带循环左移,将 CF 作为操作数的一部分循环左移。
- RCR:带循环右移,将 CF 作为操作数的一部分循环右移。
4. 控制转移指令
无条件转移指令:JMP。无条件转移到转移目标地址处执行。
条件转移指令:以条件标志或者条件标志位的逻辑运算结果作为转移依据。
条件设置指令:SET。用来将条件标志组合得到的条件值设置到一个 8 位通用寄存器中。
条件传送指令:CMOV。如果符合条件就进行传送操作,佛则什么都不做。
调用指令:CALL。是一种无条件转移指令,跳转方式与 JMP 指令类似,它具有两个功能:
- 将返回地址入栈(相当于 PUSH 操作)
- 跳转到指定地址处执行。
返回指令:RET。是一种无条件转移指令,是子程序执行后返回主程序继续执行。
5. 浮点处理指令
- 浮点装入指令 FLD 用来将存储单元中的浮点数转入到浮点寄存器栈的栈顶。
- 浮点存储指令 FST 和 FSTP 用来将浮点寄存器栈顶中的元素存储到存储单元中。
今天的文章第三章:程序的转换分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/22615.html