How to disassemble one single function using objdump?

后端 未结 7 1030
囚心锁ツ
囚心锁ツ 2020-11-29 17:59

I\'ve got a binary installed on my system, and would like to look at the disassembly of a given function. Preferrably using objdump, but other solutions would b

相关标签:
7条回答
  • 2020-11-29 18:37

    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.

    0 讨论(0)
  • 2020-11-29 18:43

    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 }'
    
    0 讨论(0)
  • 2020-11-29 18:45

    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).

    0 讨论(0)
  • 2020-11-29 18:45

    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
    
    0 讨论(0)
  • 2020-11-29 18:47

    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.

    0 讨论(0)
  • 2020-11-29 18:53

    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'
    
    0 讨论(0)
提交回复
热议问题