Vim

處理器如何確定每條指令的操作碼和操作數:使用 VIM 查看二進製文件

  • June 5, 2017

我在 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換行符,並且二進製文件包含那些(在您的版本中為 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”。

引用自:https://unix.stackexchange.com/questions/369224