2012-10-01 159 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位整数,那么您可以使用它。否则,您可能必须自己将其转换为数字,然后打印出字符串。 –