机器代码就是处理器能够直接执行的字节层面上的程序,但是对于人类来说基本上是不可读的,所以把字节按照具体含义进行『翻译』,就成了人类可读的汇编代码。注意这里的用词是『翻译』而不是『编译』,可以认为汇编代码就是机器代码的可读形式。
机器代码和 C 代码应用两套完全不同的逻辑,机器代码是纯粹从『执行』的方式来进行思考的,而 C 的话则因为较多的抽象有了『程序设计』这个概念。相信读完这一节之后,你就会意识到为什么 C 语言的出现,可以称得上计算机学科的『第二次工业革命』。
一门新语言绝非只是一套语法规则,而是一系列配套的工具加上语法规则。C 语言代码(比如有两个 c 语言文件da.c & wang.c
)最终成为机器可执行的程序,会像流水线上的产品一样接受各项处理:
- C 语言代码(da.c, wang.c)经过编译器的处理(
gcc -0g -S
)成为汇编代码(da.s, wang.s) - 汇编代码(da.s, wang.s)经过汇编器的处理(
gcc
或as
)成为对象程序(da.o, wang.o) - 对象程序(da.o, wang.o)以及所需静态库(lib.a)经过链接器的处理(
gcc
或ld
)最终成为计算机可执行的程序
我们直接来看一段代码及其经过编译生成的汇编代码,可能会有些难以理解,这是正常的,因为还没有介绍处理器具体执行指令的机制。这里我们先有一个感性的认识即可。
// 代码文件: sum.c
long plus(long x, long y);
void sumstore(long x, long y, long *dest)
{
long t = plus(x, y);
*dest = t;
}
对应的汇编代码
sumstore:
pushq %rbx
movq %rbx, %rbx
call plus
movq %rax, (%rbx)
popq %rbx
ret
比较一下我们就发现,C 语言代码被处理成了有统一格式的汇编代码,在汇编代码中,第一个字符串叫做操作符,后面可能跟着 1/2/3 个以逗号分隔的操作数,为什么是以这样的形式呢?这就要从处理器的运算方式讲起了,先来看看处理器是如何配合内存进行计算的:
![215dbcd35cd90f271dd4b7d10cd98953.png](https://i-blog.csdnimg.cn/blog_migrate/1fe0bc0371db5544794b020db79597a3.jpeg)
- 程序计数器(PC, Program counter) - 存着下一条指令的地址,在 x86-64 中称为 RIP
- 寄存器(Register) - 用来存储数据以便操作
- 条件代码(Codition codes) - 通常保存最近的算术或逻辑操作的信息,用来做条件跳转
还记得计算机是如何工作的吗
- 从 5 号架上取菜谱(根据PC取指令)// 这一步用到了 PC
- 看菜谱(指令译码) // 这一步计算机理解了机器码(汇编)并知道要做