102

我的系统上安装了一个二进制文件,并想查看给定函数的反汇编。最好使用objdump,但其他解决方案也可以接受。

这个问题中我了解到,如果我只知道边界地址,我可能能够反汇编部分代码。从这个答案中,我学会了如何将拆分调试符号转换回单个文件。

但即使在那个单一文件上操作,甚至反汇编所有代码(即没有开始或停止地址,但-d有 的普通参数objdump),我仍然在任何地方都看不到那个符号。就所讨论的函数是静态的而言,这是有道理的,因此它不会被导出。尽管如此,valgrind将报告函数名称,因此必须将其存储在某个地方。

查看调试部分的详细信息,我发现该.debug_str部分中提到了该名称,但我不知道可以将其转换为地址范围的工具。

4

10 回答 10

95

我建议使用 gdb 作为最简单的方法。您甚至可以将其作为单线进行,例如:

gdb -batch -ex 'file /bin/ls' -ex 'disassemble main'
于 2014-04-01T01:47:57.543 回答
35

gdbdisassemble/rs也显示源字节和原始字节

使用这种格式,它非常接近objdump -S输出:

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

主程序

#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 解决方法涵盖了该用例。

于 2015-06-30T12:30:51.907 回答
18

如果你有一个最近的 binutils (2.32+),这很简单。

传递--disassemble=SYMBOL给 objdump 将只反汇编指定的函数。无需传递起始地址和结束地址。

LLVM objdump 也有一个类似的选项 ( --disassemble-symbols)。

于 2020-06-06T22:51:00.540 回答
17

使用 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(字段分隔符)更改为换行符,将RS(记录分隔符)更改为两次换行符可以让您轻松搜索推荐的函数,因为它只是在 $1 字段中查找!

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

当然,您可以将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为这个脚本编写了一个自动完成功能,这确实是一个不错的功能,可以加快打字速度。

可以在此处找到该脚本。

于 2018-04-09T11:38:00.570 回答
5

为了简化使用 awk 来解析 objdump 相对于其他答案的输出:

objdump -d filename | sed '/<functionName>:/,/^$/!d'
于 2017-05-01T03:59:09.993 回答
4

这就像 gdb 解决方案一样工作(因为它将偏移量移向零),只是它不是滞后的(在我的 PC 上完成工作大约需要 5 毫秒,而 gdb 解决方案大约需要 150 毫秒):

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 }'
于 2016-08-07T16:23:42.277 回答
3

bash 完成./dasm

此解决方案完整符号名称(D 语言版本):

  • 通过键入dasm test然后按TabTab,您将获得所有功能的列表。
  • 通过键入dasm test m然后按所有以mTabTab 开头的功能将显示,或者如果只有一个功能存在,它将自动完成。

文件/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
于 2018-05-08T12:01:56.703 回答
0

也许这很容易做到:
objdump -d libxxx.so | grep -A 50 func_name_to_be_searched

于 2021-01-19T12:58:15.570 回答
0

只需使用objdump -d filename | awk '/<funcname>/,/^$/'

于 2021-11-22T14:43:12.850 回答
0

不完全是您所要求的,但如果您使用 GCC 从源代码编译 C 或 C++ 程序,您可以添加一个函数属性以将其放在二进制文件的自定义命名部分中:

extern __attribute__((noinline, section("disasm"))) void foo() {}

然后,您可以要求objdump仅显示该命名部分中的函数-jdisasm

于 2021-12-22T08:52:27.297 回答