剖析.o文件ELF组成
ELF文件结构组成
①总共13个节
②每个节都有一个编号。从ELF头开始编号,编号从0开始,编号的作用就是用来索引(找到)不同节的。
③每个.o的都是这样的结构。链接时要做的就是,将ELF格式的.o全部合成为一个完整的ELF格式可执行文件。
④.o中每个节的逻辑地址都是从0开始的
ELF头
ELF格式头放什内容?
放ELF格式所需要的一些基本信息,比如
①系统所规定的字的大小。64 OS:字大小是64bit 32 OS:字大小是32bit
②字节顺序(字节序) 用于说明系统是大端序的还是小端序的。
③其它
1)ELF格式头的大小
2)目标文件类型(可重定位目标文件、可执行目标文件、共享目标文件)
3)CPU架构:X86 或 X86_64、AMD_64
4)等等
使用readelf,查看“可重定位目标文件”的ELF头信息
readelf:读取目标文件的ELF格式信息的,跟-h选项的话,就是查看ELF格式头信息。
- [root@localhost ~]# readelf -h test.o
- ELF Header:
- Magic: 7f 4c
- Class: ELF64
- Data: 's complement, little endian
- Version: (current)
- OS/ABI: UNIX - System V
- ABI Version:
- Type: REL (Relocatable file)
- Machine: Advanced Micro Devices X86-
- Version: 0x1
- Entry point address: 0x0
- Start of program headers: (bytes into file)
- Start of section headers: (bytes into file)
- Flags: 0x0
- Size of this header: (bytes)
- Size of program headers: (bytes)
- Number of program headers:
- Size of section headers: (bytes)
- Number of section headers:
- Section header string table index:
.text
存放所有函数的机器指令,不过某些常量也会直接和指令一起存在.text当中。.text:也是只读节
eg:
- int main(void)
- {
- int a = ;
- a = a + ; //表达式中的100会直接和指令放在一起
- }
.rodata
只读数据节,存放只读数据(放某些常量数据)。
eg:
- int a = ;
- printf("%d", a);
- char *p = "hello world";
格式字符串"%d"和"hello world"这两个字符串常量,都放在了.rodata中。
.data
①初始化了全局变量
- int a = ; //初始化了的全局变量,a就是在.data节中
- int main(void)
- {
- printf("%d\n", a);
- }
②初始化了的静态局部变量
- int main(void)
- {
- static int b = ;//已经初始化了的静态局部变量
- printf("%d", a);
- }
初始化了的静态局部变量的空间就开辟在.data中。
注意:如果没有static的话,b就是自动局部变量,b空间开辟于栈中。但是只有程序运行起来后才有栈这个东西,因此作为还处在编译阶段的.o来说,自动局部变量还不存在,或者说还只是以函数代码的形式存在于.text中。当程序运行起来有了栈之后,该函数的代码会在栈中开辟自动局部变量的空间,并将数据101存入开辟的空间。
.bss
①未初始化的全局变量
- int a; //未初始化了的全局变量
- int main(void)
- {
- printf("%d", a);
- }
②未初始化的静态局部变量
- int main(void)
- {
- static int b;//未初始化的静态局部变量
- printf("%d", a);
- }
由于没有初始化数据,所以其实不占用空间,因此在.o中,.bss只是一个占位符,只有当程序真正运行起来后,才会在内存上真正的开辟.bss的空间,并在.bss空间中开辟a和b的空间,并制自动初始化为0。所以在.o中,.bss只是一个理论上的存在。
.o为什么没有开辟.bss空间?
没有实际要存放的数据,开辟空间只是浪费空间。你要知道.o这个文件是存在我们的电脑硬盘上的,.o如果有.bss空间的话,.bss是要占硬盘空间的。
.symtab:符号表
参考:.symtab
symtab记录什么
每一个.o文件都有一个符号表,用于存放.o中所定义和引用的全局符号信息(函数和全局变量的符号信息)。
- 比如a.c
- int a = ;
- int fun(int a)
- {
- ...
- }
- extern int b; //定义在了b.c中
- int main(void)
- {
- b = ;
- fun2(); //fun2定义在了c.c中
- }
- a.c -> a.o
- b.c -> b.o
- c.c -> c.o
a.o的.symtab符号表就记录如下符号的信息。
①a.o中定义的符号信息
a:a.o自己定义的全局变量符号
fun:a.o自己定义的函数符号
main:a.o自己定义的函数符号
②a.o中引用的符号信息
b:a.o引用的在b.o中定义的全局变量符号
fun2:a.o引用的在c.o中定义的fun2函数符号
注意:.symtab符号表并不记录符号的名字
.symtab记录符号的基本信息,符号是否有定义,符号对应的空间在哪个节中等,但是符号的名字本身并不存在符号表中。
.symtab符号表的意义
众多的.o之所以能被链接在一起,这张符号表所记录的信息功不可没。比如,a.o中引用的b和fun2,被定义在了b.o中,将a.o和b.o链接在一起时,必须查看各个.o中的.symtab表,才能将各自符号的定义和引用关联起来。
注意:符号表并不记录自动局部变量的符号。
- int fun()
- {
- int a = ;
- ...
- }
为什么不记录自动局部变量的符号?
自动局部变量是在程序运行起来有了栈以后才有的,在编译阶段fun函数的int a = 100,在fun函数中只是压栈和弹栈的代码。当程序运行起来有了栈后,当fun函数开始运行时,fun的压栈代码会开辟自动局部变量的空间,fun函数结束时会调用弹栈代码自动释放空间。但是如果是static修饰的静态局部变量的话,符号表中会记录符号,因为在编译阶段就会处理静态局部变量。
.rel.text
将多个.o链接到一起时,每个.o的.text会被整合为一个.text,整合.text时就必须依赖.rel.text所记录的一些有关.text中指令的位置信息。
.rel.data
将多个.o链接到一起时,每个.o的.data会被整合为一个.data,整合到一起时,就必须要依赖.rel.data所记录的一些有关.data的信息。
.debug
符号调试表,记录调试信息,编译时必须加-g选项,编译时才会在.debug节中加入调试信息。
.line
存放代码行号,因为调试的时候往往需要显示源码的行号。只有gcc编译时加了-g选项后,才会加入行号信息。
.strtab
字符串表
.symtab、.debug所用到符号名字、每个节的节名字(比如.text等)、源文件名字(***.c)等,都存在.strtab中
比如:
.text\0.rodata\0......fun\0main\0
节头部表
描述目标文件中的每个节的某些相关信息
剖析.o文件ELF组成的更多相关文章
- 深入剖析PE文件
不赖猴的笔记,转载请注明出处. 深入剖析PE文件 PE文件是Win32的原生文件格式.每一个Win32可执行文件都遵循PE文件格式.对PE文件格式的了解可以加深你对Win32系统的深入理解. 一. ...
- 考古备份:a.out文件ELF文件头中魔数的由来
来源: <程序员的自我修养>3.4节. 补充: http://wiki.osdev.org/ELF http://www.linux-mag.com/id/116/ http://en.w ...
- (转)剖析Linux文件编码的查看及修改
Linux文件编码的查看和修改都有不止一种做法,如果你需要在Linux中操作windows下的文件,那么很可能会经常遇到文件编码转换的问题,如何进行这项工作,也应该是经常工作在双系统下的操作者的必须掌 ...
- 剖析可执行文件ELF组成
对比参考:剖析.o文件ELF组成 相比.o的ELF格式,有哪些变化? .rel.text和.rel.data消失了 为什么这两个节会消失? 链接器将各.o中同名的.text和.data节整合到一起时, ...
- Linux命令——ldd和ldconfig
转自:Linux系统中“动态库”和“静态库”那点事儿 前言 在调试lua脚本的时候,报错. 我已经再lua脚本中更改了cpath package.cpath = package.cpath .. &q ...
- .symtab
参考:剖析.o文件ELF组成 目标文件 .symtab中记录的符号是从.s文件来的,所以.s这个汇编文件很关键. .symtab所记录符号的种类 示例代码 a.c ; static float a_v ...
- 预处理、编译、汇编、链接、启动代码、相关command
被忽略的过程 对于C这种编译性语言,我们平时编译时,不管是通过IDE图形界面,还是通过命令行,总感觉编译一下就完成了,然后就得到了针对某OS和某CPU的二进制可执行文件(机器指令的文件).但是实际上在 ...
- ELF文件
ELF文件格式是一个开发标准,各种UNIX系统的可执行文件都采用ELF格式,它有三种不同的类型: 可重定位的目标文件 可执行文件 共享库 现在分析一下上一篇文章中经过汇编之后生成的目标文件max.o和 ...
- 痞子衡嵌入式:ARM Cortex-M文件那些事(6)- 可执行文件(.out/.elf)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是嵌入式开发里的executable文件(elf). 第四.五节课里,痞子衡已经给大家介绍了2种output文件,本文继续给大家讲proje ...
随机推荐
- CentOS "libc.so.6: version 'GLIBC_2.14' not found"解决方法,同理'GLIBC_2.15' not found"
出现"libc.so.6: version 'GLIBC_2.14' not found"问题,是由于glibc版本过低,升级glibc即可. 由于CentOS系统RPM源目前gl ...
- python通过socket实现多个连接并实现ssh功能详解
python通过socket实现多个连接并实现ssh功能详解 一.前言 上一篇中我们已经知道了客户端通过socket来连接服务端,进行了一次数据传输,那如何实现客户端多次发生数据?而服务端接受多个客户 ...
- LeetCode_292. Nim Game
292. Nim Game Easy You are playing the following Nim Game with your friend: There is a heap of stone ...
- UITableView实现行纵向颜色渐变
实现效果如下: 其实实现很简单,开始觉得使用颜色值和tableView的indexPath.row挂钩使用即可 或者使用CAGradientLayer实现渐变 最后使用alpha实现即可.需要注意的是 ...
- shell每隔一秒钟就记录下netstat状态
说明 木马可能类似随机发送心跳包的操作,随机sleep.对这类情况写好了一个监听shell脚本,每隔一秒钟就记录下netstat状态. 代码 #!/bin/bash #功能:用于定时执行lsof 和 ...
- Vue + ElementUI的电商管理系统实例03 用户列表
1.通过路由展示用户列表页 新建user文件夹,里面新建Users.vue文件: <template> <div> <h3>用户列表组件</h3> &l ...
- SpringBoot部署到Linux上AppserverApplication,访问不到控制层
放在本地是好好的,可以请求到,放到Linux上去的话就直接404, 解决办法: SpringBoot有个加载类叫AppserverApplication.这个大家应该都知道,我们平常都是如下写: @S ...
- 【转帖】2019年中国5G行业细分市场发展现状和市场前景分析 通信基站数量快速增长
2019年中国5G行业细分市场发展现状和市场前景分析 通信基站数量快速增长 中国有 600多万个基站 平均每200个人 一个基站.. 一个基站十万块钱的话 相当于 每个人 需要分摊 500块钱. ht ...
- JDK1.8 的 HashMap 源码之注意事项
文章目录 链表变树 树形结构与Comparable,性能极致与降低 链表与树之间转换的阈值 英语渣靠着翻译插件,大概翻译的,难免有错误之处,注意甄别: 链表变树 This map usually ac ...
- CSS样式三种形式222
markdown CSS基本表现形式只有三种:标签样式.Class类样式.ID样式 标签样式: 必须与HTML标签同名.仅仅影响同名标签 Class样式:可以在任何标签中使用: class=" ...