2013年6月20日 星期四

x86 machine code 初探 (1) - base register address mode + displacement

這次新連載的東西可以寫好幾篇 (不輸給邓志那系列), 第貳篇我們來看看有 displacement 的 machine code。要學習的東西好多, 有資料結構 (之前沒學好, 要重新學習才行), compiler, lisp, forth, cortex m3 context switch, linker 的工作原理, 我知道該學習 Knuth 的一次只專注在一件事情上, 不過每個項目都那麼有趣, 實在想快點搞懂。linker 的工作原理和 machine code 有關係, 靜下心來先把這些東西完成。

像冨樫義博那樣拖稿讓人非常討厭, 我喜歡荒木飛呂彥的出稿速度, 搞不好他真的有天堂之門, 我也希望擁有天堂之門的能力, 酷阿!

廢話說太多, 來看這兩個例子, 透過例子來理解 machine code 是最好的方法了, 所以這系列我都會以例子來說明:
  1. base register address mode + displacement8
  2. base register address mode + displacement32

用 32bit 組譯出來的 machine code。

#practice x86 machine code
#.code16
.code32
.text
.global begin
begin:
  sub 126(%edi), %edi

intel syntax: sub edi, [edi+126]
註: 這個例子是 32bit mode

objdump -d address_mode.elf
1
2 address_mode.elf:     file format elf32-i386
3
4
5 Disassembly of section .text:
6
7 00000100 <_text>:
8  100:  2b 7f 7e                sub    0x7e(%edi),%edi

opcode: 2b
http://css.csail.mit.edu/6.858/2011/readings/i386/SUB.htm
2B  /r    SUB r32,r/m32    2/7    Subtract dword register from r/m dword

modrm: 7f -> 0111 1111 -> 01 111 111
mod: 01
reg: 111 (edi)
r/m: 111

mod: 01 (32bit)
[EAX]+disp83000
[ECX]+disp8 001
[EDX]+disp8 010
[EBX]+disp8 011
[--]+disp8 100
[EBP]+disp8 101
[ESI]+disp8 110
[EDI]+disp8 111

查表得到 (這個表在 intel 手冊查得, 有分 16/32 bit 兩種不同表格)
mod:01, r/m:111 => [EDI]+disp8 => [EDI] + 0x7e => [EDI + 126]
2b 7f 7e 就是這麼來的。



#practice x86 machine code
#.code16
.code32
.text
.global begin
begin:
  add 0x12345678(%edi), %esi
intel syntax: add esi, [edi+12345678h]

objdump -d address_mode.elf
1
2 address_mode.elf:     file format elf32-i386
3
4
5 Disassembly of section .text:
6
7 00000100 <_text>:
8  100:  03 b7 78 56 34 12       add    0x12345678(%edi),%esi

add opcode: http://css.csail.mit.edu/6.858/2011/readings/i386/ADD.htm
03 /r   ADD r32,r/m32      2/6    Add r/m dword to dword register

modrm: b7 -> 1011 0111 -> 10 110 111
mod:10
reg: 110 (esi)
r/m: 111

mod: 10 (32bit)
[EAX]+disp32 000
[ECX]+disp32 001
[EDX]+disp32 010
[EBX]+disp32 011
[--][--]+ disp32 100
[EBP]+disp32 101
[ESI]+disp32 110
[EDI]+disp32 111

查表得到
mod: 10
r/m: 111
=> [EDI]+disp32 => EDI + 78 56 34 12 => [EDI + 0x 12345678]


來看個 16 bit 範例:
section:disp(base,index,scale)
# practice x86 machine code
.code16
.text
.global begin
begin:
  add 0x12(%bx, %si, 1), %si

03 70 12      add    0x12(%bx,%si),%si

16bit mode 沒有 scale 這欄位, 所以 1 就被拿掉了, 而 scale 1 和沒有 scale 是一樣的。
modrm: 70 -> 0111 0000 -> 01 110 000
mod: 01
reg: 110 (SI)
r/m: 000


mod: 01 (16bit)
[BX+SI]+disp8 000
[BX+DI]+disp8 001
[BP+SI]+disp8 010
[BP+DI]+disp8 011
[SI]+disp8 100
[DI]+disp8 101
[BP]+disp8 110
[BX]+disp8 111

查表得到

mod: 01

r/m: 000
[BX+SI]+disp8 => [BX+SI] + 0x12



在 16 bit 模式下把 scale factor 改成 2 會怎樣?

# practice x86 machine code
.code16
.text
.global begin
begin:
  add 0x12(%bx, %si, 2), %si

address_mode.S: Assembler messages:
address_mode.S:8: Error: `0x12(%bx,%si,2)' is not a valid base/index expression
make: *** [address_mode.o] Error 1

組譯就不會過, 現在你知道為什麼了。


沒有留言:

張貼留言

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。