16位匯編第六講匯編指令詳解第二講


              16位匯編第六講匯編指令詳解第二講

1.比較指令

  CMP指令

  1.CMP指令是將目的操作數減去源操作數,按照定義相應的設置狀態標志

  2.CMP指令執行的功能與SUB指令(相減指令)一樣,但是不同的是CMP指令之根據結果設置標志位

  而不修改值

 可以操作的指令格式

  CMP reg,imm/reg/mem

  CMP mem,imm/reg

上面是CMP指令的語法,具體的也可以查詢幫助文檔,inter手冊

inter手冊查的辦法

第一個框代表了CMP指令的所有語法

比如

  reg,reg 表示可以比較寄存器 CMP AX,BX ....

 下面的則是機器的操作碼.根據二進制的機器碼可以反逆向出來匯編指令

比如:

  

機器碼是39代表的是CMP指令

一般CMP的指令,都是設置標志位的,然后一般會和別的指令成對執行,比如比較完畢就判斷結果.

匯編例子

  

cmp al,100
jz below
    ;al == 100會跳轉到below執行(jz下面將,這里理解為跳轉)

 2.CPU的流水線,匯編的無分支,以及優化

   什么是CPU的流水線,這樣說吧,上面我們說了,CMP會和跳轉一起使用,但是你知道這樣的代碼嗎?

使用一條跳轉,可以執行很多條指令.CPU的指令周期很長,這里說一下強制跳轉JMP

看下JMP

可以看出,最快的需要15個指令周期,最慢的需要24 + (EA:尋址方式,的有效尋址的周期)大小

那么我們可以優化一下嗎

比如 C語言中的三目運算符       a == 0 ? 0:-1;  如果a < 0,成立,則a = 0,否則= -1

如果在匯編中你想怎么寫,   是不是先判斷ax == 0? 如果 ==0 ,我就跳轉到0的地方,執行,否則跳轉到-1的地方執行

最少需要兩個跳轉是嗎

這樣浪費了很多指令周期

所以我們可以寫成這樣

mov ax,3

neg ax

sbb ax,ax

我敢說,學過匯編的人從來都只是說學過,而匯編是一門藝術,我們學習匯編,並不是學習他的指令或者語法,比如上面簡單的三條匯編指令,會匯編的人都能明白,但是我想問一下,什么意思懂嗎?

這個就是無分支三目運算符

簡單看一下吧

ax = 3 (浪費了4個指令周期,因為有立即數,要內存尋址,所以該浪費的還是得浪費)

neg ax 這個是對3求補,上堂課也說了,匯編的求補指令的原理就是 0 - 操作數(ax))的結果

 

0 - 3的話,計算機也不會算,所以要把-3變為補碼,讓0去相加

原碼:  1000 0011   (負數的源碼最高位是1) 

反碼   1111 1100    (反碼最高位不變,其余各位取反)

補碼:  1111 1101    (-3的補碼)

0 + 上補碼

0000 0000

+

1111 1101 

1111 1101  (還是負數)

在計算機中表示  FD    此時CF位被設置,因為計算機判斷進位的方法就是看最高位,如果最高位以前是0,那么經過計算最高位為1,則判斷進位了.

CF = 1

SBB  ax,ax

帶借位的相減

首先ax的值就是FD了,兩個相減沒了,但是注意,這里有符號位,所以相減的同事要把符號位減去

1111 1101

-

1111 1110(需要加上符號位1,那么二進制就成為了這種)

 = F (-1)那么看上面的推理過程

結果就是給一個3,對齊求補碼,然后算出結果為-1

當然這個只是教怎么玩匯編,不過分析程序的時候可能遇到這種優化

CPU的流水線

  上次我們說了一個JMP指令,指令周期特別長,我們可以優化成上面的那樣,但是僅僅是優化了嗎?

我們不妨這樣想,上面的確實是優化了,但是其實內部還有CPU的流水線的優化

什么是流水線

比如一個工廠,組裝汽車的,分為三步驟

第一步,取配件  (取指令)

第二步,組裝  (譯碼(解析指令))

第三步,噴漆      (CPU執行)

我們需要三個工人,可以這樣想,第一個人專門取配件,第一次執行的時候,組裝的噴漆的都等待

當配件拿到手了,那么開始組裝(這個時候第一個人又去取配件了),這時候噴漆的等着

當給了噴漆的了,那么這個時候噴漆,組裝,已經可以正常開始工作了.

例如

  取配件   組裝     噴漆

      取配件   組裝      噴漆

          取配件   組裝   噴漆...

只有第一次執行的時候,組裝需要等待取配件,噴漆等待組裝,第一次組裝的時候,第二次已經開始了

上面是什么意思那,就是說,組裝需要等待,噴漆也要等待.我們可不可以錯開,不讓他們依賴指向性

比如流水線的代碼

  

mov ax,1

sub ax,2

cmp ax,ax

 

每次的結果都需要等待上一次的結果,我們可以寫成這樣

  

1 mov ax,1
2 
3 mov bx,1
4 
5 sub ax,2
6 
7 mov cx 3
8 
9 cmp ax,ax

 

其中第二行,和倒數第二行都是我隨便加的,就是為了不讓指令依賴於上次執行,這就是最簡單的流水線,不用等待.

在這里可以說下上面的三目運算符的優化了,為什么不光光是優化,以為JMP跳轉的時候,CPU的流水線可能正常執行,比如已經知道到組裝了,這個時候你來個跳轉,那么又要從頭開始,而且組裝后面的都不執行了,所以不光光是為了優化掉跳轉,還有流水線的作用,上面的代碼看着很惡心,可是真是的環境就是這樣,不是教你怎么去寫,而是教你怎么去看,讓你明白他為什么這樣寫.當然流水線的優化還有很多種.這里只是最簡單的一個例子      

 3.乘法指令

  MUL (無符號字節乘法)

    指令格式: ax = al * r8/m8

    ax(16位寄存器)存放 al * r8(八位寄存器)或者 m8(內存中八位的值)

看下inter手冊

這里看一下,除法的指令周期很長,最低的70-77,所以也可以優化

這里可以看出  al要放乘數  其余寄存器放乘數

例如   ax = bl * al(他是乘數,你給多少,都是和他相乘的)

匯編例子

  

mov al,2 (倍數是2倍)
mov bl,8
mul bl

此時算出的記過就放在ax中,因為8位*8位的數字不會超過16位的

無符號的字乘法

當我們16位*16位的怎么辦,8 *8的結果是放在ax中

16 *16 則放在 DX(數據寄存器)(AX累加寄存器)當中

高16位放到DX當中,低16位放到AX中

其中乘法的 操作數都需要我們自己給,比如 MUL bl, 算出bl的乘法,默認會和al相乘

乘法指令是利用 OF(overflow溢出標志)和CF(進位標志)來判斷乘積的高一班是否具有有效數值

有符號的字節乘法

  IMUL r8/m8

    ax = al * r8/m8 (和上面一樣,結果放到ax中,al可以×八位的寄存器,或者內存取出的數值的8位數值

 和內存取出來的數值相乘(400的偏移處我給的是11所以最后ax結果是11)

  有符號的字乘法

16*16的和無符號的一樣

  高位放到DX當中,低位放到AX當中

談到這里我們發現,乘法的指令周期特別長,我們也可以做優化,可以用位運算

對標志位的影響:

  會影響OF和CF標志

4.位運算,左移右移

1.左移指令

  這個算是附加的,主要是我們要用位運算吧乘法優化掉

SHL  左移 ,高位補零,看下語法

可以是寄存器,內存,不支持立即數,因為立即數哪里都是- ,帶有1的則是默認寫的時候是左移一位,只能寫1

如果給1以上,就要放到CL當中了

 

寄存器和CL低八位寄存器(注意這里是CL則我們寫的時候要注意如果寄存器左移動的時候,則給CL指定個數)

左移,最高位補零

2的二進制

0000 00010   SHL 之后  0000 0100 (4)

8086不支持這樣寫

SHL ax,3
;支持這樣寫 SHL ax,1 默認的是往左移動一位
上面第一句,那些是以后出現的

說道左移,則可以用它來替代掉乘法

例如

  

mov al,2
mov bl,3
mul al

替換成
mov bl,3
mov cl,2
shl bl,cl

仔細看一下,我們轉大了,inter指令周期最起碼縮少了10倍,所以說有的時候寫一行匯編代碼,需要想很長時間,

比如 

mov ax,0

你認為是很快了是嗎,其實inter指令周期是4,不行的話自己可以查詢看一下,  reg,imm這一行

但是你寫為

xor ax,ax (xor代表異或的意思,相同為假,不同為真,ax和ax肯定各個二進制位相同,此時相同為0,則都變成0了)

和上面的一樣,ax都是變為0,而我則賺了一個1個指令周期,其實還有很多這樣的匯編代碼,都是這樣做出來的

所以說學習匯編,把它當做一門藝術來看.

2.右移指令

   SHR 邏輯右移,SAR算術右移

兩個的不同

SHR 移動的時候,以0來填充

SAR 移動的時候,符號位填充,也就是真正的右移

和左移相反

右移也可以用於正數的除法

但是除法有除法優化的原理,以后講,這里掌握兩個指令即可.

5.除法指令

除法指令也分為有符號除法,和無符號除法

  ax / r8,m8的商,放到AL中,余數放到AH中

  16位除法

  ax /r16,m16, 16位的商放到AX當中(也就是結果放到AX中),余數放到dx中

DIV (無符號字節除法)

  指令 DIV r8/m8

  或者 DIV r16/m16

6.符號擴展

什么是符號擴展?

  符號擴展是指用一個操作數的符號位(也就是最高位)擴展變大,比如8位變為16位,符號擴展不改變數據大小

CBW al符號擴展至AH  (字節擴展)

如果al的最高有效位為0,則AH ==00

AL的最高有效位為1,折AH = FFH AL不變

字擴展

CWD AX的符號擴展至DX

AX的最高有效位是0,則DX ==00

如果為1,則DX = FFFFH AX不變

 

 學習資料: 

鏈接:http://pan.baidu.com/s/1hsKi3sw 密碼:yis3

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM