彙編語言基礎知識篇章三,僞代碼知識

偽代碼是給處理器的指令,它實際上是原始十六進制代碼的可讀版。因此,彙編是最低級的編程語言。彙編中的所有東西被直接翻譯為十六進制碼。換句話說,你沒有把高級語言翻譯為低級語言的編譯器上的煩惱,彙編器僅僅把彙編代碼轉化為原始數據。

下面將討論一些用來運算,位操作等的偽代碼。還有跳轉指令,比較等偽代碼。

1.一些基本的計算偽代碼(又稱指令)

(1)MOV

這條指令用來把一個地方移往(事實上是複製到)另一個地方。這個地方可以是寄存器,內存地址或是直接數值(當然只能作為源值)。Mov指令的語法是:

mov 目標,源

你可把一個寄存器移往另一個(注意指令是在複製那個值到目標中,儘管"mov"這個名字是移的意思)

mov edx, ecx

上面的這條指令把ecx的內容複製到了ecx中,源和目標的大小應該一致。例如這個指令是非法的:

mov al, ecx;非法

這條偽代碼試圖把一個DWORD(32位)值裝入一個字節(8位)的寄存器中。這不能個由mov指令來完成(有其他的指令幹這事)。但這些指令是允許的因為源和目標在大小上並沒有什麼不同:

mov al, blmov cl, dlmov cx, dxmov ecx, ebx

內存地址由offset指示(在win32中,前一章中有更多信息)你也能從地址的某一個地方獲得一個值並把它放入一個寄存器中。下面有一個例子:

每一個塊代表一個字節

offset的值這裡是用字節的形式表示的,但它事實上是32位的值,比如3A(這不是一個常見的offset的值,但如果不這樣簡寫表格裝不下),這也是一個32位的值:0000003Ah。只是為了節省空間,使用了一些不常見的低位offset。所有的值均為16進制。

看上表的offset 3A。那個offset的數據是25, 7A, 5E, 72, EF等。例如,要把這個位於3A的值用mov放入寄存器中:

mov eax, dword ptr[0000003Ah]

(h後綴表明這是一個十六進制值)

mov eax, dword ptr[0000003Ah]這條指令的意思是:把位於內存地址3A的DWORD大小的值放入eax寄存器。執行了這條指令後,eax包含了值725E7A25h。可能你注意到了這是在內存中時的反轉結果:25 7A 5E 72。這是因為存儲在內存中的值使用了little endian格式。這意味著越靠右的字節位數越高:字節順序被反轉了。我想一些例子可以使你把這個搞清楚。

十六進制dword(32位)值放在內存中時是這樣:40, 30, 20, 10(每個值佔一個字節(8位))

十六進制word(16位)值放在內存中時是這樣:50, 40

回到前面的例子。你也可以對其他大小的值這麼做:

mov cl, byte ptr [34h] ; cl得到值0Dh(參考上表)

mov dx, word ptr [3Eh] ; dx將得到值 7DEFh (看上表,記住反序)

大小有時不是必須的。

Mov eax,[00403045h]

因為eax是32位寄存器,編譯器假定(也只能這麼做)它應該從地址403045(十六進制)取個32位的值。

可以直接使用數值:

mov edx, 5006

這只是使得edx寄存器裝有值5006,綜括號[和]用來從括號間的內存地址處取值,沒有括號就只是這個值。寄存器和內存地址也可以(他應該是32位程序中的32位寄存器):

mov eax,403045h;使eax裝有值403045h(十六進制)

mov cx,[eax];把位於內存地址eax的word大小的值(403045)移入cx寄存器。

在mov cx, [eax]中,處理器會先查看eax裝有什麼值(=內存地址),然後在那個內存地址中有什麼值,並把這個word(16位,因為目標-cx-是個16位寄存器)移入cx。

(2)ADD, SUB, MUL, DIV

許多偽代碼做計算工作。你可以猜出它們中的大多數的名字:add(加),sub(減),mul(乘),div(除)等。

Add偽代碼有如下語法:

Add 目標,源

執行的運算是 目標=目標+源。下面的格式是允許的。

這條指令非常簡單。它只是把源值加到目標值中並把結果保存在目標中。其他的數學指令有:

sub 目標,源(目標=目標-源)mul 目標,源(目標=目標×源)div 源(eax=eax/源,edx=餘數)

減法和加法一樣做,乘法是目標=目標×源。除法有一點不同,因為寄存器是整數值(注意,繞回數不是浮點數)除法的結果被分為商和餘數。例如:

28/6->商=4,餘數=430/9->商=3,餘數=397/10->商=9,餘數=718/6->商=3,餘數=0

現在,取決於源的大小,商(一部分)被存在eax中,餘數(一部分)在edx:

*:例如,如果dx=2030h,而ax=0040h,dx:ax=20300040h。dx:ax是一個雙字值。其中高字代表dx,低字代表ax,Edx:eax是個四字值(64位)其高字是edx低字是eax。

Div偽代碼的源可以是

· 8位寄存器 (al, ah, cl,...)

· 16位寄存器 (ax, dx, ...)

· 32位寄存器 (eax, edx, ecx...)

· 8位內存數 (byte ptr [xxxx])

· 16位內存數(word ptr [xxxx])

· 32位內存數(dword ptr [xxxx])

源不可以是直接數值,因為處理器不能決定源參數的大小。

(3)位操作

這些指令都由源和目標,除了"NOT"指令。目標中的每位與源中的每位作比較,並看是那個指令,決定是0還是1放入目標位中。

如果源和目標均為1,AND把輸出位設為1。

如果源和目標中有一個為1,OR把輸出位設為1。

如果源和目標位不一樣,XOR把輸出位設為1。

NOT反轉源位

一個例子:

mov ax, 3406mov dx, 13EAhxor ax,dx

ax=3406(十六進制)是二進制的0000110101001110

dx=13EA(十六進制)是二進制的0001001111101010

對這些位進行xor操作:

新dx是0001111010100100 (十進制的7845, 十六進制的1EA4)

另一個例子:

mov ecx, FFFF0000hnot ecx

FFFF0000在二進制中是11111111111111110000000000000000(16個1,16個0)如果反轉每位會得到

00000000000000001111111111111111(16個0,16個1)在十六進制中是0000FFFF。因而執行NOT操作後,ecx是0000FFFFh。

(4)步增INC/步減DEC

有兩個很簡單的指令,DEC和INC。這些指令使內存地址和寄存器步增或步減,就是這樣:

inc reg -> reg = reg + 1

dec reg -> reg = reg – 1

inc dword ptr [103405] -> 位於103405的值步增

dec dword ptr [103405] -> 位於103405的值步減

(5)NOP

這條指令什麼都不幹。它僅僅佔用空間和時間。它用作填充或給代碼打補丁的目的。

(6)移位(Bit Rotation 和 shifiting)

注意:下面的大部分例子使用8位數,但這只是為了使目的清楚。

(7)Shifting函數

SHL 目標,計數(count)

SHR 目標,計數(count)

SHL和SHR在寄存器,內存地址中像左或向右移動一定數目(count)的位。

例如:

;這兒al=01011011(二進制)

shr al, 3

它的意思是:把al寄存器中的所有位向右移三個位置。因而al會變成為00001011。左邊的字節用0填充,而右邊的字節被移出。最後一個被移出的位保存在carry-flag中。Carry-flag是處理器標誌寄存器的一位,它不是像eax或ecx一樣的,你可以訪問的寄存器(雖然有偽代碼幹這活),但它的值決定於該指令的結構。它(carry-flag)會在後面解釋,你要記住的唯一一件事是carry是標誌寄存器的一位且它可以被打開或者關閉。這個位等於最後一個移出的位。

shl和shr一樣,只不過是向左移。

;這兒bl=11100101(二進制)

shl bl, 2

執行了指令後bl是10010100(二進制)。最後的兩個位是由0填充的,carry-flag是1,因為最後移出的位是1。

還有兩個偽代碼:

SAL 目標, 計數(算術左移)

SAR 目標, 計數(算術右移)

SAL和SHL一樣,但SAR不完全和SHR一樣。SAR不是用0來填充移出的位而是複製MSB(最高位)例如:

al = 10100110

sar al, 3

al = 11110100

sar al, 2

al = 11101001

bl = 00100110

sar bl, 3

bl = 00000100

(8)Rotation(循環移動) 函數

Rol 目標,計數;循環左移

Ror 目標,計數;循環右移

Rcl 目標,計數;通過carry循環左移

Rcr 目標,計數;通過carry循環右移

循環移動(Rotation)看上去就像移(Shifting),只是移出的位又到了另一邊。

例如:ror(循環右移)

彙編語言基礎知識篇章三,偽代碼知識

如你在上圖所見,位循環了。注意,每個被推出的位又移到了另一邊。和Shifting一樣,carry位裝有最後被移出的位。Rcl和Rcr實際上和Rol,Rcr一樣。它們的名字暗示了它們用carry位來表明最後移出的位,但和Rol和Ror幹同樣的事情。它們沒有什麼不同。

(9)交換

XCHG指令也非常簡單。它同在兩個寄存器和內存地址之間交換:

eax = 237h

ecx = 978h

xchg eax, ecx

eax = 978h

ecx = 237h

彙編語言基礎知識篇章三,偽代碼知識

技術和通信的概念

2.條件跳轉

例如下面這段代碼:

mov eax, edx

sub eax, ecx

cmp eax, 2

jz loc1

xor eax, eax

jmp loc2

loc1:

xor eax, eax

inc eax

loc2:

(xor eax, eax意為:eax=0,eax清零)

讓我們來看看這些代碼:

mov eax, edx ;把edx放入eax中

sub eax, ecx ;eax-ecx

cmp eax, 2

這有一條新指令:cmp。Cmp意為compare(比較)。它能比較兩個值(或寄存器、或內存、或直接數值)並設置Z-flag(零標誌)。零標誌很像carry,也是內部標誌寄存器的一位。

Jz loc1

這也是條新的。它是條件跳轉指令。Jz=jump if zero(如果設置了零標誌就跳轉)。Loc1是一個標記指令"xor eax,eax|inc eax"內存開始處offset的標籤。因而jz loc1=如果設置了零標誌,跳往位於loc1的指令。

Cmp eax, 2;如果eax=2設置零標誌

Jz loc1;如果設置了零標誌就跳轉

= 如果eax等於2,跳往位於loc1的指令

然後有jmp loc2.這也好似一個跳轉,但是是一個無條件跳轉:它總是執行。上面的代碼,用c語言描述就是:

if ((edx-ecx)==2)

{

eax = 1;

}

Else

{

eax = 0;

}

或者,用Basic語言描述:

IF (edx-ecx)=2 THEN

EAX = 1

ELSE

EAX = 0

END IF

彙編語言基礎知識篇章三,偽代碼知識

程序員職業-編寫程序代碼在筆記本電腦上

3.標誌寄存器

標誌寄存器有一套標誌。它們設不設置取決於計算或其他時間。我不會討論它們的全部。只揀幾個重要的說:

彙編語言基礎知識篇章三,偽代碼知識

還有更多的標誌(Parity, Auxiliary, Trap, Interrupt, Direction, IOPL, Nested Task, Resume, & Virtual Mode)但因為我們不用它們,所以我不解釋。

彙編語言基礎知識篇章三,偽代碼知識

Unix 詞雲

4.跳轉系列

有一整套的條件跳轉,而且它們跳轉與否均取決於標誌的狀態。但由於大部分跳轉指令有明白的名字,你甚至無需知道哪個標誌要設置,例如:"如果大於等於就跳轉"(jge)和"符號標誌=溢出標誌"一樣,而"如果零就跳轉"和"如果零標誌=1就跳轉"一樣。死背住下面的表即可

在下表中,"意思"指的是什麼樣的計算結果該跳轉。"如果大於就跳轉"意為:

cmp x, y

jump 如果 x 比 y大 就跳

彙編語言基礎知識篇章三,偽代碼知識

所有的跳轉指令後面要跟一個參數:要跳往的偏移地址(距離)offset。


分享到:


相關文章: