1

ASM プログラミングのスターターとして、アセンブリで 2 の 38 乗の結果を取得する必要があります。私のプログラムが必要な結果を生成しない理由を理解するためにあなたの助けが必要です (10 進数で 4 が出力されます)。

.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を使用して書いています(その場合に問題がある場合)。

4

2 に答える 2

8

2^38などの 1 つの 32 ビット レジスタには明らかに収まりませんeax

2^38値( )を格納するには、27487790694439 ビットが必要です。32 ビット コードでは、たとえば次のように使用できます。などの 2 つの 32 ビット レジスタedx:eax。ただし、32 ビット コードmulでは 32 ビットファクターのみを受け入れるため(例: レジスター、その他は常に)、中間結果を 32 ビットに格納できないため、ループでeax32 ビットを使用しても機能しません。レジスタに64 ビットの結果を格納する場合でも、再びmul乗算されます。muledx:eax

rclただし、たとえば計算に使用できます。2^3832 ビット コード:

    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 O'Neill の回答に触発された非ループ実装。これは、指数 >= 32 の場合はジャンプなし、指数 < 32 の場合は 1 つのジャンプ、ecx0 の場合も機能し、63 セットをecx超える場合は.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:
于 2012-10-01T22:18:14.773 に答える
2

x86で乗算を行うedxと、結果の上位32ビットeaxが保持され、下位32ビットが保持されます。あなたがするとき:

mul esi
mov esi, edx
add esi, eax

edx結果は、 0の場合にのみ意味があるため、 mov/addは基本的にを実行しmov esi, eaxます。上位32ビットがゼロ以外の場合、上位ビットと下位ビットのかなり無意味なミッシュマッシュになってしまいます。

于 2012-10-01T20:15:50.993 に答える