前言

一个优先的symtab文章

我们常常调试错误说需要符号表,那么符号表是什么?符号表仅仅用来调试?

符号表本质就是一个映射表,举个例子:某行二进制汇编代码映射到源码第几行。

符号表的作用:

  1. 调试
  2. 重定位

调试

window工程有一个*.pdb文件,里面编包含调试符号.可参阅wiki window pdb格式。

在java工程会使用一个叫混淆的技术,混淆后会生成混淆前后的映射文件mapping.txt,这个也可以理解为符号表的一种。

linux有一个dwarf的文件格式也是专门用于调试的文件。参阅wiki DWARF。

重定位

重定位可以大致分为两种类别动态重定位静态重定位

动态重定位

假设A程序需要xxx.so中的yyyy函数那么就需要从xxx.so中的符号表进行读取。

静态重定位

我们看看下面的源代码

//mainA.cint globalvar=0x123;
fun test(){}//mainB.c
extern test();
extern int globalvar;
fun testFunB(){test();printf("I am  %d\r\n",globalvar)
}

我们程序有两个源代码,我们知道我编译的时候我们首先先将程序编译成目标文件。
也就是mainB.o mainA.o,在目标文件中mainB.o不知道test函数和globalvar变量的地址,因此我们需要在链接时修正mainB.o函数调用地址。

在编译成目标文件时,编译器会把文件中所有的函数与变量地址放入一个符号表中。
在链接时把所有目标文件的符号表合成一个,然后利用重定位表和符号表完成函数调用地址修正。

我们看链接前示意图:

链接后:

动态重定位

动态重定位和静态符号表原理都差不多,不过重定位操作延迟到调用时,关于延迟绑定可以参阅通过GDB学透PLT与GOT

静态符号表

#include <stdio.h>static int mystaticVar = 3 ;
int myglobalvar=5;
int myglobalvar2=6;
extern void testfun();
int main(){int *inp= 0x00;*inp=2;testfun();printf("hello world %d \r\n",mystaticVar);return 0;
}
void hell(){testfun();
}

编译成目标文件:
gcc -c -o main.o main.c

首先我们查看对应头表
[图2-1]

可以看到一个.symtab这个就是我们符号表数组起始地址

他的结构如下所示:

typedef struct {Elf32_Word   st_name;Elf32_Addr  st_value;Elf32_Word st_size;unsigned char   st_info;unsigned char   st_other;Elf32_Half st_shndx;
} Elf32_Sym;//32位typedef struct {Elf64_Word st_name;unsigned char   st_info;unsigned char   st_other;Elf64_Half st_shndx;Elf64_Addr st_value;Elf64_Xword    st_size;
} Elf64_Sym;//64位

当然你依然可以使用相关命令查看
[图2-2]

st_name

数值表示该符号字符串位于字符串表(.)中的下标。

[图2-3]

我们以16进制打印符号表如下图:
[图2-4]

符号第0个字节为00,第一个字节位6d对应ascii字符为m,而后遇到第一个00之前组成的字符串就是main.c

st_info

这个字段是一个复合字段,他内部决定了符号bind类型以及type
如下宏函数:

   #define ELF32_ST_BIND(i) ((i)>>4) #define ELF32_ST_TYPE(i) ((i)&0xf) #define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf) ) #define ELF64_ST_BIND(i) ((i)>>4) #define ELF64_ST_TYPE(i) ((i)&0xf) #define ELF64_ST_INFO(b,t) (((b)<<4)+((t)&0xf ))

bind

bind相关字段枚举如下图所示

其中我只需要留意三个字段STB_LOCAL,STB_GLOBAL,STB_WEAK

STB_LOCAL:
表示这个符号仅仅在本目标文件可见,其他目标文件不可见。比如静态方法和静态属性。比如本例代码mystaticVar就是对外不可见的。

STB_GLOBAL
目标文件中对外暴露的函数和属性如本例myglobalvar2

STB_WEAK
弱符号,这里不扩开讲

type

说明这个符号是什么,比如是函数还是文件或者属性

STT_NOTYPE
说明这个符号什么都不是,符号表第一项固定为此类型,以及引用外部的函数等。

STT_OBJECT

一般说明这个符号是变量数组等

STT_FUNC
一般指代函数

st_other

这个字段用于控制可见性,其枚举值如下图所示

因为STV_DEFAULT是最常见的属性也是默认属性,这里只说明此项:
如果st_other是STV_DEFAULT那么可见性交付给符号表中st_info决定

st_shndx

符号关联的节下标。
比如我们的全局变量myglobalvar2位于.data节中(在节头表下标是3)

再看看函数hell信息

其中1是节头表中的.text

st_value

这个数值根据文件不同具有不同同的意义(这里直接翻译文档,所以会有些生硬)

  1. 在可重定位文件中,st_value 包含节索引为 SHN_COMMON 的符号的对齐约束。

  2. 在可重定位文件中,st_value 包含所定义符号的节偏移。st_value 表示从 st_shndx 所标识的节的起始位置的偏移。

  3. 在可执行文件和共享目标文件中,st_value 包含虚拟地址。为使这些文件的符号更适用于运行时链接程序,节偏移(文件解释)会替换为与节编号无关的虚拟地址(内存解释)。

我们这里举例第2点
main.o中他是一个可重定位文件。
main.o的hell符号表的value为0x48,size大小为21

他表示函数位于.text位移48h,且函数体大小为21(十进制,16进制为15).

我们通过计算 函数首尾地址得到大小:5c-48+1=15h

我们再看看对于变量差别

myglobalvar节内偏移为4,大小为4(因为变量大小为4)

st_size

上文已解释

动态符号表

//main.c
#include <stdio.h>static int mystaticVar = 3 ;
int myglobalvar=5;
int myglobalvar2=6;
extern void testfun();
int main(){testfun();printf("hello world %d \r\n",mystaticVar);return 0;
}
void hell(){testfun();
}//test.c__attribute__((visibility("default"))) void testfun(){}
__attribute__((visibility("hidden")))  void testfun2(){}
int libGLobal=2;

相关编译命令:

gcc -fPIC -shared test.c -o test.so
gcc main.c -o main.out test.so

此时我们查看可执行文件的节头

你会发下多了两个.dynsym.dynstr.

他们其实作用和.symtab.strtab作用一样的,不过专门作用动态库。
如下图:

我们最后看到test.c有两个很陌生的符号

__attribute__((visibility("hidden")))__attribute__((visibility("default")))

上面两个是传递给编译器使用的,告诉这个函数或者变量是否需要导出到符号表,如果不导出其他程序无法使用,默认所有符号都是 __attribute__((visibility("default"))).

我们readelf -s test.so查看导出的符号

那你会发现没有testfun2.dynsym

ELF格式解读-符号表相关推荐

  1. 关于可重定位目标文件的格式与其符号表的概述

            我们知道一个可执行的C程序要经过语言预处理.编译器.汇编器生成扩展名为.o的可重定位目标文件,再通过链接器链接生成可执行的目标文件. 1.什么是可重定位目标文件        一个扩展 ...

  2. ELF格式解读-(1) elf头部与节头

    前言 ELF是linux动态库,可执行文件的格式.具体介绍可参阅wiki Executable and Linkable Format.可以类比到windows下exe的格式. 首先推荐一个写的不错文 ...

  3. linux elf格式 全局指针表got call跳转表plt 简介

    一.程序运行过程 首先我们对于程序运行来有一个基本的概念,程序运行起来应经过四个步骤:预处理.编译.汇编和链接,过程如下. 汇编过程调用汇编器as来完成,是用于将汇编代码转换成机器可以执行的指令,每一 ...

  4. iOS符号表恢复逆向支付宝

    推荐序 本文介绍了恢复符号表的技巧,并且利用该技巧实现了在 Xcode 中对目标程序下符号断点调试,该技巧可以显著地减少逆向分析时间.在文章的最后,作者以支付宝为例,展示出通过在 UIAlertVie ...

  5. 编译原理 符号表管理技术

    第六章 符号表管理技术 文章目录 第六章 符号表管理技术 6.1 概述 6.2 符号表的组织与内容 6.2.1 符号表的结果与内容 6.2.2 符号表的组织方式 6.3 非分程序结构语言的符号表组织 ...

  6. 编译原理学习笔记 6.2 符号表的组织与内容

    前言 参考课上PPT内容. 该学习笔记目前仅打算个人使用. 后续会进一步整理,包括添加笔记内容,标明参考资料. 更新中... 跳过目录 目录 一.符号表的结构与内容 "名字"域 & ...

  7. elf section类型_ELF结构(主要是符号表)

    1.1.1   整体结构 ELF对象格式用于目标文件(.o扩展名)和执行文件. 有些信息只出现在目标文件或执行文件中. ELF文件由下列部件构成. ELF header必须放在文件的开始;其他部件可以 ...

  8. 【Android 逆向】ELF 文件格式 ( 程序头数据 | 节区头数据 | 动态符号表 )

    文章目录 一.程序头数据 二.节区头数据 三.动态符号表 一.程序头数据 在上一篇博客 [Android 逆向]ELF 文件格式 ( ELF 程序头入口大小 | ELF 程序头入口个数 | ELF 文 ...

  9. ELF符号表分析(转载)

    An object file's symbol table holds information needed to locate and relocate a program's symbolic d ...

最新文章

  1. 报文加解密原理_加密系统的组成与过程
  2. autoburn eMMC hacking
  3. postman可以测试websocket吗_小海塔罗娱乐测试2021年可以脱单吗?
  4. 云计算:容器技术变革云计算,SaaS带动CaaS市场
  5. java编程求最小公约数_java求最大公约数与最小公倍数
  6. 基于机器视觉的电阻焊接质量检测
  7. Linux 配置mail发送邮件
  8. mysql不停库全量备份,mysql全量备份数据
  9. Jo-SRC: A Contrastive Approach for Combating Noisy Labels
  10. 推荐 :数据可视化与信息可视化浅谈
  11. 超参数优化:网格搜索法
  12. python模块-----pyqrcode
  13. 安防百科-单了解ONVIF 协议
  14. 编译ros21讲中的服务端Server时报错
  15. *7-2 CCF 2015-09-2 日期计算
  16. Excel数据透视表经典教程六《报表布局》
  17. 插件和依赖有什么区别?
  18. 前端-HTML思维导图
  19. FastDFS问题分析和总结
  20. 视觉残差函数及雅可比公式推导

热门文章

  1. fortify漏洞修复笔记
  2. [Pandas] 统计计数value_counts( )
  3. html 内容不换行,html标题不换行 html 什么代码可以不换行
  4. 【微搭低代码】小程序实现图片的上传和下载
  5. jq开发雷霆战机小游戏
  6. (与jQuery靠近乎)03-与jQuery的dom瞎搞
  7. vue+element-ui el-pagination 分页后 导出全部数据
  8. 如何快速搭建一个简易的ELK日志分析系统
  9. Unity用户手册2019.3(中文版)1.3.2 资源包
  10. 网络营销的“万剑归宗”