我在 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》。