ELF文件符号动态解析的过程

ELF文件解析和加载(附代码) 目录:1. elf文件基本概念2. elf文件结构3. elf文件装载4. 代码实现1.elf文件基本概念elf文件是一种目标文件格式,用于定义不同类型目标文件以什么样的格式,都放了些什么东西。主要 用于linux平台。windows下是PE/COFF格式。 可执行文件、可重定位文件(.o)、共享目标文件(.so)、核心转储文件都是以elf文件格式存... 阅读详情

链接器在把所需要的共享库加载到内存后,并没有把共享库中的函数的地址写到GOT表中,而是延迟到函数的第一次调用时,才会对函数的地址进行定位。(红线为第一次函数调用的顺序,蓝线为后续函数调用的顺序)
下面以puts函数为例分析第一次函数调用的过程:
在这里插入图片描述

链接器在把所需要的共享库加载到内存后,并没有把共享库中的函数的地址写到GOT表中,而是延迟到函数的第一次调用时,才会对函数的地址进行定位。(红线为第一次函数调用的顺序,蓝线为后续函数调用的顺序)
下面以puts函数为例分析第一次函数调用的过程:
(1)进入puts@plt,执行指令
(2)跳到GOT表中相应位置,此时GOT表里保存的是pushl n的地址,实际上就是顺序执行下一步
(3)执行pushl n,n为puts函数地址在GOT表中的位置,向堆栈中压入这个偏移量的主要作用就是为了找到puts函数的符号名以及puts函数地址在GOT表项中所占的位置,以便在函数定位完成后将函数的实际地址写到这个位置。
(4)跳到PTL0的位置,这步将GOT[1],即共享库链表的地址压栈
(5)顺序执行jmp GOT[2],GOT[2]保存的是_dl_runtime_resolve函数的入口
(6)执行_dl_runtime_resolve函数,该函数会找到puts函数的实际加载地址,并把它写到GOT表中,返回时就会进入puts函数内执行。
  函数后续执行就会直接跳转的GOT表puts函数对应位置,该位置保存着puts函数的地址,直接进入puts函数。

GOT表

Global Offset Table,在位置无关代码中,一般不能包含绝对虚拟地址(如共享库)。当在程序中引用某个共享库中的符号时,编译链接阶段并不知道这个符号的具体位置,只有等到动态链接器将所需要的共享库加载时进内存后,也就是在运行阶段,符号的地址才会最终确定。因此,需要有一个数据结构来保存符号的绝对地址,这就是GOT表的作用,GOT表中每项保存程序中引用其它符号的绝对地址。这样,程序就可以通过引用GOT表来获得某个符号的地址。
  在x86结构中,GOT表的前三项保留,用于保存特殊的数据结构地址,其它的各项保存符号的绝对地址。对于符号的动态解析过程,我们只需要了解的就是第二项和第三项,即GOT[1]和GOT[2]:GOT[1]保存的是一个地址,指向已经加载的共享库的链表地址(加载的共享库会形成一个链表);GOT[2]保存的是一个函数的地址,定义如下:GOT[2] = &_dl_runtime_resolve,这个函数的主要作用就是找到某个符号的地址,并把它写到与此符号相关的GOT项中

PLT表

Procedure Linkage Table,过程链接表(PLT)的作用就是将位置无关的函数调用转移到绝对地址。在编译链接时,链接器并不能控制执行从一个可执行文件或者共享文件中转移到另一个中(这时候函数的地址还不能确定),因此,链接器将控制转移到PLT中的某一项。而PLT通过引用GOT表中的函数的绝对地址,来把控制转移到实际的函数。
  在实际的可执行程序或者共享目标文件中,GOT表在名称为.got.plt的section中,PLT表在名称为.plt的section中。

原文链接:https://de4dcr0w.github.io/Linux%E5%86%85%E6%A0%B8%E5%A6%82%E4%BD%95%E8%A3%85%E8%BD%BD%E5%92%8C%E5%90%AF%E5%8A%A8%E4%B8%80%E4%B8%AA%E5%8F%AF%E6%89%A7%E8%A1%8C%E7%A8%8B%E5%BA%8F.html

以上是动态加载过程。
android中还有个/proc/虚拟文件夹,不在硬盘上。包含了各种进程和系统信息。self/maps XXX/maps
分别是自身进程映射和其他进程映射。
在maps中有个 Linker是共享库的加载/链接器,也可以称为解释器(interpreter)。(/system/bin/linker)
http://www.voidcn.com/article/p-kzjxymae-qr.html

获取其他进程函数地址一般是根据本地函数地址和模块的基址,加上远程模块的基址进行计算就可以得到远程函数的地址。

二进制文件解析

我们写个简单的程序

#include <unistd.h>  
#include <stdlib.h>    
int main(void)  {
   char buf[10];
   int n;
   n = read(STDIN_FILENO, buf, 10);
   if (n < 0) {
    perror("read STDIN_FILENO");
    exit(1);
   }
   write(STDOUT_FILENO, buf, n);
   return 0; 
}

调用read函数的情况

.text:0000000000400686                 mov     rsi, rax        ; buf
.text:0000000000400689                 mov     edi, 0          ; fd
.text:000000000040068E                 call    _read
.text:0000000000400693                 mov     [rbp+var_24], eax
.text:0000000000400696                 cmp     [rbp+var_24], 0
.text:000000000040069A                 jns     short loc_4006B5

首先进入elf的read.plt

.plt:0000000000400520 ; ssize_t read(int fd, void *buf, size_t nbytes)
.plt:0000000000400520 _read           proc near               ; CODE XREF: main+28↓p
.plt:0000000000400520                 jmp     cs:off_601028
.plt:0000000000400520 _read           endp
.plt:0000000000400520

601028地址位于got.plt这个就是常说的got表。

.got.plt:0000000000601000 ; ===========================================================================
.got.plt:0000000000601000
.got.plt:0000000000601000 ; Segment type: Pure data
.got.plt:0000000000601000 ; Segment permissions: Read/Write
.got.plt:0000000000601000 _got_plt        segment qword public 'DATA' use64
.got.plt:0000000000601000                 assume cs:_got_plt
.got.plt:0000000000601000                 ;org 601000h
.got.plt:0000000000601000 _GLOBAL_OFFSET_TABLE_ dq offset _DYNAMIC
.got.plt:0000000000601008 qword_601008    dq 0                    ; DATA XREF: sub_4004F0↑r
.got.plt:0000000000601010 qword_601010    dq 0                    ; DATA XREF: sub_4004F0+6↑r
.got.plt:0000000000601018 off_601018      dq offset write         ; DATA XREF: _write↑r
.got.plt:0000000000601020 off_601020      dq offset __stack_chk_fail
.got.plt:0000000000601020                                         ; DATA XREF: ___stack_chk_fail↑r
.got.plt:0000000000601028 off_601028      dq offset read          ; DATA XREF: _read↑r
.got.plt:0000000000601030 off_601030      dq offset __libc_start_main
.got.plt:0000000000601030                                         ; DATA XREF: ___libc_start_main↑r
.got.plt:0000000000601038 off_601038      dq offset perror        ; DATA XREF: _perror↑r
.got.plt:0000000000601040 off_601040      dq offset exit          ; DATA XREF: _exit↑r
.got.plt:0000000000601040 _got_plt        ends
.got.plt:0000000000601040

上面代码的read的位置在首次调用的时候填写的是dl_runtime_resolve()函数地址,通过此函数计算出read函数的真实地址后替换got.plt.read位置的函数,下次调用就可以直接获取read函数的地址。

参考:
https://xz.aliyun.com/t/5120

编译过程和ELF文件 目录 一、C/C++编译过程 二、ELF文件 三、符号解析和重定位 四、静态链接和动态链接 一、C/C++编译过程 C/C++程序从源代码到可执行文件需要经理预处理(预编译),编译,汇编,链接四个过程: 1、预处理:对源代码中的伪指令(以# 开头的指令)和特殊符号进行处理,如#include指令,预处理会将对应的头文件(即.h文件,声明全局变量和函数,相当于jav... 阅读详情

相关推荐

CSAPP Linux 链接:从 Hello 程序构建看链接全过程,再详解链接

下面内容大部分来自《深入理解计算机系统》(CSAPP)一书第七章链接,跟深入了解建议阅读此书第七章,推荐阅读《链接器和加载器》和《程序员的自我修养 – 链接, 装载与库》。一个hello程序的生命周期如下图所示预处理阶段:处理源代码中的预处理指令(以开头,如#include#define等),生成hello.i文件。编译阶段:将预处理后的源代码翻译成汇编代码,生成hello.s文件。汇编阶段。

有耐心做好简单事情,坚持写blog 1963

ELF文件详解

一、ELF概述 1、ELF的定义 ELF(Executable and Linkable Format)文件是一种目标文件格式,常见的ELF格式文件包括:可执行文件、可重定位文件(.o)、共享目标文件(.so)、核心转储文件等。 ELF主要用于Linux平台,Windows下是PE/COFF格式。 2、ELF文件的结构 一个完整的ELF文件一般会包括如下几个内容:ELF头、Section头、Segment头和Section。 其中由Section头组成的集合称为Section头表,...

PeakJin的博客 2万+

深入解析ELF文件格式及结构

本文还有配套的精品资源,点击获取 简介:ELF格式是一种在类UNIX系统中广泛使用的可执行文件和链接格式,用于程序和共享库的表示。它为编译器、链接器、加载器和运行时系统提供统一接口。本文深入探讨了ELF文件的三个主要部分:头部、节区表和节区,以及符号表、重定位表和动态链接等关键特性。此外,还介绍了ELF版本控制和调试信息的重要性,帮助读者全面理解ELF文件的结构和工作原理。...

weixin_28771751的博客 2596

ELF文件格式解析

ELF格式分析

夏天Alex 5444

ETL数据集成案例

一个典型的ETL数据集成案例是将多个来源的数据合并成一个数据集。假设有一个公司,该公司使用一些不同的系统来存储不同部门的数据,例如销售数据存储在一个CRM系统中,财务数据存储在一个ERP系统中,人力资源数据存储在一个HR系统中。为了更好地进行报告和分析,该公司决定将所有这些数据集成到一个数据仓库中。以下是实现这一目标的ETL过程的步骤:提取(Extract):首先,需要从每个系统中提取所需的数据。每个系统可能有不同的数据格式和结构,因此需要编写不同的提取程序或查询来提取数据。

runqu的博客 948

86 arduino 电机yl_(八)arduino入门:直流电机控制

一、本节介绍在本实验中,您将学习如何使用驱动芯片L293D和SunFounder Uno板控制小型直流(DC)电机的方向和速度。为了使初学者更容易,我们将让直流电机左右旋转,自动加速和减速。二、材料准备1 *小型直流电机1 * L293D1 * Arduino Uno板1 *面包板1 * USB数据线杜邦线三、原理讲解L293D这是一个非常实用的芯片,可以独立控制两台直流电机。在这个实验中,只有一...

weixin_29163857的博客 3568

ELF PLT Hook 原理简述

【无线平台】ELF PLT Hook 原理简述 简述 Android 是基于Linux的操作系统,因此在Android开发平台上,ELF是原生支持的可执行文件格式;ELF文件格式除了作为可执行文件,还可以作为共享库格式,也就是我们常见的so文件, 以及 object文件 (.o)、core dumps文件等。 GOT/PLT HOOK 是ELF 文件函数hook的一种实现机制,GOT/PLT Hook 主要用于实现替换某个SO的外部调用,它的优点是非常稳定,因此在生产环境通常使用这种实现方案。 GOT/PL

Knight-ZXW的博客 3404

Haclon案例-找出图中面积最大的圆

自带的函数,求得圆的面积和圆心点坐标,然后,用本章所学习的选择算子和循环算子找出面积最大的圆。的图片,试着给它加上不同种类的噪声,然后找出其中面积最大的圆,并将圆的面积标注在其圆心位置。可知,除了六个圆形之外,还有一些微小的噪声点,采用了开运算和特征选择的方法去除噪声。1. 该图片为一灰度图,对其进行二值化,二值化后如图。4. 在面积最大圆的圆心坐标位置写上该圆的面积。

qq_20660115的博客 903

ELF文件中符号的动态解析过程

本文引用并修改了http://jzhihui.iteye.com/blog/1447570 中的动态链接部分,然后加了自己的理解和注释。 用来测试的C代码为:/* hello.c */ #include <stdio.h> int main() { printf(“hello world!\n”); return 0; } $ gcc –o hello hello.c当执行一个用户

u011673554的博客 1301

STM32CubeMX+FreeRTOS+CAN总线+传感器实战:多任务系统与通信融合开发详解

本文详细介绍了基于STM32CubeMX和FreeRTOS的CAN总线与光电传感器融合开发实战。通过多任务系统设计,实现传感器数据采集与CAN通信的协同工作,提供完整的配置例程和调试技巧,适用于工业控制与机器人感知等应用场景。

n2o3p4的博客 735

YOLO系列算法改进 | 自研篇 | C3k2融合SEFN空间增强前馈网络模块 | 去模糊和提升图像细节特征,精度涨点!| WACV 2025

YOLO系列算法改进 | 自研篇 | C3k2融合SEFN空间增强前馈网络模块 | 去模糊和提升图像细节特征,精度涨点!| WACV 2025 (以YOLO26最新目标检测模型为基础,C3k2融合SEFN空间增强前馈网络模块改进Backbone)

2502_91881744的博客 238

Elf动态解析符号过程(转载) - *nix文件格式 - j4ckl1u

导读: 本篇文章以linux为平台为例,演示ELF动态解析符号的过程。不正之处,还请斧正。通常,ELF解析符号方式称为lazy MODE装载的。这种装载技术是ELF平台上默认的方式。在不同的体系平台在实现这种机制也是不同的。但是i386和SPARC在大部分上是相同的。动态连接器(rtld)提供符号的动态连接,装载共享objects和解析标号的引用。通常是ld.so,它可以是一个共享obje

xu的blog 1424

CenterPoint 工程复现

CenterPoint 工程复现,本文中使用版本:BEVerse工程下的mmdet3d (`MMDet3d v0.17.3`)版本,MMDetection3D中其他版本的使用`大同小异`。

Darchan的博客 5663

ELF文件的加载和动态链接过程

近段时间在研究Erlang核心特性的实现,也许过段时间会有个系列的总结,期待...   今天看到有人写一个深入Hello World的文章,想起来读研的时候做的一个关于程序加载和链接的课程设计,也是以Hello World为例说明的,随发出来共享。文后有下载链接。   ======================================================   本文

stonesharp的专栏 505

基于YOLOv10的建筑图纸物体检测系统:从数据集构建到UI界面实现

高度结构化的图形元素标准化的符号和标注系统多层次的细节表达精确的尺寸和位置关系。

YOLO 390

鸿蒙系统开发工程师:核心技术解析与深度面试指南

摘要: 鸿蒙系统开发工程师需具备底层驱动开发、系统移植优化及分布式架构能力。核心职责包括硬件适配(Bootloader、内核移植、HDF驱动开发)、性能调优(启动加速、功耗管理)及稳定性保障。技术要求涵盖C/C++编程、Linux内核机制、鸿蒙架构(HDF、分布式服务)及ArkTS/ArkUI基础。面试重点考察系统移植流程(如ARM板适配)、驱动开发(I2C/Display)、性能优化手段及内存/同步机制的应用。

郑伟强dev的专栏 430

ELF文件的加载

本文的目的:大家对于Hello World程序应该非常熟悉,随便使用哪一种语言,即使还不熟悉的语言,写出一个Hello World程序应该毫不费力,但是如果让大家详细的说明这个程序加载和链接的过程,以及后续的符号动态解析过程,可能还会有点困难。本文就是以一个最基本的C语言版本Hello World程序为基础,了解Linux下ELF文件的格式,分析并验证ELF文件和加载和动态链接的具有实现。

HelloJiao的专栏 398

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

ELF格式以及相关加载

ELF文件格式(中文版)    http://blog.youkuaiyun.com/yayong/archive/2004/11/12/178160.aspx Intel平台下Linux中 ELF文件动态链接的加载、解析及实例分析(一): 加载http://blog.youkuaiyun.com/yayong/archive/2004/12/03/202775.aspx Intel平台下linu

ShorminHsu的专栏 3114

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

上一篇: 关于centos python版本共存的问题
下一篇: android ndk调用第三方so文件的方法
inquisiter
博客等级 码龄10年 374粉丝 228原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值