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

计算机组成原理--计算机指令

程序员文章站 2022-07-06 13:42:50
...

编译到汇编,代码从如何变成机器码

看下面的C代码示例:

#include <stdio.h>
int main()
{
   int a = 1; 
   int b = 2;

   a = a + b;
   
return 0 ;
}

通过编译和汇编后生成机器码

[aaa@qq.com ~]# gcc -g -c test.c 
[aaa@qq.com ~]# ls
anaconda-ks.cfg  test.c  test.o
[aaa@qq.com ~]# objdump -d -M intel -S test.o
test.o:     文件格式 elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
#include <stdio.h>
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
   
return 0 ;
  18:	b8 00 00 00 00       	mov    eax,0x0
}
  1d:	5d                   	pop    rbp
  1e:	c3                   	ret    

详细的转换关系如下图所示:

计算机组成原理--计算机指令
在inter 处理器中大概支持2000多种机器指令集,常见的指令可以分为下面的五类:
计算机组成原理--计算机指令

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条件的指令如下:


    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
    } 

cmp 指令比较了前后两个操作数的值,这里的 DWORD PTR 代表操作的数据类型是 32 位的整数,而 [rbp-0x4] 则是一个寄存器的地址。所以,第一个操作数就是从寄存器里拿到的变量 r 的值。第二个操作数 0x0 就是我们设定的常量 0 的 16 进制表示。cmp 指令的比较结果,会存入到条件码寄存器当中去。
跟着的 jne 指令,是 jump if not equal 的意思,它会查看对应的零标志位。如果为 0,会跳转到后面跟着的操作数 4a 的位置。这个 4a,对应这里汇编代码的行号,也就是上面设置的 else 条件里的第一条指令。当跳转发生的时候,PC 寄存器就不再是自增变成下一条指令的地址,而是被直接设置成这里的 4a 这个地址。这个时候,CPU 再把 4a 地址里的指令加载到指令寄存器中来执行。跳转到执行地址为 4a 的指令,实际是一条 mov 指令,第一个操作数和前面的 cmp 指令一样,是另一个 32 位整型的寄存器地址,以及对应的 2 的 16 进制值 0x2。mov 指令把 2 设置到对应的寄存器里去,相当于一个赋值操作。然后,PC 寄存器里的值继续自增,执行下一条 mov 指令。这条 mov 指令的第一个操作数 eax,代表累加寄存器,第二个操作数 0x0 则是 16 进制的 0 的表示。这条指令其实没有实际的作用,它的作用是一个占位符。我们回过头去看前面的 if 条件,如果满足的话,在赋值的 mov 指令执行完成之后,有一个 jmp 的无条件跳转指令。跳转的地址就是这一行的地址 51。我们的 main 函数没有设定返回值,而 mov eax, 0x0 其实就是给 main 函数生成了一个默认的为 0 的返回值到累加器里面。if 条件里面的内容执行完成之后也会跳转到这里,和 else 里的内容结束之后的位置是一样的。计算机组成原理--计算机指令

for 循环指令

int main()
{
   0:	55                   	push   rbp
   1:	48 89 e5             	mov    rbp,rsp
	int a = 0;
   4:	c7 45 fc 00 00 00 00 	mov    DWORD PTR [rbp-0x4],0x0
	int i;
       for( i = 0; i < 5; i ++)
   b:	c7 45 f8 00 00 00 00 	mov    DWORD PTR [rbp-0x8],0x0
  12:	eb 0a                	jmp    1e <main+0x1e>
       {
          a += i;
  14:	8b 45 f8             	mov    eax,DWORD PTR [rbp-0x8]
  17:	01 45 fc             	add    DWORD PTR [rbp-0x4],eax
       for( i = 0; i < 5; i ++)
  1a:	83 45 f8 01          	add    DWORD PTR [rbp-0x8],0x1
  1e:	83 7d f8 04          	cmp    DWORD PTR [rbp-0x8],0x4
  22:	7e f0                	jle    14 <main+0x14>
       }
return 0;
  24:	b8 00 00 00 00       	mov    eax,0x0
}
  29:	5d                   	pop    rbp
  2a:	c3                   	ret    

JLE ;有符号小于等于则跳转
JMP;无条件跳转
JNE;不等于侧跳转

switch 指令

int main()
{
   0:	55                   	push   rbp
   1:	48 89 e5             	mov    rbp,rsp
   4:	48 83 ec 10          	sub    rsp,0x10
 char a = getchar();
   8:	e8 00 00 00 00       	call   d <main+0xd>
   d:	88 45 ff             	mov    BYTE PTR [rbp-0x1],al
int b = 0;
  10:	c7 45 f8 00 00 00 00 	mov    DWORD PTR [rbp-0x8],0x0
switch(a)
  17:	0f be 45 ff          	movsx  eax,BYTE PTR [rbp-0x1]
  1b:	83 f8 02             	cmp    eax,0x2
  1e:	74 13                	je     33 <main+0x33>
  20:	83 f8 03             	cmp    eax,0x3
  23:	74 17                	je     3c <main+0x3c>
  25:	83 f8 01             	cmp    eax,0x1
  28:	75 1a                	jne    44 <main+0x44>
{
case 1:
  b = 2;   
  2a:	c7 45 f8 02 00 00 00 	mov    DWORD PTR [rbp-0x8],0x2
break;
  31:	eb 11                	jmp    44 <main+0x44>
case 2:
  b = 9;   
  33:	c7 45 f8 09 00 00 00 	mov    DWORD PTR [rbp-0x8],0x9
break;
  3a:	eb 08                	jmp    44 <main+0x44>
case 3:
  b = 5;   
  3c:	c7 45 f8 05 00 00 00 	mov    DWORD PTR [rbp-0x8],0x5
break;
  43:	90                   	nop

}
return 0;
  44:	b8 00 00 00 00       	mov    eax,0x0

}
  49:	c9                   	leave  
  4a:	c3                   	ret 

if 条件多个的判断

    if (r== 0)
  4c:	83 7d fc 00          	cmp    DWORD PTR [rbp-0x4],0x0
  50:	75 09                	jne    5b <main+0x5b>
    {
	a = 1;
  52:	c7 45 f8 01 00 00 00 	mov    DWORD PTR [rbp-0x8],0x1
  59:	eb 16                	jmp    71 <main+0x71>
    }else if(r==1){
  5b:	83 7d fc 01          	cmp    DWORD PTR [rbp-0x4],0x1
  5f:	75 09                	jne    6a <main+0x6a>
        a = 2;
  61:	c7 45 f8 02 00 00 00 	mov    DWORD PTR [rbp-0x8],0x2
  68:	eb 07                	jmp    71 <main+0x71>
    }else{
       a = 3;
  6a:	c7 45 f8 03 00 00 00 	mov    DWORD PTR [rbp-0x8],0x3
}
}

从上面的汇编语言来看,判断条件大于2个话,使用switch性能更好,还有case分支中越容易发生的放在前面。

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