這邊是聽jserv 的線上講座你所不知道的 C 語言:動態連結器篇 才知道的方式
爲了怕忘記做些測試候的記錄
這邊用的範例也是base on jserv的範例做修改測試

LD_PRELOAD

透過在執行檔案之前加上 LD_PRELOAD=xxx.so 可以將後面執行程式所呼叫的function取代成xxx.so內的function
也就是我們可以做到替換libc內的函式 改成我們自己的 當程式執行時

github 上面也有人寫相關資料

測試

目標是將malloc and free 替換成自己的library 當執行測試檔時,code 的內容如下

malloc_count.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stddef.h>
#include <dlfcn.h>
void *malloc(size_t size)
{
char buf[32];
static void *(*real_malloc)(size_t) = NULL;
if (real_malloc == NULL) {
real_malloc = dlsym(RTLD_NEXT, "malloc");
}
sprintf(buf, "malloc called, size = %zu\n", size);
write(2, buf, strlen(buf));
return real_malloc(size);
}
void *free(void *ptr)
{
char buf[32];
static void *(*real_free)(void *ptr) = NULL;
if (real_free == NULL) {
real_free = dlsym(RTLD_NEXT, "free");
}
sprintf(buf, "free called, ptr address = %x\n", ptr);
write(2, buf, strlen(buf));
real_free(ptr);
}

test.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main(void)
{
char *buffer;
buffer = malloc(sizeof(char)*10);
memset(buffer, 0x41, 10);
puts(buffer);
free(buffer);
buffer = NULL;
free(buffer);
}

編譯command :
原本用的command 跟講座上面是一樣的

1
gcc -D_GNU_SOURCE -Wall -shared -ldl -fPIC -o libmcount.so malloc_count.c

編譯之後透過ls測試也是可以跑的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
memory_test$ LD_PRELOAD=libmcount.so ls
malloc called, size = 568
malloc called, size = 120
free called, ptr address = 136a250
free called, ptr address = 136a010
free called, ptr address = 0
malloc called, size = 5
free called, ptr address = 136a010
malloc called, size = 120
malloc called, size = 12
malloc called, size = 784
malloc called, size = 112
malloc called, size = 952
malloc called, size = 216

但是跑test 測試程式會出現library 找不到的問題

1
2
3
gcc -o test test.c
memory_test$ LD_PRELOAD=libmcount.so ./test
./test: symbol lookup error: libmcount.so: undefined symbol: dlsym

透過ldd 發現缺少dl library

檢查ls and test 執行檔 可以發現ls有linker ld library但是test沒有, 這也是爲何ls可以跑

猜測因該是compiler最佳化之後將librar去除掉了 查看網路上有人說-ldl拉到最後面就可以
修改後做測試確定test可以跑了

1
gcc -D_GNU_SOURCE -Wall -shared -fPIC -o libmcount.so malloc_count.c -ldl

<注意>

  1. lbrary compiler時需要加上-D_GNU_SOURCE 是因爲library有用到RTLD_NEXT
  2. free pointer 之後需要將pointer 設爲null 這樣在後面如果不小心再free 到時才不會有double free message
    double free or corruption
    C手冊上面有這一段