2010-12-30 6 views
0

9のようなeaxの数字が文字形式「9」に変換されて出力されます。私は32ビットLinuxマシンでnasmを使用しています。純粋なアセンブリで文字を1桁に変換する方法

section .data 
int: dw 9 

section .text 
global _start 

_start: 
    mov eax, 9 
    add eax, 48 
    mov ecx, [eax] 

    mov eax, 4 
    mov ebx, 1 
    mov edx, 1 
    int 0x80 

    mov eax, 1 
    mov ebx, 0 
    int 0x80 

このプログラムを実行すると、セグメント化エラーが発生します。私はgdbを使ってデバッグし、mov ecx, [eax]という行にセグメンテーションフォルトが発生します。これを修正する方法はありますか?

答えて

3

mov ecx, [eax]は、メモリアドレスとしてeaxを解釈し、その場所のデータをecxにコピーすることを意味します。これは、クラッシュの原因となっている0x00000039のメモリを逆参照しようとします。

eaxの値をecxにコピーする場合は、角括弧なしのmov ecx, eaxを使用してください。

+1

私はそれをやってみましたが、動作しません。私はそれがsyscallが文字列のアドレスを含むためにecxを必要とするからだと思う。 – Kevin

+2

バイト0x39(つまりASCII '9')をメモリに格納し、メモリアドレスを 'ecx'に入れる必要があります。これを行うための標準的な方法は、スタックにスペースを割り当てることです(http://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames#Standard_Entry_Sequenceを参照)。次にlea ecx、[ebp-4]スタック割り当てバッファのアドレス。 –

+0

ああありがとうございます。私はmov ecx、eaxをpush eaxに置き換え、lea ecx、espに置き換えて動作させた。 – Kevin

0

つまり、eaxの値をアドレスとして扱い、メモリ内でそれを調べていることを意味します。角かっこを取り除くだけです。

+0

ブラケットを外してプログラムを実行しようとすると、何も起こりません。接線備考の場合は – Kevin

1

eaxに格納されている番号9を、文字 '9'のASCIIコードポイントに48を追加することで正しく変換しますが、その値をバッファに格納してwriteと呼ぶのではなく、メモリアドレスとして、そのアドレスからecxに読み出します。メモリアドレス(9 + 48 =)57は、ヌルポインタの逆参照をキャッチするために予約されたアドレス空間の領域内にあるため、セグメンテーションを取得します。

あなたはこのような何かの代わりに(注:私はインテルのバックasswards構文を使用することを拒否。gcc numbernine.sでコンパイルし、64ビットの分布に、あなたはgcc -m32 numbernine.sを使用する必要があります):たい

 .data 
     .align 4 
     .type buf,@object 
     .size buf, 2 
buf: 
     .byte 0 
     .byte 10 

     .text 
     .align 4 
     .globl main 
     .type main,@function 
main: 
     leal buf,%ecx 
     movb $9,%al 
     addb $48,%al 
     movb %al,(%ecx) 

     subl $12,%esp 
     movl $2,8(%esp) 
     movl %ecx,4(%esp) 
     movl $1,(%esp) 
     call write 
     addl $12,%esp 

     xorl %eax,%eax 
     ret 

接線をkibitz:代替がない場合に限り、直接システムコールを行います。 Cライブラリがラッパーを提供する場合は、それを使用します。 writeの問題はそれほどありませんが、Cライブラリラッパーが裸のカーネルABIの変更からあなたを守るためにいくらかの長さになるシステムコールがたくさんあります。それ。また、Cライブラリは、sysenter(または64ビットABIにはsyscall)を使用する方法とerrnoを設定する方法を知っています。これが私がスタックに物を押して、あなたがしていたものではなくwriteを呼び出す理由です。

さらに、mainから返すことができるときに、直接システムコールを使用してプロセスを終了するのは愚かです。

+0

+1です。 コードは悪いですが、自分でコンパイルしようとしたかどうかは疑問です; – Jester

+0

修正しました。ありがとうございました。これは、私がOSXマシンからLinuxに関する質問に答えるためのものです:) – zwol