處理器如何確定每條指令的操作碼和操作數:使用 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
.
為什麼在 vim 上執行 :%!xxd 和 :%!xxd -b 命令時會添加一些行和刪除一些行
因為
vim
算作0x0a
換行符,並且二進製文件包含那些(在您的版本中為 74ls
…),所以在原始二進製文件和其他形式之間交換時,二進製文件中的這 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”。