汇编语言浅谈
[toc]
有时候我还是会好奇,c++
编译器是用c
编写的,python
也是用c
编写的(我说的是Cpython
!)那么,c
语言的编译器是用什么编写的呢?
然后东查西查,就有了这篇文章。
1.汇编语言是用什么写的呢?(禁止套娃
由上图可看出,汇编语言$Assembly$ $Language$ $(asm)$下面一层就是机器语言$Machine$ $Language$,所以,汇编语言是二进制指令的文本形式,比如00000011
用汇编就是add
,CPU在编译汇编语言时就只需将其转换为机器码便可以使用,这一步,叫做$assembling$.
2.汇编语言是怎么来的呢?
最早的时候,程序员是靠在纸带上打孔来输入指令(图灵机既视感),但是考虑到二进制的不可读性,工程师将指令改为了八进制,但是还是不方便,就改成了汇编.
3.寄存器
1.寄存器的定义
CPU除了一级缓存,二级缓存($cache$)之外,还有寄存器($register$),用来存放那些读写最频繁的数据(如循环变量)。
2.寄存器的种类
早期x86 CPU只有八个寄存器,名字分别是EAX,EBX,ECX,EDX,EDI,ESI,EBP,ESP
,虽然现在寄存器数量增加到100多个,但是名字没有变化。
我们常见的32位,64位CPU,就是寄存器的大小。
4.内存模型
只靠寄存器是不够放下你打游戏时占用几个G的内存的,大多数时候,CPU要让寄存器直接跟内存交换数据.
当一个程序开始运行时,OS会给它分配一段内存,用来存储运行产生的数据。
用户主动请求而划分出的内存叫做Heap,不会自动消失,必须手动释放。
程序自己运行占用的区域叫做Stack,随着该帧运行结束而消失,所以Stack空了之后程序就结束了.
5.高级语言的汇编
这里举一个例子
test1.cpp
|
|
保存并运行以下指令
|
|
g++会在当前目录下生成一个test1.s
文件,包含了汇编语言(我这里是x86_64的,和x86生成的可能不一样),简化后就是
|
|
从main
开始
Step 1movl $10, %edx
,将10移入到寄存器%edx
中。
Step 2movl $1, %ecx
,将1移入寄存器%ecx
中。
Step 3call minus
,调用函数minus
第一步,将%ecx
中的数移入16(%rbp)
中,%edx
中的数移入24(%rbp)
中。
第二步,将24(%rbp)
中的数移出到%eax
中
第三步,将%eax
中的数取负
第四步,将%eax
放入%edx
中。
第五步,将16(%rbp)
中的数放回%ecx
中。(好麻烦有没有
第六步,调用add
第1-4步,将%ecx
,%edx
中的数放到%edx
,%eax
中。
第五步,调用addl
,%edx=%edx+%eax
.
下一步,popq %rbp
释放%rbq
最后一步,返回上级函数
第七步,将返回的值加入返回%rsp
中
第八步,释放零时变量
第九步,返回
Step 4addq $32, %rsp
将返回的值加入%rsp
中,
Step 5popq %rbp
,
Step6 返回.