一台IBM的Plugboard程序员
一、咱们拿一小段真实的 C 语言程序来看看。sass
[root@luoahong c]# cat test.c int main() { int a = 1; int b = 2; a = a + b; }
二、要让这段程序在一个 Linux 操做系统上跑起来,咱们须要把整个程序翻译成一个汇编语言bash
[root@luoahong c]# gcc -g -c test.c [root@luoahong c]# objdump -d -M intel -S test.o
三、在一个 Linux 操做系统上,咱们能够简单地使用 gcc 和 objdump 这样两条命令,把对应的汇编代码和机器码都打印出来。函数
[root@luoahong c]# objdump -d -M intel -S test.o test.o: file format 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
咱们实际在用 GCC(GUC 编译器套装,GUI CompilerCollectipon)编译器的时候,能够直接把代码编译成机器码呀,操作系统
为何还须要汇编代码呢?缘由很简单,你看着那一串数字表示的机器码,是否是摸不着头脑?可是即便你没有学过汇编代码,翻译
看的时候多少也能“猜”出一些这些代码的含义。由于汇编代码其实就是“给程序员看的机器码”,也正由于这样,机器码和汇编代码是一一对应的。3d
从高级语言到汇编代码,再到机器码,就是一个平常开发程序,最终变成了 CPU 能够执行的计算机指令的过程。orm
你可能一会儿记不住,或者对这些指令的含义还不能一会儿掌握,这里我画了一个表格,给你举例子说明一下,帮你理解、记忆。blog
为了读起来方便,咱们通常把对应的二进制数,用 16 进制表示出来。在这里,也就是0X02324020。这个数字也就是这条指令对应的机器码。递归
回到开头咱们说的打孔带。若是咱们用打孔表明 1,没有打孔表明 0,用 4 行 8 列表明一条指令来打一个穿孔纸带,那么这条命令大概就长这样:
到这里,想必你也应该明白了,咱们在这一讲的开头介绍的打孔卡,其实就是一种存储程序型计算机。
只是这整个程序的机器码,不是经过计算机编译出来的,而是由程序员,用人脑“编译”成一张张卡片的。对应的程序,也不是存储在设备里,而是存储成一张打好孔的卡片。
可是整个程序运行的逻辑和其余 CPU 的机器语言没有什么分别,也是处理一串“0”和“1”组成的机器码而已
这一讲里,咱们看到了一个 C 语言程序,是怎么被编译成为汇编语言,乃至经过汇编器再翻译成机器码的。
除了 C 这样的编译型的语言以外,不论是 Python 这样的解释型语言,仍是 Java 这样使用虚拟机的语言,其实最终都是由不一样形式的程序,把咱们写好的代码,转换成 CPU 可以理解的机器码来执行的。
只是解释型语言,是经过解释器在程序运行的时候逐句翻译,而 Java 这样使用虚拟机的语言,则是由虚拟机对编译出来的中间代码进行解释,或者即时编译成为机器码来最终执行。
然而,单单理解一条指令是怎么变成机器码的确定是不够的。接下来的几节,我会深刻讲解,包含条件、循环、函数、递归这些语句的完整程序,是怎么在 CPU里执行的