Linux 程序开发 之 库打桩机制

news2024/10/5 20:24:39

目录

  • 前言
  • 一、库打桩定义
  • 二、编译时打桩
  • 三、链接时打桩
  • 四、运行时打桩
  • 五、处理目标文件的工具

前言

  Linux 链接器支持一个很强大的技术,称为库打桩(library interpositioning),它允许你截获对共享库函数的调用,取而代之执行自己的代码。使用打桩机制,你可以追踪对某个特殊库函数的调用次数,验证和追踪它的输入和输出值,或者甚至把它替换成一个完全不同的实现。

一、库打桩定义

  基本思想:给定一个需要打桩的目标函数,创建一个包装函数,它的原型与目标函数完全一样。使用某种特殊的打桩机制,你就可以欺骗系统调用包装函数而不是目标函数了。包装函数通常会执行它自己的逻辑,然后调用目标函数,再将目标函数的返回值传递给调用者。

  打桩可以发生在编译时、链接时或当程序被加载和执行的运行时。

  要研究这些不同的机制,我们通过下面内容中的示例程序作为运行例子。它调用C标准库(libc.so)中的malloc和 free函数。对malloc的调用从堆中分配一个32字节的块,并返回指向该块的指针。对free的调用把块还回到堆,供后续的malloc调用使用。我们的目标是用打桩来追踪程序运行时对malloc和 free的调用

二、编译时打桩

  如果学习过C++的朋友阅读本篇文章后,会发现这个打桩机制有些类似于C++中的函数重载多态性

  下面几个实例程序展示了如何使用C预处理器在编译时打桩。mymalloc.c中的包装函数调用目标函数,打印追踪记录,并返回。本地的malloc.h头文件指示预处理器用对相应包装函数的调用替换掉对目标函数的调用。像下面这样编译和链接这个程序:

 gcc -DCOMPILETIME -c mymalloc.c
 gcc -I. -o intc int.c mymalloc.o

	由于有-I.参数,所以会进行打桩,它告诉C预处理器在搜索通常的系统目录之前,先在
当前目录中查找malloc.h。注意,mymalloc.c中的包装函数是使用标准malloc.h头文件编
译的。
	运行这个程序会得到如下图的追踪信息:
	./intc

在这里插入图片描述

//int.c文件
#include <stdio.h>
#include <malloc.h>

int main(int argc, char *argv[])
{
    int *p = malloc(32);
    free(p);
    
    return 0;
}
//malloc.h文件
#define malloc(size) mymalloc(size)
#define free(size) myfree(size)

void *mymalloc(size_t size);
void myfree(void *ptr);
//mymalloc.c文件,包装函数

#ifdef COMPILETIME

#include <stdio.h>
#include <malloc.h>

/* malloc wrapper function*/
void *mymalloc(size_t size)
{
    void *ptr = malloc(size);
    printf ("malloc(%d)=%p\n" ,(int)size, ptr);
    
    return ptr;
}

/* free wrapper function */
void myfree(void *ptr)
{
    free(ptr);
    printf ("free(%p)\n", ptr) ;
}

#endif

三、链接时打桩

  Linux静态链接器支持用__wrap_f标志进行链接时打桩。这个标志告诉链接器,把对符号f的引用解析成_wrap_f(前缀是两个下划线),还要把对符号__real_f(前缀是两个下划线)的引用解析为f

  链接时打桩使用的 int.c 和编译时打桩相同,mymalloc.c不同。此外不再需要我们自己写的malloc.h文件

用下述方法把这些源文件编译成可重定位目标文件:
	gcc -DLINKTIME -c mymalloc.c
	gcc -c int.c
然后把目标文件链接成可执行文件 (注意命令中的w的大小写,有的大写有的小写):
	gcc -Wl,--wrap,malloc -Wl,--wrap,free -o intl main.o mymalloc.o
	
	-Wl,option标志把 option 传递给链接器。option中的每个逗号都要替换为一个
空格。所以-Wl,--wrap,malloc就把--wrap malloc传递给链接器,以类似的方式传递
-Wl,--wrap,free。

	执行该程序:./intl 
	打印信息如下所示

在这里插入图片描述

//int.c文件

#include <stdio.h>
#include <malloc.h>

int main(int argc, char *argv[])
{
    int *p = malloc(32);
    free(p);
    
    return 0;
}
//mymalloc.c文件,包装函数

#ifdef LINKTIME
#include <stdio.h>

void *__real_malloc(size_t size);
void __real_free(void *ptr);

/* malloc wrapper function */
void *__wrap_malloc(size_t size)
{

    void *ptr = __real_malloc(size);/* Call libc malloc */
    
    printf("malloc(%d)= %p\n" ,(int)size, ptr);
    
    return ptr;
}

/* free wrapper function */
void __wrap_free(void *ptr)
{
    __real_free(ptr); /* Call libc free */
    printf("free(%p)\n", ptr);
}
#endif

知识补充:

(1)重定位:可执行文件中代码以及数据的运行时内存地址是链接器指定的,确定程序运行
时地址的过程就是重定位(Relocation)。

	操作系统将逻辑地址转变为物理地址的过程,也就是对目标程序中的指令和数据进行
修改的过程叫重定位。

参考学习:https://copyfuture.com/blogs-details/20211201161126175P

(2)位置无关码:CPU取指时用相对地址取指令(比如pc +4),只要其相对地址没有变,
都能够取指并运行。即该段代码无论放在内存的哪个地址,都能正确运行。究其原因,是
因为代码里没有使用绝对地址,都是相对地址。

参考学习:https://www.ofweek.com/ai/2021-01/ART-201721-11000-30480569_3.html

四、运行时打桩

  编译时打桩需要能够访问程序的源代码,链接时打桩需要能够访问程序的可重定位对象文件。不过,有一种机制能够在运行时打桩,它只需要能够访问可执行目标文件。这个很厉害的机制基于动态链接器的LD_PRELOAD环境变量。

  如果 LD_PRELOAD环境变量被设置为一个共享库路径名的列表(以空格或分号分隔),那么当你加载和执行一个程序,需要解析未定义的引用时,动态链接器(LD-LINUX.So)会先搜索LD_PRELOAD库,然后才搜索任何其他的库。有了这个机制,当你加载和执行任意可执行文件时,可以对任何共享库中的任何函数打桩,包括libc.so。

  下面提供了malloc和 free的包装函数。每个包装函数中,对dlsym的调用返回指向目标libc函数的指针。然后包装函数调用目标函数,打印追踪记录,再返回。

下面是如何构建包含这些包装函数的共享库的方法:
gcc -DRUNTIME -shared -fpic -o mymalloc.so mymalloc.c -ldl

这是如何编译主程序:
gcc -o intr int.c

使用命令查阅自己的Linux系统使用的是那种shell:printenv SHELL

下面是如何从bash shell 中运行这个程序:
LD_PRELOAD="./mymalloc.so" ./intr

下面是如何在csh或tcsh中运行这个程序:
(setenv LD_PRELOAD "./mymalloc.so"; ./intr; unsetenv LD_PRELOAD)

知识补充:

	dlsym是一个计算机函数,功能是根据动态链接库操作句柄与符号,返回符号对应的
地址,不但可以获取函数地址,也可以获取变量地址。

#include<dlfcn.h>
void*dlsym(void*handle,constchar*symbol)

	handle:可以是dlopen函数返回的handle值,也可以是RTLD_DEFAULT或RTLD_NEXT
	RTLD_DEFAULT表示按默认的顺序搜索共享库中符号symbol第一次出现的地址
	RTLD_NEXT表示在当前库以后按默认的顺序搜索共享库中符号symbol第一次出现的地址
	
	symbol:要求获取的函数或全局变量的名称。

返回值:
void* 指向函数的地址,供调用使用。

在这里插入图片描述

//int.c文件

#include <stdio.h>
#include <malloc.h>

int main(int argc, char *argv[])
{
    int *p = malloc(32);
    free(p);
    
    return 0;
}
//mymalloc.c文件,包装函数
#ifdef RUNTIME
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

/*malloc wrapper function */
void *malloc(size_t size)
{
    void *(*mallocp)(size_t size);
    char *error;

    printf("3333\n");
    mallocp = dlsym(RTLD_NEXT, "malloc");/* Get address of libc malloc */
    if ((error = dlerror()) != NULL) 
    {
        fputs(error, stderr);
        exit(1);
    }

    char *ptr = mallocp(size); /* Call libc malloc */ 
    printf("malloc(%d)= %p\n", (int)size, ptr);
    return ptr;
}

/* free wrapper function*/
void free(void *ptr)
{
    void (*freep)(void *) = NULL;
    char *error;

    printf("4444\n");
    if (!ptr)
        return;

    freep = dlsym(RTLD_NEXT, "free");/* Get address of libc free */
    if ((error = dlerror()) != NULL)
    {
        fputs(error, stderr);
        exit(1);
    }

    freep(ptr); /* Call libc free */
    printf("free(%p)\n", ptr);
}
#endif

五、处理目标文件的工具

  在 Linux 系统中有大量可用的工具可以帮助你 理解 和 处理 目标文件。特别地,GNU binutils包尤其有帮助,而且可以运行在每个Linux平台上。

●AR:创建静态库,插入、删除、列出和提取成员.

●STRINGS:列出一个目标文件中所有可打印的字符串。

●STRIP:从目标文件中删除符号表信息。

●NM:列出一个目标文件的符号表中定义的符号。

●SIZE:查看目标文件、库或可执行文件中各段及其总和的大小,是 GNU 二进制工具集 GNU
Binutils 的一员

●READELF:显示一个目标文件的完整结构,包括ELF头中编码的所有信息。包含SIZE 和 
NM的功能。

●OBJDUMP:所有二进制工具之母。能够显示一个目标文件中所有的信息。它最大的作用是
反汇编.text段中的二进制指令。

Linux系统为操作共享库还提供了LDD程序:
●LDD:列出一个可执行文件在运行时所需要的共享库。

本篇文章核心内容参考自《深入理解计算机操作系统》第三版,如有侵权,联系删除。欢迎各位在评论区交流讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/81682.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

m基于ACO蚁群优化的货车运输路线规划matlab仿真,考虑车辆载重,单位运输成本等因素

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 蚁群算法是通过对自然界中真实蚂蚁的集体行为的观察,模拟而得到一种仿生优化算法,它具有很好的并行性,分布性.根据蚂蚁群体不同的集体行为特征,蚁群算法可分为受蚂蚁觅食行为启发的模型和受孵化分…

渗透学习-靶场篇-WebGoat靶场(JWT攻击)

文章目录前言一、介绍JWTJWT令牌结构获取的令牌的基本过程二、攻击方式以及靶场的搭建1.安装cWebGoat2.空加密验证攻击3.字典爆破三、认证-键值逻辑前言 本次主要学习了javaweb项目方面任意出现的一些安全问题&#xff0c;最主要的是有关于JWT身份认证上的攻击&#xff0c;并利…

es的搜索服务

1、在项目中&#xff0c;创建一个搜索服务的模块&#xff1a;search-service 2、在新创建的搜索模块中添加依赖&#xff1a; <dependencies><!--nacos--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-start…

MyBatis-Plus中的逻辑删除使用

系列文章目录 Mybatis-PlusSpringBoot结合运用_心态还需努力呀的博客-CSDN博客MyBaits-Plus中TableField和TableId用法_心态还需努力呀的博客-CSDN博客 MyBatis-Plus分页查询&#xff08;快速上手运用&#xff09;_心态还需努力呀的博客-CSDN博客_mybatis plus分页查询 MyBa…

【ESXi 7.x 升 8.x】ESXi 升级 —— 使用 ESXCLI 升级 ESXi(Offline Bundle ZIP)

目录3.1 示例 — 使用 ESXCLI 升级 ESXi&#xff08;Offline Bundle ZIP&#xff09;【目标&#xff1a;将 ESXi 6.5 U2 GA 升级为 7.0 U3f】&#xff08;1&#xff09;下载离线升级ZIP包&#xff08;2&#xff09;升级 ESXi① 查看离线包② 升级前确认ESXi版本③ 获取升级用的…

[附源码]Python计算机毕业设计大学生社团管理系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

ChatGPT教程之 01 什么是ChatGPT革命性的对话生成新工具

今天,我想揭开 ChatGPT 的神秘面纱——GANs*(生成对抗网络)的一个迷人的新应用程序,它在 AI 社区中引起了很大的轰动。 对于那些不熟悉 GAN 的人来说,它们是一种神经网络,它使用两个相互竞争的网络——一个生成器和一个鉴别器——来创建逼真的输出。生成器创建假输出,而…

Paper Note——经典Polyline类型Map论文损失函数

文章目录1. Hierarchical Recurrent Attention Networks for Structured Online Maps2. DAGMapper: Learning to Map by Discovering Lane Topology1. Hierarchical Recurrent Attention Networks for Structured Online Maps https://patrick-llgc.github.io/Learning-Deep-Le…

QT(4)-QAbstractItemView

QAbstractItemView1 说明2 常用函数2.1 交替行颜色2.1.1 alternatingRowColors2.1.2 setAlternatingRowColors2.2 autoScroll2.2.1 hasAutoScroll2.2.2 setAutoScroll2.3 autoScrollMargin2.3.1 autoScrollMargin2.3.2 setAutoScrollMargin2.4 defaultDropAction2.4.1 setDefau…

python--飞机大战

实现功能&#xff1a; 1&#xff1a;飞机的移动&#xff0c;发射子弹&#xff0c;手雷&#xff0c;生命值&#xff0c;生命条 2&#xff1a;敌飞机有3种形态&#xff08;小&#xff0c;中&#xff0c;大&#xff09;不同的飞机大小不一样&#xff0c;生命值不一样&#xff0c…

基于springboot+mybatis+mysql+vue在线订餐系统

基于springbootmybatismysqlvue在线订餐系统一、系统介绍二、功能展示1.主页(用户)2.菜单(用户)3.用户注册(用户)4.用户登陆(用户)5.我的订单(用户)6.我的购物车(用户)7.首页(管理员)8.用户管理(管理员)9.商品管理(管理员)9.订单管理(管理员)10.评论管理(管理员)三、获取源码一…

c++ 类型的转换

文章目录1. C语言中的类型转换1.1 隐式转换1.2 显示转换2. C的类型转换2.1 static_cast2.2 reinterpret_cast2.3 const_cast2.4 dynamic_cast3. 常见面试题前言&#xff1a; C给出了四种类型转换&#xff0c;这是做出的一些规范&#xff0c;为了减少隐式转换。隐式转换的问题&a…

JDK19都出来了~是时候梳理清楚JDK的各个版本的特性了【JDK14特性讲解】

JDK各个版本特性讲解-JDK14特性 一、Java14概述 Oracle在2020年3月17日宣布JAVA14 全面上市,JAVA14通过每六个月发布一次新功能,为企业和开发人员社区提供增强功能,继续了Oracle加快创新的承诺. 最新的JAVA开发工具包提供了新功能,其中包括两项备受期待的新预览功能,实例匹配的…

【Redis】分布式限流与Redis实现限流的四种方式(Redis专栏启动)

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;专注于研究 Java/ Liunx内核/ C及汇编/计算机底层原理/源码&#xff0c;就职于大型金融公司后端高级工程师&#xff0c;擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。 &#x1…

MHA高可用及故障切换

目录 一、MHA的概述 1、 MHA的概念 2&#xff0e;MHA 的组成 3&#xff0e;MHA 的特点 二、搭建 MySQL MHA的操作步骤 1、实验思路&#xff1a; 1.1、MHA架构 1.2、故障模拟 2、环境准备 3、修改 Master、Slave1、Slave2 节点的主机名 4、修改 Master、Slave1、Slav…

基于java+springboot+mybatis+vue+mysql的农产品销售商城网站

项目介绍 农产品销售成为了很多农产品商家的一项重要的创收项目。传统的销售方式采用了摆摊销售和市场的农产品的批发&#xff0c;在销售农产品方面不是很方便&#xff0c;因此采用了网络的方式进行销售。也是电子商务发展今天的一种趋势&#xff0c;建立了网站&#xff0c;前…

WebSocket——SpringBoot+Vue3+TS+SockJS+STOMP简单连接使用

WebSocket——SpringBootVue3TSSockJSSTOMP简单连接使用本文视频以及相关资源关于WebSocket文档什么时候使用WebSocketWebSocket连接头服务器返回状态码客户端使用技术Github地址npm安装为什么要安装sockjs的.d.ts文件常用方法1.连接2.关闭连接3.发送消息4.设置订阅构建1.创建w…

【Redis】Redis布隆过滤器工作原理与实战(Redis专栏启动)

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;专注于研究 Java/ Liunx内核/ C及汇编/计算机底层原理/源码&#xff0c;就职于大型金融公司后端高级工程师&#xff0c;擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。 &#x1…

判断质数复习与分解质因数

TIPS 1. 之前我们讲到比方说要得到一个整数&#xff08;十进制形式&#xff09;的每一位数字&#xff0c;就需要把这个整数先%10得到最低位的数字&#xff0c;然后呢再把这个整数/10更新一下&#xff0c;然后呢就这么循环往复直到最终这个不断更新的整数为0跳出循环。那如果这…

深度学习-神经网络(Pytorch应用)

文章目录简介卷积层池化层激活层线性层前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 简介 上图摘自网络 受生物神经网络的启发&#xff0c;每个神经元与其他神经元相连&#xff0c;当…