2016-03-29 21 views
2

で参照渡し:値渡し、私はこの問題を解決しようとしているアセンブリ

価値によってパスとして一つのパラメータを取り、応じて「X」の数を表示しますPROCプロシージャを作成します。パラメータとして渡された数値に変換します。 印刷する前に、parameterが正の数であることを確認してください。プログラムの最後に、使用されたレジスタを最初の値に戻す必要があります。

手順への入力が5であれば、コンソール上の出力は次のようになります。

XXXXX

これは私のコードです:

var db 5 ;In the dataseg 
push [var] ;in the codeseg 

proc example 
    pop cx 
    cmp cx,0 
    ja print 
print: 
    mov dl, 'X' 
    mov ah, 2h 
    int 21h 
    loop print 
    ret 
endp example 

は、このコードの動作は、ウィル期待どおりに、もしそうでなければ、なぜですか?どのように修正することができますか?

+2

に何の 'PUSHのR/m8'は、ありませんまたは 'dd')。また、 'push word ptr [var]'(または 'dword ptr')を使用して、いくつのバイトをプッシュしたいかを明示する必要があります。 – Michael

+0

スタックにパラメータを渡す必要がありますか? –

答えて

1

いいえ、あなたのコードは大きく壊れています。

関数は、mov ecx, [esp+4]のようなものでスタックからargsにアクセスします。または、16ビットコードの[sp+2]はエンコード可能なアドレス指定モードではないため、スタックフレームを作成する必要があります。
push bp/mov bp, sp/mov cx, [bp+4] (そして関数の最後にこれを元に戻す)。これについての詳細はGoogleの「スタックフレーム」と、x86関数がスタック上のargにどのようにアクセスするかについて説明します。 (または、タグwikiを参照してください)。

これは、スタックにargsを渡す必要があると仮定しています。いくつかの呼び出し規約は最初の2つの引数をレジスタに渡し、命令を保存します。小さな機能で


あなたの機能はあなたがcallで呼び出されたと仮定していることを意味しており、retで終わります。戻りアドレスは、関数入力時に[sp](または、32ビットコードで[esp])になります。その時点でpopが戻りアドレスをロードします。リターンアドレスがsp未満のときに割り込みが発生した場合は、上書きされますので、popには安全ではなく、retの前にspを再度戻してください。

argを押してから関数に落とすのは良い方法ではありません。


あなたの枝にも間違っている:jaを使用して

cmp cx, 0 
    ja print 
print:   ; execution ends up here whether the branch is taken or not 

あなたは符号なしとして、あなたの引数を処理していることを意味します。それはゼロであることによって非ポジティブであることがまだ可能であるので、それは問題ありません。しかし、私は代理人がargを署名したものとして扱うことを意図していたと思います。 jle nonpositiveのようなものを試し、nonpositive:をどこか便利な場所に入れてください。


タグのwikiにはチュートリアルや参考資料へのリンクがあります。その+デバッガ+グーグルで、あなた自身の質問に答えることができるはずです。

+0

OPは16ビットコードを使用しています。あなたの答えの中には、それが32ビットコードについて議論しているので、混乱させるものがあります。すなわち: '[esp]'、 'mov ecx、[esp + 4]'です。同様にOPのコードの構文はMASM/TASMです。 –

+0

@MichaelPetch: '[sp + 4]'(または '[sp + 2]'?)は、法的に有効なアドレスではないので、書いたくありませんでした。私はより良い答えを与えるのにもっと時間を費やしたくなかったし、16bitがどうやってばかであるかについて悩んでいた。私は有効なMASM構文ではないものを書きましたか?それは '.local_label'sを使わないのですか? –

+1

構文に関しては、MASM/TASMラベルの先頭にピリオドを追加できますが、ローカルとしては扱われません。アセンブラファイルの先頭に 'LOCALS'ディレクティブを追加し、ラベルの前に' @@ 'を付ける必要があります。 –

1

Peterの答えの補足として、MASM/TASMを使用してプロローグとエピローグコードを生成し、BPをセットアップし、手続き/関数の引数にラベルでアクセスすることができます。 MASMとTASMが使用するPROCサブルーチンについて合理的に良いチュートリアルでは、私が代わりBYTEWORDするvarを変更したhere

を見つけることができます。上記のコードは、手順exampleため、これらの命令を生成しているだろう

.MODEL SMALL 
.STACK 100H 

.DATA 
    var dw 5   ; Change to 16-bit WORD 

.CODE 

example proc C   ; C Calling convention - parameters on stack right to left 
    ARG num:WORD  ; We take one argument called `num` that is a word 

    mov cx, num  ; Move the 16-bit value in `num` to CX counter 
         ;  same as: mov cx, [bp+4] 
         ;  [bp+0] is saved copy of BP put on stack by MASM's prologue 
         ;  [bp+2] return address placed on stack by CALL 
    cmp cx, 0 
    jle negative  ; If we are less than or equal to 0, exit procedure 
    mov dl, 'X' 
    mov ah, 2h   ; ah and dl not destroyed by int 21h/ah=2 so set them once 
         ;  before loop 
print: 
    int 21h   ; Print an 'X' 
    loop print   ; Continue until loop is 0 
negative: 
    ret 
endp example 

main proc 
    mov ax, @data  ; initialize DS 
    mov ds, ax 

    push [var]  ; Push 2-byte value at `var` (pushing by value) 
    call example 
    add sp, 2   ; Remove parameter from stack 
         ;  Not necessary since we use int 21h to exit right after 
    mov ah, 4ch  ; return control to DOS 
    int 21h 
main endp 

end main    ; Entry point = label main 

example proc 
    push bp   ; Save BP on stack \ 
    mov bp, sp   ; Set BP to SP /Function prologue 
         ;  [bp+0] is saved copy of BP put on stack by prologue 
         ;  [bp+2] return address placed on stack by CALL 
         ;  [bp+4] first parameter (NUM) 

    mov cx, [bp+4]  ; Move the value at BP+4 (NUM) to CX counter 

    cmp cx, 0 
    jle negative  ; If we are less than or equal to 0, exit procedure 
    mov dl, 'X' 
    mov ah, 2h   ; ah and dl not destroyed by int 21h/ah=2 so set them once 
         ;  before loop 
print: 
    int 21h   ; Print an 'X' 
    loop print   ; Continue until loop is 0 
negative: 
    mov sp, bp   ; Restore stack pointer \ 
    pop bp    ; Restore BP register /Function epilogue 
    ret 
endp example 

私はすべてのレジスタexampleを決定するために、読者への課題として、それを残すように結果のコードが見えますPROCが変更され、宿題の要求に応じて保存/復元されます。ヒント: `dw`を(使用して` var`を宣言する必要がありますので、逆の順序でARGディレクティブとPOPそれらの後PUSHそれらは直前にRET

関連する問題