5.程序的表示转换和链接
高级语言程序中的运算是通过指令来完成的,参与运算的变量或常量就是指令中的操作数,所以了解了运算的底层逻辑以后,来进一步了解指令。
目前主流计算机都是intel架构。
5.1
5.1.1 程序和指令的关系
还是得看编程模型,硬件结构,第一章的东西。
“存储程序”的工作方式。
程序由指令组成:
程序在执行之前,数据和指令存放在存储器里,指令和数据都有地址,指令由OP、ADDR字段组成,(操作码字段,地址字段),程序的起始地址放在PC(程序计数器)里。
开始执行程序
1.根据PC取得指令
2.指令译码
3.取操作数
4.指令执行
5.回写结果
6.修改PC的值
指令和数据在形式上没有区别,都是01序列。指令执行时,指令和数据从存储器挪动到CPU,指令放在指令寄存器里,数据放在通用寄存器里。
指令中需要给出的信息:
操作性质(操作码)
源操作数1;源操作数2(可选)。(立即数,寄存器编号,存储器地址)
目的操作数地址(寄存器编号,存储地址)
存储地址的描述与操作数的数据结构有关
指令描述对谁干什么。操作数在指令里给出,就是个立即数,参考微机原理。
除了上面这些,再来回顾一下不同层次语言之间的等价转换关系。
高级语言无法直接执行,要用编译程序编译位汇编语言程序,再用汇编程序转换成机器指令,机器指令就是01序列,可以直接在硬件上执行,可以被机器理解。机器指令实际上是控制信号,控制数字电路动作。任何高级语言最终是通过执行若干条指令来完成的。
软件和硬件的交界面有个接口,这个接口就是指令系统,或者叫指令集体系结构,最关键的就是指令。
指令有微指令、机器指令、伪(宏)指令之分
这里讲的指令都是机器指令。微指令是硬件范畴,是微程序级指令,“微过程”。伪指令之由若干机器指令组成的指令序列,相当于子程序,属于软件范畴。汇编指令是机器指令的汇编表示形式,即符号表示,机器指令和汇编指令一一对应,都和机器结构有关,都是机器级指令。
机器指令是01序列,由若干字段组成
汇编指令来表示机器指令,可能有不同格式,比如intel格式,或AT&T格式
指令的功能可以用寄存器传送语言来描述(Register Transfer Language)
mov,bx,movb都是助记符
最后再回顾一下高级语言转换为机器代码的过程。
[hello.c]预处理[hello.i]编译[hello.s]汇编[hello.o]链接[hello]
预处理:高级语言源程序中#开头的文本处理
编译:生成汇编语言程序
汇编:生成机器语言文件
链接:生成最终的可执行文件
5.1.2 目标代码和ISA
gcc使用举例
其中的 -O1
为一级优化,一般用 -O2
就可以,使用 -O0
时,得到的机器码最接近原来的 C 程序。使用 gcc 的一些选项可以转化过程的中间内容
可重定位的目标程序已经是机器码了,二进制文件,想要看里面的内容需要用到反汇编工具,这个程序的起始地址都是0,显然这不是最终程序指令存放的地址,所以叫做可重定位,而且起始地址一定会重新定位到其他地方。
反汇编工具 objdump ,这个工具把机器码反汇编为汇编语言程序。
编译得到的汇编语言程序和反汇编的略有区别。
两种可执行目标文件 main.o
和 main
都是二进制文件。
main.o
可重定位目标文件main
可执行目标文件
分别 dump 出来的结果,可以看出指令都是一样的,区别在于地址不同。可执行文件地址是一个虚拟地址。
实际看看
回顾指令系统,(指令集体系结构,ISA,Instruction Set Architecture),这是个规约(Specification),规定了如何使用硬件。
使用硬件,即硬件提供的功能,实际上是被抽象成指令被软件使用的,比如说一个 CPU 支持硬件浮点运算功能,那么它一定有和浮点运算相关的专用指令。
ISA 规定了计算机硬件可以执行的指令,指令的格式操作种类,操作数数据类型,寄存器名称,编号,操作数存放的空间,编制方式,大小端,寻址方式.........所有和硬件实现相关的东西。
因此 ISA 是计算机系统里必不可少的抽象层,是对硬件的抽象。
如果没有指令系统,一个数字电路就没法叫做通用计算机。
ISA 和计算机组成(微体系结构)的关系:微结构是指令系统的电路实现。
不同的ISA 如 IA-32 ,MIPS,ARM等,可以由不同的微体系结构来实现。
同一种ISA可以有不同的计算机组成,如乘法器可用ALU或乘法器实现。
所以ISA是计算机组成的抽象。
5.2
intel,IA-32的体系结构
5.2.1 Intel 处理器
停产的:
x86前的产品:4004,8008,8080
x87外置浮点运算器
8/16bit 8087
16bit 80187,80287
32bit 80387
x86-16(16 bit):8086,8088,80186,80286
x86-32/IA-32(32bit):80386,80486,Pentium
x86-64/intel 64:Core 2
微控制器:8051,MCS-96
现在有的产品
x86-32/IA-32:EP80579,Atom
x86-64/Intel 64:Xeon e3 e5 e7,Core i3 i5 i7 i9
x86是Intel开发的一类处理器体系结构的泛称。架构就叫做x86,后来数据无法注册商标,就叫英文名了,如Core i9,现在Intel把32位x86架构的名称从x86-32改称为IA-32。
AMD提出了一个兼容IA-32指令集的64位版本,amd称为AMD64,Intel叫其位Intel64,这个体系命名为x86-64或者直接x64。
IA-32规定了
8个通用寄存器(GPR)0-7
一个 EFLAGS
PC为EIP
可寻址空间4GB(0-0xFFFFFFFF)
指令格式变长,操作码变长,指令由若干字段组成
数据存放在通用寄存器GPR里,指令存放在存储器里
因此指令中要给出的信息:
操作性质(操作码)
源操作数1 源操作数2(立即数,寄存器编号,存储地址)
目的操作数地址(寄存器编号,存储地址)
5.2.2 IA-32寄存器组织
IA-32支持的数据类型
unsigned char
整数/字节
b
8
unsigned short
整数/字
w
16
unsigned int
整数/双字
l
32
unsigned long int
整数/双字
l
32
unsigned long long int
-
-
32
char*
整数/双字
l
32
float
单精度浮点数
s
32
double
双精度浮点数
l
64
因此随着机器位数的发展,寄存器也是在不断兼容发展,新的机器也可以使用老的东西,这就出现了许多设计上的妥协。
寄存器组织:
EAX
EBX
ECX
EDX
8个寄存器的编号从000-111正好3个bit,寄存器的组织反映了体系结构发展的组织,字长扩充,指令兼容。
其中有个比较特殊的是标志寄存器,标志也叫条件码,这里要回顾ALU的硬件结构,通过数字逻辑电路,运算产生条件码保存在这个寄存器里。
6个条件标志,3个控制标志,这几个在8086里面就有,此外还有一些新机器有的标志。
5.2.3 IA-32的寻址方式
寻址方式
如何根据指令给定信息得到操作数或操作数地址
操作数所在的位置
指令中:立即数
寄存器中:寄存器寻址
存储单元中:存储器操作数,比较复杂的寻址方式
存储器操作数的寻址方式和处理器工作模式有段
实地址模式和保护模式
实地址模式基本用不到,是为了和8086保持兼容
在上电或复位时的模式
寻址空间1MB,CS<<4 + IP
保护模式
上电后,采用虚拟存储管理,多任务在隔离、保护
80286以上的处理器工作模式
寻址空间4GB,32位线性地址分段
保护模式下的寻址方式,除了直接寻址,和寄存器寻址,其他的都是存储器操作数的寻址方式,操作数都放在存储器里,最终得到的地址时存储空间里的地址。
最终的线性地址(LA),段基址 + 偏移量,
寻址过程涉及到了分段虚拟管理方式,会在后面学习。
5.2.4 高级语言中寻址举例
double类型变量在linux里4Byte对齐存放,windows里8Byte对其存放。
通过基址找到指定索引的数据。
5.2.5 IA-32 指令格式
字节数:
1或2
0或1
0或1
1、2、4
立即数
操作码和和机器模式一起确定寄存器位数(AL, AX, EAX)
对于寻址方式字段,可有可无
2bit
3bit
3bit
存储器操作数,指出基址寄存器和变址寄存器,B基址,I变址,ss比例因子,1/2/4/8这四种情况因此3bit就够了。
2bit
3bit
3bit
举个例子,机器指令
8d 04 02 leal (%edx, %eax, 1),%eax
1000 1101 0000 0100 0000 0010
不难,但是多。各个位的划分是由第一个字节op操作码决定的。
IA-32是典型的CISC(复杂指令集计算机)风格的ISA
8个通用寄存器(8,16,32)
2个专用寄存器eip, eflasg
6个段寄存器(间接给出段基址)
存储器地址空间为4GB,按字节编址,小端方式
寻址方式
立即,寄存器,存储器(SR:[B]+[I]*s+A)段基址+有效地址(基址+变址x比例因子+偏移)
相对寻址(对于指令来说的,跳转的时候,需要当前地址进行相对寻址)
指令位变长指令字、变长操作码
两种汇编语言格式
Intel格式
AT&T格式
8(%edx,%eax,4)
最后更新于