zoukankan      html  css  js  c++  java
  • 计算机指令

    在软硬件接口中,CPU帮我们做了什么?

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

    从软加工程师的角度来讲,CPU就是一个执行各种计算机指令(Instruction Code)的逻辑机器。这里的计算机指令,就好比一门CPU能够听懂的语言,我们把它叫做机器语言(Machine Language)

    不同的CPU能够听懂的语言不太一样。比如我们个人电脑用的Intel的CPU,苹果手机用的是ARM的CPU。类似这样两种CPU各自支持的语言,就是两组不同的计算机指令集(Instruction set)

    一个计算机程序,不可能只有一条指令,而是由成千上万条指令组成的。但是CPU里不能一直放着所有指令,所以计算机程序平时是存储在存储器中的。这种指令存储在存储器里面的计算机,我们就叫做存储程序型计算机

    从编译到汇编,代码怎么变成机器码?

    // test.c
    int main()
    {
        int a = 1;
        int b = 2;
        a = a + b;
    }

    要让这段程序在一个Linux操作系统上跑起来,我们需要把整个程序翻译成一个汇编语言(ASM,Assembly Language)的程序,这个过程我们一般叫编译(Compile)成好汇编代码。

    针对汇编代码,我们可以再用汇编器(Assembler)翻译成机器码(Machine Code)。这些机器码由“0”和“1”组成的机器语言表示。这一条条机器码,就是一条条的计算机指令。这样一串串的16进制数字,就是我们CPU能够真正认识的计算机指令

    在一个Linux操作系统上,我们可以简单地使用gcc和objdump这样两条命令,把对应的汇编代码和机器码都打印出来。

    [learning_log@localhost 桌面]$ gcc -g -c text.c
    [learning_log@localhost 桌面]$ objdump -d -M intel -S text.o
    text.o:     文件格式 elf64-x86-64
    
    
    Disassembly of section .text:
    
    0000000000000000 <main>:
    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    

    可以看到左侧一堆数字,这些就是一条条机器码;右边有一系列的push、mov、add、pop等,这些就是对应的汇编代码。一行C语言代码,有时候对应一条机器码和汇编代码,有时候则是对应两条机器码和汇编代码。汇编代码和机器码之间是一一对应的。

    从高级语言到汇编代码,再到机器码,就是一个日常开发程序,最终变成了CPU可以执行的计算机指令的过程。

    解析指令和机器码

    常见的指令可以分为五大类。

    第一类是算术类指令。我们的加减乘除,在CPU层面,都会变成一条条算术类指令。

    第二类是数据传输类指令。给变量赋值,在内存里读写数据,用的都是数据传输类指令。

    第三类是逻辑类指令。逻辑上的与或非,都是这一类指令。

    第四类是条件分支类指令。日常我们写的“if/else”,其实都是条件分支类指令。

    最后一类是无条件跳转指令。写一些大一点的程序,我们常常需要写一些函数或者方法。再调用函数的时候,其实就是发起了一个无条件跳转指令。

    我们说过,不同的CPU有不同的指令集,也就对应着不同的汇编语言和不同的机器码。为了方便你快速理解这个机器码的计算方式,我们选用最简单的MIPS指令集,来看机器码是如何生成的。

    MIPS的指令是一个32位的整数,高6位叫操作码(Opcode),也就是代表这条指令具体是一条什么样的指令,剩下的26位有三种格式,分别是R、I、J。

    R指令是一般用来做算术和逻辑操作,里面有读取和写入数据的寄存器的地址。如果是逻辑位移操作,后面还有位移操作的位移量,而最后的功能码,则是在前面的操作码不够的时候,扩展操作码表示对应的具体指令的。

    I指令,则通常是用来数据传输,条件分支,以及在运算的时候使用的并非变量还是常数的时候。这个时候,没有了位移量和操作码,也没有了第三个寄存器,而是把这三部分直接合并成一个地址值或者常数。

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

    add $t0,$s2,$s1

    对应的MIPS指令里的opcode是0,rs代表第一个寄存器s1的地址是17,rt代表第二个寄存器s2的地址是18,rd代表目标的临时寄存器t0的地址,是8。因为不是位移操作,所以位移量是0.把这些数字拼在一起,就变成了一个MIPS的加法指令。

    为了读起来方便,我们一般把对应的二进制数,用16进制表示,也就是0X02324020。这个数字也就是这条指令对应的机器码。

    如果想要对日常使用的Intel CPU的指令集有所了解,可以参看《计算机组成与设计:软/硬件借口》第5版的2.17小节。

  • 相关阅读:
    课后作业-阅读任务-阅读笔记-4
    《团队--学生成绩管理-阶段互评》
    《团队-学生成绩管理-阶段互评》
    团队编程项目作业4-开发文档
    阅读任务--阅读提问-3
    课后作业-阅读任务-阅读笔记3
    课后作业-阅读任务-阅读提问-3
    课后作业-阅读任务-阅读笔记-3
    结对编程项目作业5
    结对编程项目作业4
  • 原文地址:https://www.cnblogs.com/mylearning-log/p/10874797.html
Copyright © 2011-2022 走看看