システムにバイナリがインストールされています。特定の関数の逆アセンブリを確認したいと思います。 objdump
を使用することが望ましいですが、他のソリューションも同様に受け入れられます。
この質問 境界アドレスのみを知っていれば、コードの一部を逆アセンブルできるかもしれないことを学びました。 この回答 から、分割デバッグシンボルを単一のファイルに戻す方法を学びました。
しかし、その単一のファイルを操作し、すべてのコードを分解することさえできます(つまり、開始アドレスまたは停止アドレスはないが、プレーン-d
パラメータをobjdump
に追加)、まだそのシンボルがどこにも表示されない。問題の関数が静的であり、エクスポートされない限り、これは理にかなっています。それでも、valgrind
は関数名を報告するため、どこかに保存する必要があります。
デバッグセクションの詳細を見ると、.debug_str
セクション、しかしこれをアドレス範囲に変えることができるツールを知りません。
最も簡単なアプローチとしてgdbを使用することをお勧めします。次のように、ワンライナーとして実行することもできます。
gdb -batch -ex 'file /bin/ls' -ex 'disassemble main'
disassemble/rs
はソースおよび生のバイトも表示しますこの形式では、objdump -S
出力に非常に近くなります。
gdb -batch -ex "disassemble/rs $FUNCTION" "$EXECUTABLE"
main.c
#include <assert.h>
int myfunc(int i) {
i = i + 2;
i = i * 2;
return i;
}
int main(void) {
assert(myfunc(1) == 6);
assert(myfunc(2) == 8);
return 0;
}
コンパイルと逆アセンブル
gcc -O0 -ggdb3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
gdb -batch -ex "disassemble/rs myfunc" main.out
分解:
Dump of assembler code for function myfunc:
main.c:
3 int myfunc(int i) {
0x0000000000001135 <+0>: 55 Push %rbp
0x0000000000001136 <+1>: 48 89 e5 mov %rsp,%rbp
0x0000000000001139 <+4>: 89 7d fc mov %edi,-0x4(%rbp)
4 i = i + 2;
0x000000000000113c <+7>: 83 45 fc 02 addl $0x2,-0x4(%rbp)
5 i = i * 2;
0x0000000000001140 <+11>: d1 65 fc shll -0x4(%rbp)
6 return i;
0x0000000000001143 <+14>: 8b 45 fc mov -0x4(%rbp),%eax
7 }
0x0000000000001146 <+17>: 5d pop %rbp
0x0000000000001147 <+18>: c3 retq
End of assembler dump.
Ubuntu 16.04、GDB 7.11.1でテスト済み。
次の場所にあるように段落を印刷します。 https://unix.stackexchange.com/questions/82944/how-to-grep-for-text-in-a-file-and-display-the-paragraph-that -has-the-text
objdump -d main.out | awk -v RS= '/^[[:xdigit:]]+ <FUNCTION>/'
例えば。:
objdump -d main.out | awk -v RS= '/^[[:xdigit:]]+ <myfunc>/'
与えるだけ:
0000000000001135 <myfunc>:
1135: 55 Push %rbp
1136: 48 89 e5 mov %rsp,%rbp
1139: 89 7d fc mov %edi,-0x4(%rbp)
113c: 83 45 fc 02 addl $0x2,-0x4(%rbp)
1140: d1 65 fc shll -0x4(%rbp)
1143: 8b 45 fc mov -0x4(%rbp),%eax
1146: 5d pop %rbp
1147: c3 retq
-S
を使用する場合、コードのコメントに可能なシーケンスが含まれている可能性があるため、フェイルプルーフの方法はないと思います...しかし、ほとんどの場合、次のように動作します。
objdump -S main.out | awk '/^[[:xdigit:]]+ <FUNCTION>:$/{flag=1;next}/^[[:xdigit:]]+ <.*>:$/{flag=0}flag'
適応: awk/sedで複数回発生する可能性のある2つのマーカーパターン間の行を選択する方法
メーリングリストには2010年のスレッドがあり、それは不可能だと書かれています: https://sourceware.org/ml/binutils/2010-04/msg00445.html
トムによって提案されたgdb
回避策に加えて、彼らは-ffunction-section
でコンパイルする別の(より悪い)回避策についてもコメントします。
Nicolas CliftonはWONTFIXを与えました https://sourceware.org/ml/binutils/2015-07/msg00004.html 、おそらくGDBの回避策がそのユースケースをカバーしているためです。
私には2つの解決策があります:
この方法は完全に機能し、非常に短いです。 objdumpを-dオプションとpipeを使用してawk。逆アセンブルされた出力は次のようになります
000000000000068a <main>:
68a: 55 Push %rbp
68b: 48 89 e5 mov %rsp,%rbp
68e: 48 83 ec 20 sub $0x20,%rsp
sectionまたはfunctionは空行で区切られます。したがって、[〜#〜] fs [〜#〜](フィールドセパレーター)を改行に変更し、[ 〜#〜] rs [〜#〜](レコード区切り記号)を2回改行すると、$ 1フィールド内で見つけるだけなので、推奨機能を簡単に検索できます。
objdump -d name_of_your_obj_file | awk -F"\n" -v RS="\n\n" '$1 ~ /main/'
もちろん、mainを出力したい任意の関数に置き換えることができます。
この問題のための小さなbashスクリプトを作成しました。単にコピーして、たとえばdasmファイル。
#!/bin/bash
# Author: abu
# Description: puts disassembled objectfile to std-out
if [ $# = 2 ]; then
sstrg="^[[:xdigit:]]{2,}+.*<$2>:$"
objdump -d $1 | awk -F"\n" -v RS="\n\n" '$1 ~ /'"$sstrg"'/'
Elif [ $# = 1 ]; then
objdump -d $1 | awk -F"\n" -v RS="\n\n" '{ print $1 }'
else
echo "You have to add argument(s)"
echo "Usage: "$0 " arg1 arg2"
echo "Description: print disassembled label to std-out"
echo " arg1: name of object file"
echo " arg2: name of function to be disassembled"
echo " "$0 " arg1 ... print labels and their rel. addresses"
fi
x-accessを変更して、たとえば:
chmod +x dasm
./dasm test main
これは、スクリプトでgdbを呼び出すよりもmuch速いです。 objdumpを使用する方法とは別に、ライブラリをメモリにロードするnotため、安全です!
Vitaly Fadeevは、このスクリプトにオートコンプリートをプログラムしました。これは本当にすてきな機能であり、入力を高速化します。
スクリプトは here にあります。
これは、遅延がないことを除いて、gdbソリューションと同じように機能します(オフセットをゼロにシフトするという点で)(gdbソリューションは約150msかかりますが、PCでは約5msでジョブが完了します):
objdump_func:
#!/bin/sh
# $1 -- function name; rest -- object files
fn=$1; shift 1
exec objdump -d "$@" |
awk " /^[[:xdigit:]].*<$fn>/,/^\$/ { print \$0 }" |
awk -F: -F' ' 'NR==1 { offset=strtonum("0x"$1); print $0; }
NR!=1 { split($0,a,":"); rhs=a[2]; n=strtonum("0x"$1); $1=sprintf("%x", n-offset); printf "%4s:%s\n", $1,rhs }'
他の回答と比較してobjdumpの出力を解析するためにawkの使用を簡素化するには:
objdump -d filename | sed '/<functionName>:/,/^$/!d'
./dasm
のBash補完完全なシンボル名から このソリューション (D langバージョン):
dasm test
と入力してから TabTab、すべての関数のリストを取得します。dasm test m
と入力してから TabTab mで始まるすべての関数が表示されます。または、関数が1つしか存在しない場合は、自動補完されます。ファイル/etc/bash_completion.d/dasm
:
# bash completion for dasm
_dasm()
{
local cur=${COMP_WORDS[COMP_CWORD]}
if [[ $COMP_CWORD -eq 1 ]] ; then
# files
COMPREPLY=( $( command ls *.o -F 2>/dev/null | grep "^$cur" ) )
Elif [[ $COMP_CWORD -eq 2 ]] ; then
# functions
OBJFILE=${COMP_WORDS[COMP_CWORD-1]}
COMPREPLY=( $( command nm --demangle=dlang $OBJFILE | grep " W " | cut -d " " -f 3 | tr "()" " " | grep "$cur" ) )
else
COMPREPLY=($(compgen -W "" -- "$cur"));
fi
}
complete -F _dasm dasm