linux重定位命令,Linux中gcc的详解用法及其可重定位目标文件

1.gcc组成

gcc是一组编译工具的总称,包括:C编译器、C++编译器、源码预处理程序和库文件。

2.gcc编译

1.生成一个程序

7dbb2301e6beee5ab278a51510f937bc.png

gcc hello.c -o hello 把hello.c编译成一个可执行程序

如果gcc hello.c不指定输出名,生成一个a.out文件。

可以通过./hello或者./a.out来运行程序

2.gcc编译步骤(包括预处理preprocessor,编译compiler,汇编assemble,链接linker)

预处理:gcc -E hello.c -o hello.i      完成对代码的预处理

处理源文件中以“#”开头的预编译指令,包括:

– 处理所有条件预编译指令,如“#if”,“#ifdef”, “#endif”等

– 插入头文件到“#include”处,可以递归方式进行处理

– 删除所有的注释“//”和“/* */”

– 添加行号和文件名标识,以便编译时编译器产生调试用的行号信息

– 保留所有#pragma编译指令(编译器需要用)

• 经过预编译处理后,得到的是预处理文件(如,hello.i) ,

它还是一个可读的文本文件 ,但不包含任何宏定义

编译: gcc -S hello.i -o hello.s     gcc –S hello.c –o hello.s 将源代码编译成汇编代码

• 编译过程就是将预处理后得到的预处理文件(如 hello.i)

进行 词法分析、语法分析、语义分析、优化后,生成汇编代码文

• 经过编译后,得到的汇编代码文件(如 hello.s)还是可读的文 本文件,CPU无法理解和执行它

gcc命令实际上是具体程序(如ccp、cc1、as等)的包装命令,

用户通过gcc命令来使用具体的预处理程序ccp、编译程序cc1和汇编程序as等

汇编:gcc -c hello.s -o hello.o ,  gcc -c hello.c -o hello.o ,  as hello.s -o hello.o

(as是一个汇编程序)将汇编代码转换成可重定位目标文件(二进制)

• 汇编程序(汇编器)用来将汇编语言源程序转换为机器指令序列 (机器语言程序)

• 汇编指令和机器指令一一对应,前者是后者的符号表示,它们都 属于机器级指令,

所构成的程序称为机器级代码

• 汇编结果是一个可重定位目标文件(如,hello.o),其中包含 的是

不可读的二进制代码,必须用相应的工具软件来查看其内容

链接:gcc hello.o -o hello

将目标代码和所需要的库链成一个完整的应用程序。

gcc的结果输出是后缀名不相关的,只与输入参数有关

为了构造可执行文件,连接器必须完成两个主要任务:

符号解析(symbol resolution),重定位(relocation)

目标文件有三种形式:

•可重定位目标文件。包含二进制代码和数据,其形式可以在编译时与其他可重定位

目标文件合并起来,创建一个可执行目标文件。

•可执行目标文件。包括二进制代码和数据,其形式可以被直接复制到内存并执行。

•共享目标文件。一种特殊类型的可重定位目标文件,可以在加载或者运行

时被动态的加载进内存并链接。

3.使用多个源码的项目

比如有两个源程序main.c和sum.c

使用gcc编译器并链接生成可执行程序p:gcc -O2 -g -o p main.c sum.c     ./p

-O2:2级优化

-g:生成调试信息

-o:目标文件名

de0e80db99c934068ab0969a0ba65576.png

链接过程的本质(以main.c和swap.c为例)

main.c                          swap.c

int buf[2] = {1, 2};                extern int buf[];

void swap();                       int *bufp0 = &buf[0];

int main()static int *bufp1;

{ swap();void swap() {

return 0; }int temp;bufp1 = &buf[1];temp = *bufp0;*bufp0 = *bufp1;*bufp1 = temp; }

3ae68b18ae057a05c0aa7132bad2966d.png

关于ELF格式文件符号表解析及readelf命令使用

1.读取ELF文件头   readelf -h main.c

da8602fcbd3255b55fa4427a7e1f15a0.png

在 readelf 的输出中:

第 1 行,ELF Header: 指名 ELF 文件头开始。

第 2 行,Magic 魔数,用来指名该文件是一个 ELF 目标文件。第一个字节 7F 是个固定的数;后面的 3 个字节正是 E, L, F 三个字母的 ASCII 形式。

第 3 行,CLASS 表示文件类型,这里是 64位的 ELF 格式。

第 4 行,Data 表示文件中的数据是按照什么格式组织(大端或小端)的,不同处理器平台数据组织格式可能就不同,如x86平台为小端存储格式。

第 5 行,当前 ELF 文件头版本号,这里版本号为 1 。

第 6 行,OS/ABI ,指出操作系统类型,ABI 是 Application Binary Interface 的缩写。

第 7 行,ABI 版本号,当前为 0 。

第 8 行,Type 表示文件类型。ELF 文件有 3 种类型,一种是如上所示的 Relocatable file 可重定位目标文件,一种是可执行文件(Executable),另外一种是共享库(Shared Library) 。

第 9 行,机器平台类型。

第 10 行,当前目标文件的版本号。

第 11 行,程序的虚拟地址入口点。

第 12 行,与 11 行同理,这个目标文件没有 Program Headers。

第 13 行,sections 头开始处,这里 856 是十进制.。

第 14 行,是一个与处理器相关联的标志。

第 15 行,ELF 文件头的字节数。

第 16 行,因为这个不是可执行程序,故此处大小为 0。

第 17 行,同理于第 16 行。

第 18 行,sections header 的大小,这里每个 section 头大小为 64个字节。

第 19 行,一共有多少个 section 头,这里是 13个。

第 20 行,section 头字符串表索引号,从 Section Headers 输出部分可以看到其内容的偏移在 0xa0 处,从此处开始到0xcf 结束保存着各个 sections 的名字,如 .data,.text,.bss等。

2.读取节头表    readelf -S main.o

可重定位目标文件

ELF头

.text

.rodata

.data

.bss

.symtab

.rel.text

.rel.data

.debug

.line

.strtab

节头部表

ELF 头

包括16字节标识信息、文件类型 (.o, exec, .so)、机器类型(如 IA-32)、 节头表的偏移、节头表的表项大小以及 表项个数.text 节编译后的代码部分

.rodata 节只读数据,如 printf 格式串、switch 跳转表等

.data 节已初始化的全局变量

.bss 节未初始化全局变量,仅是占位符,不占 据任何实际磁盘空间。区分初始化和非 初始化是为了空间效率

.symtab 节存放函数和全局变量 (符号表)信息 , 它不包括局部变量

.rel.text 节.text节的重定位信息,用于重新修改代 码段的指令中的地址信息

.rel.data 节.data节的重定位信息,用于对被模块使 用或定义的全局变量进行重定位的信息

.debug 节调试用符号表 (gcc -g)

strtab 节包含symtab和debug节中符号及节名

Section header table(节头表)每个节的节名、偏移和大小

以下以main.o为例子解释

4fb9f0821990ca27b23fe5774b5a626c.png

Key to Flags:

W (write), A (alloc), X (execute), M (merge), S (strings)

I (info), L (link order), G (group), x (unknown)

O (extra OS processing required) o (OS specific), p (processor specific)

可重定位目标文件中,每个可装入节的起始地址总是0

6714b1337ffcdcdb259d7f75f3b59e5f.png

3.符号表机制    readelf -s main.o

cb92ad9978e65c2a0fd77215b18d4ad5.png

可以看出全局变量,静态全局变量,静态局部变量,

全局函数名都会出现在符号表中,而局部变量不会被保存在符号表中。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值