【自我修养】编译、链接底层做了些什么

知识的学习在于点滴记录,坚持不懈;知识的学习要有深度和广度,不能只流于表面,坐井观天;知识要善于总结,不仅能够理解,更知道如何表达!

编译

我们以hello.c举例子

#include<stdio.h>
//这是一些注释
int main(){
  printf("Hello World\n");
  return 0;
}

预编译(预处理)

gcc -E hello.c -o hello.i

这一阶段,主要处理哪些带"#"的,也会删除注释

  • #include的头文件,直接进行展开
  • #define删除,展开宏定义(直接替换,这阶段没有编译器介入,不做类型安全检查)
  • 处理条件预编译指令#if、#ifdef、#elif、#else、#endif
  • 添加行号和文件名标识,便于编译器编译过程打印错误或警告的行号
  • 保留#pragma,编译器需要

编译

gcc -S hello.i -o hello.s

编译过程总的讲就是做词法分析、语法分析、语义分析、及优化后生成相应的汇编代码文件。

//example
array[index] = (index + 4) * (2 + 6)

汇编

gcc -c hello.s -o hello.o

汇编器输出的是.o目标文件

汇编器将 编译器编译后生成的 汇编代码 翻译成机器可以执行的指令,也仅仅是根据汇编指令和机器指令的对应表一一翻译。

链接

编译器做了些什么

词法分析(扫描)

这一个阶段很好理解,就是将源代码的字符序列分割成一系列记号Token,比如上面程序在词法分析后生成了16个记号,下面部分列出

记号类型
array标识符
[左方括号
]右方括号
index标识符

在识别记号的同时,扫描器还做了其他事,比如将标识符放到符号表,数字、字符串常量存放到文字表等,以备后续使用

语法分析

这一步将产生语法树

在这里插入图片描述

记号被存放在一个树的数据结构上

语义分析

这一阶段只对表达式的语法层面进行分析,但他不了解语句是否有意义,比如两个指针做乘法运算,这被判定为合法的;

编译器只是分析静态语义,(动态语义是在运行期才能确定的语义);

静态语义包括:声明和类型的匹配、类型转换。

在这里插入图片描述

语法树变成这样,可以看到每个表达式(包括符号数字)都被标识了类型。

中间语言生成

这里存在一个优化的操作,比如2+6会被直接优化成8,但这一步直接在树上操作是有难度的,因此优化器会将整个语法树转换成中间代码

汇编代码生成

将中间代码翻译成汇编代码,然后对汇编代码做一些优化

链接器

我们把每个源代码的模块独立编译,然后按照需要组装起来,组装过程就是链接

链接器做的一些工作就是去定位符号,比如一个函数,他在编辑器中可以写在上面、也可以写在下面,一个变量可以定义在当前变量引用,也可以定义在别的变量引用,这些定位的操作就是链接器的作用,被称为重定位

静态链接和动态链接

大家可以看看这篇博客的讲解
静态链接、动态链接
静态链接优缺点

  • 优点快

  • 缺点:浪费空间,如果多个目标程序对同一目标文件都有依赖,那么目标文件会在内存存在多个副本

  • 缺点:更新困难,库函数如果有函数或者代码修改,我们就需要重新编译链接形成新的可执行文件

动态链接优缺点

  • 缺点:慢,链接过程推迟到了程序每次运行时期,每次运行都需要链接
  • 优点:多个程序共享同一份目标文件的副本,避免空间浪费
  • 优点:更新容易,程序下一次运行,新版本的目标文件就会被加载到内存链接起来,完成更新;

如果这篇文章有帮助到你希望留下一个赞,文中如果有不对的地方也欢迎大佬指出!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值