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 ()     {       ...     }
相关文章
相关标签/搜索