2017-06-17 9 views
1

私はstrcmpのをフックしたいと、コードは以下の通りである:linuxでLD_PRELOADを使用してstrcmpをフックしますか?

#include <stdio.h> 
#include <string.h> 


int strcmp(const char *s1, const char *s2) 
{ 
    printf("hooked strcmp\n"); 
    return 0; 
} 

// gcc test.c -shared -fPIC -o libtest.so 

#include <stdio.h> 
#include <string.h> 
#include "test.h" 

int main(int argc, char *argv[]) 
{ 
    strcmp(argv[1], "aba");   // didn't call strcmp in libtest 
    int i = strcmp(argv[1], "aba"); // call strcmp in libtest 
} 

// gcc main.c 
// LD_PRELOAD=./libtest.so ./a.out 12123 

私の質問は以下のとおりです。この二つの条件でなぜstrcmpの差分?

+0

組み込み関数が使用されていますか? – 0andriy

答えて

0

strcmpによって返された値を使用しない場合、呼び出しは何も行いません。したがってコンパイラは呼び出しを自由に削除できます。場合によっては、strcmpが何をするかを正確に知っているので、コンパイラはstrcmpへの呼び出しをインライン展開することもあります。

これは標準ライブラリヘッダで宣言されたすべての識別子(ヘッダが実際に含まれているか否か)留保規格によって容認される:任意の「外部結合を持つすべての識別子:

§ 7.1.3/1 「プログラムがそれで コンテキストで識別子を宣言または定義する場合:常に外部結合を持つ識別子として使用するために予約され

§ 7.1.3/2;次の節[すなわち標準ライブラリヘッダ]&hellipをします。 (7.1.4で許可されている以外の)&hellip;その動作は未定義です。

例外として、§ 7.1.4/2: "ライブラリ関数がヘッダーに定義された型を参照することなく宣言できるならば、関数を宣言してそれを使用することも許されますヘッダ。"


独自のstrcmpを定義すること(スタンドアロンコンパイラを使用しない限り)、明らか未定義の動作であるので、それはおそらく、単純に避けるべきです。しかし、実際には、いくつかの一般的なコンパイラでは移植不可能な方法で行うことが可能です。

最初にstring.h標準ライブラリヘッダーを含めないでください。 gccで分散、標準Cライブラリのヘッダは__attribute__((pure))strcmpを宣言:

多くの関数は、戻り値とその戻り値を除いて何の効果を持っていないだけのパラメータおよび/またはグローバル変数に依存します。このような関数は、算術演算子と同じように、共通の部分式消去とループ最適化の対象となることがあります。これらの関数は属性pureで宣言する必要があります。 (C標準に対する拡張機能です)

この宣言は、関数は(標準出力への書き込み含まれます)は、副作用を持っていないと信じているので、コンパイラはstrcmpの最初の呼び出しを排除することができます。 gccとclangの両方が、最適化を行わなくても最初の呼び出しを削除します。あなたはstrcmpに両方の呼び出しをコンパイルするために打ち鳴らすを説得することができます

、あなたは単にstring.hヘッダを含む(およびpure属性なしstrcmpを自分で宣言)しないことによって排除を回避することができます。しかし、gccはデフォルトでは、多くの標準ライブラリ関数のインラインバージョンの宣言を自動的にインクルードするので(現在のリストはhere in the GCC manualです)、最後のリンクで述べたように、-fno-builtin-strcmpを追加することで自動宣言を抑制できます。コマンドライン(標準ヘッダを含まない)

+0

ありがとう!これは#include を削除し、-fno-builtin-strcmpでコンパイルして動作します。 – binnnliu

関連する問題