so 库加载 __attribute__((constructor))

本文介绍了如何使用GCC和dlopen、dlsym等函数进行动态库生成与加载的实践,包括动态库的创建、使用及卸载过程,并通过代码示例进行了详细演示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


动态库生成: 

gcc -Wall -shared -fPIC -o libss.so libss.c // 库名和源文件自定义


动态加载:

#include <dlfcn.h>


       void *dlopen(const char *filename, int flag); // filename 动态库名(如libss.so),flag为 RTLD_NOW 或 RTLD_LAZY,RTLD_NOW 库中的所有函数在dlopen返回前都加载,

                                                                     // RTLD_LAZY 库中的函数在用时才加载


       char *dlerror(void);  // dlopen dlsym dlclose的执行若有错误,返回描述错误的字符串


       void *dlsym(void *handle, const char *symbol); //返回函数指针


       int dlclose(void *handle); // 卸载库


       Link with -ldl.


例:

udlopen.c

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

int main(int argc, char **argv)
{
	void (*print)();
	int (*add)(int, int);
	void *handle;
	
	if (argc < 2)
		return -1;
	
	handle = dlopen(argv[1], RTLD_LAZY);
	if (!handle) {
		printf("dlopen failed: %s\n", dlerror());
		return -1;
	}
	
	print = dlsym(handle, "print");
	if (!print) {
		printf("dlsym failed: %s\n", dlerror());
		return -1;
	}
	print();
	
	add = dlsym(handle, "add");
	if (!add) {
		printf("dlsym failed: %s\n", dlerror());
		return -1;
	}
	add(1, 2);
	
	dlclose(handle);
	
	return 0;
}

libss.c

#include <stdio.h>
#include <string.h>

void print() 
{
	printf("I am print\n");
}

int add(int a, int b)
{
	printf("Sum %d and %d is %d\n", a, b, a + b);
	return 0;
}
//static void king() __attribute__((constructor(101))); the following is also right
static __attribute__((constructor(101))) void king()
{
	printf("I am king\n");
}


编译执行:
gcc -Wall -shared -fPIC -o libss.so libss.c -ldl

gcc -Wall -o udlopen udlopen.c

./udlopen libss.so

I am king
I am print
Sum 1 and 2 is 3


### LD_PRELOAD 的使用方法及案例 #### 一、概述 `LD_PRELOAD` 是 Linux 系统中的一个环境变量,用于指定在程序启动时优先加载的共享(`.so` 文件)。通过 `LD_PRELOAD`,可以覆盖标准函数的行为或者实现特定的功能扩展。它的工作原理是在程序运行之前,先加载由该变量指向的一个或多个 `.so` 动态链接[^1]。 #### 二、工作流程 当设置好 `LD_PRELOAD` 后,在程序执行过程中会按照以下顺序加载动态链接: - 首先是 `LD_PRELOAD` 中指定的共享; - 接着是通过 `LD_LIBRARY_PATH` 指定路径下的共享; - 再之后是从 `/etc/ld.so.cache` 缓存中查找的标准; - 如果仍未找到,则依次从默认目录 `/lib` 和 `/usr/lib` 加载[^3]。 这种机制使得开发者可以在不修改原程序的情况下,替换掉某些系统调用或其他功能的具体实现方式。 #### 三、实际应用示例 ##### 示例 1:简单重写 printf 函数行为 下面是一个简单的例子来展示如何使用 `LD_PRELOAD` 修改 C 中的 `printf()` 行为: ```c // my_printf.c #include <stdio.h> void __attribute__((constructor)) init() { fprintf(stderr, "[Hooked] Library loaded\n"); } int printf(const char *format, ...) { va_list args; int result; va_start(args, format); result = vfprintf(stdout, format, args); // 调用原始版本打印消息 va_end(args); fprintf(stderr, "[Hooked] Printf called with '%s'\n", format); // 添加额外日志记录 return result; } ``` 编译上述代码并将其作为预加载使用: ```bash gcc -shared -o libmyprintf.so -fPIC my_printf.c export LD_PRELOAD=./libmyprintf.so ./your_program_with_printfs ``` 此时每当目标可执行文件调用了 `printf` 方法时都会触发我们自定义的日志逻辑[^2]。 ##### 示例 2:基于 LD_PRELOAD 实现内存泄漏检测工具 另一个更复杂的场景涉及构建自己的调试辅助工具——比如监控进程内的内存分配情况以便发现潜在问题。这里给出简化版操作指南如下所示: 1. **编写拦截 malloc/free 的 .so 文件** 创建一个新的源码文件 `malloc_hook.c` ,其中包含对 `malloc` 及其他相关函数的重新定义。 ```c /* malloc_hook.c */ #include <dlfcn.h> #include <stdio.h> #include <stdlib.h> typedef void* (*MallocFunc)(size_t size); static MallocFunc real_malloc = NULL; void* malloc(size_t size){ if (!real_malloc) { real_malloc = dlsym(RTLD_NEXT,"malloc"); } void *ptr = real_malloc(size); FILE *log_file = fopen("/tmp/memtrace.log","a+"); fprintf(log_file,"%p allocated %zu bytes.\n", ptr,size); fclose(log_file); return ptr; } ``` 2. **生成对应的 so 文件** 将此脚本转换成适合被加载的形式 ```bash gcc -Wall -fPIC -shared -o libmemhook.so malloc_hook.c -ldl ``` 3. **配置环境变量并测试** 设置必要的参数让待测软件能够识别新的规则集 ```bash export LD_PRELOAD=/path/to/libmemhook.so ./application_under_test cat /tmp/memtrace.log ``` 这样即可获得关于每次申请堆空间的信息汇总表单[^4]。 #### 四、注意事项 尽管 `LD_PRELOAD` 提供了许多便利之处,但也存在一定的安全隐患。如果恶意用户滥用这一特性就可能造成权限提升等问题因此建议仅限于受控环境下运用此类技巧。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值