计算机组成原理之指令(三)
目录
前言
怕什么真理无穷,进一寸有一寸的欢喜。 -- 胡适
在粗略学习完计原硬件相关的知识后,进入到学习计原指令,心底其实还是挺迷惑的,指令这一块到底有啥好学的呢?具体又要怎么学呢?学了之后对我未来编码又有那些帮忙呢?也很清楚抱着好奇心与问题去学习是最好的,但成年人的世界往往是需要抱着任务去学习。
一、什么是计算机指令
计算机指令就是指挥机器工作的指示和命令,程序就是一系列按一定顺序排列的指令,执行程序的过程就是计算机的工作过程。
如下图为曾经古老的编码方式,在纸带上打卡用来表示0或1,然后再交给计算机处理;
为什么要用如此低效的方式进行编码呢?
原因其实很简单,那就是CPU只能识别0,1这样的机器语言,那怕是今天的计算机也还是如此,只不过是现在我们有了高级语言以及更加好用的集成开发工具而已。
通过高级语言编写的代码是如何转变成CPU能识别的机器语言呢?
高级语言--经过编译--> 汇编语言 --汇编器--> 机器语言
过程如图所示:
高级语言为什么不直接转化成机器码呢?
原因其实很简单,那就是机器码不够直观,而汇编语言与机器码一一对应,其可以说是给程序员看的机器语言。如下代码,左边为机器码,与之一一对应的右边为汇编码。
int main()
{
0: 55 push rbp
1: 48 89 e5 mov rbp,rsp
int a = 1;
4: c7 45 fc 01 00 00 00 mov DWORD PTR [rbp-0x4],0x1
int b = 2;
b: c7 45 f8 02 00 00 00 mov DWORD PTR [rbp-0x8],0x2
a = a + b;
12: 8b 45 f8 mov eax,DWORD PTR [rbp-0x8]
15: 01 45 fc add DWORD PTR [rbp-0x4],eax
}
18: 5d pop rbp
19: c3 ret
二、常见的计算机指令
常见的指令有如下五类
三、指令层面看代码的执行过程
一个程序执行的时候,CPU 会根据 PC 寄存器里的地址,从内存里面把需要执行的指令读取到指令寄存器里面执行,然后根据指令长度自增,开始顺序读取下一条指令。可以看到,一个程序的一条条指令,在内存里面是连续保存的,也会一条条顺序加载。
除了简单地通过 PC 寄存器自增的方式顺序执行外,条件码寄存器会记录下当前执行指令的条件判断状态,然后通过跳转指令读取对应的条件码,修改 PC 寄存器内的下一条指令的地址,最终实现 if…else 以及 for/while 这样的程序控制流程。
- 下面以一段代码做为样例来说明该过程
int main()
{
srand(time(NULL)); // 使用当前时间进行随机数发生器的初始化
int r = rand() % 2; // rand 生成了一个随机数 r,r 要么是 0,要么是 1
int a = 10;
if (r == 0)
{
a = 1;
} else {
a = 2;
}
- 进行编译
$ gcc -g -c test.c
$ objdump -d -M intel -S test.o
- 汇编代码与机器码如下
省略部分代码。。。
if (r == 0)
3b: 83 7d fc 00 cmp DWORD PTR [rbp-0x4],0x0
3f: 75 09 jne 4a <main+0x4a>
{
a = 1;
41: c7 45 f8 01 00 00 00 mov DWORD PTR [rbp-0x8],0x1
48: eb 07 jmp 51 <main+0x51>
}
else
{
a = 2;
4a: c7 45 f8 02 00 00 00 mov DWORD PTR [rbp-0x8],0x2
51: b8 00 00 00 00 mov eax,0x0
}
代码解说:
- 1. r == 0 的条件判断,被编译成了 cmp 和 jne 这两条指令,cmp比较前后两个操作数的值,DWORD PTR 代表操作的数据类型是 32 位的整数,而 [rbp-0x4] 则是一个寄存器的地址。
- 2. jne 指令,是 jump if not equal 的意思,它会查看对应的零标志位。如果为 0,会跳转到后面跟着的操作数 4a 的位置。这个 4a,对应这里汇编代码的行号,也就是上面设置的 else 条件里的第一条指令。当跳转发生的时候,PC 寄存器就不再是自增变成下一条指令的地址,而是被直接设置成这里的 4a 这个地址。这个时候,CPU 再把 4a 地址里的指令加载到指令寄存器中来执行。
- 3. mov 指令把 2 设置到对应的寄存器里去,相当于一个赋值操作。然后,PC 寄存器里的值继续自增,执行下一条 mov 指令。
- 4. mov 指令的第一个操作数 eax,代表累加寄存器,第二个操作数 0x0 则是 16 进制的 0 的表示。这条指令其实没有实际的作用,它的作用是一个占位符。
总结:通过上述的分析发现对于计算机而言程序的指令默认是顺序执行的,而对于复杂的if条件判断语句或for循环这类语句,其实也只是改变了PC寄存器中的地址罢了。
注:极客时间徐文浩老师的深入浅出计算机组成原理