2012-10-01 202 views
0

在ASM程序起動我很需要得到的2的結果在大會38的動力,我需要你的理解幫助,爲什麼我的程序沒有產生結果我是需要(它打印4十進制):功率x86彙編

.386 
.model flat, stdcall 
option casemap:none 

include \masm32\include\windows.inc 
include \masm32\include\msvcrt.inc 
includelib \masm32\lib\msvcrt.lib 

.data 

formatstr db "%d",0 

.code 
start: 

mov eax , 2 
mov ecx , 38 
mov esi , eax 
mov edx , 0 

.while TRUE 
    mul esi 
    mov esi, edx 
    add esi, eax 
    mov edx, 0 
    mov eax, 2 
    dec ecx 
    .break .if (!ecx) 
.endw 




invoke crt__cprintf, addr formatstr, esi 


end start 

,你可以看到我使用MASM32(如果在這種情況下,任何事情)寫它。

THX。

+3

什麼是「不起作用?」 – GManNickG

+0

@GManNickG編輯 –

+4

想想存儲2^38需要多少個數字,以及結果寄存器有多少位。 – JohnTortugo

回答

8

2^38顯然不在一個32位寄存器適合如eax

要存儲的值2^38274877906944),你需要39位。在32位代碼中,您可以使用例如。兩個32位寄存器,如edx:eax。但是,在32位代碼中,mul只接受32位因子(例如寄存器,其他的總是eax),因此在循環中使用32位mul將不起作用,因爲無法存儲您的中間結果在一個32位寄存器的要被相乘再次,即使mul存儲64位結果edx:eax

但是你可以用rcl計算如。 2^38在32位代碼:

xor edx,edx 
    mov eax,2 ; now you have 2 in edx:eax 
    mov ecx,38 ; 2^n, in this case 2^38 (any value x, 1 <= x <= 63, is valid). 

x1: dec ecx  ; decrease ecx by 1 
    jz ready  ; if it's 2^1, we are ready. 

    shl eax,1 ; shift eax left through carry flag (CF) (overflow makes edx:eax zero) 
    rcl edx,1 ; rotate edx through carry flag (CF) left 
    jmp x1 

ready:   ; edx:eax contains now 2^38. 

編輯:通過@Jagged奧尼爾的回答啓發非循環的實現。這一個是不跳躍爲指數> = 32,一個跳躍指數< 32,作品也爲ecx 0,對於ecx大於63套edx:eax0

mov  ecx,38   ; input (exponent) in ecx. 2^n, in this case 2^38. 
          ; (any value x, 0 <= x <= 63, is valid). 
; the code begins here. 

    xor  eax,eax 
    xor  edx,edx   ; edx:eax is now prepared. 

    cmp  cl,64   ; if (cl >= 64), 
    setb al    ; then set eax to 0, else set eax to 1. 
    jae  ready   ; this is to handle cl >= 64. 

; now we have 0 <= cl <= 63 

    sub  ecx,1 
    setnc al    ; if (count == 0) then eax = 0, else eax = 1. 
    lea  eax,[eax+1]  ; eax = eax + 1. does not modify any flags. 
    jna  ready   ; 2^0 is 1, 2^1 = 2, those are ready now. 
    mov  ebx,ecx   ; copy ecx to ebx 
    cmp  cl,32   ; if (cl >= 32) 
    jb  low_5_bits 
    mov  cl,31   ; then shift first 31 bits to the left. 
    shld edx,eax,cl 
    shl  eax,cl   ; now shifted 31 bits to the left. 
    lea  ecx,[ebx-31] ; cl = bl - 31 

low_5_bits: 
    shld edx,eax,cl 
    shl  eax,cl 

ready: 
+0

是不是應該從'dec ecx'行開始的'x1'循環? –

+1

編號'loop'命令遞減'ecx',並且如果'ecx'不成爲零,它將跳轉到目標地址,在本例中爲'x1'。 'loop x1'實際上等同於'dec ecx; jnz x1'。有條件地跳轉到'dec ecx'行會將位僅移位19次,而不是所需的37次。 – nrz

2

在x86上執行乘法運算時,edx將保存結果的前32位,而eax將保留最後32位。當你這樣做:

mul esi 
mov esi, edx 
add esi, eax 

結果只會是在情況下有意義的是edx爲0,這樣mov/add,基本上是做mov esi, eax。如果最高32位不是零,那麼最終會得到一個毫無意義的高位和低位混雜。

+0

我想如何用兩個單獨的寄存器作爲輸入調用printf?我應該先把它放在分配的內存中嗎? –

+1

@HananN .:如果您使用的printf格式可以接受64位整數,那麼您可以使用它。否則,您可能必須自己將其轉換爲數字,然後打印出字符串。 –