0

コードは正常にコンパイルされます [ NASM]

しかし、最初の値を入力するとすぐにクラッシュします

何が問題なのかわかりません。目標は、文字列を入力し、文字列の逆を出力することです。ループ内で、ユーザーが「はい」(「Y」または「y」) と言った場合に繰り返します。

**.DATA
; Initialized Data Definitions 

strlength      EQU     40
PromptStr      dd      "Please input a string (must be less than 40 characters long): ", 0
OutputStr      dd      "The reverse string is: ", 0
AgainStr       dd      "Would you like ot try again? ('Y' or 'y' for yes): ", 0 

.UDATA
; Uninitialized Data Definitions 

string         resb    strlength

.CODE
; Program Code

.STARTUP

nwln                    ; start output at a new line
PutStr      PromptStr
nwln
while:
    GetStr              string
    mov                 EBX, string

    loop_in:
        push            dword[EBX]
        add             EBX, 4
        cmp             dword[EBX], 0
        jnz             loop_in

    loop_out:
        XOR             EBX, EBX
        pop             EBX
        PutCh           [EBX]
        cmp             dword[EBX], 0
        jnz             loop_out

    nwln
    PutStr              AgainStr
    GetStr              EBX
    mov                 AL, [EBX]
    cmp                 AL, 'Y'
    jz                  while
    cmp                 AL, 'y'
    jz                  while

    Pause


.EXIT**

最初のループを次のように変更しました

loop_in:
        mov             AL, [EBX]
        push            byte[AL]
        add             EBX, 4
        cmp             byte[AL], 0
        jnz             loop_in

そして、このエラー「エラー:無効な実効アドレス」が表示されます

「バイト」に変えると

loop_in:
        push            byte[EBX]
        add             EBX, 4
        cmp             byte[EBX], 0
        jnz             loop_in

「エラー: オペコードとオペランドの組み合わせが無効です」というメッセージが表示されます

行 {add EBX, 4}

だから私は変わった

loop_in:
        push            EBX
        inc             EBX
        cmp             byte[EBX], 0
        jnz             loop_in

    loop_out:
        XOR             EBX, EBX
        pop             EBX
        PutCh           [EBX]
        cmp             byte[EBX], 0
        jnz             loop_out

そして今それはコンパイルされ、私はここまで来ました

Please input a string (must be less than 40 characters long):
asdf
fdsaêë

Windowsにクラッシュする前に

4

2 に答える 2

0

これをどのように「コンパイル」しましたか。アセンブリ ソースをコンパイルしないため、アセンブルし、必要に応じてリンクします。

私はあなたのマクロ ファイルを持っていないので、ここでは C ライブラリのいくつかの関数を使用しましたが、すべて同じである必要があります。

    push    dword [stdin]
    push    MAX_INPUT
    push    string
    call    fgets                           
    add     esp, 4 * 3

    ;~ fgets adds the NL char to string, replace with NULL
    push    string
    call    RemoveNL

    mov     esi, string
    xor     ebx, ebx
PushChar:
    movzx   eax, byte[esi + ebx]
    test    eax, eax
    jz      PopChar
    push    eax
    inc     ebx
    jmp     PushChar

PopChar:
    push    fmtchar
    push    dword [stdout]
    call    fprintf                         
    add     esp, 4 * 3    
    dec     ebx
    jnz     PopChar

    jmp     Done

RemoveNL:
    mov     esi, [esp + 4]
    xor     ecx, ecx
    dec     ecx
.FindNL:
    inc     ecx
    cmp     byte [esi + ecx], 10
    jne     .FindNL
    mov     byte [esi + ecx], 0
    ret     4

説明のために:

    mov     esi, string
    xor     ebx, ebx
PushChar:
    movzx   eax, byte[esi + ebx]
    test    eax, eax
    jz      PopChar
    push    eax
    inc     ebx
    jmp     PushChar

入力を取得するために呼び出すものを呼び出すと、文字列に文字が含まれます。のアドレスを に移動stringし、文字配列へのインデックスとして使用するためにゼロアウトしますesiebx最初に、esi + ebx のポインターからバイトを移動し、それをeaxゼロ拡張eaxに移動します。これにより、char の ASCII 値が eax の下位バイトに移動され、未使用の上位バイトがゼロになります。NULL次にターミネータを探し、testそれが現在のインデックスでゼロの場合、値をスタックにプッシュします。値が 0 でない場合はeax、スタックにプッシュし、ebx(インデックス) を 1 つ増やしてループを続行します。

PopChar:
    push    fmtchar
    push    dword [stdout]
    call    fprintf                         
    add     esp, 4 * 3    
    dec     ebx
    jnz     PopChar

すでにスタック上にあり、スタックが LIFO であるため、印刷関数/マクロのパラメーターとして再度pop値を指定する必要はありません。最後にプッシュされた文字は印刷の準備ができています。pushここでは、プッシュされた 2 つのパラメーターのみが表示されますが、fprintf3 つのパラメーターをプッシュしたかのように esp を調整します。印刷された文字をスタックから削除すると、次の文字の準備が整います。いつ停止するかをどうやって知るのですか?ebxループからの数値を使用し、PushCharその値を 0 になるまで減らします。

出力: ここに画像の説明を入力

于 2013-10-10T02:47:32.840 に答える