计算机中的指令跳转

Posted ᝰFour Years

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算机中的指令跳转相关的知识,希望对你有一定的参考价值。

前言

在上一章中说了,高级语言为什么怎么样成为计算机能够读懂的语言,下面就来说说这些计算机能够读懂的语言中,他们究竟是如何设计的

CPU是如何执行指令的?

在我们现实常用的CPU中,有几百亿的晶体管通过电路起来,在逻辑上我们可以认为CPU就是由一个个寄存器所组成,而CPU的内部,是由多个触发器或者锁存器组成的简单电路。N个触发器或者锁存器就能组成一个N位寄存器

在CPU中有很多功能不同的寄存器

  1. PC寄存器,他是指令地址寄存器,是用来存放下一条需要执行的计算机指令的内存地址
  2. 指令寄存器,是用来存放当前正在执行的指令
  3. 条件码寄存器,是用来存放正在执行的指令

在其他的还有一些通用的寄存器,既可以存放数据,又可以存放地址
阿萨在所这里插入图片描述
实际上,在一个程序运行的时候,CPU会根据PC寄存器中的地址,从内存把需要执行的指令读取到指令寄存器中执行,然后另指令长度自增,开始顺序读取下一条指令,里面指令在内存中是连续保存的,也会一条条顺序加载。

if else 就是程序的跳转

下面我们看一个简单的程序

#include <time.h>
#include <stdlib.h>
int main()
{
  srand(time(NULL));
  int r = rand() % 2;
  int a = 10;
  if (r == 0)
  {
    a = 1;
  } else {
    a = 2;
  } 

我们将他编译为汇编代码


    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
    } 

我们可以看到在上面,if判断语句被编写为cmp和jne命令

cmp命令会去比较上面两个值的,同时它会将比较结果存在条件码寄存器中,如果比较的结果为True,就会把零标识码设置为1,cmp命令执行完之后,pc寄存器就会开始自增。

jne指令的意思就是jump if not equal的意思,他会去查看零标识码,如果为0的话,就会跳转到后面4a的位置,pc寄存器中存的就会变成4a,之后CPU就会将CPU的指令加载到指令寄存器中执行

这条 mov 指令的第一个操作数 eax,代表累加寄存器,第二个操作数 0x0 则是 16 进制的 0 的表示。这条指令其实没有实际的作用,它的作用是一个占位符。我们回过头去看前面的 if 条件,如果满足的话,在赋值的 mov 指令执行完成之后,有一个 jmp 的无条件跳转指令。跳转的地址就是这一行的地址 51。我们的 main 函数没有设定返回值,而 mov eax, 0x0 其实就是给 main 函数生成了一个默认的为 0 的返回值到累加器里面。if 条件里面的内容执行完成之后也会跳转到这里,和 else 里的内容结束之后的位置是一样的。

在上面我们说过打孔卡的原理,打孔卡会一条一条的读取指令,然后执行,如果检测到跳转的指令,机器将带动纸片移动到跳转的位置

循环


int main()
{
    int a = 0;
    for (int i = 0; i < 3; i++)
    {
        a += i;
    }
}

他的汇编代码如下


    for (int i = 0; i <= 2; i++)
   b:   c7 45 f8 00 00 00 00    mov    DWORD PTR [rbp-0x4],0x0
  12:   eb 0a                   jmp    1e 
    {
        a += i;
  14:   8b 45 f8                mov    eax,DWORD PTR [rbp-0x4]
  17:   01 45 fc                add    DWORD PTR [rbp-0x8],eax

  1a:   83 45 f8 01             add    DWORD PTR [rbp-0x4],0x1
  1e:   83 7d f8 02             cmp    DWORD PTR [rbp-0x4],0x2
  22:   7e f0                   jle    14 
  24:   b8 00 00 00 00          mov    eax,0x0
    }

可以看见循环和上面if else的不同,他的跳转指令在jle之前,通过不断地判断,在判断不正确之前,不断重复前面的操作,直到jle满足,才执行后面的操作

实际上在汇编层面上的语言类似于我们C语言中的goto,直接指定地址去跳转,但是goto是无条件的跳转,而在这里是需要经过判断的

总结

我们发现我们使用三个简单的寄存器就可以完成程序的if else等操作,就是pc寄存器保存下一次的指令,指令寄存器记录当前正在执行的指令,并通过自增操作走向下一个指令,同时使用条件码寄存器进行判断,我们就能进行判断,从而实现循环和判断

以上是关于计算机中的指令跳转的主要内容,如果未能解决你的问题,请参考以下文章

计算机中的指令跳转

我想知道如何计算计算机系统中给定虚拟机命令的跳转指令

汇编指令JMP是啥意思?

汇编指令JMP是啥意思?

lua语言的跳转指令怎么用?

单片机中跳转指令偏移量如何计算?