处理器如何确定每条指令的操作码和操作数:使用 VIM 查看二进制文件

处理器如何确定每条指令的操作码和操作数:使用 VIM 查看二进制文件

我在 FreeBSD 10.3 上运行命令view /bin/ls,可以看到未修改的二进制文件:

在此输入图像描述

然后在 vim/view 上运行命令:%!xxd,我可以看到十六进制格式的文件,如下所示。我注意到页面底部 vim 宣布添加了 1708 行并删除了 74 行。

在此输入图像描述

我通过命令关闭 vim :q!,然后再次打开它,view /bin/ls然后运行 ​​vim 命令:%!xxd -b以查看二进制格式的文件,如下所示。页面底部写着添加了 4555 行,删除了 74 行。

在此输入图像描述

现在我想知道:

  • 为什么在vim上运行:%!xxd和命令时有些行被添加,有些行被删除:%!xxd -b

  • 对于十六进制格式,即%!xxd运行命令时,行地址为 00000000、00000010、00000020、00000030 等。看起来这是因为每行包含 16 个字节,因此 0x10 增量是有意义的。

  • 对于二进制格式,即%!xxd -b运行命令时,行地址为00000000、00000006、0000000c、00000012等。看起来这是因为每行包含 6 个字节,因此 0x06 增量是有意义的。

  • 以前我认为每个二进制文件在一行中包含每个处理器指令,并且在每行的开头都有该指令的相对地址,第一条指令从 0 开始。但根据我对 vim 上二进制文件的观察,事实并非如此。现在我想知道处理器如何确定每条指令的操作码和操作数,如果指令未在二进制文件上逐行格式化。


更新:

十六进制格式的最后五行是:

00006a70: 0100 0000 3000 0000 0000 0000 4862 0000  ....0.......Hb..
00006a80: 3e03 0000 0000 0000 0000 0000 0100 0000  >...............
00006a90: 0100 0000 0100 0000 0300 0000 0000 0000  ................
00006aa0: 0000 0000 8665 0000 d500 0000 0000 0000  .....e..........
00006ab0: 0000 0000 0100 0000 0000 0000 0a         .............

二进制格式的最后五行是:

00006aa4: 10000110 01100101 00000000 00000000 11010101 00000000  .e....
00006aaa: 00000000 00000000 00000000 00000000 00000000 00000000  ......
00006ab0: 00000000 00000000 00000000 00000000 00000001 00000000  ......
00006ab6: 00000000 00000000 00000000 00000000 00000000 00000000  ......
00006abc: 00001010                                               .

因此,我认为十六进制和二进制格式的字节总数是相同的,我的意思是两者代码最后一个字节的地址都是0x6abc

答案1

为什么在 vim 上运行 :%!xxd 和 :%!xxd -b 命令时会添加一些行并删除一些行

因为vim算作0x0a换行符,并且二进制文件包含这些换行符(您的版本中为 74 行ls...),因此在原始二进制文件和其他形式之间交换时,二进制文件中的这 74 行将被删除,新行将被删除。添加用于(更详细的)十六进制显示。vim只是计算它所0x0a看到的。

现在我想知道处理器如何确定每条指令的操作码和操作数

魔法!这很复杂,并且有很多关于这个主题的书。简而言之,链接器(或同等学历)对于特定的二进制格式(在您的情况下为 ELF,尽管确实存在其他格式 - a.out、Mach-O,...)将指示起始地址

$ readelf -h /bin/ls
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x37f0
...

程序被提升到内存后,操作码的执行将开始于。起始地址通常(但可能不是)位于.text二进制文件部分的某个位置:

$ objdump -DS /bin/ls | less -p .text
...

在我的 OpenBSD 系统上显示:

Disassembly of section .text:

00000000000037f0 <revnamecmp-0x460>:
    37f0:       49 89 e4                mov    %rsp,%r12
    37f3:       48 83 ec 08             sub    $0x8,%rsp
    37f7:       48 83 e4 f0             and    $0xfffffffffffffff0,%rsp
    37fb:       48 83 c4 08             add    $0x8,%rsp
...

也许值得一看的书籍包括 Jeff Duntemann 的《Assembly Language Step-by-Step》和 Ryan O'Neill 的 ELF 《Learning Linux Binary Analysis》。

相关内容