如何使用 objecdump 反汇编一个函数?

我已经在我的系统上安装了一个二进制文件,并且希望查看一个给定函数的反汇编。最好使用 objdump,但其他解决方案也可以接受。

这个问题我已经知道,如果我只知道边界地址,我可能能够分解部分代码。从 这个答案我已经学会了如何把我的分裂调试符号回到一个单一的文件。

但是即使操作那个单独的文件,甚至反汇编所有的代码(即没有开始或停止地址,但是 objdump-d参数) ,我仍然看不到任何地方的符号。这是有意义的,因为所讨论的函数是静态的,所以它不会被导出。然而,valgrind将报告函数名,因此它必须存储在某个地方。

查看调试部分的细节,我找到了 .debug_str部分中提到的名称,但我不知道有什么工具可以将其转换为地址范围。

97488 次浏览

I would suggest using gdb as the simplest approach. You can even do it as a one-liner, like:

gdb -batch -ex 'file /bin/ls' -ex 'disassemble main'

gdb disassemble/rs to show source and raw bytes as well

With this format, it gets really close to objdump -S output:

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;
}

Compile and disassemble

gcc -O0 -ggdb3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
gdb -batch -ex "disassemble/rs myfunc" main.out

Disassembly:

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.

Tested on Ubuntu 16.04, GDB 7.11.1.

objdump + awk workarounds

Print the paragraph as mentioned at: 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>/'

e.g.:

objdump -d main.out | awk -v RS= '/^[[:xdigit:]]+ <myfunc>/'

gives just:

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

When using -S, I don't think there is a fail-proof way, as the code comments could contain any possible sequence... But the following works almost all the time:

objdump -S main.out | awk '/^[[:xdigit:]]+ <FUNCTION>:$/{flag=1;next}/^[[:xdigit:]]+ <.*>:$/{flag=0}flag'

adapted from: How to select lines between two marker patterns which may occur multiple times with awk/sed

Mailing list replies

There is a 2010 thread on the mailing list which says it is not possible: https://sourceware.org/ml/binutils/2010-04/msg00445.html

Besides the gdb workaround proposed by Tom, they also comment on another (worse) workaround of compiling with -ffunction-section which puts one function per section and then dumping the section.

Nicolas Clifton gave it a WONTFIX https://sourceware.org/ml/binutils/2015-07/msg00004.html , likely because the GDB workaround covers that use case.

This works just like the gdb solution (in that that it shifts the offsets towards zero) except that it's not laggy (gets the job done in about 5ms on my PC whereas the gdb solution takes about 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 }'

To simplify the usage of awk for parsing objdump's output relative to other answers:

objdump -d filename | sed '/<functionName>:/,/^$/!d'

Disassemble One Single Function using Objdump

I have two solutions:

1. Commandline Based

This method works perfectly and additional a simple one. I use objdump with the -d flag and pipe it through awk. The disassembled output looks like

000000000000068a <main>:
68a:    55                      push   %rbp
68b:    48 89 e5                mov    %rsp,%rbp
68e:    48 83 ec 20             sub    $0x20,%rsp

To start with, I begin with the description of the objdump output. A section or function is separated by an empty line. Therefore changing the FS (Field Separator) to newline and the RS (Record Separator) to twice newline let you easily search for your recommended function, since it is simply to find within the $1 field!

objdump -d name_of_your_obj_file | awk -F"\n" -v RS="\n\n" '$1 ~ /main/'

Of course you can replace main with any other function you would like to print.

2. Bash Script

I have written a small bash script for this issue. Paste and copy it and save it as e.g. dasm file.

#!/bin/bash
# Author: abu
# filename: dasm
# 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

Change the x-access and invoke it with e.g.:

chmod +x dasm
./dasm test main

This is much faster than invoking gdb with a script. Beside the way using objdump will not load the libraries into memory and is therefore safer!


Vitaly Fadeev programmed an auto-completion to this script, which is really a nice feature and speeds up typing.

The script can be found here.

Bash completion for ./dasm

Complete symbol names to this solution (D lang version):

  • By typing dasm test and then pressing TabTab, you will get a list of all functions.
  • By typing dasm test m and then pressing TabTab all functions starting with m will be shown, or in case only one function exists, it will be autocompleted.

File /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

If you have a very recent binutils (2.32+), this is very simple.

Passing --disassemble=SYMBOL to objdump will disassemble only the specified function. No need to pass the start address and the end address.

LLVM objdump also has a similar option (--disassemble-symbols).

maybe this is easy to do:
objdump -d libxxx.so | grep -A 50 func_name_to_be_searched

Just use objdump -d filename | awk '/<funcname>/,/^$/'

Not exactly what you asked, but if you are compiling a C or C++ program from source with GCC, you can add a function attribute to put it in a custom named section of the binary:

extern __attribute__((noinline, section("disasm"))) void foo() {}

Then you can ask objdump to show only functions in that named section with -jdisasm.

For those who want to look at the assembly of a binary with debug symbols. As per the man page:

objdump -d <binary> --disassemble=<symbol>

should do the trick. No need to use gdb or any other utilities.

In gcc-objdump,it can be objdump -C --disassemble="funcName" -j.text procName