后台核心技术开发与应用实践读书笔记(四)
第4章 编译
4.1 编译与链接
过程:预处理->编译->汇编->链接
- 预处理:主要处理那些源代码文件只能够的以”#”开始的预编译指令。比如“#include”、“#define”,过滤所有注释,添加行号,保留#pragma编译器指令等,最后生成一个.i文件
- 编译:编译器扫描(词法分析)、语法分析、语义分析、源代码优化、代码生成和目标代码优化 。生成.s文件
- 汇编:经过汇编器汇编得到可重定位目标程序.o文件
- 链接:把每个源代码独立的编译,然后按照要求进行“组装”,这个过程就是链接。原理就是把一些指令对其他符号地址的引用加以修正。链接过程主要包括了地址和空间分配、符号决议和重定位等
-
静态链接
对函数库的链接是放在编译时期完成的是静态链接所有相关的目标文件与牵涉到的函数库被链接合成 个可执行文件 程序在运行时,与函数库再无瓜葛,因为所有需要的函数已复制到相关位置 这些函数库被称为静态库,通常文件名为“ libxxx.a ”的形式。
-
动态链接
除了静态链接,也可以把对 些库函数的链接载入推迟到程序运行时期( runtime ),这
就是动态链接库( dynamic link library )技术 动态库文件名命名规范和静态库文件名命名规
范类似,也是在动态库名增加前缀 lib ,但其文件扩展名为 .so 例如:将创建的动态库名为
mymath 后,则动态库文件名就是 libmymath.so。动态库的搜索路径顺序:
- 编译目标代码时指定的动态库搜索路径;
- 环境变量 LD_LIBRARY_PATH 指定的动态库搜索路径;
- 配置文件/etc/ld so.conf 中指定的动态库搜索路径;即只需在在该文件中追加一行库所在的完整路径如 11/root/test/conf/lib ”即可,然后 ldconfig 是修改生效;
- 默认的动态库搜索路径 lib ;
- 默认的动态库搜索路径/usr/lib
-
动态库与静态库重名问题
动态库文件与静态库文件同名的时候,,编译器会先到 path 目录下搜索 libxxx.so 文件,如果没有找到,则继续搜索 libxxx.a (静态库)
-
静态链接库与动态链接库各自的特点
-
动态库有利于进程资源的共享
程序运行时调用某个动态链接库函数,操作系统会首先查看正在运行的程序,看内存中是否已经有了此函数的拷贝,如果有就共享,没有则链接载入,虽然会带来时间开销,但是减少了空间开销。而静态库每个程序都得将它拷贝到自己的代码中
-
可以将一些程序升级变得简单。
静态库如果库发生改变,使用库的程序要重新编译。动态库只要接口没变,只需要将新生成的动态库替换原来的即可
-
可以做到链接载入完全由程序员在代码中控制
有需求才调入的原则
-
因为动态库函数必须在运行的时候才被装载,所以执行过程,用静态库速度更快
-
-
g++与gcc的区别
- 两者都可以编译c代码与c++代码
- .c文件,gcc当做c程序,g++当做C++程序。.cpp两者都当做是c++程序
- 编译阶段g++会调用gcc
- 编译可以用 gcc/g++,而链接可以用 ++或者 gee-lstde++。gcc不能自动和c++程序使用库链接
- externa“C”与两者并无关系
4.2 makefile 的编写
-
书写规则,第一部分为依赖关系,第二部分为生成目标的方法:
target : prerequisites <tab>command <tab>command
target也就是一个目标文件,可以是.o文件,也可以是执行文件,还可以是一个标签(Label)。
prerequisites就是,要生成那个target所需要的文件或是目标。command也就是make需要执行的命令(任意的Shell命令)。这里要注意的是在命令前面要加上一个tab键,不是空格,是按一个tab键按出来的空格。
-
make clean
用于清除编译产生的二进制文件,保留源文件:clean: @echo "cleaning project" -rm main *.o @echo "clean completed"
在rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事
-
变量,用
$(objects)
的方式来使用 -
$@
扩展成当前规则的目的文件名;$<
扩展成依靠列表中的第一个依靠文件;$^
扩展成整个依靠列表(除掉重复文件名)
4.3 目标文件(ELF)
ELF是一种二进制文件、可执行文件、目标代码、共享库和核心转储的标准文件格式
- ELF文件类型
-
可重定位的目标文件
汇编生成的.o文件。连接器将器做为目标文件的输入,链接处理后生成一个可执行的目标文件或者一个可被共享的对象文件(.so文件)。
-
可被执行的目标文件(.exe)
除了.exe,还有一种是可执行的脚本(如shell脚本)文件。
-
可被共享的目标文件
就是动态库文件,.so文件。如果拿前面的静态库来生成可执行程序中都会有一份库代码的拷贝。如果磁盘中存储这些可执行程序,就会占用额外的磁盘空间。
-
ELF内容
- ELF文件主要由文件头(ELF header)、代码段(.text)、数据段(.data)、.bss段、只读数据段(.rodata)、段表(section table)、符号表(.symtab)、字符串表(.strtab)、重定位表
-
代码段与数据段分开的原因:
1.权限分别管理。对进程来说,数据段是可读写的,指令段是只读的。这样可以防止程序指令被改写。
2.指令区与数据区的分离有助于提高程序的局部性,有助于对CPU缓存命中率的提高。
3.当系统运行多个改程序的副本的时候,他们对应的指令都是一样的,此时内存只需要保留一份改程序的指令即可。当然,每个副本进程的数据区域是不一样的,他们是进程私有的 -
与ELF有关的工具
- 阅读 ELF 文件的工具一readelf
- 获得二进制文件里符号的工具一nm
- 减少目标文件大小的工具一一strip
具体使用见原书