我的系统上安装了二进制文件,并希望查看给定函数的反汇编。最好使用objdump
,但其他解决方案也是可以接受的。
从this questions我了解到,如果我只知道边界地址,我可能能够反汇编部分代码。从this answer开始,我学会了如何将分割调试符号转换回单个文件。
但是即使在单个文件上运行,甚至反汇编所有代码(即没有开始或停止地址,但只有-d
参数到objdump
),我仍然没有在任何地方看到该符号。这是有道理的,因为有问题的函数是静态的,所以它不会被导出。然而,valgrind
将报告函数名称,因此必须将其存储在某处。
查看调试部分的详细信息,我发现.debug_str
部分中提到的名称,但我不知道可以将其转换为地址范围的工具。
答案 0 :(得分:65)
我建议使用gdb作为最简单的方法。您甚至可以将其作为单行,例如:
gdb -batch -ex 'file /bin/ls' -ex 'disassemble main'
答案 1 :(得分:17)
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上测试。
objdump -d main.out | awk -v RS= '/^[[:xdigit:]]+ <FUNCTION>/'
e.g:
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'
改编自:How to select lines between two marker patterns which may occur multiple times with awk/sed
邮件列表上有一个2010年的帖子,说不可能:https://sourceware.org/ml/binutils/2010-04/msg00445.html
除了Tom提出的gdb
解决方法之外,他们还评论了使用-ffunction-section
进行编译的另一种(更糟糕的)解决方法,即每个部分放置一个函数然后转储该部分。
Nicolas Clifton给了它一个WONTFIX https://sourceware.org/ml/binutils/2015-07/msg00004.html,可能是因为GDB解决方法涵盖了这个用例。
答案 2 :(得分:9)
我有两个解决方案:
这种方法效果很好,也很短。我将 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
部分或功能由空行分隔。因此,将 FS (Field Seperator)更改为换行符并将 RS (Record Seperator)更改为两行换行符,可以轻松搜索推荐的函数,因为它只是在内部查找$ 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更快 。除了使用objdump的方式,不将库加载到内存中,因此更安全!
Vitaly Fadeev 为此脚本编写了自动完成功能,这是一个非常好的功能,可以加快输入速度。
可以找到脚本here。
答案 3 :(得分:6)
如果您有最新的binutils(2.32+),这非常简单。
将--disassemble=SYMBOL
传递给objdump只会反汇编指定的函数。无需传递起始地址和结束地址。
LLVM objdump也具有类似的选项(--disassemble-symbols
)。
答案 4 :(得分:4)
这就像gdb解决方案一样(因为它将偏移量移向零)除了它没有延迟(在我的PC上大约5ms完成工作,而gdb解决方案大约需要150ms):
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 }'
答案 5 :(得分:2)
为了简化awk用于解析objdump输出相对于其他答案的用法:
objdump -d filename | sed '/<functionName>:/,/^$/!d'
答案 6 :(得分:2)
./dasm
完整符号名称至this solution(D lang版本):
dasm test
,然后按 Tab Tab ,您将获得所有功能的列表。 dasm test m
然后按 Tab Tab 将显示以 m 开头的所有功能,或仅显示一个函数存在,它将自动完成。档案/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
答案 7 :(得分:0)
也许这很容易做到:
objdump -d libxxx.so | grep -A 50 func_name_to_be_searched