[嵌入式03] Linux使用gcc编译以及ELF文件介绍

文章目录

  • 一、gcc常用命令
    • 1、代码编写
    • 2、编译过程
      • 2.1 预处理
      • 2.2 编译
      • 2.3 汇编
    • 3、多个程序文件的编译
    • 4、检错
    • 5、库文件连接
      • 5.1 编译成可执行文件
      • 5.2 链接
      • 5.3 强制性使用静态链接库
  • 二、分析ELF文件
    • 1、ELF文件的段
    • 2、反汇编ELF
  • 三、GCC的战友们

一、gcc常用命令

1、代码编写

创建并编写test.c

#include
int main(void)
{
	printf("Hello World!\n");
	return 0;
}

2、编译过程

过程 代码
预处理 gcc -E test.c -o test.i 或gcc -E test.c
编译为汇编代码 gcc -S test.i -o test.s
汇编 gcc -c test.s -o test.o
连接 gcc test.o -o test

2.1 预处理

gcc -E test.c -o test.i 或gcc -E test.c

输出test.i文件中存放着test.c经预处理之后的代码,后面的指令直接在命令行窗口输出预处理后的代码。
gcc的-E选项,可以让编译器在预处理后停止,并输出预处理结果。

本例中,预处理结果将stdio.h文件的内容插入到test.c中。

2.2 编译

gcc -S test.i -o test.s

预处理之后,可直接对生成的 test.i 文件编译,生成汇编代码。

编译过程就是对预处理完的文件进行一系列的词法分析,语法分析,语义分析及优化后生成相应的汇编代码。

gcc 的-S 选项,表示在程序编译期间,在生成汇编代码后,停止,-o 输出汇编代码文件。

2.3 汇编

gcc -c test.s -o test.o
对于上一步生成的汇编代码文件 test.s,gas汇编器负责将其编译为目标文件。

汇编过程调用对汇编代码进行处理,生成处理器能识别的指令,保存在后缀为.o的目标文件中。由于每一个汇编语句几乎都对应一条处理器指令,因此,汇编相对于编译过程比较简单,通过调用 Binutils 中的汇编器 as 根据汇编指令和处理器指令的对照表一一翻译即可。

当程序由多个源代码文件构成时,每个文件都要先完成汇编工作,生成.o 目标文件后,才能进入下一步的链接工作。
注意:目标文件已经是最终程序的某一部分了,但是在链接之前还不能执行。
2.4 连接

gcc test.o -o test

gcc 连接器是 gas 提供的,负责将程序的目标文件与所需的所有附加的目标文件连接起来,最终生成可执行文件。
附加的目标文件包括静态连接库和动态连接库。

在命令行窗口执行 ./test
[嵌入式03] Linux使用gcc编译以及ELF文件介绍_第1张图片

3、多个程序文件的编译

通常整个程序是由多个源文件组成的,相应地也就形成了多个编译单元,使用 GCC 能够很好地管理这些编译单元。
假设有一个由 test1.c 和 test2.c 两个源文件组成的程序,为了对它们进行编译,并最终生成可执行程序 test,可以使用下面这条命令:

gcc test1.c test2.c -o test

如果同时处理的文件不止一个,GCC 仍然会按照预处理、编译和链接的过程依次进行。上面这条命令大致相当于依次执行如下三条命令:

gcc -c test1.c -o test1.o
gcc -c test2.c -o test2.o
gcc test1.o test2.o -o test

4、检错

gcc -pedantic test.c -o test1

gcc -pedantic test.c -o test1

gcc -Wall test.c -o test2

-Wall:帮助发现一些不符合ANSI/ISO C标准的代码,当出现不符合的代码,gcc会发出尽可能多的警告信息

gcc -Werror test.c -o test3

-Werror:gcc会在所有产生警告的地方停止编译,迫使进行代码的修改

5、库文件连接

库文件:动态链接库(.so),静态链接库(.a)
函数库:头文件(.h),库文件(.so)

注意:头文件一般放在/usr/include目录下,库文件一般放在/usr/lib目录下

5.1 编译成可执行文件

首先我们要进行编译 test.c 为目标文件,这个时候需要执行

gcc –c –I /usr/dev/mysql/include test.c –o test.o

gcc -c -I /usr/include 源文件 -o 生成.o文件

5.2 链接

我们把所有目标文件链接成可执行文件:

gcc –L /usr/dev/mysql/lib –lmysqlclient test.o –o test

gcc -L /usr/lib 动态链接库文件名 生成.o文件 -o 生成可执行文件

5.3 强制性使用静态链接库

默认情况下, GCC 在链接时优先使用动态链接库,只有当动态链接库不存在时才考虑使用静态链接库,如果需要的话可以在编译时加上-static 选项,强制使用静态链接库。

gcc –L /usr/dev/mysql/lib –static –lmysqlclient test.o –o test

gcc -L /usr/lib -static 静态链接库文件名 生成.o文件 -o 生成可执行文件

静态库链接时搜索路径顺序:

  1. ld 会去找 GCC 命令中的参数-L
  2. 再找 gcc 的环境变量 LIBRARY_PATH
  3. 再找内定目录 /lib /usr/lib /usr/local/lib 这是当初 compile gcc 时写在程序内的

动态链接时、执行时搜索路径顺序:

  1. 编译目标代码时指定的动态库搜索路径
  2. 环境变量 LD_LIBRARY_PATH 指定的动态库搜索路径
  3. 配置文件/etc/ld.so.conf 中指定的动态库搜索路径
  4. 默认的动态库搜索路径/lib
  5. 默认的动态库搜索路径/usr/lib

二、分析ELF文件

ELF是一种文件格式,用于存储Linux程序。

ELF文件分三种类型:
1、目标文件(通常是.o)
2、可执行文件(我们的运行文件)
3、动态库(.so)

1、ELF文件的段

一个典型的 ELF 文件包含下面几个段:
.text:已编译程序的指令代码段。
.rodata:ro 代表 read only,即只读数据(譬如常数 const)。
.data:已初始化的 C 程序全局变量和静态局部变量。
.bss:未初始化的 C 程序全局变量和静态局部变量。
.debug:调试符号表,调试器用此段的信息帮助调试。

查看ELF

readerlf -S test
[嵌入式03] Linux使用gcc编译以及ELF文件介绍_第2张图片

2、反汇编ELF

由于 ELF 文件无法被当做普通文本文件打开,如果希望直接查看一个 ELF 文件包含的指令和数据,需要使用反汇编的方法。
使用 objdump -D对其进行反汇编如下:
[嵌入式03] Linux使用gcc编译以及ELF文件介绍_第3张图片
使用objdump -S将其反汇编并且将其C语言源代码混合显示出来。
[嵌入式03] Linux使用gcc编译以及ELF文件介绍_第4张图片

三、GCC的战友们

一组二进制程序处理工具,包括:addr2line、ar、objcopy、objdump、as、ld、ldd、readelf、 size 等。这一组工具是开发和调试不可缺少的工具 ,分别简介如下:

工具 用途
addr2line 用来将程序 地址转 换成其所对应的程序源文件及所对应的代码行,也可以得到所对应的函数。该工具将帮助调试器在调试的过程中定位对应的源代码位置
as 主要用于汇编
ld 主要用于链接
ar 主要用于创建静态库
ldd 可以用于查看一个可执行程序依赖的共享库
objcopy 将一种对象文件翻译成另一种格式,譬如将.bin 转换成.elf、或者将.elf 转换成.bin 等
objdump 主要的作用是反汇编
readelf 显示有关 ELF 文件的信息
size 列出可执行文件每个部分的尺寸和总尺寸,代码段、数据段、总大小等

你可能感兴趣的:(linux,c#)