欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

计算机组成原理之指令(三)

程序员文章站 2022-07-06 13:45:36
...

目录

前言

一、什么是计算机指令

二、常见的计算机指令

三、指令层面看代码的执行过程


前言

怕什么真理无穷,进一寸有一寸的欢喜。 -- 胡适

在粗略学习完计原硬件相关的知识后,进入到学习计原指令,心底其实还是挺迷惑的,指令这一块到底有啥好学的呢?具体又要怎么学呢?学了之后对我未来编码又有那些帮忙呢?也很清楚抱着好奇心与问题去学习是最好的,但成年人的世界往往是需要抱着任务去学习。


一、什么是计算机指令

   计算机指令就是指挥机器工作的指示和命令,程序就是一系列按一定顺序排列的指令,执行程序的过程就是计算机的工作过程。

  如下图为曾经古老的编码方式,在纸带上打卡用来表示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寄存器中的地址罢了。

注:极客时间徐文浩老师的深入浅出计算机组成原理

 

相关标签: 计算机组成原理