真正了不起的程序员对自己的程序的每一个字节都了如指掌!

前面对于目标文件只是做了概念上的阐述,如果不彻底深入目标文件的具体细节,这样的分析就是泛泛而谈没有意义,也没有深入的理解。就象知道TCP/IP协议是基于包的结构,但是从来没有看到过包的结构是什么样的(说得好像就是我),包的头部有哪些内容?目标地址和源地址是怎样存放的?如果不能细致且深入的去了解,就会步入一个误区:很多问题其实在表面上看似很简单,实际深入内部会发现很多鲜为人知的秘密,或者发现以前自己认为理所当然的东西居然是错误的!!!我需要做的,就是改变这个现状!

1.挖掘SimpleSection.o中的信息

<span style="font-size:18px;">/**SimpleSection.c**linux:*  gcc  -c  SimpleSection.c**Windows:*  cl SimpleSection.c /c /Za*/
int printf(const char* format, ...);
int global_init_var = 84;
int global_uninit_var;void func1(int i)
{printf("%d\n",i);
}
int main(void)
{static int static_var = 85;static int static_var2;int a = 1;int b;func1(static_var + static_var2 + a + b);return a;
}</span>
利用GCC对源文件进行编译可以得到目标文件:
<span style="font-size:18px;">$ gcc -c SimpleSection.c</span>

查看目标文件中的内容如下:

从上面的结果中,我们能够看到:SimpleSection.o中的段的数量比我们想象中的要多,除了最基本的代码段、数据段和BSS段以外,还有3个段分别是只读数据段(.rodata)、注释信息段(.comment)、堆栈提示段(.note.GNU-stack)。先不考虑这三个额外的段。想了解一下关于段的几个重要的属性,首先最容易理解的就是段的长度(Size)和段所在的位置(File Offset),每个段中的第二行 “CONTENTS”/"ALLOC"等表示的就是段的各种属性。“CONTENTS”表示该段在文件中是存在的。我们能够发现在BSS段中是没有“CONTENTS”的,这表示它实际上在EFL文件中根本不存在内容。所以,在EFL文件中实际存在的也就是“.text”、".data"、“.comment”、“.rodata”这4个段了。对于本项目,他们在ELF中的结构如下图所示:

代码段
将所有段的内容以十六进制的形式打印,并对所有包含指令的段进行反汇编,得到以下结果:
“Contents of Section  .text”就是.text的数据以十六进制方式打印出来的内容,总共0x5b字节,跟前面我们了解到的".text"段中的长度相一致。最左面一列指的是偏移量,中间四列指的是十六进制内容,最后一列是该段的ASCII码形式。
对照下面反汇编的结果,我们可以很明显的看到,.text段里所包含的正是SimpleSection.c里面两个函数func1()和main()函数的指令。
数据段与只读数据段
.data段保存的是那些已经初始化了的全局静态变量或局部静态变量。前面的SimpleSection.c代码中一共有两个这样变量,分别是global_init_var和static_var。这两个变量每一个都是4个字节,总共八个字节,所以“.data”这个段的大小为8个字节。
“.rodata”中只存放只读数据。本例中存放的就是字符串常量,刚好是4个字节。单独设立“.rodata”段有很多好处,不管是在语义上支持了C++的const关键字,而且操作系统自加载时可以将“.rodata”段的属性映射为只读,这样对于这个段的任何修改操作都会作为非法操作处理,大大保证了程序的安全性。
BSS段
.bss段存放的是未初始化的全局变量和局部静态变量。如示例代码中,global_uninit_var和static_var就是被存放在.bss段,其实更准确的说法是,.bss段为他们预留了空间。
其他段
除了.data、.text、.bss这3个最常用的段之外,ELF文件也有可能包含其他的段,用来保存与程序相关的其他信息。具体如下表所示:
这些段的名字都是由"."作为前缀,表示这些表的名字是系统保留的,应用程序也可以使用一些非系统保留的名字作为段名。如我们可以在ELF文件结构中插入一个“music”段,里面存放一首MP3,当ELF文件结构运行起来以后可以读取这个段并播放该首歌。但是,应用程序自定义的段名不能使用"."作为前缀,否则容易与系统保留段名冲突。

2.ELF文件结构描述

其实,通过上面的SimpleSection.o实例,我们已经基本了解到了ELF文件的轮廓,下面我们可以正式地看一下ELF的文件总体结构。如下图所示:
ELF目标文件格式的最前部是ELF文件头(File Header),它包含了描述整个文件的基本属性,比如ELF文件版本、目标机器型号、程序入口地址等。紧接着是ELF文件各个段。其中,ELF文件中与段有关的重要结构就是段表(Section Header Table),该表描述了ELF文件中语段有关的所有段的信息,比如每个段的段名、段的长度、在文件中的偏移、读写权限以及其他属性。本处,仅想详细讨论一下符号表的作用,以为他和程序的链接有着很大的关联。
连接的接口——符号
链接过程的本质就是要把多个不同的目标文件之间相互关联到一起。为了使不同目标文件之间能够在相互粘合,这些目标文件之间必须有固定的规则才可以。在链接中,目标文件之间相互拼接实际上是目标文件地址间的相互引用,即对函数以及变量的地址进行引用。比如目标文件B要用到目标文件A中的函数“foo”,那么我们就成目标文件A定义了函数“foo”,称目标文件B引用了目标文件A中的函数“foo”。在链接中,我们将函数以及变量都通称为符号,函数名或者变量名就是符号名。
我们可以将符号看作是链接中的黏合剂,整个连接过程正是基于符号才能正常地完成。链接过程中很重要的一环就是符号的管理,每一个目标文件都会有一个相应的符号表,这个表里面记载着目标文件中所有要用的到的符号,每一个定义的符号有一个对应的值,叫做符号值。对于变量以及函数而言,符号值就是他们的地址。除了函数和变量之外,也会存在其他几种不常用的符号,如下面所示:

3.调试信息

目标文件里面还有可能包含调试信息。几乎所有现代的编译器都支持源代码级的调试(比如我们可以在函数里面设置断点、可以监视变量变化、可以单步执行等),前提是编译器必须提前将源代码与目标代码之间的关系(比如目标代码中的地址对应源代码中哪一行?函数和变量的类型?结构体的定义?字符串保存到那个文件里面?)。设置有些高级的编译器或调试器支持查看STL容器中的相关内容。

目标文件里面到底有什么(2)?相关推荐

  1. 目标文件里面到底有什么(1)?

    目标文件是指:编译器编译源代码后生成的文件,那么目标文件里面到底存放的是什么呢?或者说我们的源代码在经过编译以后是怎么样存储的呢? 目标文件从结构上将,它是已经编译后的可执行文件格式,只是好没有经过链 ...

  2. 《程序员的自我修养-链接-装载与库》第三章 目标文件里有什么(1)

    目录 0.引言 1.目标文件的格式 1.1 目标文件的格式及ELF文件格式的文件的分类 1.2 目标文件与可执行文件格式的小历史 2.目标文件是什么样的 2.1 程序与目标文件简介 2.2 BSS历史 ...

  3. Lichee(三) Android4.0该产品的目标文件夹,Lichee链接---extract-bsp

    由<Lichee() 在sun4i_crane平台下的编译>介绍了编译lichee的基本情况,我们终于得到了编译后的结果例如以下: out/ ├── android │   ├── bIm ...

  4. 如何修复GIT错误:目标文件为空?

    本文翻译自:how to fix GIT error: object file is empty? When I try to commit changes, I get this error: 当我 ...

  5. build文件_把编译时间加入到目标文件

    出处:https://www.cnblogs.com/pingwen/p/8183728.html 1.问题背景:如何保证发布出去的bin文件是最终测试通过的版本? 一般的来讲,代码到了测试后期,ma ...

  6. 把编译时间加入到目标文件

    原文:https://www.cnblogs.com/pingwen/p/8183728.html 1.问题背景:如何保证发布出去的bin文件是最终测试通过的版本? 一般的来讲,代码到了测试后期,ma ...

  7. linux下几种目标文件的分析

    本文中用到的命令: gcc -c addvec.c  生成可重定位目标文件addvec.o readelf addvec.o -a 读取可重定位目标文件addvec.o gcc -O2 -c main ...

  8. 如何分析linux下的几种目标文件

    为什么80%的码农都做不了架构师?>>>    作者:snsn1984 本文中用到的命令: gcc -c addvec.c 生成可重定位目标文件addvec.o readelf ad ...

  9. 浅显易懂 Makefile 入门 (03)— 目标文件搜索(VPATH 和 vpath 的区别和使用)、隐含规则

    1. 目标文件搜索(VPATH和vpath) 如果需要的文件是存在于不同的路径下(即源文件与 Makefile 文件不在同一个路径下),在编译的时候就用到了 Makefile 中为我们提供的目录搜索文 ...

最新文章

  1. 不去参加团建k歌,第二天被降薪降职
  2. 朴素贝叶斯分类器的应用-转载加我的理解注释
  3. [导入]Ajax使用初步
  4. 计算机辅助管理与制造,计算机辅助设计与制造,对产品的设备进行管理,完成产品加工制造...
  5. 2020年4月中国编程语言排行榜程序员工资统计,人工智能工资大跌
  6. Nginx源码阅读 ---- 模块的初始化
  7. 离线安装docker镜像
  8. iOS 客户端对于运营商劫持的一点点对抗方式
  9. 软件著作权算法软件设计说明书_软件著作权设计说明书模板.docx
  10. 压电式雨量传感器RS485数据解析协议
  11. 中专高一第一学期计算机应用期中基础考题,职业中专第一学期计算机应用基础WIN7和Word2010版期末考试题...
  12. 计算机常用的四种加密方法,电脑常见的几种加密方法
  13. 互联网正在化有形为无形,这是一场深刻而又彻底的嬗变
  14. 2023年全国最新会计专业技术资格精选真题及答案3
  15. 蓝桥 Python 大于等于n的最小完全平方数
  16. zend studio自动换行
  17. mode在python中的意思_无法理解.mode()在python中的用法
  18. break能跳出几层
  19. K-means均值聚类算法寻找质心,Python
  20. mysql 管理数据库和管理表笔记

热门文章

  1. Cisco路由器密码恢复方法
  2. hdu 5358(尺取法)
  3. 贪心算法之——会场安排(nyoj14)
  4. 给创新工场求职者的一封信
  5. 经典背包问题 01背包+完全背包+多重背包
  6. 不写画面的网页程序设计,Web API、Web Service、WCF Service
  7. anyproxy学习4-Linux(Centos)搭建anyproxy环境
  8. 华为交换机配置Telnet
  9. weblogic patch log显示
  10. ubuntu16.04 nginx安装