第7章 比高斯更快的計算

第七章 比高斯更快的計算

這一章的主題是彙編計算累加和,以及尋址方式的學習。

and、or指令

and是按位與,or是按位或。

兩者的目的操作數都必須是8位或者16位的內存單元或者通用寄存器,源操作數必須是與目的操作數同寬度的內存單元、通用寄存器或者立即數。注意,與其他指令一樣,源操作數和目的操作數不能都爲內存單元。

兩者對標誌寄存器的影響相同:OF和CF被清零,SF、ZF、PF依計算結果而定,AF位的狀態未定義。

計算機中的棧段一般是從高地址向低地址生長,也就是說壓棧減地址,出棧加地址。在這裏,我們選的棧段初始地址爲0x0000,由於計算機內部採用補碼運算,所以在壓棧第一個元素時,採用0x0000-0x10,即從0xfffe開始存。由於Intel處理器採用小端方式,所以低地址存低字節,即0xfffe存低字節,0xffff存高字節,之後再壓棧、出棧都按這個邏輯。

棧段

數據段段基地址在DS中保存,附加段段基地址在ES中保存,棧段段基地址在SS中保存。

push

  • 對於當前的8086平臺,push的操作數必須爲16位,也就是說,壓棧內容必須爲2字節。
  • push指令執行時,首先將棧指針寄存器SP的內容減去操作數的字節長度(此處爲2),然後把要壓棧的數據存放到邏輯地址SS:SP所指向的內存位置。
  • 不影響任何標誌位

pop

與push相反,過程是先取數據,再+2。同樣不影響任何標誌位。

Bochs棧調試

在Bochs中,查看棧信息使用命令“print-stack”,後面可以跟參數指定要打印接下來的多少元素,使用該命令會打印出從SP指向的棧頂向下的一系列元素。但是由於此處計算機不會區分數據區和棧區,而我們的棧高地址處是棧底元素,所以可能會打印出不在棧中的值。

8086處理器的尋址方式

1. 寄存器尋址

操作數直接位於寄存器中

2. 立即數尋址

操作數是個立即數

3. 內存尋址

3.1 直接尋址

給出一個內存地址作爲偏移地址,以此訪問

3.2 基址尋址

使用基址寄存器BX或BP來保存偏移地址。這允許在基址寄存器的基礎上使用一個偏移量,比如

mov dx, [bp-2]

3.3 變址尋址

類似於基址尋址,但是不同的是這裏使用的是變址寄存器SI和DI,同樣允許偏移量

3.4 基址變址尋址

組合BX、BP和SI、DI,來提供地址,同樣允許偏移量。

本章習題

  1. 把line31~37改成如下代碼即可
         ;以下計算1到100的和 
         xor ax,ax
         mov cx,100
     @f:
         add ax,cx
         loop @f
  1. 要求用匯編計算並顯示1+2+···+1000的結果。這個實驗有水平,很多東西我都沒想到,最後沒寫出來。下面是修改的從line30往後。
         ;修改計算1到1000的和 
         xor ax,ax
         xor dx,dx
         mov cx,1000
     @f:
         add ax,cx
         adc dx,0
         loop @f

         ;以下計算累加和的每個數位 
         xor cx,cx              ;設置堆棧段的段基地址
         mov ss,cx
         mov sp,cx

         mov bx,10              ;line 17~line 20還必須得有,不然不行
         xor cx,cx
         inc cx
         div bx
         or dl,0x30
         push dx
     @d:                        ;如果沒有上面那一塊,直接這一塊計算,原先dx中的高位值就會清零,結果就錯了
         inc cx                 ;而如果上面17~20做了,由於除以了10,高位dx中就不會再有非零數據了,只保存每次計算的餘數,所以不再會出錯
         xor dx,dx
         div bx
         or dl,0x30
         push dx
         cmp ax,0
         jne @d

         ;以下顯示各個數位 
     @a:
         pop dx
         mov [es:di],dl
         inc di
         mov byte [es:di],0x07
         inc di
         loop @a
       
         jmp near $ 
       

times 510-($-$$) db 0
                 db 0x55,0xaa

adc指令就是一個add指令的擴展,在計算完add之後會把CF位也加上,這樣可以使用16位寄存器計算多於16位的數據。比如這裏。**注意,因爲兩個二進制數相加,最多隻能進一位,不可能進兩位(比較容易證),所以line6~7簡單兩行代碼就能完成多於16位的計算。**因爲每次最多進一位,所以直接adc dx,0 即可保存所有高於16位的信息,不用考慮那麼多。

相比於源代碼,多出來了line17~20,原因註釋裏說了。由於計算後,dx中保存高16位,ax中保存低16位,而結果是500500,要大於16位的最大值65535,但是在一次÷10之後,50050<65535,所以在低16位,即ax中就能放得開了,dx就可以清零了,用來每次除法保存餘數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章