gcc编译器背后的故事

0、知识储备

  • GCC:是编译工具(编辑器),能将C语言编写的程序转换为处理器能处理的二进制代码。
  • Binutils:二进制程序处理工具,包括:ar、as、size、ldd等。
    (1)as:主用于汇编。
    (2)ld:主用于链接。
    (3)ar:主用于创建静态库:
  • 若将多个.o目标文件生成一个库文件,则需要静态库和动态库(共享库)。
  • windows系统下:静态库是.lib为后缀的文件,动态库是.dll为后缀的文件; linux系统下:静态库是.a为后缀的文件,动态库是.so为后缀的文件。
  • 静态库和动态库区别在于代码被载入的时间不同:静态库的代码在编译过程中已被载入可执行程序,所以体积较大。动态库的代码在可执行程序运行时被载入内存,简单引用,体积较小。
  • linux系统下,可用ldd命令查看可执行程序的共享库。
  • 多个程序同时运行时 ,且包含动态库,则动态库更节省内存。
    (4)ldd:可查看可执行程序的动态库。
    (5)size:列出可执行文件每个部分的尺寸和总尺寸,代码段、数据段和总大小等。
    (6)objdump:反汇编。
    (7)readelf:显示有关ELF文件的信息。

1、准备工作

编写如下代码:

#include<stdio.h>
int main(void)
{
printf("Hello World!\n");
return 0;
}

在这里插入图片描述

2、编程过程

2.1 预处理

使用gcc进行预处理命令如下:

$ gcc -E hello.c -o hello.i
//将源文件hello.c文件预处理生成hello.i文件
//gcc 的选项-E使gcc在进行完预处理后即停止

在这里插入图片描述
部分hello.i代码片段如下:
在这里插入图片描述

2.2 编译

使用gcc编译命令如下:

$ gcc -S hello.i -o hello.s
//将预处理生成的hello.i文件编译生成hello.s文件
//gcc的选项-s使gcc在执行完编译后停止,生成汇编程序

在这里插入图片描述
hello.s代码片段如下:
在这里插入图片描述

2.3 汇编

使用gcc汇编命令如下:

$ gcc -c hello.s -o hello.o
//将编译生成的hello.s文件汇编生成目标文件hello.o
//gcc的选项-c使gcc在执行完汇编后停止,生成目标文件

//或直接调用as进行汇编
$ as -c hello.s -o hello.o
//使用as将hello.s文件汇编生成目标文件

注意:hello.o目标文件为ELF格式的可重定向文件。

2.4 链接

1、链接也分为动态链接和静态链接:
(1)静态链接:程序在编译阶段直接把静态库加入到可执行文件中去,这样的可执行文件会比较大。
(2)动态链接:程序执行时再从系统中将相应的动态库加入到内存中去。

  • Linux系统中,gcc编译链接时动态库搜索路径的顺序通常为:
    1)从gcc命令参数-L指定路径寻找;
    2)再从环境变量LIBRARY_PATH指定的路径寻址;
    3)再从默认路径/lib、/usr/lib、/usr/local/lib寻找。

  • Linux系统中,执行二进制文件时的动态库搜索路径的顺序通常为:
    1)先搜索编译目标代码时指定的动态库搜索路径;
    2)再从环境变量LD_LIBRARY_PATH指定的路径寻址;
    3)再从配置文件/etc/ld.so,sonf中指定的动态库搜索路径;
    4)再从默认路径/lib、/usr/lib寻找。

  • 再Linux系统下,可用ldd命令查看一个可执行程序依赖的动态库。

注意:链接动态库和静态库有可能重合,所以,当有同名的静态库和动态库文件时,gcc链接默认优先选择动态库,若要让链接选择静态库则需指定-static,强制性使用静态库链接。

2、若命令“gcc hello.c -o hello动态库进行链接,生成ELF可执行文件的大小(用size命令查看)和链接的动态库(用ldd命令查看),示例如下:

$ gcc hello.c -o hello
$ size hello
$ ldd hello

在这里插入图片描述
3、若使用命令“gcc -static hello.c -o hello”则会使用静态库进行链接,生成ELF可执行文件的大小(用size命令查看)和链接的动态库(用ldd命令查看),示例如下:

$ gcc -static hello.c -o hello
$ size hello//可见text的代码尺寸极大
$ ldd hello//说明没有动态链接库

在这里插入图片描述

注:链接器链接后生成的最终文件为ELF格式可执行文件,其通常被链接为不同的段,常见的有:.text、.rodata、.data和.bss等段。

3、分析ELF文件

3.1 ELF文件的段

一个典型的ELF文件包含下面几个段:

  • .text:已编译程序的指令代码段。
  • .rodata:ro表示read only,即只读数据。
  • .data:已初始化的C程序全局变量和静态局部变量。
  • .bss:未初始化的C程序全局变量和静态局部变量。
  • .debug:调试符号表,调试器用此段的信息帮助调试。

在这里插入图片描述
可以使用readelf -S查看其各个section的信息如下:

$ readelf -S hello

部分代码如下:
在这里插入图片描述

3.2 反汇编ELF

因为ELF无法当作普通文件打开,若希望直接查看一个ELF文件包含的指令和数据,则需要用反汇编方法。

使用objdump -D对其进行反汇编,如下所示:

$ objdump -D hello

部分代码如下:
在这里插入图片描述
使用objdump -S将其反汇编并且将其C语言源代码混合显示出来:

$ gcc -o hello -g hello.c//要加上-g选项
$ objdump -S hello

部分代码如下:
在这里插入图片描述

4、总结

gcc是一个十分强大的编译工具,他的编译工具集能巧妙地将C语言编写的程序转换为处理器能处理的二进制代码。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值