编译链接实战(9)elf符号表
文章目录
- 符号的概念
- 符号表探索
前面介绍了elf文件的两种视图,以及两种视图的各自几个组成部分:

elf文件有两种视图,链接视图和执行视图。在链接视图里,elf文件被划分成了elf 头、节头表、若干的节(section);在执行视图里,elf文件被划分成了elf头、程序头表、段(segment)。
可以看到,段实际上包含了若干个节,执行视图是给程序启动用的,用于指示如何加载程序;而链接视图是连接时使用的,用于指示链接器如何链接文件。
节头表就是一个表,可以理解成一个结构体数组,每一项用于描述一个节。每个我们今天来看下其中的一个节【符号表】。
今天我们关注**.symtab和.dynsym**这两个节。
动态符号表 (.dynsym) 用来保存与动态链接相关的导入导出符号,不包括模块内部的符号。
而 .symtab 则保存所有符号,包括 .dynsym 中的符号。
符号的概念
什么是符号?我们将函数和全局变量(static局部变量也算)统称为符号(Symbol),函数名和变量名就是符号名(Symbol Name),我们可以将符号看做是链接中的粘合剂,整个链接过程正是基于符号才能够正确完成。每个目标文件都会有一个符号表(Symbol Table),即上图的.symtab段,这个表里记录了目标文件所用到的所有符号。每个定义的符号有一个对应的值,叫做符号值(Symbol Value),对于变量和函数来说,符号值就是它们的地址。
在本目标文件中引用的全局符号,却没有定义在本目标文件中,一般叫做外部符号。
实际上段名(比如.text),汇编语言里的标签(比如_start、_edata、_end),源文件名也是符号。
备注:局部变量临时分配在栈中,不会在过程外被引用,所以不会产生符号。
弱符号
符号可以分为强符号和弱符号。
- 强符号:函数名、初始化的全局变量名;
- 弱符号:未初始化的全局变量名。
符号表探索
我们来写一个测试程序:
oop.c:
#include <stdio.h>
int g_a = 10;
static int g_s_b;
static int g_s_c = 0;
int g_d;
__thread int g_tls_e;
static __thread int g_tls_s_f;
__thread int g_tls_g = 0;
extern int g_e_h;
extern void fun1();
void fun()
{int l_i;g_d = 10; static int l_s_i;g_e_h= 10;//外部变量和函数如果不使用的话,编译器不会为其产生符号表,因为会优化 fun1();printf("hello\n");return;
}//定义一个弱函数
__attribute__((weak)) void fun_weak()
{return;
}
该程序定义了若干个变量用于覆盖所有情况。
前缀g表示全局,l表示局部,s表示静态,tls表示线程局部数据,e表示extern。
进行编译而不链接:
gcc oop.c -c
得到oop.o可重定位对象文件,前面说过,也是elf格式文件。
查看其节头表:
$ readelf -S oop.o --wide
There are 15 section headers, starting at offset 0x458:Section Headers:[Nr] Name Type Address Off Size ES Flg Lk Inf Al[ 0] NULL 0000000000000000 000000 000000 00 0 0 0[ 1] .text PROGBITS 0000000000000000 000040 000043 00 AX 0 0 1[ 2] .rela.text RELA 0000000000000000 000330 000078 18 I 12 1 8[ 3] .data PROGBITS 0000000000000000 000084 000004 00 WA 0 0 4[ 4] .bss NOBITS 0000000000000000 000088 000010 00 WA 0 0 4[ 5] .tbss NOBITS 0000000000000000 000088 00000c 00 WAT 0 0 4[ 6] .rodata PROGBITS 0000000000000000 000088 000006 00 A 0 0 1[ 7] .comment PROGBITS 0000000000000000 00008e 00002c 01 MS 0 0 1[ 8] .note.GNU-stack PROGBITS 0000000000000000 0000ba 000000 00 0 0 1[ 9] .note.gnu.property NOTE 0000000000000000 0000c0 000020 00 A 0 0 8[10] .eh_frame PROGBITS 0000000000000000 0000e0 000058 00 A 0 0 8[11] .rela.eh_frame RELA 0000000000000000 0003a8 000030 18 I 12 10 8[12] .symtab SYMTAB 0000000000000000 000138 000198 18 13 8 8[13] .strtab STRTAB 0000000000000000 0002d0 00005a 00 0 0 1[14] .shstrtab STRTAB 0000000000000000 0003d8 00007a 00 0 0 1
Key to Flags:W (write), A (alloc), X (execute), M (merge), S (strings), I (info),L (link order), O (extra OS processing required), G (group), T (TLS),C (compressed), x (unknown), o (OS specific), E (exclude),D (mbind), l (large), p (processor specific)
通过readelf的-s选项可以查看符号表:
$ readelf -s oop.o Symbol table '.symtab' contains 17 entries:Num: Value Size Type Bind Vis Ndx Name0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS oop.c2: 0000000000000000 0 SECTION LOCAL DEFAULT 1 .text3: 0000000000000004 4 OBJECT LOCAL DEFAULT 4 g_s_b4: 0000000000000008 4 OBJECT LOCAL DEFAULT 4 g_s_c5: 0000000000000004 4 TLS LOCAL DEFAULT 5 g_tls_s_f6: 0000000000000000 0 SECTION LOCAL DEFAULT 6 .rodata7: 000000000000000c 4 OBJECT LOCAL DEFAULT 4 l_s_i.08: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 g_a9: 0000000000000000 4 OBJECT GLOBAL DEFAULT 4 g_d10: 0000000000000000 4 TLS GLOBAL DEFAULT 5 g_tls_e11: 0000000000000008 4 TLS GLOBAL DEFAULT 5 g_tls_g12: 0000000000000000 56 FUNC GLOBAL DEFAULT 1 fun13: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND g_e_h14: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND fun115: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND puts16: 0000000000000038 11 FUNC WEAK DEFAULT 1 fun_weak
strip之后就查询不到静态符号表信息了,但是动态符号表信息还是可以查到的。
可以看到该符号表包含了17项(entry),每一项用Elf32_Sym结构体描述:
typedef struct
{Elf32_Word st_name; /* Symbol name (string tbl index) */Elf32_Addr st_value; /* Symbol value */Elf32_Word st_size; /* Symbol size */unsigned char st_info; /* Symbol type and binding */unsigned char st_other; /* Symbol visibility */Elf32_Section st_shndx; /* Section index */
} Elf32_Sym;
每一列的值其实都和结构体的成员相对应。
-
Name 符号的名字
-
Ndx 表示其所在section的序号,初始化过的全局变量g_a肯定在数据段.data,函数在代码段.text,【未经初始化的全局变量】和static变量在.bss段(static不管是否初始化都在bss段)。由于.bss段在程序启动时会被清0,所以未初始化的全局变量和static变量的值是0。
对于在本文件中引用到,但是在其他文件定义的符号,其Ndx为UND,例如本例的extern变量和函数。在链接阶段,找到该符号的定义之后,会对其Ndx进行修正。 -
Value 该符号的值(注意不是变量的值),符号的值就是指符号的地址,对于编译的中间文件.ol来说,value其实是该符号在其所在的section的偏移,是个相对值;对于链接后的可执行文件来说,该值是个绝对值,表示符号的绝对地址。
-
Type 表示符号的类型,常见的几种类型如下:
484 #define STT_NOTYPE 0 /* Symbol type is unspecified */485 #define STT_OBJECT 1 /* Symbol is a data object */486 #define STT_FUNC 2 /* Symbol is a code object */487 #define STT_SECTION 3 /* Symbol associated with a section */488 #define STT_FILE 4 /* Symbol's name is file name */489 #define STT_COMMON 5 /* Symbol is a common data object */490 #define STT_TLS 6 /* Symbol is thread-local data object*/
-
OBJECT 表示全局变量和static变量
FUNC 表示函数
FILE 文件名
COM 公用全局变量
TLS 线程本地数据 -
Bind列有以下几个常见值:
472 #define STB_LOCAL 0 /* Local symbol */473 #define STB_GLOBAL 1 /* Global symbol */474 #define STB_WEAK 2 /* Weak symbol */
分别表示局部、全局、弱符号。
- Vis表示该符号的可见范围,visibility的缩写:
/* Symbol visibility specification encoded in the st_other field. */#define STV_DEFAULT 0 /* Default symbol visibility rules */#define STV_INTERNAL 1 /* Processor specific hidden class */#define STV_HIDDEN 2 /* Sym unavailable in other modules */#define STV_PROTECTED 3 /* Not preemptible, not exported */
相关文章:
编译链接实战(9)elf符号表
文章目录符号的概念符号表探索前面介绍了elf文件的两种视图,以及两种视图的各自几个组成部分:elf文件有两种视图,链接视图和执行视图。在链接视图里,elf文件被划分成了elf 头、节头表、若干的节(section)&a…...
React合成事件的原理是什么
事件介绍 什么是事件? 事件是在编程时系统内发生的动作或者发生的事情,而开发者可以某种方式对事件做出回应,而这里有几个先决条件 事件对象 给事件对象注册事件,当事件被触发后需要做什么 事件触发 举个例子 在机场等待检票…...
Arduino-交通灯
LED交通灯实验实验器件:■ 红色LED灯:1 个■ 黄色LED灯:1 个■ 绿色LED灯:1 个■ 220欧电阻:3 个■ 面包板:1 个■ 多彩杜邦线:若干实验连线1.将3个发光二极管插入面包板,2.用杜邦线…...
【论文笔记】Manhattan-SDF == ZJU == CVPR‘2022 Oral
Neural 3D Scene Reconstruction with the Manhattan-world Assumption 本文工作:基于曼哈顿世界假设,重建室内场景三维模型。 1.1 曼哈顿世界假设 参考阅读文献:Structure-SLAM: Low-Drift Monocular SLAM in Indoor EnvironmentsIEEE IR…...
好消息!Ellab(易来博)官方微信公众号开通了!携虹科提供专业验证和监测解决方案
自1949年以来,丹麦Ellab一直通过全球范围内的验证和监测解决方案,协助全球生命科学和食品公司优化和改进其流程的质量。Ellab全面的无线数据记录仪,热电偶系统,无线环境监测系统,校准设备,软件解决方案等等…...
想要去字节跳动面试Android岗,给你这些面试知识点
关于面试字节跳动,我总结一些面试点,希望可以帮到更多的小伙伴,由于篇幅问题这里没有把全部的面试知识点问题都放上来!!目录:1.网络2.Java 基础&容器&同步&设计模式3.Java 虚拟机&内存结构…...
Java的Lambda表达式的使用
Lambda表达式是Java 8中引入的一个重要特性,它是一种简洁而强大的语法结构,可以用于替代传统的匿名内部类。 Lambda表达式的语法结构如下: (parameters) -> expression或者 (parameters) -> { statements; }其中,paramet…...
Spring MVC 源码 - HandlerMapping 组件(三)之 AbstractHandlerMethodMapping
HandlerMapping 组件HandlerMapping 组件,请求的处理器匹配器,负责为请求找到合适的 HandlerExecutionChain 处理器执行链,包含处理器(handler)和拦截器们(interceptors)handler 处理器是 Objec…...
超店有数,为什么商家要使用tiktok达人进行营销推广呢?
近几年互联网发展萌生出更多的短视频平台,而tittok这个平台在海外也越来越火爆。与此同时,很多商家也开始用tiktok进行营销推广。商家使用较多的方式就是达人营销,这种方法很常见且转化效果不错。那为什么现在这么多商家喜欢用tiktok达人进行…...
【分享】订阅万里牛集简云连接器同步企业采购审批至万里牛系统
方案场景 面临着数字化转型的到来,不少公司希望实现业务自动化需求,公司内部将钉钉作为办公系统,万里牛作为ERP系统,两个系统之前的数据都储存在各自的后台,导致数据割裂,数据互不相通,人工手动…...
C++类和对象_02----对象模型和this指针
目录C对象模型和this指针1、成员变量和成员函数分开存储1.1、空类大小1.2、非空类大小1.3、结论2、this指针概念2.1、解决名称冲突2.2、在类的非静态成员函数中返回对象本身,可使用return *this2.3、拷贝构造函数返回值为引用的时候,可进行链式编程3、空…...
瑞芯微RK3568开发:烧录过程
进入rk3568这款芯片的烧录模式共有3种方式,先讲需要准备的环境要求。 一、软硬件环境 1、配套sdk版本的驱动DriverAssitant_vx.x.x和RKDevTool_Release_vx.x,版本不对应可能无法烧录,建议直接在sdk压缩包里获取; 2、如果正确安…...
【数据结构】——树和二叉树的概念
目录 1.树概念及结构 1.1树的概念 1.2 树的相关性质 1.3 树的表示 1.4 树在实际中的运用(表示文件系统的目录树结构) 2.二叉树概念及结构 2.1二叉树概念 2.2 特殊的二叉树 2.3 二叉树的性质 1.树概念及结构 1.1树的概念 树是一种非线性的数据结构…...
Meta分析在生态环境领域里的应用
Meta分析(Meta Analysis)是当今比较流行的综合具有同一主题的多个独立研究的统计学方法,是较高一级逻辑形式上的定量文献综述。20世纪90年代后,Meta分析被引入生态环境领域的研究,并得到高度的重视和长足的发展&#x…...
PrivateLoader PPI服务发现RisePro恶意软件窃取分发信息
称为PrivateLoader的按安装付费(PPI)软件下载器服务正用于恶意软件RisePro的信息窃取。Flashpoint 于 2022 年 12月13日发现了新的窃取者,此前发现了在名为Russian Market的非法网络犯罪市场上使用该恶意软件泄露的“几组日志”。RisePro是一…...
SQL93 返回购买 prod_id 为 BR01 的产品的所有顾客的电子邮件(一)
描述你想知道订购 BR01 产品的日期,有表OrderItems代表订单商品信息表,prod_id为产品id;Orders表代表订单表有cust_id代表顾客id和订单日期order_date;Customers表含有cust_email 顾客邮件和cust_id顾客idOrderItems表prod_idorde…...
Git ---- 概述
Git ---- 概述1. 何为版本控制2. 为什么需要版本控制3. 版本控制的工具集中式版本控制工具分布式版本控制工具4. Git 简史5. Git 工作机制6. Git 和代码托管中心Git 是一个免费的、开源的分布式版本控制系统,可以快速高效地处理从小型到大型的各种项目。 Git 易于学…...
用 tensorflow.js 做了一个动漫分类的功能(二)
前言:前面已经通过采集拿到了图片,并且也手动对图片做了标注。接下来就要通过 Tensorflow.js 基于 mobileNet 训练模型,最后就可以实现在采集中对图片进行自动分类了。这种功能在应用场景里就比较多了,比如图标素材站点࿰…...
小林coding
一、图解网络 问大家,为什么要有TCP/Ip网络模型? 对于同一台设备上的进程通信,有很多种方式,比如有管道、消息队列、共享内存、信号等方式,对于不同设备上的进程通信,就需要有网络通信,而设备是…...
操作系统真相还原_第6章:完善内核
文章目录6.1 函数调用约定简介6.2 汇编语言和C语言混合编程汇编调用CC调用汇编6.3 实现打印函数流程程序编译并写入硬盘执行6.4 内联汇编简介汇编语言AT&T语法基本内联汇编扩展内联汇编6.1 函数调用约定简介 调用约定: calling conventions 调用函数时的一套约…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...
五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...
算法250609 高精度
加法 #include<stdio.h> #include<iostream> #include<string.h> #include<math.h> #include<algorithm> using namespace std; char input1[205]; char input2[205]; int main(){while(scanf("%s%s",input1,input2)!EOF){int a[205]…...
uniapp获取当前位置和经纬度信息
1.1. 获取当前位置和经纬度信息(需要配置高的SDK) 调用uni-app官方API中的uni.chooseLocation(),即打开地图选择位置。 <button click"getAddress">获取定位</button> const getAddress () > {uni.chooseLocatio…...
