先貼程式:
// RLTD_NEXT is only supported in _GNU_SOURCE. #define _GNU_SOURCE #include <stdio.h> #include <dlfcn.h> void *malloc(size_t size) { void* (*m)(size_t); // 「標準」取得 function pointer 的寫法. 見 TLPI 42.1.2 p863 的說明 *(void**)(&m) = dlsym(RTLD_NEXT, "malloc"); printf("local malloc\n"); return m(size); } int main(void) { int *t = malloc(sizeof(int)); *t = 3; printf("%d\n", *t); return 0; }
編譯和執行結果:
$ gcc m.c -ldl -o m $ nm m | grep malloc 0000000000400604 T malloc $ ./m local malloc 3
若去掉 malloc(), 加上 #include stdlib.h, 用 nm 看則是:
$ nm m | grep malloc U malloc@@GLIBC_2.2.5
表示在 m 裡面沒有定義 malloc, 它存在 glibc 裡。malloc 後面的 "@@GLIBC_2.2.5" 是 version tag。當 shared library 裡有多個版本 malloc 時, 可用 version tag 來區別要用的是那一個 malloc, 詳情見 TLPI 42.3.2。
這裡的關鍵是 glibc 定義了擴充功能 — 假的 library handle: RTLD_DEFAULT 和 RTLD_NEXT。用前者取函式 (變數) 就和原本 ld.so 找 symbol 的方式一樣; 而後者則會找「下一個」, 這是針對實作 wrapper 的需求而定的。
由於是 glibc 的擴充, 編譯時要在開頭加上 #define _GNU_SOURCE 或在命令列加 -D_GNU_SOURCE, dlfcn.h 才會載入 RTLD_NEXT。關於 _GNU_SOURCE 的說明, 見《讀懂函式庫的 man page》。
沒有留言:
張貼留言