2017-08-01 2 views
1

アセンブリ8086の1行に4つの異なる文字列を表示する際に問題が発生しました。出力は "You are"、 "first name"、 "middle name"、および "last name"である必要があります。最初の2つはうまく動作しますが、最後の2つのオーバーラップは最初のものと重なっています。つまり、 "あなたは" "ミドルネーム"によって書き換えられ、さらに "ラストネーム"によって書き換えられます。最後の2つの前に次の行を使用するとうまく印刷されますが、4行すべてを1行に表示し、3行には表示しません。私はネットを検索しようとしましたが、ほとんどの答えは2つの文字列のみを表示することに限定されています。なぜアセンブリ内の出力で複数の文字列が重複/上書きされますか?

;=====output====== 

mov ah, 09 
mov dx, offset crlf ;next line 
int 21h 

mov ah, 09 
mov dx, offset msg4    ;displays "You are" 
int 21h 

mov ah, 09 
mov dx, offset string1 + 2  ;displays inputted "first name" 
int 21h 

mov ah, 09 
mov dx, offset string3 + 2  ; this should appear next to string1, 
int 21h       not rewrite msg4... 

mov ah, 09 
mov dx, offset string2 + 2  ; this should appear next to string3, not 
int 21h        rewrite msg4 and string3 

これは、出力は以下のように終わるものです:

Enter 1st name: Helena 
Enter last name: Ramos 
Enter middle name: Ang 

Ramosre Helena     ;"Ang" rewrites "You are", and then 
            "Ramos" rewrites it again 

           ; This is what I want to see: 
           ;  You are Helena Ang Ramos 

「私はかなりのアセンブリで初心者だし、私の教授たちはドンことを考えると、まさに最も有用先生ではありませんどの本も持っていますが、クラスの配布資料は指示を定義するだけです。ラボの演習では彼が書いたコードをコピーして貼り付けているので、私のクラスメートのほとんどは実際のプログラミングで独学です。これは宿題のほんの一部ですが、実際の宿題ではミドルネームの代わりにミドルネームを表示する必要がありますが、4つの文字列すべてを正しく表示することさえできません。この時点で、スタックに文字列がどのようにプッシュされているかに問題があると感じましたが、私の限られた知識は私がなぜそれを理解するのを妨げています。

完全なコードもし興味があるなら:

org 100h 
.model small 
.stack 200 

.data 
msg1 db "Enter 1st name: $" 
string1 db 50,?,50 dup ('$') 
msg2 db 0ah, 0dh, "Enter last name: $" 
string2 db 50,?,50 dup ('$') 
msg3 db 0ah, 0dh, "Enter middle name: $" 
string3 db 50,?,50 dup ('$') 

msg4 db 0ah, 0dh, "You are $" 

crlf db 0ah, 0dh, '$' 

.code 

mov ax, @data 
mov ds, ax 

mov ah, 09 
mov dx, offset msg1 
int 21h 

mov ah, 0ah 
mov dx, offset string1 ;input first name 
int 21h 

mov ah, 09 
mov dx, offset msg2 
int 21h 

mov ah, 0ah 
mov dx, offset string2 ;input last name 
int 21h 

mov ah, 09 
mov dx, offset msg3 
int 21h 

mov ah, 0ah 
mov dx, offset string3 ;input middle name 
int 21h 

;=====output====== 

mov ah, 09 
mov dx, offset crlf ;next line 
int 21h 

mov ah, 09 
mov dx, offset msg4    ;displays "You are" 
int 21h 

mov ah, 09 
mov dx, offset string1 + 2  ;displays inputted "first name" 
int 21h 

mov ah, 09 
mov dx, offset string3 + 2  ; this should appear next to string1, 
int 21h       not rewrite msg4... 

mov ah, 09 
mov dx, offset string2 + 2  ; this should appear next to string3, not 
int 21h        rewrite msg4 and string3 

答えて

2

あなたは何が起こるか、デバッガで確認する必要があります。

あなたは、あなたが最初のプロンプトで「ヘレナ」を入力した後、string1アドレスのメモリ内容があることがわかります希望の場合:

32 07 48 65 6C 65 6E 61 0D 24 24 24 24 ... 

これらのデータについて重要なことは、また、CR(と呼ばれる値0Dれますキャリッジリターン)をアドレスstring1 + 2 + 7 - 1(文字列データに到達するために+2、+ 7は入力の長さ、-1は最後の文字に戻る)に移動します。

他の2つの入力についても同じことが適用されます。

あなたが最終ラインの出力を開始しますたら、画面上で書きます:

You are Helena、そこにバックラインの先頭にBIOSカーソルを返します。最初のCRは、来るが、それは続いていませんLF(0Ah)、カーソルは1行下にも移動せず、代わりに2行目の出力が行の先頭を上書きします。

は修正するには:ユーザによって入力されたそれぞれの名前を表示する先を、実行します。

mov ah, 09 
    mov dx, offset string1 + 2  ;displays inputted "first name" 

    movzx bx, byte ptr [dx-1]  ; bx = length of input 
    mov byte ptr [bx + dx - 1], '$' ; overwrite last input char (most likely CR) with '$' 
    int 21h 

(リアルモードは、モード[bx + dx -1]をアドレッシングをサポートしていない場合、単にadd bx,dxを行うと...その後[bx-1]を使用してマイメモリがぼやけている、私はもっと多くのプロテクトモードx86アセンブリをやっていました。アドレシングモードははるかにリラックスして普遍的です)。

もしも8086が偶数をもたない場合、xor bx,bxmov bl,[dx-1]は同じことをすることができます(メモリから読み込み、ゼロに伸ばす)。

EDIT:実際にあなたが名前の間にスペースを入れて、むしろSPACE ' 'でその最後の文字を上書きすることがあります...とstring3あなたが新しいため、その終わりCR + LFペアで書くことmov word ptr [bx+dx-1],0A0Dhでそれを上書きすることで、できるだけ長い入力(全部で50文字)でメモリの上書きを避けるために、string3バッファの後ろにもう1バイトを置くべきです。


EDIT:いくつかのより多くのコメント...

は、それはインターネットの時代だ任意のブック

を持っていません。 8086(おそらくemu8086にあると思います)を教えることは、それ自体が残酷な冗談のよ​​うなものです。そして、この知識は、今後のプログラミング関連の新たな視点を与えるでしょう。あなたはemu8086のチュートリアルをいくつか試してみることができるはずです(ただし、私は質についてはわかりませんが、いくつかの質問で判断すると基本的なチュートリアルしか見つけるのは難しいですが...)それは個人的な使用のための電子形式で読むために、それは非常に徹底的で詳細です...しかし、巨大(あなたのコースが本当に悪い場合は、まだ16b DOS版をチェックしたいかもしれませんし、あなたの側で適切な研究が必要とされる領域)を特定する。

を、私は文字列はあなたがやった

スタックにプッシュされている方法に問題があると感じていますあなたのコードのどこにでもスタックに触れないでください...このライトであなたのコメントはかなり恐ろしく聞こえるでしょう、それは200-300ページを読むことを意味しても、おそらく本当にその本を掘るべきです。結局のところ、あなたは "緊急"を使用しなかったので、アセンブリやコンピュータアーキテクチャの基本に追いつくのに数カ月の時間がかかりそうです。


「SPACEのEDIT」のFIX:

しかし、あなたは、スペースでその最後の文字を上書きするときに、ユーザーが50文字長い名前を入力した場合、その後、名前は何より'$'は終了しませんので、あなたがすべきむしろ、このように、それらを超えて固定ターミネータを持っているあなたのバッファを定義します:

string1 db 50,0,51 dup ('$') ; after 50 byte buffer there's one more '$' 

これは、ASMプログラミングにおける最も困難な部品の一つである、誤ったデータの定義に起因する、任意のバッファ/スタックオーバーフローのバグを回避するために、そして安全でない使い方メモリの。デバッガの最小/最大入力で常にコードをテストし、メモリ内容を見て、期待どおりに動作するかどうか、または予期しないメモリの上書きが発生したかどうか、そしてどこでそれが起こるかを確認してください。場合たとえば、あなたは、いくつかのコーナーケースの入力がなくなってFFバイト作られたデバッガで見た場合、あなたは(あなたがあなたの元の間違ったを持って知っている次に

string1 db 50,0,51 dup ('$') 
    db 0FFh 
msg2 db 0ah, 0dh, "Enter last name: $" 

:あなたはまた、同様に、バッファ間のいくつかのガード値を定義することもできます最初のバイトは52、ユーザーは52文字の長い名前を入力します)。


(リアルモードでは有効ではありません、元のモード[dx]に取り組むことを提案)リアルモードで有効な8086のコードと修正:

は、コードの末尾に最初の手順を追加し、最後に上書きされます入力された文字+パスカルのような文字列(長さが先に文字列自体のバイトのメモリに保存されている)の1以上のバイト:

; input: 
; dx = address of string ([dx-1] must contain length of string) 
; ax = two chars to be written at the end of string (al = first, ah = second) 
changeEndOfInputString: 
    push si   ; preserve original si and bx values 
    push bx 
    mov si,dx  ; use SI for addressing in real mode 
    xor bx,bx  ; bx = 0 
    mov bl,[si-1] ; bx = (zero extended) string length 
    mov [si+bx-1],ax ; overwrite last inputted char + one more 
    pop bx   ; restore bx and si and return 
    pop si 
    ret 

そして今、名前文字列の表示には、スペースや改行を追加するためにそれを使用します必要です。

;=====output====== 

    ;display "You are " 
    mov ah, 9 
    mov dx, offset msg4 
    int 21h 

    ;display inputted "first name" with space added 
    mov dx, offset string1 + 2 
    mov ax, 2420h ; 20h = ' ', 24h = '$' (ASCII encoding) 
    call changeEndOfInputString 
    mov ah, 9 
    int 21h 

    ;display inputted "middle name" with space added 
    mov dx, offset string3 + 2 
    mov ax, 2420h ; 20h = ' ', 24h = '$' (ASCII encoding) 
    call changeEndOfInputString 
    mov ah, 9 
    int 21h 

    ;display inputted "last name" with CR+LF added 
    mov dx, offset string2 + 2 
    mov ax, 0A0Dh ; 0Dh = CR, 0Ah = LF (DOS "new line") 
    call changeEndOfInputString 
    mov ah, 9 
    int 21h 

そして、あなたの文字列バッファがこれらの変更に対処するために最後に追加バイトを持っていることを確認してください。

string1 db 50,0,51 dup ('$') ; first name buffer 
string2 db 50,0,52 dup ('$') ; last name buffer 
string3 db 50,0,51 dup ('$') ; middle name buffer 

場合、ユーザは、完全な50個の文字を入力するため、「姓」のバッファは、52「$」を必要とします50番目と51番目の文字はCR + LFに上書きされるので、52番目の '$'はint 21h,9サービスの文字列ターミネータとして保存します。

入力は' '+'$'で変更されるので、最初の+中間の名前バッファは51で$ 'です。したがって、50文字の入力の場合、51番目の文字は変更後も' $ 'に設定されたままです。それは入力編集のために有効であり、そしてあなたが任意の有効なを提供していませんどのくらいのバッファコンテンツのDOSを伝える、実際にいくつかのDOSバージョンでの入力値だから

はまた、?00Ahサービスバッファの2番目のバイトを設定されていませんバッファ内の呼び出し前の文字列。

そして最後の注意:

crlf db 0ah, 0dh, '$' 

これはLF + CR(間違った順序)で、DOS "新しい行が" CR + LFである必要があり、期待通りすなわち13、10 10、13は主に動作しますしかし、組み立ての世界では、これは何らかの形でバグですが、それは大きな影響を及ぼさないことは幸いです。 (すべての文字列定義で間違っています)。

だから私はbxに置き換えようとしましたが、エラーはありませんが、それでも上書きされます。

あなたは、いくつかのコードが何を期待しませんどこをチェックする機会、そしてどのような状況で、メモリやレジスタの内容があるを持っているので、デバッガを使用することを学ぶために絶対にMUST

あなたが8086エミュレータと互換性のアセンブラを検索するために、それはあまりにも怠惰な(私の頭の中で私は 3があなたの元の質問と徹底遅い(約10分)シミュレーションの読み取りを取った、デバッガなしで組み立てでプログラムする機会を持っていません私はあなたが文字列を上書きする理由を理解するまで、「唯一のCR」はソースから見つけるのが簡単ではないためです。そして私は何年ものx86アセンブリプログラミングをやって、メガバイトのASMソースコードを書きました。そして、このミスを発見するのはまだ難しかったです。私がデバッガを持っていて、それを実行すると、ユーザーの入力後にstring1バッファの内容をチェックした直後に問題が発見されます。

また、別の例のデバッガの必要性を説明するために、私はASMプログラミングを学んだときにコンピュータを持っていなかったので、紙にコードを書く必要がありました。通常1週間に1回。通常、それはいくつかのバグが原因で墜落したが、私はマシン上で、それをデバッグするのに十分な時間を持っていなかったので、私は紙で自宅でバグを見つけなければならなかった(そしてインターネットがSOに尋ねるために戻って1985年の周りにありませんでした)。すべてのバグが修正されたバージョンの作業には3〜5週間かかりました。私がデバッガを使ってコンピュータを自由に使えたら、おそらく1時間ですべての修正を行うだろう。その後、再び、今私は(も、他のプログラミング言語で)ソースを読むことによってだけ多くのバグを参照してください、それは私の脳は、すべてのドット、昏睡や数に着目し、その紙の経験の後に行ってきました方法です...

+0

私は8086を使用して、 movzxは動作しません。私は 'mov bl、[dx-1]'を試しましたが、 '(63)おそらく16進数のゼロ接頭辞はありません。または 'h'接尾辞なし。または間違ったアドレス指定。または未定義のVAR:[DX - 01H] ''私は、サブ[DX]、01、または '12月[DX]'を使用して、その周りに働いて試してみたが、それは同じエラーになります。 dxは間接アドレッシングでは受け入れられないので、bxに置き換えようとしましたが、エラーはありませんが、それでも上書きされます。私はdxで立ち往生しています。 – AnAn

+0

@AnAnああ、リアルモードの喜び、私はそれらを完全に忘れてしまった。私は有効なリアルモードアドレッシングと8086命令で答えを数分で編集します(コードを検証するためにアセンブラをいくつか取得した後)。 BTW 'sub [dx]、1は' dx'からではなく、メモリの内容から1を引きます。角括弧 '[] 'は、"そこで値を操作するためのメモリへのアドレスとしての角括弧内の値の使用 "を意味します。答えの最後に – Ped7g

+0

@AnAnは...基本的に新しい答えです...しかし、あなたは自分を試す難しくする必要がある、と私は、ランダムな推測や他の場所からのコードの一部のコピーペーストをしようとして意味するものではありません。それは高水準言語ではうまくいくかもしれませんが、アセンブリではあなたが書いたことを完全に理解しなければなりません。合理的な時間に正しいコードを「推測」する機会はありません。だからあなたの現在の問題から判断するあなたは、いくつかの書籍/チュートリアルを読む必要に数週間を過ごす(「スタック」に言及、LF + CR、間違って私の元のコードを修正することができないことは、 '[DX]'、デバッガを使用できないことに対処逆転しました)コードを使って実験してください。 – Ped7g

関連する問題