linux C 包裝函數使用

       之前在meego性能優化團隊實習的時候,爲了提升APP啓動速度,我曾計算APP調用malloc的次數和耗時,並以此數據爲依據探討內存池對軟件優化的可能性。通俗地講,我須要將某些函數的調用重定向到咱們本身定義的替代函數中來,這樣的替代函數就叫作包裝函數(wrapper function)。對malloc這個具體的場景來講咱們不只須要hack函數的調用,還要獲取本來glibc定義的「real malloc」的句柄(函數指針)以使程序正常運行下去,固然若是這一切能夠在不須要從新編譯軟件的前提下完成就更好了。html

我總結了Linux環境下包裝函數的幾種實現方法:linux

1.LD_PRELOAD+dlsym性能優化

這對組合中,LD_PRELOAD完成了hack,而dlsym能夠幫組咱們獲取到real malloc。LD_PRELOAD是一個環境變量,它能夠影響程序的運行時的連接,讓咱們指定優先加載的動態連接庫。雖然這個方法沒法hack靜態連接的符號,不過還好gcc編譯的標準C函數大多包含在動態連接庫libc.so.6中,因此這個方法仍是可行的。app

my_malloc.cide

#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
void* malloc(size_t sz) { 
    void *(*libc_malloc)(size_t) = dlsym(RTLD_NEXT, "malloc");
    printf("malloc\n");
    return libc_malloc(sz);
}

main.c函數

#include<stdio.h>
#include <malloc.h>
int main(int argc, char** argv) {
    int* ptr = (int *)malloc(sizeof(int));
    free(ptr);
    return 0;
}

gcc -o main.o -Wall -O2 main.c
gcc -o my_malloc.so -shared my_malloc.c -Wall -ldl -fPIC 
export LD_PRELOAD=/path/.../my_malloc.so
./main.o性能

注意:
1.my_malloc.c中若是不加"#define _GNU_SOURCE",編譯時報錯「RTLD_NEXT undeclared」,由於glibc不會自動使用某些GNU extensions,因此須要定義這個宏啓用這些extensions。
2.LD_PRELOAD後面的so文件必定要使用絕對路徑或者把so文件放入LD_LIBRARY_PATH指定的目錄下,不然會找不到so文件。
3.LD_PRELOAD的做用效果是全局的,使用完後要及時恢復。優化

 

2.ld --wrap指針

適用:Linuxcode

ld有一個wrap選項,linux man的解釋是:Use a wrapper function for symbol. Any undefined reference to symbol will be resolved to "__wrap_symbol". Any undefined reference to "__real_symbol" will be resolved to symbol.

void * __wrap_malloc (size_t size) {
    printf ("malloc\\n");
    return __real_malloc (size);
}

全部對malloc的調用被解析爲調用__wrap_malloc,而__real_malloc則會被解析爲原始malloc函數。這種方法在gDEBugger上獲得了實際應用,gDEBugger是一個OpenGL Profiler,它能夠給出每一個OpenGL函數的調用次數使用時間等數據,它的實現方法就是爲全部OpenGL函數定義wrapper函數,在wrapper函數中添加統計代碼。

3.GCC Malloc Hook

gcc only malloc only

參考文獻:http://www.gnu.org/s/hello/manual/libc/Hooks-for-Malloc.html 這種方法其實有很強的侷限性,只針對使用gcc編譯的malloc,realloc,free等內存管理函數。gcc定義了一批函數指針變量,例如__malloc_hook指向「malloc」實際調用的函數,初始化時先保存真正的malloc函數指針而後將本身定義的malloc函數指針賦值給__malloc_hook。

/* Prototypes for __malloc_hook, __free_hook */     
#include &lt;malloc.h&gt;          
 
/* Prototypes for our hooks.  */     
static void my_init_hook (void);     
static void *my_malloc_hook (size_t, const void *);     
static void my_free_hook (void*, const void *);          
 
/* Override initializing hook from the C library. */     
void (*__malloc_initialize_hook) (void) = my_init_hook;          
static void     my_init_hook (void)     { 
    old_malloc_hook = __malloc_hook;       
    old_free_hook = __free_hook;       
    __malloc_hook = my_malloc_hook;       
    __free_hook = my_free_hook;     
}         
static void *     my_malloc_hook (size_t size, const void *caller)     {       
    void *result;       
    /* Restore all old hooks */       
    __malloc_hook = old_malloc_hook;       
    __free_hook = old_free_hook;       
    
    /* Call recursively */       
    result = malloc (size);       
    /* Save underlying hooks */       
    old_malloc_hook = __malloc_hook;       
    old_free_hook = __free_hook;       
    /* printf might call malloc, so protect it too. */       
    printf ("malloc (%u) returns %p\\n", (unsigned int) size, result);       
    /* Restore our own hooks */       
    __malloc_hook = my_malloc_hook;       
    __free_hook = my_free_hook;       
    return result;     
}          

static void     my_free_hook (void *ptr, const void *caller)     {       
    /* Restore all old hooks */       
    __malloc_hook = old_malloc_hook;       
    __free_hook = old_free_hook;       
    
    /* Call recursively */       
    free (ptr);       
    
    /* Save underlying hooks */       
    old_malloc_hook = __malloc_hook;       
    old_free_hook = __free_hook;       
    
    /* printf might call free, so protect it too. */       
    printf ("freed pointer %p\\n", ptr);       
    /* Restore our own hooks */       
    __malloc_hook = my_malloc_hook;       
    __free_hook = my_free_hook;     
}          

int main ()     {       ...     }
相關文章
相關標籤/搜索