由于有事导致这一章很久才开始看,这一章由于没有对应的实验,所以我一边看书一边复现书上的编译链接过程,本篇文章算是复现过程记录吧
编译到链接的基本过程
最后一步应该是需要加很多 [system object files and args]
才能链接成功
符号和符号表
练习题7.1
符号解析
函数和已初始化的全局变量是强符号,未初始化的全局变量是弱符号。
Linux 链接器使用下面的规则来处理多重定义的符号名:
- 规则1:不允许出现多个同名的强符号
- 规则2:如果有一个强符号和多个弱符号同名,那么选择强符号
- 规则3:如果有多个弱符号同名,那么从这些弱符号中任意选择一个
静态链接库
重定位
加载
动态链接库
库打桩机制
编译时打桩
链接时打桩
运行时打桩
在 WSL 上复现不成功呢
在 Ubuntu20.04 的服务器上也 GG
问题解决参考了这篇 CSAPP第三版运行时打桩Segmentation fault
原因大概是因为循环递归调用,包装函数 malloc
中使用了 printf
,而 printf
本身又会调用 malloc
,这样就造成了无限循环递归,所以 RE 了,解决办法是在代码里面加一个静态计数变量 malloc_count
,仅仅在 malloc_count=1
时才调用 printf
,修改后的代码如下:
/* $begin interposer */
#ifdef RUNTIME
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
/* malloc wrapper function */
void *malloc(size_t size)
{
static int malloc_count = 0;
void *(*mallocp)(size_t size);
char *error;
++malloc_count;
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 */
if(malloc_count == 1) {
printf("malloc(%d) = %p\n", (int)size, ptr);
}
malloc_count = 0;
return ptr;
}
/* free wrapper function */
void free(void *ptr)
{
void (*freep)(void *) = NULL;
char *error;
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
/* $end interposer */
这样就成功实现运行时打桩了
Comments | NOTHING