2013-07-02 4 views
6

私はNASM構文(ああ、これはもう一度ではない、、あなたはすべて考えている)でx86 Linuxアセンブリを学んでいる。私は単にEAXの値をstdoutに出力するサブルーチンを作ろうとしています。コードは実行され、エラーなく終了しますが、何も印刷されません。なぜ私は理解できません。これは、この(私は抜本的な何かが欠けている場合を除き、これは、おそらく無関係である)のように見える私のメインファイルから呼び出されLinux x86 NASM - サブルーチン:EAXからdwordを出力

segment .bss 
    to_print: resd 1 

segment .text 
    global print_eax_val 

print_eax_val:     ;  (top) 
    push dword ebx   ;Stack: edx 
    push dword ecx   ;  ecx 
    push dword edx   ;  ebx 
           ;  (bot) 

    mov  ecx,eax    ;ecx = eax 

    mov  [to_print],ecx  ;to_print = ecx 

    mov  eax, 4    ;sys_write 
    mov  ebx, 1    ;to stdout 
    add  ecx, 47    ;add 47 for ASCII numbers 
    mov  edx, 2    ;double word = 2 bytes 
    int  0x80 

    mov  eax, [to_print]  ;eax = original val 
    pop  edx     ;pop the registers back from the stack 
    pop  ecx 
    pop  ebx     ;Stack: empty 

    ret 

:まず第一に、ここで私が働いているファイルです。

segment .data 
     hello db  "Hello world!", 0 
     newline db  0xA 
     len  equ $ - hello 
     len2 equ $ - newline 

segment .text 
     extern print_nl 
     extern print_eax_val 
     global main 

main: 
     enter 0,0 

     call print_nl 

     mov  eax, 1 

     call print_eax_val 

     mov  ebx, 0   ;exit code = 0 (normal) 
     mov  eax, 1   ;exit command 
     int  0x80   ;ask kernel to quit 

print_nlは、改行を定義して印刷する別のサブルーチンです。これは正常に実行され、期待どおりに新しい行が印刷されます。

問題は私のsys_writeコールの長さパラメータと関係がありますか?私はresd 1と予約したEAXto_printの両方のラベルのサイズであるdwordのサイズである2を与えています。私は絶望から1,4,8,16,32までの長さを変えようとしました...何も働いていませんでした。

EDIT:不思議に思っている人のため、ここでは、私は、コードを固定する方法である:(Iは私が変更された行にアスタリスクを入れます):

segment .bss 
    to_print: resd 1 

segment .text 
     global print_eax_val 

print_eax_val:      ;  (top) 
     push dword ebx   ;Stack: edx 
     push dword ecx   ;  ecx 
     push dword edx   ;  ebx 
            ;  (bot) 

     mov  ecx,eax    ;ecx = eax 

     mov  [to_print],ecx  ;to_print = ecx 

**** add  dword [to_print], 48 

     mov  eax, 4    ;sys_write 
     mov  ebx, 1    ;to stdout 
**** mov  ecx, to_print 
     mov  edx, 2 
     int  0x80 

**** sub  dword [to_print], 48 
     mov  eax, [to_print]  ;eax = original val 
     pop  edx     ;pop the registers back from the stack 
     pop  ecx 
     pop  ebx     ;Stack: empty 

     ret 

基本的には、ecxアドレスが含まれている必要があり値を指定するのではなく、印刷するブロックの値を指定します。選択された答えに指摘されているように、のみが0〜9の範囲で動作します。

EDIT 2:sys_write(edxに格納されているもの)の2番目のパラメータについて少し混乱しました。私はそれが単にバイト数を指していると思う。したがって、dwordの場合、私が使用していたように、ダブルワードが4バイトまたは32ビットであるため、4を使用するのが適切です。私はそれがx86がリトルエンディアンであるために動作していると思います。だから、メモリ内で、to_printの六角値は次のようになります。

90 00 00 00

そして2の付属の長さと、SYS_WRITEを取得します。

90 00

をだから、値が運よくありません堕落する。私はto_printに上記の値を与えるつもりはない知っているので

私は後でresb 1を使用して、代わりにバイトとしてto_printを格納するためのコードを変更し、byte代わりのdwordを使用してアクセスする...バイトは、ここで結構です9.

答えて

4

私はアセンブラで非常に錆びていますが、ECXには書き込むバッファのアドレスが含まれている必要があります。

print_eax_valは、EAXのバイナリ値を取得し、0(これは48ではなく47であるはずです)にASCIIオフセットを加えて、その1文字を印刷することです。これを行うには、to_printに値を格納する前に48を追加し、ECXにto_printのアドレスを置き、長さ(EDX)を1に設定します。これは、1文字のみを書き込むためです。

これは0x0000と0x0009の間のEAX値に対してのみ機能することに注意してください。 9時を過ぎると、他のASCII文字が得られます。

EAXの任意のバイナリ値を取得し、それを10進文字列に変換する方法については、SOの範囲をはるかに超えています。

+0

ありがとうございました!あなたの答えはとても役に立ちました。ええ、私はこれが0から9の間だけ働くことを理解します、私はちょうど基本のいくつかを落とそうとしています。たぶん私はいくつかの配列/ポインターint to文字列のビジネスから始まるだろう。私は、更新されたコードで自分の投稿を編集し、知りたい人は誰でも編集します。 –

+3

私はアセンブリ言語に取り組んであなたに拍手し、あなたが幸運を祈ります。ところで、あなたの質問は、プロトタイプ良いSOの質問です。あなたは正確に必要な情報を与え、あなたが試したことを示し、特定の質問をしました。 +1 –

+1

もう一度おねがいします。私は確かにあなたの答えを「プロトタイプのよいSO」答えとして分類します。私が取り組んでいるプロジェクトでは、巨大なC++のsegfault/pointer meltdownの後でいくつかのx86アセンブリを学ぶことにしました。まず第一に、それは素敵な転換です。第二に、コードを書くときに私が実際にやっていることを知りたいのです。 –

3

writeシステムコールでは、で指定された長さの%ecxが指し示す、印刷する文字バッファが必要です。一方、%eaxのようなレジスタは32ビットの整数を含んでいます。

実際に%eaxを印刷する場合は、最初にその整数を一連の文字に変換する必要があります。 ASCII 10進数または16進数、または好きなベースに変換できますが、文字にする必要があります。

+0

ご協力ありがとうございます!あなたの答えは完全に参考になりました(インターネットは実際にアセンブリ言語のq&aには驚くほど疎ですが、どこに見えるかわからないかもしれません)。私は最初に他の答えを得ましたが、私は2つの正解を選ぶことができたら、私はします。 –

+0

非常にマイナーなnit: 'dword'のサイズは2ではなく、4です。 –

+0

Hah、アセンブリでは(私がこれまでに学んだことから)間違ったことはありません。私は、その長さパラメータに入れるべきものについて混乱していました。詳細については、私の記事の2を参照してください。しかし、ありがとう! –

関連する問題