Objdump का उपयोग करके एक एकल फ़ंक्शन को कैसे अलग किया जाए?


91

मुझे अपने सिस्टम पर एक बाइनरी स्थापित हो गई है, और किसी दिए गए फ़ंक्शन के डिस्सैड को देखना चाहेंगे। अधिमानतः उपयोग करना objdump, लेकिन अन्य समाधान भी स्वीकार्य होंगे।

से इस सवाल मैंने सीखा है कि मैं कोड का जुदा भाग करने में सक्षम है, तो मैं सिर्फ सीमा का पता जान हो सकता है। इस उत्तर से मैंने सीखा है कि अपने विभाजन डिबग प्रतीकों को एक ही फाइल में कैसे वापस लाया जाए।

लेकिन यहां तक ​​कि उस एकल फ़ाइल पर काम करना, और यहां तक ​​कि सभी कोड (यानी बिना शुरुआत या रोक पता, लेकिन सादे -dपैरामीटर के साथ objdump), मैं अभी भी कहीं भी उस प्रतीक को नहीं देखता हूं। यह समझ में नहीं आता है कि प्रश्न में फ़ंक्शन स्थिर है, इसलिए इसे निर्यात नहीं किया जाता है। फिर भी, valgrindफ़ंक्शन नाम की रिपोर्ट करेगा, इसलिए इसे कहीं संग्रहीत करना होगा।

डिबग अनुभागों के विवरणों को देखते हुए, मुझे वह नाम .debug_strअनुभाग में उल्लिखित लगता है , लेकिन मुझे ऐसा कोई उपकरण नहीं है जो इसे पता सीमा में बदल सके।


2
एक मामूली पक्ष नोट: यदि कोई फ़ंक्शन चिह्नित है static, तो यह संकलक द्वारा अपनी कॉल साइटों में इनलाइन किया जा सकता है। इसका मतलब यह हो सकता है कि वास्तव में किसी भी कार्य को अलग करने के लिए कोई कार्य नहीं हो सकता है । यदि आप अन्य कार्यों के लिए प्रतीकों को देख सकते हैं, लेकिन जिस फ़ंक्शन की आप तलाश कर रहे हैं, यह एक मजबूत संकेत नहीं है कि फ़ंक्शन को इनलाइन किया गया है। Valgrind अभी भी मूल पूर्व-इनलाइन फ़ंक्शन को संदर्भित कर सकता है क्योंकि ELF फ़ाइल डिबगिंग सूचना भंडार है जहां से प्रत्येक व्यक्तिगत निर्देश उत्पन्न होता है, भले ही निर्देश कहीं और स्थानांतरित किए गए हों।
दाविदग

@davidg: सच है, लेकिन जब से टॉम द्वारा जवाब इस मामले में काम किया, यह मामला नहीं लगता है। फिर भी, क्या आपको पता है कि विधानसभा कोड को एनोटेट करने का एक तरीका है कि प्रत्येक निर्देश कहां से आया है?
एमवीजी

1
सुन कर अच्छा लगा! addr2lineपीसी / आईपी से स्वीकार करेंगे stdinऔर अपने संबंधित स्रोत कोड लाइनों का प्रिंट आउट लेंगे । इसी प्रकार, objdump -lसोर्स लाइनों के साथ ओब्जंप को मिलाया जाएगा; हालांकि भारी inlining के साथ अत्यधिक अनुकूलित कोड के लिए, या तो कार्यक्रम के परिणाम हमेशा विशेष रूप से सहायक नहीं होते हैं।
दाविद्ग

जवाबों:


87

मैं सबसे सरल दृष्टिकोण के रूप में gdb का उपयोग करने का सुझाव दूंगा। आप इसे एक-लाइनर के रूप में भी कर सकते हैं, जैसे:

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

4
+1 अनिर्दिष्ट सुविधा! -ex 'command'में नहीं है man gdb? लेकिन वास्तव में gdb डॉक्स में सूचीबद्ध है । दूसरों के लिए भी, जैसे सामान /bin/lsछीन लिया जा सकता है, इसलिए यदि वह सटीक कमांड कुछ भी नहीं दिखाता है, तो किसी अन्य ऑब्जेक्ट को आज़माएं! फ़ाइल या ऑब्जेक्ट को नंगेवर्ड तर्क के रूप में भी निर्दिष्ट कर सकते हैं; जैसे,gdb -batch -ex 'disassemble main' /bin/ls
hoc_age

3
मैन पेज निश्चित नहीं है। लंबे समय तक यह वास्तव में बनाए नहीं रखा गया था, लेकिन अब मुझे लगता है कि यह मुख्य डॉक्स से उत्पन्न हुआ है। इसके अलावा "gdb --help" अब और भी पूरा हो गया है।
टॉम ट्रोमी

7
gdb /bin/ls -batch -ex 'disassemble main'के रूप में अच्छी तरह से काम करता है
स्टीफन

1
यदि आप column -ts$'\t'GDB आउटपुट को फ़िल्टर करने के लिए उपयोग करते हैं, तो आपके पास कच्ची बाइट्स और स्रोत कॉलम अच्छी तरह से संरेखित होंगे। इसके अलावा, -ex 'set disassembly-flavor intel'अन्य -exएस से पहले इंटेल असेंबली सिंटैक्स में परिणाम होगा।
रुस्लान

मैंने disassemble fnविधि का उपयोग करते हुए, ऊपर कहा। लेकिन ऐसा लगता है कि जब बाइनरी फ़ाइल में एक ही नाम के साथ कई फ़ंक्शन होते हैं, तो केवल एक ही डिसैम्बल्ड होता है। क्या उन सभी को अलग करना संभव है या मुझे कच्चे पते के आधार पर उन्हें अलग करना चाहिए?
TheAhmad

28

disassemble/rsस्रोत और कच्चे बाइट्स को दिखाने के लिए gdb

इस प्रारूप के साथ, यह वास्तव में objdump -Sआउटपुट के करीब हो जाता है :

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

main.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;
}

संकलन और जुदा करना

gcc -O0 -ggdb3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
gdb -batch -ex "disassemble/rs myfunc" main.out

disassembly:

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.

उबंटू 16.04, GDB 7.11.1 पर परीक्षण किया गया।

objdump + awk workarounds

अनुच्छेद का उल्लेख करें : /unix/82944/how-to-grep-for-text-in-a-file-and-display-the-paragraph-bhat-has-the -टेक्स्ट

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

उदाहरण के लिए:

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

बस देता है:

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   

उपयोग करते समय -S, मुझे नहीं लगता कि कोई विफल-प्रूफ तरीका है, क्योंकि कोड टिप्पणियों में कोई भी संभावित अनुक्रम हो सकता है ... लेकिन निम्नलिखित कार्य लगभग सभी कार्य हैं:

objdump -S main.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 वर्कअराउंड उस केस का उपयोग करता है।


जीडीबी दृष्टिकोण साझा पुस्तकालयों और ऑब्जेक्ट फ़ाइलों पर ठीक काम करता है।
टॉम ट्रॉमी

16

Objdump का उपयोग करके एक एकल फ़ंक्शन को इकट्ठा करें

मेरे पास दो उपाय हैं:

1. कमांडलाइन आधारित

यह विधि पूरी तरह से काम करती है और एक सरल अतिरिक्त है। मैं -d ध्वज के साथ objdump का उपयोग करता हूं और awk के माध्यम से इसे पाइप करता हूं । असंतुष्ट आउटपुट जैसा दिखता है

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

के साथ शुरू करने के लिए, मैं ओबजडम्प आउटपुट के विवरण के साथ शुरू करता हूं। किसी अनुभाग या फ़ंक्शन को एक खाली रेखा द्वारा अलग किया जाता है। इसलिए एफएस (फील्ड सेपरेटर) को नईलाइन में बदलना और आरएस (रिकॉर्ड सेपरेटर) को दो बार नईलाइन में बदलना आपको अपने अनुशंसित फ़ंक्शन की आसानी से खोज करने देता है, क्योंकि यह केवल $ 1 क्षेत्र के भीतर खोजना है!

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

बेशक आप किसी भी अन्य फ़ंक्शन के साथ मुख्य को बदल सकते हैं जिसे आप प्रिंट करना चाहते हैं।

2. बैश स्क्रिप्ट

मैंने इस मुद्दे के लिए एक छोटी सी बैश स्क्रिप्ट लिखी है। पेस्ट करें और इसे कॉपी करें और इसे सेव करें जैसे कि dasm फ़ाइल।

#!/bin/bash
# Author: abu
# filename: dasm
# 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

एक्स-एक्सेस को बदलें और उदाहरण के लिए इसे लागू करें:

chmod +x dasm
./dasm test main

यह स्क्रिप्ट के साथ gdb को आमंत्रित करने की तुलना में बहुत तेज़ है। जिस तरह से objdump का उपयोग करके पुस्तकालयों को स्मृति में लोड नहीं किया जाएगा और इसलिए सुरक्षित है!


विटाली फादेव ने इस स्क्रिप्ट को एक ऑटो-पूरा करने के लिए प्रोग्राम किया, जो वास्तव में एक अच्छी सुविधा है और टाइपिंग को गति देता है।

स्क्रिप्ट यहां मिल सकती है


ऐसा लगता है कि यह निर्भर करता है objdumpया gdbतेज है। एक विशाल बाइनरी (फ़ायरफ़ॉक्स 'libxul.so) के objdumpलिए हमेशा के लिए लेता है, मैंने इसे एक घंटे के बाद रद्द कर दिया, जबकि gdbएक मिनट से भी कम समय लगता है।
शमौन

6

यदि आपके पास एक बहुत हाल ही में बिनुटिल (2.32+) है, तो यह बहुत सरल है।

पासिंग --disassemble=SYMBOLobjdump लिए केवल निर्दिष्ट समारोह एकत्रित न होगा। प्रारंभ पता और अंतिम पते को पास करने की आवश्यकता नहीं है।

LLVM objdump में भी एक समान विकल्प ( --disassemble-symbols) है।


धन्यवाद। Binutils के लिए चांगेलॉग 2.32, 02 फरवरी 2019: lists.gnu.org/archive/html/info-gnu/2019-02/msg00000.html " Objdump's --disassemble विकल्प अब एक पैरामीटर ले सकता है। इस प्रतीक से अगले प्रतीक या समारोह के अंत तक जारी रहेगा। "
ऑग्सक्स

5

अन्य उत्तरों के सापेक्ष ओबजंप के आउटपुट को पार्स करने के लिए awk के उपयोग को सरल बनाने के लिए:

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

4

यह gdb समाधान की तरह ही काम करता है (इसमें कि यह ऑफ़सेट को शून्य की ओर स्थानांतरित करता है) सिवाय इसके कि यह शिथिल न हो (मेरे पीसी पर लगभग 5ms में काम हो जाता है जबकि gdb समाधान में लगभग 150ms लगते हैं):

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 }'

मैं अभी परीक्षण नहीं कर सकता, लेकिन जब मैं इसके लिए चक्कर लगाऊंगा तो मैं आगे देखूंगा। क्या आप "शून्य की दिशा में बदलाव" पर थोड़ा विस्तार कर सकते हैं? मुझे यहाँ gdb उत्तरों में यह स्पष्ट नहीं दिखाई दिया, और मैं थोड़ा और सुनना चाहता हूँ कि वास्तव में वहाँ क्या हो रहा है और क्यों।
19

यह मूल रूप से ऐसा दिखता है जैसे कि आप जिस फ़ंक्शन को लक्षित करते हैं (जो कि पहला awkकाम करता है) ऑब्जेक्ट फ़ाइल में एकमात्र फ़ंक्शन था, अर्थात, भले ही फ़ंक्शन शुरू होता है, कहते हैं 0x2d, दूसरा awk इसे 0x00घटाकर (घटाकर) 0x2dप्रत्येक निर्देश के पते से), जो उपयोगी है क्योंकि असेंबली कोड अक्सर फ़ंक्शन की शुरुआत के सापेक्ष संदर्भ बनाता है और यदि फ़ंक्शन 0 से शुरू होता है, तो आपको अपने सिर में घटाव करने की ज़रूरत नहीं है। Awk कोड बेहतर हो सकता है लेकिन कम से कम यह काम करता है और काफी कुशल है।
PSkocik

रेट्रोस्पेक्ट में ऐसा लगता -ffunction-sectionsहै कि प्रत्येक फ़ंक्शन को 0. से शुरू करने का एक आसान तरीका है
PSkocik

3

बैश पूरा होने के लिए ./dasm

इस समाधान के लिए पूर्ण प्रतीक नाम (डी लैंग संस्करण):

  • टाइप करके dasm testऔर फिर दबाने पर TabTab, आपको सभी फ़ंक्शन की सूची मिल जाएगी।
  • टाइप करके dasm test mऔर फिर m से TabTab शुरू होने वाले सभी फ़ंक्शन को दबाकर दिखाया जाएगा, या यदि केवल एक फ़ंक्शन मौजूद है, तो यह स्वतः पूर्ण हो जाएगा।

फ़ाइल /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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.