2012年1月29日 星期日

使用 RTLD_NEXT 實作 wrapper

先貼程式:

// 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》

沒有留言:

張貼留言

在 Fedora 下裝 id-utils

Fedora 似乎因為執行檔撞名,而沒有提供 id-utils 的套件 ,但這是使用 gj 的必要套件,只好自己編。從官網抓好 tarball ,解開來編譯 (./configure && make)就是了。 但編譯後會遇到錯誤: ./stdio.h:10...