(十七)编译过程(2): 汇编过程

本专栏总结王利涛《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

猜你喜欢

转载自blog.csdn.net/weixin_38956024/article/details/107659867