1

ユーザーが入力した値を取得して(結果の三角形のサイズを変えるため)、それを使用して減少するドットの行を書き込むことにより、画面上にドットの三角形を作成しようとしています。

コードは次のとおりです。

section .data
        global  _start

        char    db      ' '

        prompt_text     db      "Enter triangle size (2-99) "
        prompt_length   equ     $-prompt_text

section .bss
        tri_size        resb    3
        tri_size_length equ     $-tri_size

section .text
_start:
        call    prompt
        call    insert_size

        mov     rax,    [tri_size]

outer_loop:
        mov     rbx,    [tri_size]

inner_loop:
        call    dot
        dec     bx
        cmp     bx,     0
        jg      inner_loop

        call    linefeed

        call    dec_length

        dec     ax
        cmp     ax,     0
        jne     outer_loop

        call    linefeed
        call    exit

prompt:
        mov     rax,    4
        mov     rbx,    1
        mov     rcx,    prompt_text
        mov     rdx,    prompt_length
        int     80h
        ret

insert_size:
        mov     rax,    3
        mov     rbx,    0
        mov     rcx,    [tri_size]
        mov     rdx,    tri_size_length
        int     80h
        ret

dot:
        mov     [char], byte '.'
        call    print_char
        ret

linefeed:
        mov     [char], byte 10
        call    print_char
        ret

print_char:

        push    rax
        push    rbx
        push    rcx
        push    rdx


        mov     rax,    4
        mov     rbx,    1
        mov     rcx,    char
        mov     rdx,    1
        int     80h

        pop     rdx
        pop     rcx
        pop     rbx
        pop     rax
        ret

dec_length:

        push    rax
        push    rbx
        push    rcx
        push    rdx

        mov     rax,    [tri_size]
        dec     ax
        mov     [tri_size],     rax

        pop     rdx
        pop     rcx
        pop     rbx
        pop     rax
        ret

exit:
        mov     rax,    1
        mov     rbx,    0
        int     80h

問題:

  • プログラムの実行時に、ユーザーが入力した数値を最初の行のドット数に使用したい。ただし、任意の数字を入力すると、それぞれに 1 つのドットを含む多数の行が印刷され、約 1 秒後に 32768 ドットを含む行が印刷されます。これに 32767 ドットのラインなどが続きます。各ラインのドット数は、1 ドットのラインまで減少し続けます。

32768 は 10000000_00000000 の 16 進数であることに気付きましたが、それ以外は完全に行き詰まっており、何か助けていただければ幸いです!

PS私はx84-64 Linuxを使用しており、YASMでアセンブルしています

4

1 に答える 1

2

入力を読み取るときに、コードに 2 つの問題があります。まず、修正。その後、現在の結果の説明。

insert_size:
    mov     rax,    3
    mov     rbx,    0
    mov     rcx,    [tri_size]          ; issue 1
    mov     rdx,    tri_size_length
    int     80h
    ret                                 ; issue 2 (sort of)

修正

まず、rcxバッファのアドレスが含まれている必要がありますが、アドレスではなく の内容を取得していtri_sizeます。tri_sizeは bss セクションにあるため、0 で初期化されるため、OS に NULL バッファーに読み込むように指示しています。システム コールの結果を確認すると、このためエラー コードが表示されます。

次に、入力を読み取るときは、数値ではなく文字列を読み取っています。数値として使用する場合は、最初に変換する必要があります。両方の問題を修正したコードを次に示します。

insert_size:
    mov     rax,    3
    mov     rbx,    0
    mov     rcx,    tri_size           ; 1
    mov     rdx,    tri_size_length
    int     80h
    mov     dh,     0                  ; 2
    mov     ah,     0
    mov     dl,     [tri_size]         ; 3
    mov     ah,     [tri_size+1]
    sub     dl,     '0'                ; 4
    cmp     al,     '0'                ; 5
    jb      done
    cmp     al,     '9'                ; 6
    ja      done
    imul    dx,     10                 ; 7
    sub     al,     '0'                ; 8
    add     dx,     ax                 ; 9
done:
    mov     [tri_size], dx             ; 10
    ret

最初の問題は簡単に修正できます。内容ではなくアドレスを取得するには、ブラケットを削除するだけです。2 つ目はより複雑です。まず、16 ビット レジスタを使用しますが、読み取りは 8 ビットのみなので、ステップ 2 でそれぞれの上位バイトに 0 を入れます。次に、文字列の最初の 2 バイトを読み取ります。次に、最初の文字を文字から数字に変換します。ASCII の数字は連続しているため、文字「0」を減算することでこれを行うことができます。これは、最初の文字が有効な数字であると想定していることに注意してください。

1 文字しか入力されていない可能性があるため、2 番目の文字が有効な数字であるとは想定できません。したがって、ステップ 5 と 6 では、それぞれ '0' より小さいか '9' より大きいかどうかを確認し、どちらかが true の場合は最後にジャンプします。両方を通過すると、2 番目の文字は数字になります。これは、最初の数字が 10 の位にある必要があることを意味するので、10 を掛けます。次に、2 番目の文字を数字に変換し、最初の文字に追加します。両方の文字がテストされたので、結果を期待される場所に保存して返すことができます。


説明

修正で説明されているように、NULL バッファーを渡しているため、エラーが返されます。変数tri_sizeは変更されないため、まだ 0 が含まれています。これは、両方のカウンターが 0 から始まることを意味します。これをチェックしないため、最初のドットが出力されてbx減分され、-1 になります。-1 は 0 より大きくないため、内側のループが終了し、改行が出力され、カウンターaxが減分され、-1 になります。これはゼロではないため、外側のループにループ バックします。これは、カウンターが -32768 になるまで 32768 回発生します。

ここでデクリメントbxすると -32769 になりますが、この数値は 16 ビットの 2 の補数では表現できません。代わりにオーバーフローし、得られる数値は 32767 です。これは 0 よりも大きいため、0 になるまで内側のループを続行し、合計 32768 ドットを出力します。内側のループが終了し、改行が出力された後、カウンター とaxの両方が減分され、結果として 32767 になります。この時点から、プログラムは入力が 32767 であるかのように動作します。つまり、そこから三角形が 0 ドットになることを意味します。

興味深いことに、内部ループbxが 0 より大きいかどうかをテストした場合、65536 ドットから 0 までの三角形が得られ、その前に 1 ドット ラインはありません。

于 2013-11-10T03:28:35.800 に答える