J'ai un binaire installé sur mon système et j'aimerais regarder le désassemblage d'une fonction donnée. Utiliser de préférence objdump
, mais d’autres solutions seraient également acceptables.
De this questions J'ai appris que je pourrais peut-être désassembler une partie du code si je ne connaissais que les adresses limites. De cette réponse j'ai appris à reconvertir mes symboles de débogage divisés en un seul fichier.
Mais même en opérant sur ce fichier unique, et même en désassemblant tout le code (c'est-à-dire sans adresse de démarrage ou d'arrêt, mais en clair -d
paramètre sur objdump
), je ne vois toujours pas ce symbole nulle part. Ce qui est logique dans la mesure où la fonction en question est statique, elle n'est donc pas exportée. Néanmoins, valgrind
rapportera le nom de la fonction, il doit donc être stocké quelque part.
En regardant les détails des sections de débogage, je trouve ce nom mentionné dans le .debug_str
_ section, mais je ne connais pas d’outil qui puisse en faire une plage d’adresses.
Je suggérerais d'utiliser gdb comme approche la plus simple. Vous pouvez même le faire en une ligne, comme:
gdb -batch -ex 'file /bin/ls' -ex 'disassemble main'
disassemble/rs
pour afficher également les octets source et brutsAvec ce format, il se rapproche vraiment de objdump -S
sortie:
gdb -batch -ex "disassemble/rs $FUNCTION" "$EXECUTABLE"
principal 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;
}
Compiler et démonter
gcc -O0 -ggdb3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
gdb -batch -ex "disassemble/rs myfunc" main.out
Démontage:
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.
Testé sur Ubuntu 16.04, GDB 7.11.1.
Imprimez le paragraphe comme indiqué à: https://unix.stackexchange.com/questions/82944/how-to-grep-for-text-in-a-file-and-display-the- paragraphe-that -has-the-text
objdump -d main.out | awk -v RS= '/^[[:xdigit:]]+ <FUNCTION>/'
par exemple.:
objdump -d main.out | awk -v RS= '/^[[:xdigit:]]+ <myfunc>/'
donne juste:
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
Lorsque vous utilisez -S
, Je ne pense pas qu'il existe un moyen infaillible, car les commentaires de code pourraient contenir une séquence possible ... Mais ce qui suit fonctionne presque tout le temps:
objdump -S main.out | awk '/^[[:xdigit:]]+ <FUNCTION>:$/{flag=1;next}/^[[:xdigit:]]+ <.*>:$/{flag=0}flag'
Il y a un fil 2010 sur la liste de diffusion qui dit que c'est impossible: https://sourceware.org/ml/binutils/2010-04/msg00445.html
Outre la solution de contournement gdb
proposée par Tom, ils commentent également une solution de contournement (pire) de la compilation avec -ffunction-section
qui met une fonction par section puis décharge la section.
Nicolas Clifton lui a donné un WONTFIX https://sourceware.org/ml/binutils/2015-07/msg00004.html , probablement parce que la solution de contournement de la GDB couvre ce cas d'utilisation.
J'ai deux solutions:
Cette méthode fonctionne parfaitement et est également très courte. J'utilise objdump avec l'option - d et le conduit vers awk . La sortie désassemblée ressemble à
000000000000068a <main>:
68a: 55 Push %rbp
68b: 48 89 e5 mov %rsp,%rbp
68e: 48 83 ec 20 sub $0x20,%rsp
Une fonction ou est séparée par une ligne vide. Par conséquent, changer le [~ # ~] fs [~ # ~] (séparateur de champ) en nouvelle ligne et le [ ~ # ~] rs [~ # ~] (Séparateur d’enregistrement) permet de rechercher facilement deux fois votre fonction recommandée, puisqu’il s’agit simplement de la trouver dans le champ $ 1!
objdump -d name_of_your_obj_file | awk -F"\n" -v RS="\n\n" '$1 ~ /main/'
Bien sûr, vous pouvez remplacer main par n'importe quelle fonction que vous voulez afficher.
J'ai écrit un petit script bash pour ce numéro. Copiez-le simplement et enregistrez-le, par exemple. dasm fichier.
#!/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
Changez le x-access et appelez-le avec, par exemple:
chmod +x dasm
./dasm test main
C'est beaucoup plus rapide que d'appeler gdb avec un script. En plus d'utiliser objdump , pas ne chargera les librairies en mémoire et sera donc plus sûr!
Vitaly Fadeev a programmé l'auto-complétion pour ce script, ce qui est vraiment une fonctionnalité intéressante et accélère la frappe.
Le script peut être trouvé ici .
Cela fonctionne comme la solution gdb (en ce sens que les décalages sont décalés vers zéro), sauf que ce n'est pas lent (le travail est fait en 5 ms environ sur mon PC, alors que la solution gdb prend environ 150 ms):
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 }'
Pour simplifier l'utilisation de awk pour analyser la sortie d'objdump par rapport à d'autres réponses:
objdump -d filename | sed '/<functionName>:/,/^$/!d'
./dasm
Noms de symbole complets à cette solution (version D lang):
dasm test
puis en appuyant sur TabTab, vous obtiendrez une liste de toutes les fonctions.dasm test m
puis en appuyant sur TabTab toutes les fonctions commençant par m seront affichées ou, si une seule fonction existe, elle sera complétée automatiquement.Fichier /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