• 【计算机组成原理】05-代码是如何变成机器码的


      在 20 世纪 60-70 年代,写程序还要用到打孔卡(Punched Card)。Coder 需要先把程序想好,在纸带上打孔,然后把打孔卡交给计算机去处理。

    FORTRAN 程序打孔卡

      不难看出,这张类似答题卡的纸带上,通过打孔或不打孔来代表“0”和“1”。

      时至今日,CPU 本身也没有理解高级编程语言的能力,仍然只能处理机器码,也就是一连串的“0”和“1”。那么我们用高级编程语言编写的代码,是如何转变成一连串的“0”和“1”的?这一串数字,又是如何在 CPU 中处理的?这篇博客就来看看,机器码计算机指令(Instruction Code)究竟是怎么回事。

    1. CPU 在软硬件接口中做了什么

    1.1 硬件工程师眼中的 CPU

      从硬件角度来看,CPU 就是一个超大规模集成电路,通过电路实现了加法、乘法等处理逻辑。

    1.2 软件工程师眼中的 CPU

      从软件角度来讲,CPU 就是一个执行各种计算机指令(Instruction Code)的逻辑机器。

    1.3 计算机也有多语种——计算机指令与计算机指令集

      计算机指令,就好比一种 CPU 能听懂的语言,我们也把它叫做机器语言(Machine Language)

      正如人类有多种语言,不同 CPU 能听懂的语言也不大一样。Intel 的 CPU 和 ARM 的 CPU,语言就不同。这是因为它们使用了不同的计算机指令集(Instruction Set)

    1.4 存储程序型计算机

      计算机程序是由成千上万条指令组成的,不可能将这些指令一直存放在 CPU 中。计算机程序通常是存储在存储器中的,这种计算机就叫做存储程序型计算机(Stored-program Computer)

      既然提到存储程序型计算机,那么必然有不存储程序的计算机咯。没错,在现代计算机出现之前,出现过插线板计算机(Plugboard Computer)。这种设备通过插拔电线来完成各种计算任务。

    IBM 的 Plugboard Computer

    2. 代码到机器码的华丽变身——编译与汇编

      我们用一段 C 语言代码来看看,我们平时编写的代码是如何变成计算机指令的。

    1 // test.c
    2 int main()
    3 {
    4   int a = 1; 
    5   int b = 2;
    6   a = a + b;
    7 }

      想在 Linux 系统上运行这段代码,要先把它翻译成汇编语言(Assembly Language,ASM)的程序。从高级编程语言代码到汇编语言的过程就是编译(Compile)

      汇编代码还不是机器码,要用汇编器(Assembler)处理汇编代码,才能生成机器码(Machine Code)。这些机器码由“0”和“1”组成的机器语言表示。这些机器码就是一条条计算机指令,这些计算机指令才是 CPU 真正能读懂的。

    高级编程语言到机器语言的过程

      在 Linux 系统中,使用 gcc 和 objdump 这两条指令,可以将对应的汇编代码和机器码都打印出来。

    1 $ gcc -g -c test.c
    2 $ objdump -d -M intel -S test.o

      左侧的数字就是机器码,右边的 push、mov、add、pop 等就是汇编代码。一行 C 语言代码,有时只对应一条机器码和汇编代码,有时则对应两条机器码和汇编代码。汇编代码和机器码则是一一对应的。

     1 test.o:     file format elf64-x86-64
     2 Disassembly of section .text:
     3 0000000000000000 <main>:
     4 int main()
     5 {
     6    0:   55                      push   rbp
     7    1:   48 89 e5                mov    rbp,rsp
     8   int a = 1; 
     9    4:   c7 45 fc 01 00 00 00    mov    DWORD PTR [rbp-0x4],0x1
    10   int b = 2;
    11    b:   c7 45 f8 02 00 00 00    mov    DWORD PTR [rbp-0x8],0x2
    12   a = a + b;
    13   12:   8b 45 f8                mov    eax,DWORD PTR [rbp-0x8]
    14   15:   01 45 fc                add    DWORD PTR [rbp-0x4],eax
    15 }
    16   18:   5d                      pop    rbp
    17   19:   c3                      ret    

      我们在使用 GCC(GNU Compiler Collection,GNU 编译器)时,可以直接将高级编程语言代码编译成机器码。那为什么还要让汇编代码在中间转一手呢?这是因为机器码很难看懂,但汇编则容易理解得多。换句话说,汇编就是给程序员看的机器码。也正是基于这一点,机器码和汇编代码是一一对应的。

    3. 解析指令和机器码

    3.1 指令的分类

      上一节中反编译出的汇编代码和机器指令到底是什么意思呢?Intel CPU 有 2000 多条 CPU 指令,我们无法一一掌握。但通常来说,常见指令可以分成五类。

    3.1.1 算数类指令

      加减乘除等运算,在 CPU 层面都会变成算术类指令。

    3.1.2 数据传输类指令

      变量赋值、读写内存等操作,用的都是数据传输类指令。

    3.1.3 逻辑类指令

      与或非都是此类指令。

    3.1.4 条件分支类指令

      if-else 等都是此类指令。

    3.1.5 无条件跳转指令

      调用函数时,就是发起了一个无条件跳转指令。

    指令分类

    3.2 汇编器如何将汇编代码翻译成机器码

      前文说过,不同的 CPU 有不同的指令集,自然也就对应着不同的汇编语言和不同的机器码。我们以最简单的 MIPS 指令集为例,看看机器码是如何生成的。

      MIPS 指令集是一组由 MIPS 公司在 80 年代中期设计出的 CPU 指令集,最近已经开源。如果想进一步研究 CPU 和指令集细节,请戳

      MIPS 的指令是一个 32 位整数,其中高 6 位是操作码(Opcode),用于说明这是一条什么样的指令。剩下的 26 位有三种格式,分别为 R、I、J。

    MIPS 指令示意

    3.2.1 R 指令

      用于算术和逻辑操作,其中有读取、写入数据用到的寄存器地址。如果是逻辑位移操作,后面还会加上位移操作的位移量。最后的功能码,是在前面的操作码不够时,扩展操作码以表示具体指令的。

      rs(register source):第一个源寄存器;

      rt 则有二义性。有些资料中说 t 是 target 之意,也有资料称 t 是 s 的下一个字母,并非具体单词的缩写。此处应为第二个源寄存器,所以我偏向于第二种解释。

      rd(register destination):目标寄存器。

    3.2.2 I 指令

      用于数据传输、条件分支,以及运算时使用的并非常量而是常数的时候。

      此时没有位移量和操作码,也没有第三个寄存器,于是把这三部分直接成一个地址值或常数。

    3.2.3 J 指令

      跳转指令,高 6 位之外的 26 位都是一个跳转后的地址。

      接下来,我们用一条语句为例来解释:

    1 add $t0,$s2,$s1

      这条语句在 MIPS 指令中,opcode 为 0x0,rs 地址为 0x11,rt 地址为 0x12,rd 是目标的临时寄存器地址,假设为 0x8。因为我们是加法而非位移操作,所以位移量为 0。将以上数字拼起来,就是下图所示:

    MIPS 指令示例(首行为十进制)

      接下来,我们将这条指令的机器码打在打孔卡上(打孔表示 1,不打孔表示 0):

    MIPS 指令的打孔卡

    4. 拓展资料

      如果想了解 Intel CPU 的指令集,可以参考《计算机组成与设计:软 / 硬件接口》第 5 版的 2.17 小节。

  • 相关阅读:
    Python·安装扩展包的几种方法
    Arduino系列硬件资源介绍
    树莓派USB摄像头的使用
    树莓派frp服务器和客户端配置教程
    树莓派frp内网穿透
    用Windows远程桌面连接树莓派的方法
    控制窗体的位置和大小
    树霉派更换软件镜像源
    I2C的库函数应用示例
    I2C总线的Arduino库函数
  • 原文地址:https://www.cnblogs.com/murongmochen/p/14083892.html
Copyright © 2020-2023  润新知