【深入理解计算机系统】库打桩 - 阅读笔记
文章目录
- 库打桩机制
- 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实…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...

Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...
LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用
中达瑞和自2005年成立以来,一直在光谱成像领域深度钻研和发展,始终致力于研发高性能、高可靠性的光谱成像相机,为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...