链接学习之obj文件探索
Windows的gcc环境,往官网http://sourceforge.net/project/showfiles.php?group_id=2435 下载MinGW,安装,安装完毕后按照包

配置环境变量
a.在PATH的值中加入"C:\Program Files\MinGWStudio\MinGW\bin"。这是寻找gcc编译器的路径。如果PATH中还有其他内容,需要用英文状态下分号进行分割
b.新建LIBRARY_PATH变量,在其值中加入"C:\Program Files\MinGWStudio\MinGW\lib"。这是标准库存放的路径。
c.新建C_INCLUDE_PATH变量,在其值中加入"C:\Program Files\MinGWStudio\MinGW\include"。这是Include查找头文件的路径。
先是一个及其简单的C程序

Hello.c
预处理
C:\Users\居士\Desktop\Update\Link C>gcc -E hello.c -o hello.i
i文件局部

如上图#后面的数字 210代表行号 stdio.h中能找到对应代码

编译
C:\Users\居士\Desktop\Update\Link C>gcc -S hello.i -o hello.s
编译后的 内容仍然是文本,打开s文件仍然可以看懂其内容

学过汇编的人能看懂里面表达啥,对于我而言只认得pushl,movl,andl等几个指令,以及%ebp,%esp这几个寄存器,还有常数$-16,$0。其余cif_offset这些就需要百度才知道了。总体来说还是看不懂的。
汇编
C:\Users\居士\Desktop\Update\Link C>gcc -c hello.s -o hello.o
汇编得到的是一个二进制的文件,是一个可重定向目标文件,里面包含着机体代码。这里虽然表面上是一个o文件,由于本人使用的是Windows平台,编译出来的还是类似于通过VC编译出来的obj格式的文件,而并非Linux平台下的ELF文件。
在网上找的命令可以通过下面命令看到格式化后的o文件
C:\Users\居士\Desktop\Update\Link C>readelf -a hello.o

但是在windows下生成的实际上是obj文件,用VS的另一个工具可以打开,该工具在以下目录
D:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\dumpbin.exe
命令为dumpbin /all {目标文件文件名} > {输出文件的文件名}
因此之前看书上面说的ELF文件的格式就对不上了,文件的结构需要找别的资料去参考。这里借助了dumpbin以外还使用了CFF Explorer。
obj文件内容分析
在网上看过别人分析的obj文件是用在VC下写的一段很简单的C++代码生成的,和我这个用MinGW的gcc下的C程序有出入。
总的来说无论是obj还是o文件,都是基于COFF(Common Object File Format)文件,它与我们平常写的代码不一样,它是有一个一定格式的文件,链接器(或加载器)则按照这个结构来链接(或执行)这些文件,先罗列一下整个obj文件的结构
File Header 文件头
Optional Header
Section Header Table 节头部表
Section Raw Data 节的原始数据
Relocation Table 重定向表
Symbol Table 符号表
String Table 字符串表
再看通过dumpbin生成的文件
FILE HEADER:文件头

这个文件头在obj文件中占了0~13共14个字节。

这个文件头的大小是固定的,它实际上是winnt.h里面的一个结构体。细心的可以发现结构中一些值是直接以数值的形式存放在文件中,例如machine的值14C,存放为4C 01,符号表的地址指针1B8,存放成B8 01。我想表达的是因为windows是采用了小段法存放数据的机器,高低位间作了互换。Winnt.h文件在C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include目录中(我的是64位系统)。结构体定义如下

各个字段的解析可以参考MSDN上的内容
结构体解析 https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms680313(v=vs.85).aspx
大体就是说了编译时机器的情况,时间,还有与本文件关系大的符号表的位置,符号的数量,optional header的数量。
接下来就是各个节的说明了,先已第一个节作为例子,介绍完这个节的结构后再通过CFF Explorer对比o文件里的内容。再去介绍各个节的作用。

这里包含了节的头部,节的原始数据,还有一个重定向表,节的头部是这样的一个结构

头部的作用是描述整个节的信息,例如SizeOfRawData代表原始数据的数量,PointerToRawData即是原始数据起始的地址。NumberOfRelocations是重定向条目的数量。
节头部数据结构详情可参考MSDN中的以下位置 https://msdn.microsoft.com/en-us/library/windows/desktop/ms680341(v=vs.85).aspx
Raw Data则是节的原始数据,这里其实没啥结构的,不同的节就存放他们对应的数据。
Relocations是重定位信息,实际上它是重定位表的一部分,只属于这个节的一部分。这个重定向的一个条目结构如下,

这个就是在链接时给引用外部的符号重定位时用的
以上仅是该o文件中最全的一个节的结构,当然还有可能会有其他的"节成员",只是当前这个C程序太简单,以致其他成员未出现。但是不是每个节都有原始数据,有些节是空的,有些节就不带重定向信息。
下面逐个看这个o文件里面的每个节。
第一个节是.text节,图不再截了,就之前的那个图,.text节存放的是已编译的机器代码。利用objdump工具可以看到这节的原始数据(也就是机器代码整理后的结果),命令如下

要看懂这些指令的话,还需要懂得处理器的指令集(参考《深入了解计算机系统》的第四章)。
第二节是是data节,按书上的介绍data节是存放已初始化的全局或静态C变量,这个C程序中没有用到全局变量或静态变量,这节就没有内容

第三节是bss节,是存放未初始化的全局或静态C变量,以及被初始化为0的全局或C变量,但是这个姐实际不占用控件

第四个节是rdata节,放的就是只读数据,这里存在了一个宏定义,"hello c!"这样的一个字符串,这部分数据就存放在这一节中

第五个节叫"/4",rdata$zzz估计是别名,不知具体的作用,貌似是存放了编译器的信息,版本之类的

第六个节叫"/15",eh_frame,更加不知道他的作用,貌似是有对.text节的引用,难道是调用main函数外层的东西?

节部分完结了之后就是符号表

符号表的介绍直接引用MSDN的内容
对于以符号号码开头的行,下列说明描述了含有与用户相关的信息的列:
- 开头的 3 位数字是符号索引/号码。
- 如果第三列包含 SECTx,则符号在对象文件的那一节中定义。 但如果出现 UNDEF,则它不在那个对象中定义并且必须在其他地方被解析。
- 第五列 (Static, External) 说明符号是否只在那个对象的内部可见,或者是否是公共的(外部可见)。 静态符号 _sym 不会链接到公共符号 _sym;这些符号是名为 _sym 的函数的两种不同实例。
编号行中的最后一列是符号名(修饰名和未修饰名)
来自 <https://msdn.microsoft.com/zh-cn/library/b842y285.aspx>
每条符号表的记录是一下的结构

有几条记录是多出了一行的,那部分数据是对这个符号的补充说明,结构如下

在符号表之后就是字符串表了,但是在dumpbin生成d文件中只是列举了字符串表的大小

但在其他资料中介绍,字符串表示存放着节名的字符串。听过CFF Explorer中的内容查看,确实定义了4个字符川,就是重复的.rdata$zzz和.eh_frame

dumpbin如何分析得出这个o文件
那又有一个问题来了,编译系统是如何根据这份二进制的o文件来读取到这些信息呢,尝试一下通过CFF Explorer来分析读取到这个文件的信息,人为模拟一下dumpbin的工作。这个过程推导出前面那个obj文件结构这个结论。
首先是读取固定大小的文件头,通过文件头的结构获取到几个与本个o文件有关的信息:
- 有6个节
- 符号表的起始位置是1B8,符号数量是12个
那么就相当于把o文件已经分成了几块
|
文件头 |
未知部分1 |
符号表 |
未知部分2 |
|
0~13 |
14~1B7 |
1B8~?? |
??~329 |
那么节这部分有可能存放在未知部分1中。查看各个节的头部信息,分析出节1到节6是从104~18F。可以查看各个节的原始数据得出


其他节就不一一列举了
另外还有各个节头部信息中提及到的重定位信息,整个文件有中重定位信息只有两个节:节1的重定位是190开始;节6的重定位信息是1AE开始,节1的重定位项有3个,节6的重定位项有1个,粗略推断节1的重定位信息是重190~1AD,节6的重定位信息是1AE~1B7,每条重定位信息的长度大概是10个字节
如

是对应

0A 00估计对应Offset,10 00对应Symbol Index,14 00对应Type,可视Applied To这个就解析不清了,因为节6的重定位信息如下


还有字符串表的信息,字符串的大小是一个4字节用小端法存储的无符号整数,2E应该是2E 00 00 00,纵观整个文件存放了这个信息的就在位置为2FC处,因此估计字符串表是从2FC处到329结尾处了
|
文件头 |
未知部分1 |
节原始数据 |
重定向表 |
符号表 |
字符串表 |
|
0~13 |
14~103 |
104~18F |
190~1B7 |
1B8~2FB |
2FC~329 |
剩余的未知部分1应该就是存放节头部信息的节头部表,从14~103,也是通过数量以及数据的比对,节共有6个,此部分数据共240个,平均每个节头部信息占40个字节,下面就拿了40个字节的信息

可以看到节的名称.text 是2E 74 65 78 74;原始数据的起始地址104,就是04 01 00 00;重定向表190,就是90 01 00 00,其他成员就不列举了。其他头部也不列举了。
最终得到的结构是
|
文件头 |
节头部表 |
姐原始数据 |
重定向表 |
符号表 |
字符串表 |
|
0~13 |
14~103 |
104~18F |
190~1B7 |
1B8~2FB |
2FC~329 |
再细分一下的就是
|
文件头 |
0~13 |
|
节1头部 |
14~3B |
|
节2头部 |
3C~63 |
|
节3头部 |
64~8B |
|
节4头部 |
8C~B3 |
|
节5头部 |
B4~DB |
|
节6头部 |
DC~103 |
|
节1原始数据 |
104~127 |
|
节4原始数据 |
128~133 |
|
节5原始数据 |
134~157 |
|
节6原始数据 |
158~18F |
|
节1重定向表 |
190~1AD |
|
节6重定向表 |
1AE~1B7 |
|
符号表 |
1B8~2FB |
|
字符串表 |
2FC~329 |
链接学习之obj文件探索的更多相关文章
- 目前以lib后缀的库有两种,一种为静态链接库(Static Libary,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(Import Libary,以下简称“导入库”)。静态库是一个或者多个obj文件的打包
前以lib后缀的库有两种,一种为静态链接库(Static Libary,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(Import Libary,以下简称“导入库”) ...
- 动态链接 - dll和so文件区别与构成
动态链接,在可执行文件装载时或运行时,由操作系统的装载程序加载库.大多数操作系统将解析外部引用(比如库)作为加载过程的一部分.在这些系统上,可执行文件包含一个叫做import directory的 ...
- [计算机图形学] OpenGL读取obj文件并显示其3D效果
读取三维网格模型(Wavefront OBJ文件) 无法向立方体:cube.obj 有法向兔子模型:bunny.obj 有法向有纹理八字模型:Eight.obj OBJ文件的格式可参考:http: ...
- obj文件的连接问题以及tlib的基本用法
1.基础研究 用tcc将程序编译为.obj文件. 这里也可以使用tcc -linclude run.c来将run.c文件编译成run.obj文件. 再用tcc对下面的程序进行编译链接,发现提示错误: ...
- 树莓派学习笔记——使用文件IO操作GPIO SysFs方式
0 前言 本文描写叙述假设通过文件IO sysfs方式控制树莓派 GPIO端口.通过sysfs方式控制GPIO,先訪问/sys/class/gpio文件夹,向export文件写入GPIO编号, ...
- 什么是obj文件?
百度百科: 程序编译时生成的中间代码文件.目标文件,一般是程序编译后的二进制文件,再通过链接器(LINK.EXE)和资源文件链接就成可执行文件了.OBJ只给出了程序的相对地址,而可执行文件是绝对地址. ...
- Liunx学习笔记(三) 文件权限
一.文件权限 1.查看文件权限 (1)文件权限 在 Linux 中对于文件有四种访问权限,列举如下: 可读取:r,Readable 可写入:w,Writable 可执行:x,Execute 无权限:- ...
- 关于obj文件的理解
编译器先编译.cpp为obj文件,看看文件内有没有冲突,然后再进行链接,链接头文件引入的lib库等等,然后就生成exe文件了,下面这个图说的很好:
- CSharpGL(9)解析OBJ文件并用CSharpGL渲染
CSharpGL(9)解析OBJ文件并用CSharpGL渲染 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码中包含10多个独立的Demo ...
随机推荐
- Django模板语言的复用
一.include标签 由于在项目中,往往会出现多个页面拥有一个或几个相同的页面版块,或是一个页面多个页面版块是相同的,基于这个问题,我们可以采用模板语言复用include标签来帮我们解决,这样就避免 ...
- Shell脚本笔记(七)控制Shell脚本
控制Shell脚本 一.处理信号 1) SIGHUP本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联. ...
- 面试题fugui
1.什么是栈溢出,在什么情况下可能会出现 栈溢出是由于C语言系列没有内置检查机制来确保复制到缓冲区的数据不得大于缓冲区的大小,因此当数据足够大时,将会溢出缓冲区的范围. python函数调用是通过栈这 ...
- 使用scrapy爬取百度股票
1.spiders文件夹下的爬虫文件 # -*- coding: utf-8 -*- import scrapy import re import random from scrapy.http.re ...
- 学习Struts--Chap06:Struts2之数据验证
1.数据验证的概述 1.1.数据验证的重要性 数据验证是非常必要的,不但和我们的常识性理解有关系,还有可能涉及到一些非法输入等问题,所以我们需要进行必要的数据验证,以保证我们在数据输入的时候都是正确且 ...
- Microsoft.AspNet.Identity: UserID用整型数据表示, 而不是GUID
第一篇: 这个好像不太好 http://stackoverflow.com/questions/19553424/how-to-change-type-of-id-in-microsoft-aspn ...
- python部分面试- 测试维度
2. 软件测试的维度 1. 正确性:功能 正确 2. 健壮性: 意外的输入,不会崩溃 3. 性能: 大压力, 依然能工作 4. 可靠性: 长时间,不会崩溃 5. 易用性: 目标客户,都易用 6. 安全 ...
- CSS魔法堂:一起玩透伪元素和Content属性
前言 继上篇<CSS魔法堂:稍稍深入伪类选择器>记录完伪类后,我自然而然要向伪元素伸出"魔掌"的啦^_^.本文讲讲述伪元素以及功能强大的Contet属性,让我们可以通 ...
- hdu5299 Circles Game
Circles Game Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Tot ...
- 科技论文之Latex公式&符号
近期在写文章.有好多数学公式的命令都忘记了. 今天索性一起整理下. 1 能够在文章的作者上引用的符号 2 一些括号使用方法 3 一些高等数学的公式 4 交,并集 5 一些二项式 6 矩阵写法 7 ...