記事ディレクトリ
1はじめに
ライブラリパイルテクノロジーは、共有ライブラリ関数への呼び出しを傍受できます。アプリケーションでは、関数呼び出しの入力値と出力値を制御したり、関数呼び出しを独自のロジックに置き換えたりすることができます。
基本的な考え方:コンパイル時関数またはリンク時関数シンボルによって実装された検索メカニズムを介して、ターゲット関数と同じプロトタイプでラッパー関数を作成します実行時に動的リンクライブラリの検索メカニズムまたはロードメカニズムを分析し、ターゲット関数をカスタムラッパー関数に置き換えます。
2.テスト環境
システム環境:Ubuntu14.04
Gccバージョン:gccバージョン4.8.4(Ubuntu 4.8.4-2ubuntu1〜14.04.4)
3.コンパイル時に積み上げる
3.1。関連文書
3.1.1.main.c
#include <stdio.h>
#include <malloc.h>
int main()
{
size_t len = 10;
char * msg = calloc(1,len);
snprintf( msg,len,"%s","aloha");
printf("msg:%s\n",msg);
free(msg);
msg = 0;
return 0;
}
3.1.2.newcalloc.h
#define calloc(nmemb,size) newcalloc(nmemb,size)
#define free(ptr) newfree(ptr)
void *newcalloc(size_t nmemb, size_t size);
void newfree(void *ptr);
3.1.3.newcalloc.c
#include <stdio.h>
#include <malloc.h>
void *newcalloc(size_t nmemb, size_t size)
{
static int _newcalloc_calltime = 0;
++_newcalloc_calltime;
printf("calloc ptr(%d,%d) ,call times=%d\n",nmemb,size,_newcalloc_calltime);
void * ptr = calloc( nmemb,size);
printf("calloc return=%p\n",ptr);
return ptr;
}
void newfree(void *ptr)
{
static int _newfree_calltime = 0;
++_newfree_calltime;
free(ptr);
printf("free(%p),call times =%d\n",ptr,_newfree_calltime);
}
3.2。コンパイルコマンド
gcc -m32 -g -c newcalloc.c;
gcc -m32 -g -I。- o main main.c newcalloc.o;
./main
注:テスト状況から、ここでは-Iコンパイルオプションが指定されていないため、を押すことができます。実行されることを期待します。つまり、main.cの山括弧に含まれている場合でも、最初に現在のディレクトリから検索されます。
3.3。実行ステータスと実行コマンド
calloc ptr(1,10)、call times = 1
calloc return = 0x8734008
msg:aloha
free(0x8734008)、call times = 1
3.4。説明
1.コンパイル中にパイルするには、ソースコードにアクセスする必要があります。基本的に、最初に独自のラッパー関数を定義し、ラッパー関数で標準のターゲットメソッドを呼び出して、再配置可能なファイルを生成します。次に、マクロ定義によって変換されたヘッダーファイルを定義します(名前は、パイルする関数が配置されているヘッダーファイルと同じです)。gccがコンパイルされると、同じ名前のヘッダーファイルが最初にローカルで検索され、ラッパー関数が呼び出されます
。パッケージファイルnewcalloc.cのコンパイルは個別にコンパイルする必要があり、マクロ定義変換のヘッダーファイルと同じディレクトリにコンパイルすることはできません。そうしないと、ループネストされた再帰呼び出しになり、最終的にプログラム例外が発生します。
4.コンパイル時に積み上げる
4.1。関連文書
4.1.1.main.c
#include <stdio.h>
#include <malloc.h>
int main()
{
size_t len = 10;
char * msg = calloc(1,len);
snprintf( msg,len,"%s","aloha");
printf("msg:%s\n",msg);
free(msg);
msg = 0;
return 0;
}
4.1.2。newcalloc.c
#include <stdio.h>
//#include <stdlib.h>
void * __real_calloc(size_t nmemb, size_t size);
void __real_free(void *ptr);
void * __wrap_calloc(size_t nmemb, size_t size)
{
static int _newcalloc_calltime = 0;
++_newcalloc_calltime;
printf("calloc ptr(%d,%d) ,call times=%d\n",nmemb,size,_newcalloc_calltime);
void * ptr = __real_calloc( nmemb,size);
printf("calloc return=%p\n",ptr);
return ptr;
}
void __wrap_free(void *ptr)
{
static int _newfree_calltime = 0;
++_newfree_calltime;
__real_free(ptr);
printf("free(%p),call times =%d\n",ptr,_newfree_calltime);
}
4.2。コマンドをコンパイルしてコマンドを実行する
gcc -m32 -g -c newcalloc.c;
gcc -m32 -g -c main.c;
gcc -m32 -Wl、–wrap、calloc -Wl、–wrap、free -o main main.o newcalloc.o;
。/メイン
4.3。操作
calloc ptr(1,10)、call times = 1
calloc return = 0x840b008
msg:aloha
free(0x840b008)、call times = 1
4.4。説明
1.コンパイル中のパイルには、再配置可能なオブジェクトファイルへのアクセスが必要です
。2。静的リンカーは-wrap fオプションを使用したパイルをサポートします。つまり、シンボルfへの参照を__wrap_fに解析し、シンボル__real_fへの参照を解析します。 fに。
5.運転中の積み上げ
5.1。関連文書
5.1.1.main.c
#include <stdio.h>
#include <malloc.h>
int main()
{
size_t len = 10;
char * msg = calloc(1,len);
snprintf( msg,len,"%s","aloha");
printf("msg:%s\n",msg);
free(msg);
msg = 0;
return 0;
}
5.1.2.newcalloc.c
#include <stdio.h>
#include <stdlib.h>
#define __USE_GNU
#include <dlfcn.h>
//#define _GNU_SOURCE
void * calloc(size_t nmemb, size_t size)
{
void * (*callocp)(size_t nmemb, size_t size);
char * error;
callocp = dlsym(RTLD_NEXT,"calloc");
if((error=dlerror())!=NULL)
{
printf("dlsym calloc error,msg:%s\n",error);
exit(1);
}
static int _newcalloc_calltime = 0;
++_newcalloc_calltime;
printf("calloc ptr(%d,%d) ,call times=%d\n",nmemb,size,_newcalloc_calltime);
void * ptr = callocp( nmemb,size);
printf("calloc return=%p\n",ptr);
return ptr;
}
void free(void *ptr)
{
void (*freep)(void *ptr);
char * error;
freep = dlsym(RTLD_NEXT,"free");
static int _newfree_calltime = 0;
++_newfree_calltime;
freep(ptr);
printf("free(%p),call times =%d\n",ptr,_newfree_calltime);
}
5.2。コマンドをコンパイルしてコマンドを実行する
gcc -m32 -g -shared -fpic -o newcalloc.so newcalloc.c -ldl;
gcc -m32 -g -o main main.c;
LD_PRELOAD = "./ newcalloc.so" ./main
5.3。操作
calloc ptr(1,10)、call times = 1
calloc return = 0x8fb5008
msg:aloha
free(0x8fb5008)、call times = 1
5.4。説明
1.このメカニズムは、動的リンカーのLD_RELOAD環境変数に基づいています。プログラムをロードして実行し、未定義の参照を解決する必要がある場合、動的リンカー(LD-LINUX.SO)は最初にLD_PRELOADライブラリーを検索し、見つからない場合は他のライブラリーを検索します。
2.マクロ定義_GNU_SOURCEが機能しません。dlfcn.hファイルを表示するには、__ USE_GNU(前に定義した#include <dlfcn.h>)を使用する必要があります。
6.参考文献
「コンピュータシステムの詳細な理解」中国語版、[アメリカ] Randal E. Bryant待機、2019.3、China Machinery Industry Press