从 objdump 获取仅十六进制输出

从 objdump 获取仅十六进制输出

举例来说,我有这个 C 函数:

void f(int *x, int *y)
{
    (*x) = (*x) * (*y);
}

当保存到时f.c,编译gcc -c f.c会产生f.o.objdump -d f.o给出这个:

f.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <f>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
   8:   48 89 75 f0             mov    %rsi,-0x10(%rbp)
   c:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  10:   8b 10                   mov    (%rax),%edx
  12:   48 8b 45 f0             mov    -0x10(%rbp),%rax
  16:   8b 00                   mov    (%rax),%eax
  18:   0f af d0                imul   %eax,%edx
  1b:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  1f:   89 10                   mov    %edx,(%rax)
  21:   5d                      pop    %rbp
  22:   c3                      retq  

我希望它输出更像这样的内容:

55 48 89 e5 48 89 7d f8 48 89 75 f0 48 8b 45 f8 8b 10 48 8b 45 f0 8b 00 0f af d0 48 8b 45 f8 89 10 5d c3

即,只是函数的十六进制值。有一些objdump标志可以做到这一点吗?否则,我可以使用什么工具(例如 awk、sed、cut 等)来获得所需的输出?

答案1

您可以使用以下命令提取文本段中的字节值:

$ objcopy -O binary -j .text f.o fo

-O 二进制选项:

objcopy 可用于通过使用二进制输出目标(例如,使用 -O 二进制)来生成原始二进制文件。当 objcopy 生成原始二进制文件时,它本质上会生成输入对象文件内容的内存转储。所有符号和重定位信息都将被丢弃。内存转储将从复制到输出文件的最低部分的加载地址开始。

选项-j .text

-jsectionpattern
--only-section=sectionpattern
仅将指定的部分从输入文件复制到输出文件。该选项可以多次给出。
请注意,不当使用此选项可能会导致输出文件无法使用。节模式中接受通配符。

最终结果是一个fo仅包含该部分的二进制值的文件 ( ) .text,即没有符号或重定位信息的可执行代码。

然后打印fo文件的十六进制值:

$ od -An -v -t x1 fo
 55 48 89 e5 48 89 7d f8 48 89 75 f0 48 8b 45 f8
 8b 10 48 8b 45 f0 8b 00 0f af d0 48 8b 45 f8 89
 10 90 5d c3

答案2

怎么样

awk '/^....:/{a=substr($0,9,20);sub(/ +$/,"",a);b=b" "a}END{print substr(b,2)}'

在这种情况下,将返回

55 48 89 e5 48 89 7d f8 48 89 75 f0 48 8b 45 f8 8b 10 48 8b 45 f0 8b 00 0f af d0 48 8b 45 f8 89 10 5d c3

答案3

另一种选择是使用readelf

$ readelf -x .text f.o

Hex dump of section '.text':
  0x00070c00 f30f1efa 488d15fd 13100048 8d357606 ....H......H.5v.
  0x00070c10 1100488d 3dc33809 00e902f5 fffff30f ..H.=.8.........
  0x00070c20 1efa5548 8d2d9606 1100be22 00000045 ..UH.-....."...E
  ...

对于一些特定的 .elf 文件,由于未知原因(可能是特定的架构不兼容)objdumpobjcopy丢失,并且readelf是我能找到的唯一可行的解​​决方案。

答案4

解决方案1:

42sh$ objcopy -j .text f.o /proc/self/fd/1 -O verilog | tail -n +2 | tr '\n' ' ' | tr -d '\r'
8B 07 0F AF 06 89 07 C3 42sh$

您会看到 '\n' 在空格中进行了转换,因此我们得到了尾随空格而不是最后一个换行符。 tail 和 tr 仅用于完全按照您的要求进行转换。

解决方案2:

42sh$ objcopy -O binary -j .text f.o /proc/self/fd/1 | xxd -ps -c 36 | sed 's,..,& ,g; s, $,,'
8b 07 0f af 06 89 07 c3
42sh$

这里我们要求 objcopy 以原始二进制文件打印,然后我们用 xxd (代表十六进制转储)而不是 od (代表八进制转储)进行十六进制编码,就像接受的答案一样。

-c 是字符数,如果您希望所有符号都在一行中,则可以使用大量字符。 sed 使用两个替换,如解释的那样https://askubuntu.com/a/661687/772955一个用于散布空格,一个用于删除最后一个空格。 sed 保留 \n

常见解释:

objcopy 只读取我们想要的部分。

在这两种解决方案中,我们通过直接写入管道 /dev/stdout 来避免临时文件,该管道在 Linux 上指向 /proc/self/fd/1 ,在 darwin 上指向 /dev/fd/1 。

如果是二进制输出,我们需要转换为十六进制。

然后我们用 sed/tr 进行美化,可以使用 awk/perl

编辑1:

谢谢@Stéphane Chazelas

相关内容