2016-03-14 63 views
4

所以我使用C++與程序集來執行16位有符號乘法。裝配中的16位乘法?

我知道,對於16位,被乘數是AX,乘數是寄存器或內存操作數16位,產品存儲在EDX:EAX中,其大小是操作數的兩倍。

我是初學者,所以我第一次嘗試用8位有符號乘法,它的工作原理:

#include "stdafx.h" 
#include <stdio.h> 

int main() 
{ 
    char X, Y; 
    short Z; 
    _asm 
    { 
     MOV X, 5 
     MOV Y, 11 

     MOV AL, X 
     MOV BL, Y 
     IMUL BL 

     MOV Z, AX 

    } 

    printf("The result times is = %i", Z); 



    getchar(); 
    //system("pause"); 
    return 0; 
} 

,但我不確定爲什麼下面的代碼不會爲16位,而不是工作。

#include "stdafx.h" 
#include <stdio.h> 

int main() 
{ 
    short X, Y; 
    int Z; 
    _asm 
    { 
      MOV X, 5 
      MOV Y, 11 

      MOV AX, X 
      MOV BX, Y 
      IMUL BX 

      MOV Z, [DX::AX] 

    } 

    printf("The result times is = %i", Z); 



    getchar(); 
    //system("pause"); 
    return 0; 
} 
+3

我不確定你是在考慮某個特定目的還是在玩耍。 'MOV Z,[DX :: AX]'_MASM_語法無效。如果您確定要用16位寄存器對16位寄存器進行有符號乘法運算並得到DX:AX,那麼您將不得不用'MOV Z,[DX :: AX]'替換類似於'MOV字ptr [Z],AX''MOV字ptr [Z + 2],DX'。我假設'int'是一個32位有符號整數。您必須手動將AX和DX移動到變量Z中。如果你有32位寄存器可用,那麼你可以簡化代碼。 –

+0

我想基本上只使用16位整數作爲x和y並將它們相乘。將存儲在DX:AX中的結果;我想存儲在Z中,它將被printf讀取並輸出乘法值。我明白我出錯的地方,我的語法不正確。感謝您的幫助,我所指的教科書沒有提到word ptr的使用,並且被卡住了,我知道我需要它。再次感謝您的幫助。 – user5894146

+1

'MOV字ptr [Z],AX'移動AX中的16位值並將其存儲到存儲器地址爲Z的16位字中。由於x86是Little Endian,因此必須存儲較低的16位(AX )在_Z_的前2個字節中。 'MOV word ptr [Z + 2],DX'然後將高16位(從_DX_)存儲到存儲器地址爲Z + 2(32位整數值的高位)的16位字中。 –

回答

1

不起作用的原因是指令MOV Z, [DX::AX]不存在。

結果將被存儲在DX:AX中,但要將這兩個寄存器的結果存儲在內存位置,您必須執行兩個存儲操作。

lea ecx,z  //load the address of z into cx 
mov [ecx],ax  //8086 is little endian, so store the lower bytes first. 
mov [ecx+2],dx //store the high bytes 

我必須說,我很驚訝看到16位程序集。 386是1985年推出的,所以你比時代落後了大約30年。

相乘兩個16位值的方法是:

movsx eax, word ptr x  //sign extension prevents partial register writes 
movsx edx, word ptr y  //use movzx if you want to do an unsigned mul 
imul eax,edx     //multiply, but only store result in EAX. 
mov z,eax     //save result in one go. 

使用的在86 16個寄存器導致非常慢的代碼,因爲處理器不用於該操作模式的優化。有時16位代碼可能比正常代碼慢許多倍。
下面的代碼將運行很多,比以上更快。

  1. 它不會因部分寄存器寫入而導致停頓。
  2. 它不對部分寄存器執行操作。
  3. 它不使用兩個寫入(其中一個未對齊),其中一個寫入就足夠了。

在最後一個例子中,您也不必瞭解little endian的微妙之處。
您應該不惜一切代價避免使用16位寄存器。
等效的32位代碼幾乎總是快得多。
如果您無法將兩個16位寫入組合成一個32位,則將16位值寫入存儲器是唯一的例外。

+0

16位是愚蠢的,而不是學習x86的好方法,但它在現代CPU上不會很慢。除了'mov'以外的指令(例如'add r/m16,imm16',但不包含'add r/m16,imm8'),對於帶有立即數(除imm8​​以外)的指令,英特爾CPU仍然會對操作數大小前綴進行解碼處理32位或64位模式,或用於在16位模式下添加r/m32,imm32)。但是,英特爾CPU(P6和SnB系列)重命名部分寄存器以避免錯誤的依賴關係,Haswell在編寫部分寄存器之後讀取更寬的寄存器時將刪除合併它們的懲罰。 –

+0

無論如何,是的,我同意整體的觀點,特別是[學習DOS系統調用API/ABI在同一時間](http://stackoverflow.com/a/34918617/224132)作爲學習16位與分割同時只是讓學習變得更加困難。而32位操作系統通常是可用的[即使沒有調零上16b](http://stackoverflow.com/questions/34377711/which-2s-complement-integer-operations-can-be-used-without-zeroing-high -Bits-IN)。但是很少有使用情況,而16位操作系統通常不會破壞性能。 –

+1

令我難以置信的是,許多大學生不得不爲他們的課程學習8086 asm(通常在emu8086中,沒有像movsx這樣的386便​​利)。這是SO上阻塞x86標籤的許多不良16位問題的來源。 –