.symtab
参考:剖析.o文件ELF组成
.symtab中记录的符号是从.s文件来的,所以.s这个汇编文件很关键。
.symtab所记录符号的种类
示例代码
a.c
extern int a_va1 = ;
static float a_va2 = 200.0; static void a_fun2(void)
{
a_va2 += ;
} extern int a_fun1(int a)
{
b_va1 = b_va1+;
b_fun1();
a_fun2();
}
b.c
int b_va1 = ; int b_fun2(void)
{
...
} int main(void)
{
fun1();
a_va1 = a_va1 + ; }
extern:表示定义的函数和全局变量可以被其它模块引用,如果不写extern,默认就是extern,为了不麻烦,一般都不会明确的写extern。
static:表示定义的函数和全局变量,只能被本模块有效。
.symtab中所记录的符号,严格说起来就两种:
①全局符号
某模块定义以后,除了自己外,其它所有模块也可以引用
我们以a.o模块为例来讲。
1)由a.o模块定义,可由其它模块引用的全局符号
a_fun1:a.o定义,其它模块(b.o)可以引用
a_va1:a.o定义,其它模块(b.o)可以引用
2)由a.o模块引用,但是由其它模块定义的全局符号
b_fun1:a.o引用,但是由b.o定义
b_va1:a.o引用,但是由b.o定义
每个条目所包含的符号基本信息有哪些呢?
②本地符号
模块自己定义,而且只能由自己引用的符号
a.o的a_fun2和a_va2,由于加了static修饰,表示符号只在模块内有效,所以a_fun2和a_va2属于典型的由本模块定义、而且只能由本模块引用的本地符号。
旁注:有关static
在写c代码时,对于那些只在本模块定义和引用的函数与全局变量来说,我们要养成使用static的好习惯,这样子符号就是只在本模块有效的本地符号。如果不写static的话,会带来命名冲突、错误调用等等一些列可能的不良后果,特别是对于大型c工程文件来说,出现这类不良后果的概率非常高。
C++向下兼容C,自然也是支持static的。除此之外C++ namespace中有一种匿名namespace,其行为和static很像,参考:C++——namespace
.symtab是如何记录符号信息的
.symtab符号表包含很多条目,每个条目记录的就是一个符号的基本信息。
每个条目所包含的符号基本信息有哪些呢?
int name;
int value;
int size;
char type;
char bind;
char section;
信息含义:
1)name
name中记录的并不是名字的字符串,我们前面说过所有的字符串都是放在了.strtab中。name里面只记录字符串在.strtab中的偏移,通过这个偏移就能在.strtab中索引到符号的名字。
比如
name = 5 //偏移5
假如.strtab中的内容为main\0fun2\0a_va\0......
使用偏移5到.strtab中进行搜索,当遇到\0时就截止,那么取出来的就是符号fun2。
2)value
放的是地址:指向符号所代表的空间。
比如:
(a)如果符号是初始化了的全局变量
int a = ;//全局变量
int main(void)
{ }
初始化了的全局变量,它的空间在.data节中,那么value中放的就是这个空间的起始地址。通过value中的地址值,就可以找到符号对应的空间,这对于后续的“链接”操作来说很重要。
(b)如果符号是函数的话
int fun()
{ }
fun函数指令存放在了.text节中,value中放的就是fun函数在.text节中的起始地址,其实就是函数第一条指令的地址。
(c)需要强调的地方
不过对于.o(可重定位目标文件)和可执行目标文件来说,value的值有所不同。
可重定位目标文件
value总中放的只是相对于节起始地址的偏移。
可执行目标文件
value中放的是绝对地址。“可重定位目标文件”被连接在一起后,value中放的就是链接时重定位后的绝对地址。
3)size
size代表的是value所指向空间的大小,毕竟value只是起始地址,不能说明空间的大小。
比如:
(a)如果符号是初始化了的全局变量的话
size代表的全局变量在.data中所占字节数。
(b)如果符号是函数的话
size代表的是函数指令在.text中所占空间的大小
4)type
符号类型,有如下几种类型。
(a)FUNC:符号代表的是函数
(b)OBJECT:符号代表的是全局变量
(c)FILE:符号是源文件的名字
5)bind
就两种情况,LCOAL、GLOBAL
(a)bind=LOCAL
表示符号是本地的:符号在模块中定义后,只能由本模块引用,static修饰的全局变量和函数就是这种情况。
(b)bind=CLOBAL(全局符号)
表示符号在本模块定义,但是可以被其它模块引用(使用),extern修饰的全局变量和函数就是这种情况。
6)section
section的值有四种情况,节索引号、ABS、UNDEF、COM
①section=节索引号
说明符号所对应的空间在哪个节里面。
如果section == 1
符号代表的空间在.text节,说明符号代表的是函数,因为只有函数指令才会保存在.text中。
如果section == 3
符号代表的空间在.data中,说明符号是初始化了的全局变量,因为只有初始化了的全局变量才会在.data节。
②section=ABS
表示该符号不需要被“链接程序”处理。
比如,如果符号名是***.c,这个符号不是全局变量、不是函数,只是一个源文件名而已,链接器(ld/collect2)在链接“可重定位目标文件”时,这个符号不需要被处理。
③section=UNDEF
表示这个符号,只是在本模块中被引用了,这个符号并不是由本模块定义的,在本某块找不到定义,所以这个符号的section就被标注为了UNDEF,表示这个符号被定义在了其它模块中,链接时要到其它模块中去找搜寻它的定义。
其它模块:
· 其它自己写的.c所对应的.o
· 静态库
· 动态库
如果是链接时,在其它目标文件中还找不到该符号的定义的话,链接程序就会报错,提示找不到这个符号。出错的原因有两种:
你忘了链接所需的目标文件
比如gcc a.o b.o,结果写成gcc a.o,少了一个,肯定会找不到。
符号名压根就写错了,不可能找得到
④section=COM
表示还未被分配空间(位置)的未初始化的数据目标,比如未初始化的全局变量。
int a;
int main(void)
{
...
}
未被初始化的全局变量都放在.bss中的,但是前面就说过,由于没有数据,所以.bss没有实际空间,只有当程序运行时才有实际.bss节的空间。
查看目标文件的.symtab符号表信息
readelf -h:查看ELF头中的信息
readelf -s:查看.symtab符号表
.symtab的更多相关文章
- [zhuan]动态链接库中的.symtab和.dynsym
http://blog.csdn.net/beyond702/article/details/50979340 原文如下: shared library (.so) "Program Lib ...
- 【腾讯Bugly干货分享】Android Linker 与 SO 加壳技术
本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57e3a3bc42eb88da6d4be143 作者:王赛 1. 前言 Andr ...
- iOS系统分析(二)Mach-O二进制文件解析
➠更多技术干货请戳:听云博客 0x01 Mach-O格式简单介绍 Mach-O文件格式是 OS X 与 iOS 系统上的可执行文件格式,类似于windows的 PE 文件 与 Linux(其他 Un ...
- C++开始前篇,深入编译链接(补充1)
针对这些问题,这次做一个补充: 一,可重定位文件的格式是什么,以main.o为例, 格式为ELF ,包括:{1,ELF Header 它描述了整个文件的文件属性,包括文件是否可以执行,是静态链接还是动 ...
- ELF文件
ELF文件格式是一个开发标准,各种UNIX系统的可执行文件都采用ELF格式,它有三种不同的类型: 可重定位的目标文件 可执行文件 共享库 现在分析一下上一篇文章中经过汇编之后生成的目标文件max.o和 ...
- Linux模块
一.为什么要使用模块 由于linux使用的是整体结构,不是模块化的结构,整体结构实现的操作系统可扩展性差.linux为了扩展系统,使用了模块的技术,模块能够从系统中动态装入和卸载,这样使得linux也 ...
- 20145233 2016-2017 1 linux题目总结
20145233 2016-2017 1 linux题目总结 第一周考试知识汇总 判断:实验楼环境中所有的默认系统用户名和密码均为 shiyanlou.(x ). 填空:Linux Bash中,Ctr ...
- linux下实现在程序运行时的函数替换(热补丁)
声明:以下的代码成果,是参考了网上的injso技术,在本文的最后会给出地址,同时非常感谢injso技术原作者的分享. 但是injso文章中的代码存在一些问题,所以后面出现的代码是经过作者修改和检测的. ...
- linux实践之ELF文件分析
linux实践之ELF文件分析 下面开始elf文件的分析. 我们首先编写一个简单的C代码. 编译链接生成可执行文件. 首先,查看scn15elf.o文件的详细信息. 以16进制形式查看scn15elf ...
随机推荐
- Python - Django - 母版和继承
可以把多个页面相同的部分提取出来,放在一个母板里,这些页面只需要继承这个母板就好了 通常会在母板中定义页面专用的 CSS 块和 JS 块,方便子页面替换 定义块: {% block 名字 %} {% ...
- Linux脚本检测当前用户是否为root用户
#/bin/bash if [ $UID -ne 0 ]; then echo Non root user. Please run as root. else echo Root user fi
- vi 替换命令 以及“找不到模式”解决
转自:https://www.cnblogs.com/zfyouxi/p/5181363.html 在linux vi编辑工具中使用替换命令操作时,会出现明明有匹配查找模式的数据.却报“找不到模式”问 ...
- 用MATLAB的Classficiation Learner工具箱对12个数据集进行各种分类与验证
准备材料 以所有的特征集作为variable进行像Bayes吖.SVM吖.决策树吖......分类.同时对数据进行预处理,选出相关度高的特征子集作为新的一组data进行分类(预处理的代码不必放出来). ...
- springboot 通过docker 打包编译镜像
添加plugin <?xml version="1.0" encoding="UTF-8"?> <project xmlns="ht ...
- 编程语言、Python介绍及其解释器安装、运行Python解释器的两种方式、变量、内存管理
一.编程语言介绍 1.1 机器语言:直接用计算机能理解的二进制指令来编写程序,直接控制硬件. 1.2 汇编语言:在机器语言的基础上,用英文标签取代二进制指令来编写程序,本质上也是直接控制硬件. 以上2 ...
- python 之 前端开发( JavaScript变量、数据类型、内置对象、运算符、流程控制、函数)
11.4 JavaScript 11.41 变量 1.声明变量的语法 // 1. 先声明后定义 var name; // 声明变量时无需指定类型,变量name可以接受任意类型 name= " ...
- JAVA堆,栈的区别,用AarrayList、LinkedList自定义栈
大家都知道java模拟机在运行时要开辟空间所以它有特定的五个内存划分: 1.寄存器: 2.本地方法区: 3.方法区: 4.栈内存: 5.堆内存: 但是我们今天来注重讲一下栈和堆 ...
- mdk编译时的内存分析
内存四区(代码区,全局区,栈区,堆区) Code:即代码域,它指的是编译器生成的机器指令,这些内容被存储到ROM区. RO-data:Read Only data,即只读数据域,它指程序中用到的只读数 ...
- CSS实现自适应分隔线的N种方法
分割线是网页中比较常见的一类设计了,比如说知乎的更多回答 这里的自适应是指两边的横线会随着文字的个数和父级的宽度自适应 偷偷的看了一下知乎的实现,很显然是用一块白色背景覆盖的,加一点背景就露馅了 心想 ...