Comment démonter une seule fonction en utilisant objdump?

j'ai un binaire installé sur mon système, et tiens à regarder le démontage d'une fonction donnée. Utiliser de préférence objdump , mais d'autres solutions seraient également acceptables.

à Partir de cette question j'ai appris que je pourrais être capable de démonter une partie du code si je ne connais que la limite d'adresses. De cette réponse j'ai appris à transformer mes symboles de débogage fractionnés en un seul fichier.

mais même en travaillant sur ce fichier unique, et même en démontant tout le code (i.e. sans adresse de départ ou d'arrêt, mais simple -d paramètre à objdump ), Je ne vois toujours pas ce symbole où que ce soit. Ce qui est logique dans la mesure où la fonction en question Est statique, donc elle n'est pas exportée. Néanmoins, valgrind va signaler le nom de la fonction, il doit donc être stocké quelque part.

en regardant les détails des sections de debug, je trouve que nom mentionné dans la section .debug_str , mais je ne connais pas d'outil qui puisse transformer cela en une plage d'adresses.

53

6 réponses

je suggère d'utiliser gdb comme approche la plus simple. Vous pouvez même le faire comme une doublure, comme:

gdb -batch -ex 'file /bin/ls' -ex 'disassemble main'
54
répondu Tom Tromey 2014-04-01 01:47:57

gdb disassemble/rs pour afficher les octets source et raw ainsi que

avec ce format, il se rapproche vraiment de objdump -S sortie:

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

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

démontage:

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   "151930920"x0,-0x4(%rbp)

4           i = i + 2;
   0x00000000004004e1 <+11>:    83 45 fc 02     addl   "151930920"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    "151930920"x0,%eax

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

testé sur Ubuntu 16.04, GDB 7.11.1.

objdump + awk solutions de contournement

imprimer le paragraphe comme indiqué à: 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>/'

p.ex.:

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

donne simplement:

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   "151960920"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 

en utilisant -S , Je ne pense pas qu'il y ait une méthode infaillible, car les commentaires du code pourraient contenir n'importe quelle séquence possible... Mais les travaux suivants presque tout le temps:

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

adapté de: Comment sélectionner des lignes entre deux motifs de marqueur qui peuvent apparaître plusieurs fois avec awk / sed

liste de Diffusion réponses

il ya un fil 2010 sur la liste de diffusion qui dit que ce n'est pas possible: https://sourceware.org/ml/binutils/2010-04/msg00445.html

outre la solution de contournement gdb proposée par Tom, ils commentent également une autre solution de contournement (pire) de compiler avec -ffunction-section qui met une fonction par section et puis jeter 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 GDB couvre que cas d'utilisation.

10

démonter une seule fonction en utilisant Objdump

j'ai deux solutions:

1. Basé Sur La Ligne De Commande

Cette méthode fonctionne parfaitement et est également très court. J'utilise objdump avec -d et pipe à awk . La sortie démontée ressemble à

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

Un section ou la fonction est séparée par une ligne vide. Par conséquent, changer le FS (séparateur de champ) à newline et le RS (séparateur D'enregistrement) à deux fois newline vous permet de rechercher facilement votre fonction recommandée, car il est tout simplement de trouver dans le champ $1!

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

bien sûr, vous pouvez remplacer principal à n'importe quelle fonction que vous voulez être sortie.

2. Bash Script

j'ai écrit un petit script bash pour ce numéro. Il suffit de le copier et de le sauvegarder comme par exemple dasm fichier.

#!/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:   ""151920920" " 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 "         ""151920920" " arg1    ... print labels and their rel. addresses" 
fi

modifier le x-access et l'invoquer avec par exemple:

chmod +x dasm
./dasm test main

C'est beaucoup plus rapide qu'invoquer gdb avec un script. À côté de la manière en utilisant objdump sera pas charger le les bibliothèques dans la mémoire et est donc plus sûr!


Vitaly Fadeev a programmé l'autocomplétion de ce script, qui est vraiment une belle fonctionnalité et accélère la dactylographie.

le script se trouve ici .

5
répondu abu_bua 2018-09-29 20:21:52

cela fonctionne comme la solution gdb (en ce qu'elle déplace les offsets vers zéro) sauf qu'elle n'est pas lente (fait le travail en environ 5ms sur mon PC alors que la solution gdb prend environ 150ms):

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 "151900920"; } 
                NR!=1 {  split("151900920",a,":"); rhs=a[2]; n=strtonum("0x"); =sprintf("%x", n-offset); printf "%4s:%s\n", ,rhs }'
4
répondu PSkocik 2016-08-07 16:23:42

pour simplifier l'utilisation de awk pour analyser la sortie d'objdump par rapport à d'autres réponses:

objdump -d filename | sed '/<functionName>:/,/^$/!d'
2
répondu fcr 2017-05-01 04:23:27

Bash completion pour ./dasm

symbole Complète des noms de à cette solution (D lang version):

  • En tapant dasm test , puis en appuyant sur Onglet Onglet , vous obtiendrez une liste de toutes les fonctions.
  • En tapant dasm test m , puis en appuyant sur Onglet Onglet toutes les fonctions commençant par m seront affichées, ou si une seule fonction existe, elle sera autocompletée.

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
1
répondu Vitaly Fadeev 2018-09-28 13:42:05