读书-程序员的自我修养-链接、封装与库(10: 第四章:静态链接(3)--C++问题,ABI,静态库libc.a,printf .o,hello.c 整个编译链接过程

1. C++相关问题

1.1 C++的两个问题

C++的一些语言特性使得必须由编译器和链接器共同支持才能完成工作。
最主要的有两个方面。

  1. 一个是c++的重复代码消除。
    例如模版,外部内联函数,虚函数表。
  2. 一个是全局构造与析构。

1.2 c++ 与 ABI

ABI: Application Binary Interface 应用二进制接口

在讨论是不是两个编译器编译的目标文件能形成一个可执行文件问题时。
他们需要满足:采用统一的目标文件格式,拥有同样的符号修饰标准、变量的内存分布方式相同、函数的调用方式相同等等。

1.2.1 ABI 定义

其中,我们把(编译器)符号修饰标准、变量内存布局,函数调用方式等这些跟可执行代码二进制兼容性相关的内容成为ABI。

1.2.2 ABI 和 API 的区别

ABI 是指二进制层面的接口
API 是指源代码级别的接口,如printf ,如POSIX 是一个API标准。

2. 静态库链接

2.1 语言库概念

一种语言的开发环境往往会附带有语言库(Language Library)。
语言库又称为库函数。这些库是对操作系统API的包装。
例如:printf 内部调用的是 write
又如 strlen 就没有调用系统函数

2.2 ar -t libc.a //查看静态库 libc.a 包含哪些文件

root@ubuntu-admin-a1:/usr/lib# ar -t /usr/lib/x86_64-linux-gnu/libc.a
init-first.o
libc-start.o
sysdep.o
version.o
check_fds.o
libc-tls.o
elf-init.o
……

2.2.1 objdump -t libc.a grep -w printf //查找 printf 在 libc.a 库的哪个目标文件

libc.a 库里面包含了 1400多个目标文件。

root@ubuntu-admin-a1:/home/4Chapter# objdump -t /usr/lib/x86_64-linux-gnu/libc.a | grep -w printf
……
printf.o:     file format elf64-x86-64
0000000000000000 g     F .text	000000000000009e printf
……
root@ubuntu-admin-a1:/home/4Chapter# 

其实,printf.o 也依赖其他的目标文件,stdout 和 vfprintf
linux 系统库很复杂,多层级调用。

2.2.2 why 一个目标文件只包含一个函数?

  1. 减少空间浪费
  2. 详细解释
    由于运行库有成百上千个函数,数量非常庞大,每个函数独立地放在一个目标文件中可以尽量减少空间的浪费,哪些没有被利用到的目标文件/函数就不要链接到最终的输出文件中。

2.3 hello.c 整个编译链接过程

上图

2.3.2 gcc -static --verbose hello.c //查看 hello.c 整个编译链接过程

root@ubuntu-admin-a1:/home# gcc -static --verbose hello.c
Using built-in specs.
COLLECT_GCC=gcc
……
/usr/lib/gcc/x86_64-linux-gnu/5/cc1 -quiet -v -imultiarch x86_64-linux-gnu hello.c 
-quiet -dumpbase hello.c -mtune=generic -march=x86-64 -auxbase hello 
-version -fstack-protector-strong -Wformat -Wformat-security 
-o /tmp/ccudI8qs.s
……
as -v --64 -o /tmp/ccsbu0Fy.o /tmp/ccudI8qs.s
……
/usr/lib/gcc/x86_64-linux-gnu/5/collect2 
-plugin /usr/lib/gcc/x86_64-linux-gnu/5/liblto_plugin.so 
……
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o 
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o 
……
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crtn.o
root@ubuntu-admin-a1:/home# 

上面只留下关键步骤:

  1. 调用 cc1 程序,这个就是 gcc 的c语言编译器
    它将hello.c编译成一个临时的汇编文件 ccudI8qs.s
  2. 调用 as 程序, 这个是 GNU 的汇编器
    它将 ccudI8qs.s 汇编成临时目标文件 ccsbu0Fy.o,这个其实就是前面的 hello.o.
  3. 调用 collect2 程序来完成链接。
    这个 collect2 可以看做是 ld 链接器的一个包装
    其中,可以看到 有 crt1.o crti.o crtn.o 等等目标文件被链接到最终的可执行文件。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值