Ответ 1
Я бы предложил использовать gdb в качестве простейшего подхода. Вы можете сделать это как однострочный, например:
gdb -batch -ex 'file /bin/ls' -ex 'disassemble main'
У меня есть двоичный файл, установленный в моей системе, и хотел бы посмотреть на разборку данной функции. Предпочтительно использовать objdump
, но приемлемы и другие растворы.
Из этих вопросов Я узнал, что, возможно, я смогу разобрать часть кода, если знаю только граничные адреса. Из этого ответа Я узнал, как превратить мои разделительные символы отладки в один файл.
Но даже работая над этим единственным файлом и даже дизассемблируя весь код (т.е. без начального или конечного адреса, но обычный -d
параметр до objdump
), я все равно не вижу этот символ нигде. Что имеет смысл, поскольку рассматриваемая функция статична, поэтому она не экспортируется. Тем не менее, valgrind
сообщит имя функции, поэтому его нужно где-то хранить.
Глядя на детали разделов отладки, я нахожу это имя, указанное в разделе .debug_str
, но я не знаю инструмент, который может превратить его в диапазон адресов.
Я бы предложил использовать gdb в качестве простейшего подхода. Вы можете сделать это как однострочный, например:
gdb -batch -ex 'file /bin/ls' -ex 'disassemble main'
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 $0x0,-0x4(%rbp)
4 i = i + 2;
0x00000000004004e1 <+11>: 83 45 fc 02 addl $0x2,-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 $0x0,%eax
7 }
0x00000000004004ed <+23>: 5d pop %rbp
0x00000000004004ee <+24>: c3 retq
End of assembler dump.
Протестировано на Ubuntu 16.04, GDB 7.11.1.
Распечатайте абзац, как указано на странице: https://unix.stackexchange.com/questions/82944/how-to-grep-for-text-in-a-file-and-display-the-paragraph-that-has-the -текст
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 $0x2,-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
я не думаю, что есть -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 с опцией -d и передаю его в awk. Разобранный выход выглядит как
000000000000068a <main>:
68a: 55 push %rbp
68b: 48 89 e5 mov %rsp,%rbp
68e: 48 83 ec 20 sub $0x20,%rsp
Раздел или функция отделяются пустой строкой. Таким образом, изменение FS (полевой разделитель) на новую строку и RS (запись разделитель) на двойной перевод строки позволяет вам легко искать рекомендуемую функцию, поскольку ее просто найти в поле $ 1!
objdump -d name_of_your_obj_file | awk -F"\n" -v RS="\n\n" '$1 ~ /main/'
Конечно, вы можете заменить main на любую функцию, которую хотите выводить.
Я написал небольшой скрипт для этой проблемы. Просто скопируйте его и сохраните как, например, файл 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 не будет загружать библиотеки в память и поэтому безопаснее!
Виталий Фадеев запрограммировал автозаполнение для этого скрипта, что действительно хорошая функция и ускоряет набор текста.
Сценарий можно найти здесь.
Это работает так же, как и решение gdb (в том смысле, что он сдвигает смещения к нулю), за исключением того, что он не отстает (выполняется работа примерно на 5 мс на моем ПК, тогда как решение gdb занимает около 150 мс):
objdump_func:
#!/bin/sh
# $1 -- function name; rest -- object files
fn=$1; shift 1
exec objdump -d "[email protected]" |
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 }'
Чтобы упростить использование awk для синтаксического анализа вывода objdump относительно других ответов:
objdump -d filename | sed '/<functionName>:/,/^$/!d'
./dasm
Полные имена символов для этого решения (версия 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