2016-04-01 14 views
6

は、次の関数を考えてみましょう:gccにPICコードで直接関数を呼び出させるにはどうしたらいいですか?

extern void test1(void); 
extern void test2(void) { 
    test1(); 
} 

これは、コードのgccがAMD64 Linux上-fpicずに生成している:私は-fpicでコンパイルすると

test2: 
    jmp test1 

、gccが明示的にシンボルの介在を可能にするために、PLTを通じて呼び出します。

test2: 
    jmp [email protected] 

これは厳密には必要ではありませんdは位置独立コードであり、サポートしたくない場合は省略することができます。必要に応じて、リンカはジャンプターゲットをPLTシンボルに書き換えます。

コンパイルされたコードを共有ライブラリに不適切なものにすることなく、ソースコードを変更せずに、関数呼び出しを明示的にPLTを実行するのではなくターゲットに直接渡すことはできますか?

+1

ライブラリ/実行ファイル内の呼び出しを意味しますか?それはどういうわけか、プライベートエイリアスなどを定義することによって可能になるはずです。しかし、あなたが動的にしかリンクしていないライブラリの関数を呼び出す場合、実行時リンカー*がそのような参照を解決できるかどうかはわかりません。 –

+0

@PeterCordes '-fpic'を指定しないと、リンカは必要に応じてシンボルへの参照を自動的にPLT参照へ書き換えます。つまり、コンパイラがすべての関数に対して通常の呼び出しを生成し、リンカーが別の共有オブジェクトに行く呼び出しを書き直したいという動作です。 – fuz

+1

['-fno-semantic-interposition'](http://stackoverflow.com/questions/35745543/new-option-in-gcc-5-3-fno-semantic-interposition)は何をしたいのですか? http://stackoverflow.com/questions/34102989/shared-object-in-linux-without-symbol-interposition-fno-semantic-interpositionも参照してください。この質問はそれらのいずれかと重複していますか? –

答えて

1

、ジャンプは直接になります。

今隠されたとしてtest1()は、そのソースの翻訳単位で定義されていないかもしれないが、私は害はC言語を除いてその相違から来るべきではないと考えていますポインターの1つが非表示の参照で取得されたものとパブリック1つで取得されたものがある場合は、&test1 == &test1が壊れている可能性があります(パブリックリファレンスは、プリロードまたは現在のルックアップスコープ、非表示の参照(直接ジャンプをもたらす)は効果的な介入を防止します)

これに対処するより適切な方法は、test1()という2つの名前を定義することです。パブリック名とプライベート/非表示の名前です。

gccとclangでは、これはいくつかのエイリアスマジックで行うことができます。これは、シンボルを定義する翻訳単位でのみ行うことができます。

#define PRIVATE __attribute__((__visibility__("hidden"))) 
#define PUBLIC __attribute__((__visibility__("default"))) 
#define PRIVATE_ALIAS(Alias,OfWhat) \ 
    extern __typeof(OfWhat) Alias __attribute((__alias__(#OfWhat), \ 
           __visibility__("hidden"))) 

#if HERE 
PUBLIC void test1(void) { } 
PRIVATE_ALIAS(test1__,test1); 
#else 
PUBLIC void test1(void); 
PRIVATE void test1__(void); 
#endif 

void call_test1(void) { test1(); } 
void call_test1__(void) { test1__(); } 

void call_ext0(void) { void ext0(void); ext0(); } 
void call_ext1(void) { PRIVATE void ext1(void); ext1(); } 

上記コンパイル(-O3、x86-64で):

マクロが、それはきれいにすることができ、それは小さいですので、ここで= 1を定義

call_test1: 
     jmp  [email protected] 
call_test1__: 
     jmp  test1__ 
call_ext0: 
     jmp  [email protected] 
call_ext1: 
     jmp  ext1 

は(さらにTEST1呼び出しをインラインローカルおよび-O3はオン)。

ライブサンプルhttps://godbolt.org/g/eZvmp7です。

-fno-semantic-interpositionでも、それはC言語の保証を壊してしまいます。エイリアシングの細かさがない大きなハンマーです。

+0

'-fno-semantic-interposition'は私が望むものだと思います。 – fuz

2

あなたがソースコードを変更できない場合は、大きなハンマーを使用することができます。共有ライブラリを作成する場合、

内 定義にグローバルシンボルへの参照をバインド:-Bsymbolicリンカフラグを共有ライブラリー(ある場合)。通常、共有ライブラリにリンクされたプログラムの場合、 は、共有ライブラリ内の定義 を上書きする可能性があります。このオプションは、共有ライブラリをサポートするELFプラットフォーム でのみ意味があります。

ただし、ライブラリの一部がシンボルの挿入に依存している場合は、破損することに注意してください。私はエクスポートする必要がない(隠された可視性を設定する)関数や隠れたエイリアス(特に制御された方法でPLTレスのライブラリ内呼び出しを行うように設計されている)を呼び出すことをお勧めします。あなたは隠されたtest1()__attribute__((__visibility__("hidden")))を宣言した場合

関連する問題