code

objdump를 사용하여 하나의 단일 함수를 분해하는 방법은 무엇입니까?

codestyles 2020. 11. 5. 08:02
반응형

objdump를 사용하여 하나의 단일 함수를 분해하는 방법은 무엇입니까?


내 시스템에 바이너리가 설치되어 있으며 주어진 함수의 분해를보고 싶습니다. 을 사용하는 objdump것이 좋지만 다른 솔루션도 사용할 수 있습니다.

에서 이 질문에 나는 단지 경계 주소를 알고 있다면 내가 코드의 분해 부분 수있을 것을 배웠다. 이 답변 에서 분할 디버그 기호를 단일 파일로 다시 바꾸는 방법을 배웠습니다.

그러나 해당 단일 파일에서 작동하고 모든 코드를 분해하더라도 (즉, 시작 또는 중지 주소없이 일반 -d매개 변수를으로 objdump) 여전히 해당 기호를 볼 수 없습니다. 문제의 함수가 정적이므로 내 보내지 않는 한 의미가 있습니다. 그럼에도 불구하고 valgrind함수 이름을보고하므로 어딘가에 저장해야합니다.

디버그 섹션의 세부 사항을 살펴보면 섹션에서 언급 한 이름을 찾았 .debug_str지만이를 주소 범위로 바꿀 수있는 도구를 모릅니다.


가장 간단한 방법으로 gdb를 사용하는 것이 좋습니다. 다음과 같이 한 줄로 할 수도 있습니다.

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

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

분해 :

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.

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에 언급 된대로 단락을 인쇄합니다. -본문

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

gdbTom이 제안한 해결 방법 외에도 -ffunction-section섹션 당 하나의 함수를 넣은 다음 섹션을 덤프하는 컴파일의 또 다른 (더 나쁜) 해결 방법에 대해서도 설명 합니다.

Nicolas Clifton이 WONTFIX https://sourceware.org/ml/binutils/2015-07/msg00004.html을 주었습니다 . 아마도 GDB 해결 방법이 해당 사용 사례를 다루기 때문일 것입니다.


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

A section or function is seperated by an empty line. Hence changing the FS (Field Seperator) to newline and the RS (Record Seperator) to twice newline let you easily search for your recommended function, since it is simply to find within the $1 field!

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

Of course you can replace main to any function you want to be output.

2. Bash Script

I have written a small bash script for this issue. Simply copy it and save it as e.g. dasm file.

#!/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

Change the x-access and invoke it with e.g.:

chmod +x dasm
./dasm test main

This is much faster than invoking gdb with a script. Beside the way using objdump will not load the libraries into memory and is therefore safer!


Vitaly Fadeev programmed the autocompletion to this script, which is really a nice feature and speeds up typing.

The script can be found here.


This works just like the gdb solution (in that that it shifts the offsets towards zero) except that it's not laggy (gets the job done in about 5ms on my PC whereas the gdb solution takes about 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 }'

To simplify the usage of awk for parsing objdump's output relative to other answers:

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

Bash completion for ./dasm

Complete symbol names to this solution (D lang version):

  • By typing dasm test and then pressing TabTab, you will get a list of all functions.
  • By typing dasm test m and then pressing TabTab all functions starting with m will be shown, or in case only one function exists, it will be autocompleted.

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

참고URL : https://stackoverflow.com/questions/22769246/how-to-disassemble-one-single-function-using-objdump

반응형