X86指令內幕 ——深入瞭解Prefix
1. Legacy prefix
1.1 legacy prefix 的作用
legacy prefix 主要有以下作用:
- 調整記憶體運算元的屬性
- 增強指令的功能
- 提供額外的作用
1.2 legacy prefix 分類
(1) operand size override prefix:66H --- 改變運算元大小
(2) address size override preifx:67H --- 改變運算元地址模式
(3) segment override prefix:改變 memory 運算元段選擇子,包括:
- 2E --- CS register
- 3E --- DS register
- 26 --- ES register
- 64 --- FS register
- 65 --- GS register
- 36 --- SS register
(4) rep/repz prefix:F3H --- 串指字重複執行
(5) repnz prefix:F2H --- 串指字重複執行
(6) lock prefix: F0H --- LOCK
1.3 REX prefix 的作用
★ 改變指令運算元的 default operand size(可以使用 64 位 operands),同樣是起 operand size override 的作用
★ 訪問 x64 體系所有 16 個 registers:rax ~ r15,xmm0 ~ xmm15
2. 指令系統的上下文環境
要徹底瞭解 prefix,必須要結合 3 個很重要的上下文環境:
- 指令本身的 default operand-size 和 default address-size 以及 effective operand size 和 effective address size
- assembler 編譯器上文環境
- 當前 processor 的執行上下文環境。
x86/x64 指令編碼會根據上面提到的 3 個上下文環境而對運算元的位置、大小以及地址進行調整改變。
這裡運算元是記憶體運算元。出現調整的情形,這是因為:
- effective operands-size 可以為:16
- operands 的地址位置因段選擇子的不同而不同(cs、ds、es、ss、fs 以及 gs)。
- effective address-size 可以為:16 位、32 位以及 64 位
也就是說:指令編碼因指令運算元的 operand size, address size 以及 segment 的不同而不同
3. 預設和有效(default 與 effective)上下文環境
在 x86/x64 平臺的指令系統裡有兩個很重要的概念:
★ 預設(default)概念
包括:預設運算元大小以及預設地址大小(default operand-size 與 default address-size)。
- 在 32 位下:default operands-size 和 default address-size 都是 32 位。
- 在 16 位下:default operands-size 和 default address-size 都是 16 位。
在 64 位下,情況有些特殊:
|
在 64 位下 default operands-size 是 32 位,是基於 x86 平滑擴充套件為 x64 的設計理念。
★ 有效(effective)概念
包括:有效的運算元大小以及有效地址大小(effective operand-size 與 effective address-size)
- 在 32 位下:effective operand size 與 effective address-size 可以為:16 位和 32 位
- 在 16 位下:effective operand size 與 effective address-size 可以為:16 位和 32 位。
- 在 64 位下:effective operand size 可以為:16 位、32 位和 64 位。
- 在 64 位下:effective address-size 可以為:32 位與 64 位。
模式 | effective operand size | effective address size | 備註 |
16 位 | 16, 32 | 16, 32 | |
32 位 | 16, 32 | 16, 32 | |
64 位 | 16, 32, 64 | 32, 64 |
在 64 位模式下,情況又有些特殊:在 64 位下支援 16 位,32 位以及 64 位的運算元大小。但是不支援 16 位的地址大小。
4. 調整運算元的大小(66H prefix - Operand Size Override)
4.1 Operand Size Override 行為
是指: |
基於這種需求,在指令編碼中使用 66H prefix 來實現 operand size override
4.2 66H prefix(Operand-Size Override prefix)
66H 位元組這個 prefix 用來更改 operands size,當然只能在指令所支援的 effective operand-size 範圍內進行調整。
66H 在 Opcode 表中就是一個 prefix,它不是 Opcode
4.3 Operand Size Override 的規則
怎樣進行 Override 以及 Override 什麼? 都是有固定的規則的,這和 default operand size 以及 effective operand size 有緊密的關係
表 4.3.1
模式 | default operand size | effective operand size | prefix | REX prefix | 描述 |
16 模式 | 16 | 16 | --- | --- | 16 位模式下的 2 種 default operand size 的情形 |
32 | 66H | ||||
32 | 16 | 66H | |||
32 | --- | ||||
32 模式 | 16 | 16 | --- | --- | 32 位模式下的 2 種 default operand size 的情形 |
32 | 66H | ||||
32 | 16 | 66H | |||
32 | --- | ||||
64 模式 | 32 | 16 | 66H | --- | 64 位模式下的 2 種 default operand size 情形 |
32 | --- | --- | |||
64 | --- | REX.W = 1 | |||
* 64 | 16 | 66H | --- | ||
64 | --- |
每一種模式下都分為 2 種 default operand size 情形,除了 64 位模式下 default operand size 是 32 時,有 3 種 effective operand size 外,其它都是 2 種 effective operand size
表中:--- 表示無需 prefix,REX.W = 1 表示:調整到 64 位(REX.W = 0 它是使用 default operand size)
* 標註處的 default operand size = 64 只有少數的指令 default operand size 是 64 位,大部分指令的 default 是 32 位的。
- 在 16 位模式下
- 當 default operand size 是 16 位時:需要調整為 32 位,需要加 66H prefix
- 當 default operand size 是 32 位時:需要調整為 16 位,需要加 66H prefix
- 在 32 位模式下
- 當 default operand size 是 16 位時:需要調整為 32 位,需要加 66H prefix
- 當 default operand size 是 32 位時:需要調整為 16 位,需要加 66H prefix
- 在 64 位模式下
- 當 default operand size 是 32 位時:需要調整為 16 位時,需要加 66H prefix。需要調整到 64 位時,需要加 REX prefix
- 當 default operand size 是 64 位時: 不能調整到 32 位,調整到 16 位時,需要 66H prefix
在 64 位的 default operand size 下,effective 只有 2 種:16 位和 64 位。因此:只能使用 66H prefix 調整到 16 位,不能調整到 32 位
4.4 為什麼需要改變運算元大小?
原因很簡單:16 位程式碼下需要訪問 32 位資料或者 32 位程式碼需要訪問 16 位資料。
4.5 看看幾個例子
例 1: 在 16 位的 default operand size 下,指令: mov eax, ebx
由於在 16 位下,如果運算元的大小預設是 16 位的,這條指令要訪問 32 位的暫存器,那麼需要使用 66H prefix 進行 operand size override
89 d8 ---> 66 89 d8 (使用 66H prefix 將 16 位 registers 改為 32 位 registers)
例 2: 在 32 位 default operand size 下,指令 mov ax, bx
由於在 32 位下,如果運算元的大小預設是 32 位的,這條指令要訪問 16 位暫存器,同樣需要使用 66H prefix 進行調
89 d8 ---> 66 89 d8 (使用 66H prefix 將 32 位 registers 改為 16 位 registers)
表 4.5.1 (在 16 位和 32 位模式下適用)
指令 | default operand size | 指令編碼 |
mov eax, ebx | 16 | 66 89 d8 |
32 | 89 d8 | |
mov ax, bx | 16 | 89 d8 |
32 | 66 89 d8 |
上表是這 2 條指令分別在不同的 default operand size 下的指令編碼情況
有些人或許會感到疑惑,為什麼例 1 與例 2 編譯器生成的結果是一樣的。這就是 assembler 在不同的 編譯上下文環境 譯為相同的指令編碼。
例3:在 32 位 default operand size 下,指令:mov ax, [11223344h]
在 Microsoft 的語法裡,在記憶體運算元前一般要加指示字 word ptr,指明運算元的大小:mov ax, word ptr [11223344h] 實際上,在這條指令裡,這個指示字不是必須的,加指示字只是比較直觀。但有些情況是必須要加的,如:mov dword ptr [11223344h], 1
這條指令有兩種譯法:
- 66 a1 44 33 22 11
- 66 8b 05 44 33 22 11
使用 66H prefix 進行 operand size override
第 1 條 encode 中,a1 是 opcode,44332211 是 immediate(而不是 dispalcement,因為不是 ModRM 定址提供的), 66 改變了預設的運算元大小,將 32 位調整為 16 位。
第 2 條 encode 的 opcode 是 8b, ModRm 是 05, 而 44332211 是 dispalcement 而不是 immediate(需要 ModRM 定址)。
例4: 在 16 位 default operand size 下,同樣一條指令:mov eax, [11223344]
同樣一樣指令,但目的運算元大小不同,並且 assembler 編譯上下文環境不同。
它兩種譯法為:
- 66 67 a1 44 33 22 11
- 66 67 8b 05 44 33 22 11
與例 3 所不同的是:這條指令增加了 67H prefix 來進行 address size override
表 4.5.2
指令 | default operand size | 指令編碼 |
mov ax, [11223344h] | 16 | 66 67 a1 44 33 22 11 |
32 | 66 a1 44 33 22 11 | |
mov eax, [11223344h] | 16 | 66 67 a1 44 33 22 11 |
32 | a1 44 33 22 11 |
這裡必須有一點要認識到的:當在 16 模式下, 地址 [11223344h] 多數編譯器會它截斷只取低 16 位地址
那麼:mov ax, [11223344h] 會被編譯為 66 a1 44 33 (它不需 67H prefix 進行 address size override)
5. 編譯上下文環境(assembler)
在一個組合語言原始檔裡,需要給編譯器一些編譯指示:指示目的碼將生成是多少的?目標平臺是什麼?檔案格式是什麼?等等...
這個就編譯上下文環境。
例如:
作業系統的引導初始化程式碼部分是 16 位的,現在絕大多數 OS 是 32 位的,因此,在當前系統下寫引導程式碼,則需要求編譯器編譯為 16 位真實模式程式碼。因此,你不得不寫 16 位程式碼,編譯器根據情況將 32 位操作和地址調整至 16 運算元和地址。但在大部分情況下,不需要作調整,直接生成 16 位程式碼即可。
5.1 生成多少位的機器指令
以 nasm 編譯器為例,下面給出一些程式碼片斷:
; ********************************************************* %include "include/arch/x64.inc" ; mouseOS 0.02 project
org BOOT_SEG ; for int 19 ; A20 gate enable
; How do ? cli
db 0x66 ; adjust to 32-bit operand size ; third: enable proected mode
jmp dword code32_sel:code32_entry ; Now: entry 32bit protected mode, but paging is disable code32_entry: mov di, 0 |
上面程式碼片斷顯示:在一個原始檔中,使用 bits 16 指示 nasm 生成 16 位的程式碼,並且使用 bits 32 指示 nasm 生成 32 位程式碼。 還可以使用 bits 64 來生成 64 位程式碼。
5.2 在原始碼中指定位模式
上面程式碼片斷中,使用 bits 偽指令來指示 nasm 生成何種程式碼。
這樣的結果是:
實際上是:要 nasm 假設指令將執行在 16 位,32 位還是 64 位模式? |
如下例子:
bits 16 mov eax, ebx |
程式碼中使用 bits 16 指示生成 16 位程式碼,它實際上是要 nasm 假設下面的指令將要執行在 16 位模式下。
00000000 6689D8 mov eax,ebx |
這和表 4.5.1 和 表 4.5.2 所列的編碼是一致的。 使用到了 66H prefix 和 67H prefix 進行 override
對於 16 位和 32 位模式來說,這個指令的位模在式相當於指出 default opernad size 是多少。但是對 64 位模式來說,並不代表 nasm 將假設指令的 default operand size 是 64 位。
6. processor 當前執行上下文環境
processor 處於什麼模式下,這是系統程式設計師需要考慮的問題,從而通過程式碼體現出來,編譯器根據程式碼生成相應的程式碼。
也就是說: |
機器指令 | processor 在 16 位模式下 | processor 在 32 位模式下 | processor 在 64 位模式下 |
69 8d | mov ax, bx | mov eax, ebx | mov eax, ebx |
上表顯示,同一條機器指令,當 processor 執行在不同的模式下,指令的解碼是不同的。但是隻不同在於 operand size
7. 調整地址大小(67H prefix - Address Size Override)
當需要改變地址大小的時候,也需要使用 67H prefix 來進行調整。同樣是在所支援的 effective address-size 範圍內。
7.1 Address Size Override 行為
是指: |
7.2 67H prefix(address size override prefix)
指令中可以 67H 進行 address size override,同樣 67H 不是 opcode,processor 的解碼邏輯遇到它會把它當作 prefix
7.2 Address size override 規則
怎樣進行 Override 以及 Override 什麼? 都是有固定的規則的,這和 default address size 以及 effective address size 有緊密的關係
表 7.2.1
processor 模式 | default address size | effective address size | prefix |
16 位模式 | 16 | 16 | --- |
32 | 67H | ||
32 | 16 | 67H | |
32 | --- | ||
32 位模式 | 16 | 16 | --- |
32 | 67H | ||
32 | 16 | 67H | |
32 | --- | ||
64 位模式 | 64 | 32 | 67H |
64 | --- |
與 Operand size override 規則一樣,在 effective address size 範圍裡調整為另一個 address size 需要使用 67H prefix
在 64 位模式下 default address size 是 64 位,不能調整到 16 位地址。
7.3 為什麼要調整地址大小
以 16 位模式為例,如果需要訪問 64K 以上的地址,需要什麼 32 位的定址模式。
那麼需要使用 67H prefix 將 16 位定址模式調整到 32 位定址模式。
7.4 Address size override 的幾個例子
例1:在 16 位下,以序言裡的指令為例:mov dword ptr [eax+ecx*8+0x11223344], 0x12345678
由於在 16 位的 default operands size 和 default address size 下,但該指令使用 32 位 operand size 以及 32 位 address size
也就是說既要調整 operand size 也要調整 address size。所以,應加上 66H prefix 調整 operand-size,再加上 67H prefix 調整 address-size。
最終的 encode 為: 66 67 c7 84 c8 44 33 22 11 78 56 34 12
例2:在 32 位模式下,指令:mov eax, dword ptr [11223344]
該指令的編碼為: a1 44 33 22 11
對這個編碼,我們手工進行調整,加上 67H prefix: 67 a1 44 33 22 11
那麼此時,用 67H prefix 調整為 16 位地址,那麼在彙編語句將變為: mov eax, dword ptr [3344]
結果是: 加了 67H prefix 之後,它的地址將被截斷為 16 位。即地址:0x3344,多出 22 11 兩個位元組屬下條指令邊界了。
例3:在 32 位下,指令:mov eax, dword ptr [bx + si + 0x0c]
很顯然,這條彙編語句源運算元的地址是 16 位的。
在當前的 32 位編譯環境下,應使用 67H prefix 將這個 16 位地址調整 32 位地址。
最終的 encodes 是: 67 8b 40 0c
40H 這個 ModRM 定址的地址方式是: [bx + si + 0x0c] (16 位),當使用 67H prefix 調整為 32 位地址時是:[eax + 0x0c]
若這條指令的 encode 放在 16 位下執行,彙編形式變為: mov eax, dword ptr [eax + 0x0c](16 位下,67H prefix 調整的結果)
7.5 16 位定址模式與 32 位定址模式的區別
上面的 3 個例子顯示了 16 位地址和 32 位地址的區別,主要來自 16 位的記憶體運算元定址只支援 BX 與 BP 暫存器作為基址暫存器,SI 和 DI 暫存器作為變址暫存器,比 32 位的記憶體定址少得多。
表7.5.1 assembler 在 32 位下和 16 位下的區別(assembler 編譯上下文環境)
序號 | 指令 | 在 32 位下編譯的結果 | 在 16 位下編譯的結果 |
1 | mov dword ptr [eax + ecx * 8 + 0x11223344], 0x12345678 | c7 84 c8 44 33 22 11 78 56 34 12 | 66 67 c7 84 c8 44 33 22 11 78 56 34 12 |
2* | mov eax, dword ptr [0x11223344] | a1 44 33 22 11 | 66 a1 44 33 |
3 | mov eax, dword ptr [bx + si + 0x0c] | 67 8b 40 0c | 66 8b 40 0c |
表1中顯示的是在不同的編譯上下文環境,同一條指令產生的不同編碼(例如,在 nasm 編譯器使用 bits 16 和 bits 32 指示字)
注意:
在第 2 條時,地址 [0x11223344] 在 16 位程式碼的編譯環境中,不同的編譯器會有不同的處理結果:
★ 大多數 assembler(編譯器)會將 [0x11223344] 截斷為 [0x3344]。
★ 但是,一個功能強大的,全面的 assembler 應該將 [0x11223344] 還原為 [0x11223344],產生的編碼應是: 66 67 a1 44 33 22 11
有關 16 位定址模式和 32 位定址模式,詳細請參看 AMD 與 Intel 手冊
7.6 67H prefix 的深層含義
67H prefix(address-size override)指示 processor 對記憶體運算元定址模式上的轉變:
★ 當執行在 16 位程式碼時,將要使用 32 位地址(default address-size 是 16 位)。因此,記憶體定址要用 32 位定址模式。
★ 當執行在 32 位程式碼時,將要使用 16 位地址(default address-size 是 32 位)。因此,記憶體定址要用 16 位定址模式。
表2:processor 在 16 位下與 32 位下解析區別 (processor 執行上下文環境)
序號 | 指令編碼 encods(機器指令) | processor 執行在 32 位下時解析為 | processor 執行在 16 位下時解析為 |
1* | c7 84 c8 44 33 22 11 78 56 34 12 | mov dword ptr [eax + ecx * 8 + 0x11223344], 0x12345678 | mov word ptr [si + 0x44c8], 0x2233 |
2* | 66 67 c7 84 c8 44 33 22 11 78 56 34 12 | mov word ptr [si + 0x44c8], 0x2233 | mov dword ptr [eax + ecx * 8 + 0x11223344], 0x12345678 |
3 | 67 8b 40 0c | mov eax, dword ptr [bx + si + 0x0c] | mov ax, word ptr [eax + 0x0c] |
4 | 8b 40 0c | mov eax, dword ptr [eax + 0x0c] | mov ax, word ptr [bx + si + 0x0c] |
表2中顯示在不同的執行上下文環境,同一條機器指令編碼產生的不同行為。
注意:
★ 第1條中,機器碼:c7 84 c8 44 33 22 11 78 56 34 12 當 processor 在 16 位下,只解析前面的 c7 84 c8 44 33 22
剩下的 11 78 56 34 12 將被視為下一條指令。
★ 第2條中,機器碼:66 67 c7 84 c8 44 33 22 11 78 56 34 12 當 processor 在 32 位下,只解析前面的 66 67 c7 84 c8 44 33 22
剩下的 11 78 56 34 12 將被視為下一條指令。
7.7 67H prefix 總結
在彙編程式碼層面上,assembler 根據當前編譯環境,將彙編語句生成相應的 encodes 決定是否使用 67H prefix
在機器程式碼層面上,processor 根據當前執行環境來決定如何解析機器指令
8. 調整段選擇子(Segment override)
對於大多數記憶體操資料來說,預設以 DS 為段基址的。常見的是:DS 段基址,SS 段基址。
與 operand-size / address-size 一樣,當需要調整預設的 segment 時,需要使用相應的 segment override prefix
8.1 預設 segment register
與 default opernads-size、default address-size 一樣,segment registers 同樣有 default segment register
8.1.1 基址暫存器(base register)
default segment register 與記憶體運算元中的 base register 相關。
例如:mov eax, dword ptr [eax] 指令中的 [eax] 運算元 eax 就是 base register
預設暫存器規則:
- 基址暫存器為 ebp 的,預設的段暫存器(default segment register)是:SS
- 基址暫存器為 esp 的,預設的段暫存器(default segment register)是:SS
- 在串處理指令中(如:movsb,scanb,cmpb 等),源串預設段暫存器為 DS, 目標串預設段暫存器為 ES
- 無基址暫存器的運算元中,預設段寄存寄均為 DS (如:mov eax, [0x11223344],源運算元就是無基址暫存器)
- 所有程式碼段的預設段暫存器都是 CS
- 除上面幾種情況下,所有記憶體運算元的預設段暫存器都是 DS
8.2 Segment override 例子
foo: |
[ebp-0xc]:這個記憶體運算元預設是基於 SS 段的
[eax]:這個記憶體運算元預設是基於 DS 段的。
因此,對於上面的片段,[ebp - 0x0c] 是在 SS segment,即 stack 內。
[eax] 這個記憶體地址按照程式的意圖是訪問 stack 內的資料,所以,這裡我將它調整為 stack segment
lea eax, [ebp - 0x0c]
mov eax, dword ptr ss:[eax](調整為訪問 stack)
為什麼一般程式都不會這麼寫呢? 那是因為,現代的作業系統都是採用平坦的記憶體模式,即:CS=SS=DS=ES,所以對 [eax] 這個運算元不需調整其結果是正確的。
8.2.1 [eax] 記憶體運算元進行調整為:mov eax, dword ptr ss:[eax]
產生的編碼是: 36 8b 00
其中,36 也就是 SS segment-override prefix,將 DS 段調整為 SS 段。
8.3 Segment override prefix
- CS segment:2E
- DS segment:3E
- ES segment:26
- FS segment:64
- GS segment:65
- SS segment:36
當需要進行調整段暫存器時,就使用以上的 segment-override prefix。
9. 通過 prefix 增強指令功能(F3 prefix 與 F2 prefix)
這些 prefix 對 Opcode 進行補充,增強指令的功能,優化指令執行。起重複執行指令的功能
- F3: rep/repz prefix
- F2: repnz prefix
看下面這段 c 程式碼:
char *move_char(char *d, char *s, unsigned count) while (count--) return p; |
這是典型的、經典的字串複製c程式碼,對應以下類似的彙編程式碼:
最初版本:
move_char:
push ebp
mov ebp, esp
sub esp, 0x0c
mov eax, [ebp+8]
mov edi, eax
mov esi, [ebp+0x0c]
mov ecx, dword ptr [ebp+0x10]
move_loop:
mov bl, byte ptr [esi]
mov byte ptr [edi], bl
inc esi
inc edi
dec ecx
jnz move_loop
mov esp, ebp
pop ebp
ret
----------------------------------------------------------------
上面的程式碼效能低下,是很死板的實現,優化的空間巨大。
x86 為串提供了相應的串操作指令(ins,outs,lods,stos,scas,cmps),對這些串指令提供 prefix 來增強優化這些指令。
9.1 rep prefix 或者 repz prefix(F3H prefix)
可以看到 F3H prefix 有兩重意義:rep 和 repz,但是使用的範圍是不同的:
prefix 含義 | 使用範圍 | 結束條件 |
rep | movs,lods,stos,ins,outs | ecx = 0 |
repz/repe | scas,cmps | ecx = 0 或 ZF = 0(比較結果不為零) |
它們的使用範圍和結束條件都不同。
9.1.1 rep 的意義
rep 重複執行指令一定的次數,這個次數在 ecx 中提供。
用虛擬碼描述為:
if (ecx != 0) { |
首先判斷 ecx 是否為 0,不為 0 則執行指令。
使用 rep 優化版本:
mov_char: |
使用串指令 movsb 配合 rep prefix 進行復制,rep movsb 的編碼為:
- f3 a4
9.1.2 repz/repe 的意義
F3 prefix 另一層意義是 repe/repz,用於改變標誌位的串操作:scas, cmps 指令
意思是:當比較結果相等(ZF=1)並且迴圈次數(ecx)不為 0 時進行重複操作。(重複的條件是:ZF = 1 & ecx <> 0)
即:它的結束條件是:ecx = 0 或者 ZF = 0, 意思是:不相等時或者次數到了,就不重複執行指令
它的 c 偽碼形式如下:
if (ecx != 0 && ZF = 1) { |
常見運用一些跳過字元的邏輯上,如下面 C 程式碼,用於截除串前面空格:
char *trim(char *s) return s; |
rep 與 repe/repz 是相同的 prefix,作用於不同的串指操作意義也不同:
- f3 a4 --- 這時它是 rep
- f3 ae --- 這時它是 repz/repe
當作用於不修改標誌位的串指令時,它的意義是 rep,作用於修改標誌位的串指令時,它的意義是 repz/repe
9.2 repne/repnz(F2H prefix)
F2H prefix 是表達 repne/repnz 意思是: 結果不相等(不為零)時迴圈。(重複條件是 ZF == 0 並且 ecx <> 0)
結束條件是:ecx = 0 或者 ZF = 1 即:結果相等時退出迴圈。
同樣也是用於改變標誌位的串操作 scas 和 cmps
它的 c 偽碼形式如下:
if (ecx != 0 && ZF = 0) { |
常見一些查詢字元的邏輯上,如下面 C 程式碼:
char *get_char(char *s, char c) ret |
10 附加功能(LOCK prefix)
對於寫記憶體的一些指令增加了鎖地址匯流排的功能,這些寫記憶體的指令如常見的 sub,add 等指令,通過 Lock prefix 來實現這功能,使用 Lock prefix 將會使 procesor 產生 LOCK# 訊號鎖地址匯流排
注意:
Lock prefix 僅使用在一些對記憶體進行 read-modify-write 操作的指令上,如:add, sub, and 等指令。 否則,將會產生 #UD (無效操作碼) 異常
如下指令所示:
lock add dword ptr [eax], 1 |
它的指令編碼是:
- f0 81 00 01 00 00 00
F0: Lock prefix 鎖地址匯流排。
相關推薦
X86指令內幕 ——深入瞭解Prefix
1. Legacy prefix 1.1 legacy prefix 的作用 legacy prefix 主要有以下作用: 調整記憶體運算元的屬性 增強指令的功能 提供額外的作用 1.2 legacy prefix 分類 (1) operand size over
X86指令內幕 —— 序
C 的經典入門例子: int main(){ printf("Hello, World/n"); return 0;} 下面來看看 x86/x64 指令 encode 的 2 個例子: mov word ptr es:[eax + ecx * 8 +
深入瞭解Angularjs指令中的 [(ngModel)]的實現原理
討論[(ngModel)]之前,先講下屬性繫結和事件繫結。 在屬性繫結中,值從模型中流動到檢視上的目標屬性。[],通過把屬性名放在方括號中來標記出目標屬性。這是從模型到檢視的單向資料繫結。 在事件繫結中,值從檢視上的目標屬性流動到模型。(),通過把屬性名放在圓括號中來標記出目標屬性。這是從檢視到模型的(
X86指令編碼內幕 --- 指令格式
在序言裡的例子裡: mov dword ptr es:[eax + ecx * 8 + 0x11223344], 0x12345678 這裡稍作修改:將記憶體運算元 operand size 的指示符 word ptr 改回 dword ptr,使得指令的 opera
X86指令編碼內幕 --- ModRM 定址模式
ModRM 定址模式 在 x86/x64 指令集的世界裡: Opcode 對指令提供操作碼,ModRM 最主要作用是對指令的 operands 提供定址,另一個作用是對 Opcode 進行補充,而 SIB 則是對 ModRM 進行補充定址 有兩種情況下是無需用 Mo
X86指令編碼內幕 --- 指令 Opcode 碼
指令 Opcode 碼 x86 指令編碼的核心是:Opcode、ModRM 以及 SIB。Opcode 提供指令的操作碼,ModRM 及 SIB 提供運算元的定址模式。 指令編碼設計模式是:Opcode 的設計要考慮兼顧 ModRM。ModRM 要服務於 Opcode,S
3.4 復雜的x86指令舉例
完全 32位 進制 條件 依次 指定位置 內存 立即數 二次 計算機組成 3 指令系統體系結構 3.4 復雜的x86指令舉例 x86作為復雜指令系統的代表,自然會有不少相當復雜的指令。在這一節我們將會看到其中有代表性的一些例子。 關於復雜的x86指令,我們這裏舉四個例子
IP地址是什麼,618IP代理帶你深入瞭解
618IP代理,帶你深入瞭解什麼是IP地址,如何運用好IP地址,已經怎麼更改自己的IP地址QQ3218080091 IP地址對於經常上網的人應該都不陌生,ip地址又可以分成內網ip地址和公網ip地址,今天就來簡單介紹下這兩者的區別。 通常我們所說的內網也就是區域網,是內網的計算機以網路地址轉換協議,通過一
深入瞭解以太坊虛擬機器第2部分——固定長度資料型別的表示方法
在本系列的第一篇文章中,我們已經看到了一個簡單的Solidity合約的彙編程式碼: contract C { uint256 a; function C() { a = 1; } } 該合約歸結於sstore指令的呼叫: // a = 1 sstore(0x0,
深入瞭解以太坊虛擬機器第3部分——動態資料型別的表示方法
Solidity提供了在其他程式語言常見的資料型別。除了簡單的值型別比如數字和結構體,還有一些其他資料型別,隨著資料的增加可以進行動態擴充套件的動態型別。動態型別的3大類: 對映(Mappings):mapping(bytes32 => uint256), mapping(addres
Android LayoutInflater原理分析,帶你一步步深入瞭解View
有段時間沒寫部落格了,感覺都有些生疏了呢。最近繁忙的工作終於告一段落,又有時間寫文章了,接下來還會繼續堅持每一週篇的節奏。 有不少朋友跟我反應,都希望我可以寫一篇關於View的文章,講一講View的工作原理以及自定義View的方法。沒錯,承諾過的文章我是一定要兌現的,而且在View這個話題上我還
用Unity做遊戲,你需要深入瞭解一下IL2CPP
這次我們翻譯了一篇Unity官方部落格上的文章,原文題目為AN INTRODUCTION TO IL2CPP INTERNALS ,作者是從事Unity軟體開發的Joshua Peterson。文章的看點在於,它是以IL2CPP內部開發人員的角度來講述的,所以對於開發者來說非常有參考價值。 如果
JavaScript 深入瞭解物件中的屬性
轉載:JavaScript 深入瞭解物件中的屬性 JavaScript 深入瞭解物件中的屬性 本篇主要介紹JS中物件的屬性,包括:屬性的分類、訪問方式、檢測屬性、遍歷屬性以及屬性特性等內容。 目錄 1. 介紹:描述屬性的命名方式、查詢路徑以及分類 2. 屬
Python核心知識點:深入瞭解字串的拆分,連線及拼接教程
生活中總有幾樣註定的事:死亡、稅單以及需要處理字串的程式設計師。 字串可以有多種形式。 它們可以是非結構化的文字,使用者名稱,產品描述,資料庫列表名,或者其它任何我們使用語言描述的內容。 既然字串資料幾乎無處不在,那麼掌握所使用的工具如何進行字串處理是非常重要的。 幸運的是,與其它語言甚至舊版本的Python
Qt學習筆記(1) — 深入瞭解Hello World的建立過程
年初的時候就準備學習Qt了,因為工作原因被擱淺好久,現在開始學也不晚,以後每週更新2遍博文作為總結。 學過Windows開發的,會覺得Qt很親切,學起來不是很費勁(PS: 環境搭建比較簡單,本文不作說明),但是還得從Hello World開始一步步來。下面,筆者將用4種不同的方
深入瞭解Thread之構造器
xl_echo編輯整理,歡迎轉載,轉載請宣告文章來源。更多IT、程式設計案例、資料請聯絡QQ:1280023003,加群298140694。百戰不敗,依不自稱常勝,百敗不頹,依能奮力前行。——這才是真正的堪稱強大!! 在之前的文章中我們對多執行緒和實現執行緒等基礎知識有了一
深入瞭解JavaScript底層原理
[TOC] 1. 七種內建型別 基本型別: null,undefined,boolean,number(浮點型別),string,symbol(es6)。 物件:Object。 複製程式碼 型別轉換 typeof: typeof 1 // 'number' typeof '1' // 's
一。深入瞭解JDK1.8 從Package java.io開始
Package java.io 通過資料流,序列化和檔案系統提供系統輸入和輸出。 See: 描述 介面摘要 介面
深入瞭解原型
說原型之前先說說物件,好像在工作中,物件用的挺多的,原型基本上沒有用。既然沒有用那我還要不要學習呢?思考了很久,還是學一學,萬一以後的工作用的著呢?領導常說,上一份工作是為下一份工作做準備的,所以在工作中要多學東西,不要因為暫時不用,而放棄學習,目光要放得長遠。既然這樣我就簡單學一學原型。說原型之前先溫習一下
深入瞭解機器學習之降低損失:迭代方法
迭代學習可能會讓您想到“Hot and Cold”這種尋找隱藏物品(如頂針)的兒童遊戲。在我們的遊戲中,“隱藏的物品”就是最佳模型。剛開始,您會胡亂猜測(“w1 的值為 0。”),等待系統告訴您損失是多少。然後,您再嘗試另一種猜測(“ 的值為 0.5。”),看看損失是多少。哎呀,這次更接