【深入理解计算机系统】库打桩 - 阅读笔记
文章目录
- 库打桩机制
- 1. 编译时打桩
- 2. 链接时打桩
- 3. 运行时打桩
库打桩机制
Linux 链接器支持一个很强大的技术,称为库打桩 (library interpositioning),它允许你截获对共享库函数的调用,取而代之执行自己的代码。使用打桩机制,你可以追踪对某个特殊库函数的调用次数,验证和追踪它的输入和输出值,或者甚至把它替换成一个完全不同的实现。
下面是它的基本思想:给定一个需要打桩的目标函数,创建一个包装函数,它的原型与目标函数完全一样。使用某种特殊的打桩机制,你就可以欺骗系统调用包装函数而不是目标函数了。包装函数通常会执行它自己的逻辑,然后调用目标函数,再将目标函数的返回值传递给调用者。
打桩可以发生在编译时、链接时或当程序被加载和执行的运行时。
需求: 我们需要在主程序main.c中跟踪对库函数malloc和free的使用情况。(下面3种打桩以这个为例子)
1. 编译时打桩
编译时打桩的本质就是借助#define
预处理指令,让预处理器在预处理阶段帮助我们替换malloc
为我们自己实现的mymalloc
,这就是编译时打桩。
• mymalloc.c
建立mymalloc.c文件, 定义需要的包装函数mymalloc和myfree。
#ifdef COMPILETIME
#include <stdio.h>
#include <malloc.h>//定义malloc 包装函数
void *mymalloc(size_t size)
{void *ptr = malloc(size);printf("my_malloc:%d=%p\n", (int)size, ptr);return ptr;
}//定义free 包装函数
void *myfree(void *ptr)
{free(ptr);printf("my_free:%p\n", ptr);
}#endif
• malloc.h
该文件向预处理器指明用mymalloc.c中的包装函数替换库里的目标函数。
#define malloc(size) mymalloc(size)
#define free(ptr) myfree(ptr)void *mymalloc(size_t size);
void *myfree(void *ptr);
• main.c
#include <stdio.h>
#include <malloc.h>int main()
{int *p = malloc(32);free(p);return 0;
}
编译指令:
gcc -DCOMPILETIME -c mymalloc.c
gcc -I. main.c mymalloc.o -o main
-D
选项: 指定宏参数,设置COMPILETIME
宏。
-I.
选项: 指示C预处理器在搜索通常的系统目录前,先在当前目录中查找malloc.h
运行程序可得到下面的结果:
[wqj@VM-0-15-centos compile]$ ./main
my_malloc:32=0xfb8010
my_free:0xfb8010
2. 链接时打桩
Linux的静态连接器支持使用--wrap f
标志进行链接时打桩。这个标志告诉链接器,请把符号f
的引用解析为__wrap_f
,并且将对符号__real_f
的引用解析为f
。
举个栗子:
--wrap malloc
<==> 将符号malloc
的引用解析为__wrap_malloc
,将__real_f
的引用解析为malloc
。
这就使得,用户在使用malloc
接口时,malloc
的引用被解析为了__wrap_malloc
,因此程序会去调用__wrap_malloc
。在__wrap_malloc
中,我们可以再去调用__real_malloc
方法,此时就会真正的去调用malloc
方法。而我们也可以在__wrap_malloc
方法中添加或修改一些额外的信息。(当然也可以完全实现一个自己的方法,不去调用__real_malloc
)
注意: 在Linux指令当中,我们使用的是下面的形式的:
linux> gcc -Wl,--wrap,malloc -Wl,--wrap,free -o main main.o mymalloc.o
这里的--wrap,malloc
中的,
会被翻译为空格。每一个函数的替换单位就是-Wl,--wrap,f
。
• mymalloc.c
#ifdef LINKTIME
#include <stdio.h> void* __real_malloc(size_t size);
void __real_free(void* ptr); void* __wrap_malloc(size_t size)
{ void* ptr = __real_malloc(size); //call libc's malloc printf("mymalloc:%d=%p\n", (int)size, ptr); return ptr;
} void __wrap_free(void* ptr)
{ __real_free(ptr); //call libc's free printf("myfree:%p\n", ptr);
}
#endif
main.c文件同1.编译时打桩的main.c
编译指令:
gcc -DLINKTIME -c mymalloc.c
gcc -c main.c
gcc -Wl,--wrap,malloc -Wl,--wrap,free -o main main.o mymalloc.o
-Wl,option
标志把 option
传递给链接器。option
中的每个逗号都要替换为一个空格。所以 -Wl,--wrap,malloc
就把 --wrap malloc
传递给链接器,以类似的方式传递 -Wl,--wrap,free
。
运行结果:
[wqj@VM-0-15-centos link]$ ./main
mymalloc:32=0x1fee010
myfree:0x1fee010
3. 运行时打桩
运行时打桩主要依靠动态链接器的LD_PRELOAD
环境变量。如果LD_PRELOAD
环境变量被设置为一个动态库的路径名的列表(以空格或分隔间隔的列表, 一个元素也可以),那么当你加载和执行一个程序,需要解析未定义的引用时,动态链接器会优先搜索LD_PRELOAD
库,然后才会去搜索其它的库。
有了上面这个机制,当你加载和执行任意的可执行文件时,可以对任何动态库的任何函数打桩,包括libc.so
。
• mymalloc.c
#ifdef RUNTIME
#define _GNU_SOURCE //定义GUN宏,允许你使用一些被限制的特性(feature)
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h> //malloc wrapper function
void* malloc(size_t size)
{ void* (*malloc_ptr)(size_t size); char* error; malloc_ptr = dlsym(RTLD_NEXT, "malloc"); //Get Address of libc malloc if((error = dlerror()) != NULL){ fprintf(stderr, "%s\n", error); exit(1); } void* ptr = malloc_ptr(size); printf("my_malloc:%d=%p\n",(int)size, ptr); return ptr;
} //free wrapper function
void free(void* ptr)
{ void (*free_ptr)(void*) = NULL; char* error; if(!ptr){ return; } free_ptr = dlsym(RTLD_NEXT, "free"); //Get Address of libc free if((error = dlerror()) != NULL){ fprintf(stderr, "%s\n", error); exit(2); } free_ptr(ptr); printf("my_free:%p\n", ptr);
}
#endif
main.c文件同1.编译时打桩的main.c
编译指令:
gcc -DRUNTIME -shared -fPIC mymalloc.c -o libmymalloc.so -ldl
gcc main.c -o main
运行指令:
[wqj@VM-0-15-centos running]$ LD_PRELOAD="./libmymalloc.so" ./main
my_malloc:32=0x1d85010
my_free:0x1d85010
或者
[wqj@VM-0-15-centos running]$ (setenv LD_PRELOAD "./libmymalloc.so"; ./main; unsetenv LD_PRELOAD)
my_malloc:32=0x1d85010
my_free:0x1d85010
上面的那种是设置本地变量LD_PRELOAD
,下面的则是设置环境变量LD_PRELOAD
。本地变量与环境变量的区别见Linux详解 — 进程管理2 (进程状态、环境变量与命令行参数)
相关文章:
【深入理解计算机系统】库打桩 - 阅读笔记
文章目录库打桩机制1. 编译时打桩2. 链接时打桩3. 运行时打桩库打桩机制 Linux 链接器支持一个很强大的技术,称为库打桩 (library interpositioning),它允许你截获对共享库函数的调用,取而代之执行自己的代码。使用打桩机制,你可以…...

RocketMQ高性能原理分析
目录一、读队列与写队列1.概念介绍2.读写队列个数关系分析二、消息持久化1.持久化文件介绍2.持久化结构介绍:三、过期文件删除1.如何判断文件过期2.什么时候删除过期文件四、高效文件写1.零拷贝技术加速文件读写2.文件顺序写3.刷盘机制五、 消息主从复制六、负载均衡…...

前端面试当中CDN会问啥------CDN详细教程来啦
⼀、CDN 1. CDN的概念 CDN(Content Delivery Network,内容分发⽹络)是指⼀种通过互联⽹互相连接的电脑⽹络系统,利 ⽤最靠近每位⽤户的服务器,更快、更可靠地将⾳乐、图⽚、视频、应⽤程序及其他⽂件发送给⽤户&…...
刷题记录:牛客NC19429红球进黑洞 区间拆位异或+区间求和
传送门:牛客 题目描述: 区间求和区间异或k 输入: 10 10 8 5 8 9 3 9 8 3 3 6 2 1 4 1 1 2 6 2 9 10 8 1 1 7 2 4 7 8 2 8 8 6 2 2 3 0 1 1 2 2 9 10 4 1 2 3 输出: 33 50 13 13一道区间求和区间异或的题目,可以称得上是线段树的一道好题 首先对于异或运算来说,并不满足…...
信息数智化招采系统源码——信息数智化招采系统
信息数智化招采系统 服务框架:Spring Cloud、Spring Boot2、Mybatis、OAuth2、Security 前端架构:VUE、Uniapp、Layui、Bootstrap、H5、CSS3 涉及技术:Eureka、Config、Zuul、OAuth2、Security、OSS、Turbine、Zipkin、Feign、Monit…...

20230217使AIO-3399J开发板上跑通Android11系统
20230217使AIO-3399J开发板上跑通Android11系统 2023/2/17 15:45 1、解压缩SDK:rk3399-android-11-r20211216.tar.xzrootrootrootroot-X99-Turbo:~$ tar xvf rk3399-android-11-r20211216.tar.xz 2、编译U-boot: rootrootrootroot-X99-Turbo:~/rk3399-a…...

Java 基础面试题——面向对象
目录1.面向对象和面向过程有什么区别?2.面向对象的有哪些特征?3.静态变量和实例变量有什么区别?4.Java 对象实例化顺序是怎样的?5.浅拷贝和深拷贝的区别是什么?5.1.浅拷贝5.2.深拷贝5.3.总结6.Java 中创建对象的方式有哪几种&…...
PDF文件替换内容(电子签章),依赖免费pdfbox
首先提前准备,压入如下依赖 <!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox --> <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId>…...

nvm 控制 node版本
nvm 官网 https://nvm.uihtm.com/ 1、卸掉nodejs,根据官网操作 2、如果之前安装过的nodejs,且安装的目录改变了,需重新配置系统环境 第一步:打开此电脑 > 右键属性 > 高级系统设置 > 环境变量 第二步: 在系统变量中选中…...

javaEE 初阶 — 传输层 TCP 协议中的异常情况与面向字节流的粘包问题
文章目录1 粘包问题1.1 什么是粘包问题1.2 如何解决粘包问题2 异常情况TCP 的十个特性:确认应答机制 超时重传机制 连接管理机制 滑动窗口 流量控制与拥塞控制 延迟应答与捎带应答 1 粘包问题 1.1 什么是粘包问题 面向字节流引入了一个比较麻烦的粘包问题。 …...

IP路由基础
——IP路由基础(IA)—— HCIA全套笔记已经上线(arpAAAvlanTrunk链路聚合vlan间通信ACL广域网技术以太网交换...........)_孤城286的博客-CSDN博客 目录 ——IP路由基础(IA)—— (1&#…...

12.centos7部署sonarqube9.6
12.centos7部署sonarqube9.6环境:sonarqube9.6Postgresql13JDK11sonarqube9.6下载地址:Postgresql13 rpm下载地址:JDK11下载地址:准备工作:修改文件句柄数(最大文件数)和用户最大进程数限制修改…...
大学四年自学Java编程,现在拿到28万年薪的offer,还是觉得挺值的
最近刚拿到美团的Java后端工程师的offer,(底薪、奖金、补贴、年终奖、五险一金)总包加在大概有28万的年薪,实际到手不会有这么多,但是我对于这个待遇还是非常满意的。说来还是非常的感慨,我属于那种从大一到…...

MySQL的日志详解
目录 一.介绍 日志分类 二.错误日志 三.二进制日志—binlog 概述 日志格式 操作 四.查询日志 五.慢查询日志 一.介绍 在任何一种数据库中,都会有各种各样的日志,记录着数据库工作的方方面面,以帮助数据库管理员追踪数据库曾经发生过的…...
输出该股票所有收盘比开盘上涨3%以上的日期
1:输出该股票所有收盘比开盘上涨3%以上的日期 #codingutf-8 import tushare as ts import pandas as pd import numpy as np#获取某支股票的历史行情数据 dfts.get_hist_data(code600519,start2001-01-01) #将互联网上的数据获取并且存储到本地 df.to_csv(./maotai…...

数值卡,让数据可视化玩出新花样丨三叠云
数值卡 路径 仪表盘 >> 仪表盘设计 功能简介 1. 数值卡增加「数值标题」、「图标」、「进度条」功能,使得应用场景更为广泛,实现数据可视化,让用户能够轻松地获取、处理信息。 2.「数据模型」支持0个维度1个指标、1个维度1个指标。…...

有这几个表现可能是认知障碍前兆
我国目前对于认知障碍的认知率、就诊率、诊断率很低,然而认知障碍如果能在早期发现,并及时治疗,生活质量会有效提高,缓解家属的精神和经济负担。所以,认知障碍的前兆一定要了解。1.记忆力减退,一周内的重要…...

java面试题-阿里真题详解
前言 大家好,我是局外人一枚,最近有不少粉丝去阿里巴巴面试了,回来之后总结不少难题给我,以下是面试的真题,跟大家一起来讨论怎么回答。 阿里一面 1、说⼀下ArrayList和LinkedList区别 ⾸先,他们的底层数…...
JSON格式解析关键词搜索API
为了进行此平台API的调用,首先我们需要做下面几件事情。 1、 获取一个KEY。 2、 参考API文档里的接入方式和示例。 3、查看测试工具是否有需要的接口,响应实例的返回字段是否符合参数要求。 4、利用平台的文档中心和API测试工具,对接口进…...

【Java基础】泛型(二)-泛型的难点:通配符
本文将尝试将通配符和泛型中的继承,多态一并讲解 关于泛型中继承的注意事项 因为Integer、Double继承了Number,根据多态性,以下语句是合法的 Number n new Integer(10); // OK, 父类引用变量可以指向子类对象 n 2.9 // OK,n实…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...
6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础
第三周 Day 3 🎯 今日目标 理解类(class)和对象(object)的关系学会定义类的属性、方法和构造函数(init)掌握对象的创建与使用初识封装、继承和多态的基本概念(预告) &a…...

五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...

云安全与网络安全:核心区别与协同作用解析
在数字化转型的浪潮中,云安全与网络安全作为信息安全的两大支柱,常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异,并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全:聚焦于保…...
【Ftrace 专栏】Ftrace 参考博文
ftrace、perf、bcc、bpftrace、ply、simple_perf的使用Ftrace 基本用法Linux 利用 ftrace 分析内核调用如何利用ftrace精确跟踪特定进程调度信息使用 ftrace 进行追踪延迟Linux-培训笔记-ftracehttps://www.kernel.org/doc/html/v4.18/trace/events.htmlhttps://blog.csdn.net/…...
【java】【服务器】线程上下文丢失 是指什么
目录 ■前言 ■正文开始 线程上下文的核心组成部分 为什么会出现上下文丢失? 直观示例说明 为什么上下文如此重要? 解决上下文丢失的关键 总结 ■如果我想在servlet中使用线程,代码应该如何实现 推荐方案:使用 ManagedE…...
在Spring Boot中集成RabbitMQ的完整指南
前言 在现代微服务架构中,消息队列(Message Queue)是实现异步通信、解耦系统组件的重要工具。RabbitMQ 是一个流行的消息中间件,支持多种消息协议,具有高可靠性和可扩展性。 本博客将详细介绍如何在 Spring Boot 项目…...
[QMT量化交易小白入门]-六十二、ETF轮动中简单的评分算法如何获取历史年化收益32.7%
本专栏主要是介绍QMT的基础用法,常见函数,写策略的方法,也会分享一些量化交易的思路,大概会写100篇左右。 QMT的相关资料较少,在使用过程中不断的摸索,遇到了一些问题,记录下来和大家一起沟通,共同进步。 文章目录 相关阅读1. 策略概述2. 趋势评分模块3 代码解析4 木头…...

STM32 低功耗设计全攻略:PWR 模块原理 + 睡眠 / 停止 / 待机模式实战(串口 + 红外 + RTC 应用全解析)
文章目录 PWRPWR(电源控制模块)核心功能 电源框图上电复位和掉电复位可编程电压监测器低功耗模式模式选择睡眠模式停止模式待机模式 修改主频一、准备工作二、修改主频的核心步骤:宏定义配置三、程序流程:时钟配置函数解析四、注意…...