Как разобрать одну функцию с помощью objdump?

у меня есть двоичный файл, установленный в моей системе, и я хотел бы посмотреть на разборку данной функции. Предпочтительно использовать objdump, но другие решения также были бы приемлемыми.

С этот вопрос я узнал, что я мог бы разобрать часть кода, если бы знал только граничные адреса. От ответ я узнал, как превратить мои символы Split debug обратно в один файл.

но даже работая на этот единственный файл и даже разборка всего кода (т. е. без адреса запуска или остановки, но простой до objdump), Я все еще не вижу этого символа нигде. Что имеет смысл, поскольку рассматриваемая функция статична, поэтому она не экспортируется. Тем не менее, valgrind сообщит имя функции, поэтому оно должно быть сохранено где-то.

глядя на детали разделов отладки, я нахожу это имя, упомянутое в , но я не знаю инструмент, который может превратите это в диапазон адресов.

6 ответов


Я бы предложил использовать gdb как самый простой подход. Вы даже можете сделать это как однострочный, например:

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

gdb disassemble/rs чтобы показать исходные и необработанные байты, а также

С этим форматом он становится очень близким к objdump -S выход:

gdb -batch -ex "file $EXECUTABLE" -ex "disassemble/rs $FUNCTION"

а.с:

#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 -std=c99 -O0 -g a.c
gdb -batch -ex 'file a.out' -ex "disassemble/rs myfunc"

разборки:

Dump of assembler code for function main:
a.c:
1       int main(void) {
   0x00000000004004d6 <+0>:     55      push   %rbp
   0x00000000004004d7 <+1>:     48 89 e5        mov    %rsp,%rbp

2           int i;
3           i = 0;
   0x00000000004004da <+4>:     c7 45 fc 00 00 00 00    movl   x0,-0x4(%rbp)

4           i = i + 2;
   0x00000000004004e1 <+11>:    83 45 fc 02     addl   x2,-0x4(%rbp)

5           i = i * 2;
   0x00000000004004e5 <+15>:    d1 65 fc        shll   -0x4(%rbp)

6           return 0;
   0x00000000004004e8 <+18>:    b8 00 00 00 00  mov    x0,%eax

7       }
   0x00000000004004ed <+23>:    5d      pop    %rbp
   0x00000000004004ee <+24>:    c3      retq   
End of assembler dump.

протестировано на Ubuntu 16.04, GDB 7.11.1.

objdump + awk обходные пути

Распечатать абзац, как указано на: https://unix.stackexchange.com/questions/82944/how-to-grep-for-text-in-a-file-and-display-the-paragraph-that-has-the-text

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

например:

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

дает просто:

000000000000064a <myfunc>:
 64a:   55                      push   %rbp
 64b:   48 89 e5                mov    %rsp,%rbp
 64e:   89 7d fc                mov    %edi,-0x4(%rbp)
 651:   83 45 fc 02             addl   x2,-0x4(%rbp)
 655:   d1 65 fc                shll   -0x4(%rbp)
 658:   8b 45 fc                mov    -0x4(%rbp),%eax
 65b:   5d                      pop    %rbp
 65c:   c3                      retq 

при использовании -S, Я не думаю, что есть отказоустойчивый способ, так как комментарии кода могут содержать любую возможную последовательность... Но почти все время работает следующее:

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

адаптировано из: Как выбрать линии между двумя шаблоны маркеров, которые могут возникать несколько раз с awk/sed

ответы на список рассылки

в списке рассылки есть поток 2010, который говорит, что это невозможно:https://sourceware.org/ml/binutils/2010-04/msg00445.html

кроме gdb обходной путь, предложенный Томом, они также комментируют другой (худший) обходной путь компиляции с -ffunction-section что кладет одну функцию в раздел и после этого сбрасывать раздел.

Николас Клифтон дал ему WONTFIX https://sourceware.org/ml/binutils/2015-07/msg00004.html, вероятно, потому, что обходной путь GDB охватывает этот вариант использования.


демонтировать одну функцию с помощью Objdump

у меня есть два решения:

1. На Основе Командной Строки

этот метод работает отлично и также очень короткий. Я использую objdump С - d и труба на на awk. Разобранный вывод выглядит как

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

A раздел или функции отделяется пустой строкой. Следовательно, изменение FS (разделитель полей) для новой строки и RS (запись Seperator) в два раза newline позволит вам легко найти рекомендуемую функцию, так как это просто найти в поле $1!

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

конечно, вы можете заменить main для любой функции, которую вы хотите вывести.

2. Bash Script

Я написал небольшой скрипт bash для этой проблемы. Просто скопируйте его и сохраните его как dasm файл.

#!/bin/bash
# Author: abu
# Description: puts disassembled objectfile to std-out

if [ $# = 2 ]; then
        sstrg="^[[:xdigit:]]{2,}+.*<>:$"
        objdump -d  | awk -F"\n" -v RS="\n\n" ' ~ /'"$sstrg"'/'
elif [ $# = 1 ]; then
        objdump -d  | awk -F"\n" -v RS="\n\n" '{ print  }'
else
    echo "You have to add argument(s)"
    echo "Usage:   " " 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 "         " " arg1    ... print labels and their rel. addresses" 
fi

изменить x-access и вызвать его, например:

chmod +x dasm
./dasm test main

это много быстрее, чем вызов gdb со скриптом. Кроме того, использование objdump будет не загрузите библиотеки в память и, следовательно, безопаснее!


Виталий Фадеев запрограммировал автозаполнение для этого скрипта, что действительно хорошая функция и ускоряет ввод текста.

сценарий может быть найдено здесь.


это работает так же, как решение gdb (в том, что он сдвигает смещения к нулю), за исключением того, что он не отстает (получает работу примерно за 5 мс на моем ПК, тогда как решение gdb занимает около 150 мс):

objdump_func:

#!/bin/sh
#  -- function name; rest -- object files
fn=; shift 1
exec objdump -d "$@" | 
awk " /^[[:xdigit:]].*<$fn>/,/^$/ { print $0 }" |
awk -F: -F' '  'NR==1 {  offset=strtonum("0x"); print ; } 
                NR!=1 {  split(,a,":"); rhs=a[2]; n=strtonum("0x"); =sprintf("%x", n-offset); printf "%4s:%s\n", ,rhs }'

чтобы упростить использование awk для разбора вывода objdump относительно других ответов:

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

завершение Bash для ./dasm

полные имена символов to данное решение (версия D lang):

  • введя dasm test и нажмите клавишу TabTab, вы получите список всех функций.
  • введя dasm test m и нажмите клавишу TabTab все функции, начиная с 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