本专栏总结王利涛《C语言嵌入式Linux高级编程》第三期课程
一、汇编过程
1)基本流程
- 词法分析
- 语法分析
- 代码生成
- 赋值信息
2)主要工作
- 指令翻译(二进制)
- 生成各种表信息
二、指令生成
1)基本过程
- 参考ISA指令集,将汇编代码翻译为对应的二进制指令代码。
- 编译器以文件为单位进行,可是源文件里函数的地址是以0地址偏移,当代码端链接之后,它们的相对地址就发生变化了。在后面的链接过程中,最重要的是修改代码段合并之后的地址,因为合并之后它们的基地址发生改变。在链接之前,首先要生成各种表信息。
三、生成各种表信息
1)生成表信息
- 符号表、重定位表(需要改变地址的,存放在此表);
- 这些表是可重定位目标文件必需的section;
- 为后面的链接过程提供信息。
2)符号表
- 分析汇编语言各个section的信息;
- 将各个符号在section内的偏移地址填充到符号表;
如sub.o文件,它定义了add、sub、mul、div函数
$readelf -s sub.o 查看它的符号表
....
0000000 ... add ; 在单个源文件里,它是以0地址作为基地址,然后偏移
000000d ... sub
0000018 ... mul
0000024 ... div
3)符号表
- 未找到符号定义的情况:
①不报错,可能在其它文件或库中定义,链接之后才知道;
②相关值使用需要填充;
③这些符号需要后续填充,使用一个重定位表记录。
$readelf -r main.o 查看重定位表
....
0000000 ... add ;未定义,不知道类型,也不知道地址,但不报错,等链接时候,在其它文件还找不到定义,就会出错。(这些符号被重定位表记录)
0000000 ... sub
0000000 ... mul
0000000 ... div
四、编译总结
各代码在符号表中的位置
main.c
#include <stdio.h>
(2)int add(int a, int b);
(2)int sub(int a, int b);
(4)int global_val = 10;
(5)int unint_global_val;
(6)int main(void)
{
(1)int a, b;
(4)static int static_local_val = 20;
(5)static int unint_static_val;
(1)a = add(2, 3);
(1)b = sub(5,4);
(3)printf ("a=%d\n",a);
(3)printf ("b=%d\n", b);
return0;
}
-------------------------------------------------------
-------------------------------------------------------
main.o
ELF headler
program hander table
.init
(1).text
(2).rel text (重定位段)
(3).rodata
(4).data
.rel data
(5).bss
(6).systab
.strtab
setcion header table