CSAPP:第 7 章 链接

发布于 18 天前  17 次阅读


由于有事导致这一章很久才开始看,这一章由于没有对应的实验,所以我一边看书一边复现书上的编译链接过程,本篇文章算是复现过程记录吧

编译到链接的基本过程

image-20230114120727381

image-20230114120554006

最后一步应该是需要加很多 [system object files and args] 才能链接成功

image-20230114120804915

符号和符号表

image-20230114122822229

image-20230114190241943

image-20230114190256195

image-20230114122805377

练习题7.1

image-20230114124902140

符号解析

函数和已初始化的全局变量是强符号,未初始化的全局变量是弱符号。

Linux 链接器使用下面的规则来处理多重定义的符号名:

  • 规则1:不允许出现多个同名的强符号
  • 规则2:如果有一个强符号和多个弱符号同名,那么选择强符号
  • 规则3:如果有多个弱符号同名,那么从这些弱符号中任意选择一个

静态链接库

image-20230114190425911

image-20230114135409922

重定位

image-20230114154134137

加载

image-20230114154806894

动态链接库

image-20230114155424568

image-20230114160440908

库打桩机制

编译时打桩

image-20230114162333381

链接时打桩

image-20230114164133742

运行时打桩

在 WSL 上复现不成功呢

image-20230114175706274

在 Ubuntu20.04 的服务器上也 GG

image-20230114175600143

问题解决参考了这篇 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 */

这样就成功实现运行时打桩了

image-20230114181457013


昨日的月光悄然退场,曦阳已经渐亮