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



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



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



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



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

303   6  

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) в два раза новая строка позволит вам легко найти рекомендуемую функцию, так как это просто найти в поле $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 "[email protected]" | 
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

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

  • введя dasm test и нажмите клавишу TabTab, вы получите список всех функций.
  • введя dasm test m и нажмите клавишу TabTab все функции, начиная с m будет показано, или в случае, если имеется только одна функция, это будет автоматически завершена.

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
    Ничего не найдено.

Добавить ответ:
Отменить.