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


89

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

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

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

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


2
참고 : 함수가으로 표시 static되면 컴파일러가 호출 사이트로 인라인 할 수 있습니다. 이것은 그 자체 로 분해 할 기능이 실제로 없을 수도 있음을 의미 할 수 있습니다 . 다른 기능에 대한 기호를 찾을 수 있지만 찾고있는 기능이 아닌 경우 이는 해당 기능이 인라인되었음을 나타내는 강력한 힌트입니다. Valgrind는 명령이 다른 곳으로 이동하더라도 ELF 파일 디버깅 정보가 각 개별 명령이 시작된 위치를 저장하기 때문에 원래의 사전 인라인 함수를 계속 참조 할 수 있습니다.
davidg

@davidg : 사실이지만이 경우에 Tom의 대답이 효과가 있었기 때문에 그렇지 않은 것 같습니다. 그럼에도 불구하고 각 명령어의 출처에 대한 정보로 어셈블리 코드에 주석을 추가하는 방법을 알고 있습니까?
MvG 2014

1
듣기 좋습니다! addr2linePC / IP를 받아 stdin해당 소스 코드 행을 인쇄합니다. 마찬가지로 objdump -lobjdump를 소스 행과 혼합합니다. 인라인이 많은 고도로 최적화 된 코드의 경우 두 프로그램의 결과가 항상 특별히 도움이되는 것은 아닙니다.
davidg

답변:


86

가장 간단한 방법으로 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"도 이제 더 완벽합니다.
Tom Tromey 2014 년

7
gdb /bin/ls -batch -ex 'disassemble main'작동합니다
stefanct

1
column -ts$'\t'GDB 출력을 필터링하는 데 사용 하면 원시 바이트와 소스 열이 잘 정렬됩니다. 또한 -ex 'set disassembly-flavor intel'다른 -exs 전에 인텔 어셈블리 구문이 발생합니다.
Ruslan

disassemble fn위의 방법을 사용하여 호출했습니다 . 하지만 바이너리 파일에 같은 이름의 함수가 여러 개 있으면 하나만 디스 어셈블되는 것 같습니다. 모두 분해 할 수 있나요, 아니면 원시 주소를 기준으로 분해해야하나요?
TheAhmad

26

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 해결 방법

/unix/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 해결 방법이 해당 사용 사례를 다루기 때문일 것입니다.


gdb 접근 방식은 공유 라이브러리 및 개체 파일에서 잘 작동합니다.
Tom Tromey

16

Objdump를 사용하여 하나의 단일 함수 분해

두 가지 해결책이 있습니다.

1. 명령 줄 기반

이 방법은 완벽하게 작동하며 간단한 방법을 추가합니다. objdump-d 플래그와 함께 사용 하고 awk를 통해 파이프 합니다 . 분해 된 출력은 다음과 같습니다.

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

우선 objdump 출력에 대한 설명부터 시작합니다. 또는 기능은 빈 라인으로 분리된다. 따라서 FS (Field Separator)를 개행으로 변경하고 RS (Record Separator)를 두 번 개행으로 변경하면 단순히 $ 1 필드 내에서 찾기 만하면 추천 기능을 쉽게 검색 할 수 있습니다!

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

물론 메인 을 교체 할 수 있습니다. 을 인쇄하려는 다른 기능으로 있습니다.

2. Bash 스크립트

이 문제에 대한 작은 bash 스크립트를 작성했습니다. 붙여넣고 복사 한 후 예를 들어 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

x-access를 변경하고 다음 과 같이 호출하십시오.

chmod +x dasm
./dasm test main

이것은 스크립트로 gdb를 호출하는 것보다 훨씬 빠릅니다. objdump를 사용하는 방법 외에도 라이브러리를 메모리에로드 하지 않으므로 더 안전합니다!


Vitaly Fadeev 는이 스크립트에 자동 완성 기능을 프로그래밍했습니다. 이것은 정말 멋진 기능이며 타이핑 속도를 높여줍니다.

스크립트는 여기 에서 찾을 수 있습니다 .


objdump또는 gdb더 빠른지 여부에 따라 다릅니다 . 거대한 바이너리 (Firefox의 libxul.so) objdump는 영원히 걸리기 때문에 1 시간 후에 취소했지만 gdb1 분도 채 걸리지 않았습니다.
Simon

5

다른 답변과 관련하여 objdump의 출력을 구문 분석하기 위해 awk 사용을 단순화하려면 다음을 수행하십시오.

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

4

이것은 gdb 솔루션과 똑같이 작동합니다 (오프셋을 0으로 이동한다는 점에서).

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

지금은 테스트 할 수 없지만이 문제를 다룰 때가 기대됩니다. "0으로 상쇄되는 이동"측면에 대해 좀 더 자세히 설명해 주시겠습니까? 나는 여기에 gdb 답변에서 명시적인 것을 보지 못했고 실제로 무슨 일이 일어나고 왜 그 이유에 대해 조금 더 듣고 싶습니다.
MvG

기본적으로 대상 함수 (첫 번째 awk기능)가 객체 파일의 유일한 함수 인 것처럼 보이게 합니다. 즉, 함수가에서 시작하더라도 0x2d두 번째 awk는이를 방향으로 이동합니다 0x00( 0x2d이는 어셈블리 코드가 함수의 시작과 관련하여 참조를 만드는 경우가 많고 함수가 0에서 시작하면 머리에서 빼기를 수행 할 필요가 없기 때문에 유용합니다. awk 코드는 더 좋을 수 있지만 적어도 작업을 수행하고 상당히 효율적입니다.
PSkocik

돌이켜 보면로 컴파일하는 -ffunction-sections것이 각 함수가 0에서 시작하는지 확인하는 더 쉬운 방법 인 것 같습니다.
PSkocik

4

최신 binutils (2.32+)가 있다면 이것은 매우 간단합니다.

--disassemble=SYMBOLobjdump에 전달 하면 지정된 함수 만 디스 어셈블됩니다. 시작 주소와 끝 주소를 전달할 필요가 없습니다.

LLVM objdump에도 유사한 옵션 ( --disassemble-symbols)이 있습니다.


감사합니다. binutils 2.32의 변경 사항, 2019 년 2 월 2 일 : lists.gnu.org/archive/html/info-gnu/2019-02/msg00000.html " Objdump 의 --disassemble 옵션은 이제 디스 어셈블리 시작 기호를 지정하는 매개 변수를 사용할 수 있습니다. 디스 어셈블리 이 기호에서 다음 기호 또는 기능의 끝까지 계속됩니다. "
osgx

3

배시 완성 ./dasm

이 솔루션대한 전체 기호 이름 (D lang 버전) :

  • 입력 dasm test한 다음를 누르면 TabTab모든 기능 목록이 표시됩니다.
  • 입력 dasm test mm으로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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.