之前的文章 《编译系统-自底向上研究方法》ELF符号段,《编译系统-自底向上研究方法》链接器分析, 已经讲解了 可运行文件格式 ELF 以及 链接器的一些主要的作用。
无论是 操作系统运行 可执行文件,还是 链接器 把多个 .o
目标文件合并在一起,他们操作的都是二进制的数据。
而 本文要讲的汇编器,操作的是 ASII 码,也就是文本字符串。实际上,处理 二进制数据,比文本数据 方便得多,读二进制数据,只需要一个结构体不断解析就行了,二进制数据是非常规范化的数据。
而解析文本字符串,需要用到的技术复杂一点。
先给一个 main.c
的文件源码,如下:
int sum(int *a,int n);
int array[3] = {7,5,1};
int main() {
int val = sum(array,3);
return val;
}
对应的汇编指令如下:
.file "main.c"
.text
.globl array
.data
.align 8
.type array, @object
.size array, 12
array:
.long 7
.long 5
.long 1
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $3, %esi
leaq array(%rip), %rdi
call sum@PLT
movl %eax, -4(%rbp)
movl $8, %eax
movl -4(%rbp), %eax
movl %ebx, %eax
movl %eax, -4(%rbp)
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0"
.section .note.GNU-stack,"",@progbits
C程序代码不用管,咱们主要看 汇编代码。先看这两条 汇编代码,movl $3, %esi
,movl -4(%rbp), %eax
,这两条指令都是从上面的代码摘下来的。我们看一下这两条汇编最后生成的机器码是怎样的,还是用的 objdump
命令。
如上图所示,8b
跟 be
这两个机器码都是 mov
指令。实际上,汇编指令跟机器码是 一对多的关系,根据参数的不同,指令机器码会有所不同。我再多加几条不同参数的 mov
指令,方便对照。
一条 mov
指令 有 3个 符号(token),mov
指令机器码,源数据,目的地。源数据有 3 种类型:
1,立即数,例如 $8 ,第一条指令是把 8 直接放进去 eax
寄存器。AT&T 的汇编语法,立即数前面要加 $ 。
2,内存地址,-0x4(%rbp)
就是内存地址,把这个地址的4个字节内容 复制给 eax
寄存器。
3,寄存器,源数据 是寄存器,例如把 ebx
寄存器的内存 复制 给 eax
寄存器。
根据 源数据 类型的不同,mov
对应的机器码也是不一样的,上图可以看出,分别是 b8 ,8b,89,这3个都对应着 mov
指令。
所以 汇编器 as 在对 汇编指令 做词法分析的时候,只要拆出来 3 个符号 mov
指令机器码,源数据,目的地。判断源数据是哪一种,就能生成对应的机器码。这里的 ASII 码转成 二进制指令,实际上只是一个找对应的过程。由于 汇编器不会做 逻辑优化 ,所以他的编译过程实际上非常简单。逻辑优化已经被上面的 编译器给做了。
汇编器 as 除了根据 一对多 规则,把ASII 码指令 转成 二进制指令之外,还有一个比较重要的事情,汇编器也做了。
就是生成 ELF 文件格式,头部,段表啊,这些东西。汇编器会根据不同的平台生成不同的文件格式,例如 Windows 平台的是 PE 格式。
这里讲一个扩展的知识点,ASII码汇编指令 跟 二进制指令 跨平台都是很低的,但是他们的跨平台又有点区别,二进制指令实际上是 CPU 指令,只要 CPU 架构一样就能运行。但是 汇编指令 有很多种风格,例如 AT&T 跟 intel 风格。
举个例子,一个 intel I7 的机器装了个 windows10 系统,编译 main.c
生成的是 intel
风格的汇编指令。一个 intel I7 的机器装了个 ubuntu18系统,编译 main.c
生成的是 AT&T
风格的汇编指令,这两种汇编指令语法有点差异,互不通用的,但是他们编译出来的二进制机器码是一样的。因为大家都是 I7 的CPU。
下篇文章会用 clion
来搭建环境,调试 as 汇编器的内部逻辑。
由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。如果读者有任何宝贵意见,可以加我微信 Loken1,QQ:2338195090。