9

実行可能ファイルで nm または readelf -s の出力を処理しようとしています。ただし、出力で静的関数を互いに区別するのに問題があります。

これが私が取り組んでいるものです:

test.c

static int foo() {
    int x = 6;
}

main() {}

その他.c

static int foo() {
    int x = 5;
}

私はこれらを次のようにコンパイルします:

gcc -o test test.c other.c

次に nm コマンドを実行して、すべてのシンボルを取得します。

nm test

その中には、次の 2 つの記号 (私の静的関数用) が表示されます。

00000000004004ed t foo
0000000000400500 t foo

特定の foo 関数がどのファイルから出現したかを区別できる方法はありますか? または、これを機能させるためにコンパイルする前に魔法をかける必要がありますか?

私のユースケースでは、最終的なバイナリとそれが使用するオブジェクトファイルにアクセスできますが、実際に自分でビルドしてシンボルテーブルがあることを確認することはできません。

ありがとう!

4

4 に答える 4

11

あなたの質問は、実行可能ファイルがあれば、または別のツールstaticを使用して、それにコンパイルされた (ローカル) 関数の名前をいつでも発見できると仮定しています。nmしたがって、2 つ以上のそのような名前が同じ場合を確認し、それらがどのソース ファイルからコンパイルされたかをどのように発見するかという問題を提起することができます。

しかし、その仮定は誤りです。gcc の場合、ファイルが最適化されてコンパイル-O0されると、オブジェクト ファイルのシンボル テーブルにローカル シンボルが出力されます。-O0がデフォルトであるため、次の場合に適用されます。

gcc -o test test.c other.c

ただし、ファイルがより高い最適化レベルでコンパイルされている場合 (リリース ビルド用であることは確かです)、ローカル シンボルはオブジェクト ファイルのシンボル テーブルから除外されます。したがって、リンカーはそれらを見ることさえありません。そのため、実行可能ファイルからそれらを回復することはできませnmん。

サンプル ファイルを次のようにコンパイルします。

gcc -O1 -o test test.c other.c

次にnm test、次のことがわかります。

00000000004004ed t foo
0000000000400500 t foo

他のすべての静的関数名とともに消えました。

その場合、あなたが言うように、実行可能ファイルのビルド方法を制御できない場合、質問が発生する可能性さえあることを保証できません.

ファイルが でコンパイルされるように実行可能ファイルをビルドする方法を制御できる場合-O0は、静的関数名をソース ファイルに結び付ける方法がいくつかあります。同様に単純なものは次の 2 つです。

readelf -s test

objdump -t test

それぞれが、そこから来るシンボルの各チャンクの先頭にソースファイル名をリストします。

(そして、言う必要がある場合はgdb、@Amol によって提案されたアプローチは、実行可能ファイルが最適化されてコンパイルされている必要があるという制限を回避しません-O0)

于 2015-06-08T19:39:58.930 に答える
3

次のシーケンスを試しました。

デバッグ シンボルを使用せずに出力ファイルを削除したgdb場合は、オブジェクト ファイルを作成できます。以下のコマンドに従ってください。

$ gdb a.out

出力として次のようになります

Reading symbols from /home/amol/amol/a.out...(no debugging symbols found)...done.

その後 (gdb)、ターミナルに来ます

次のコマンドを順番に入力します(コマンドを(gdb)入力すると、プロンプトがデフォルトで表示されます)

 (gdb) maint print symbols filename
 (gdb) maint print psymbols filename
 (gdb) maint print msymbols filename

これで、フォルダにfilenameという名前のファイルが 1 つ表示されます。このファイルをテキスト エディタで開くと、次のような情報が表示されます。

[ 8] t 0x80483b4 foo section .text  test.c
[ 9] T 0x80483c3 main section .text  other.c
[10] t 0x80483c8 foo section .text  other.c

foo()ここでは、どの関数がどのファイルから来ているかをはっきりと見ることができ.cます。これがお役に立てば幸いです。

于 2015-06-08T18:51:52.763 に答える
0

ストリップされた実行可能ファイルで動作する場合は、関数に文字列を埋め込み、実行可能ファイルでそれらを検索できます。

#define STR1(x) #x
#define STR(x) STR1(x)
#define FUNCID(funcname) __asm__ __volatile__ (\
    "jmp 1f;"\
    ".string \"" __FILE__ "/" STR(funcname) "()\";"\
    "1:"\
)

static int foo() {
    FUNCID(foo);
    return rand();
}
于 2015-06-08T21:09:30.097 に答える