25

レジスタの値を 10 進形式で表示するための純粋なアセンブリコードを誰か教えてもらえますか? printf ハックを使用してから gcc でコンパイルすることはお勧めしません。

説明:

さて、私はNASMでいくつかの調査と実験を行い、cライブラリのprintf関数を使用して整数を出力できると考えました。オブジェクト ファイルを GCC コンパイラでコンパイルしたところ、すべて問題なく動作しました。

ただし、達成したいのは、任意のレジスタに格納されている値を 10 進数形式で出力することです。

私はいくつかの調査を行い、DOSコマンドラインの割り込みベクトル021hが文字列と文字を表示できると考えましたが、2または9はahレジスタにあり、データはdxにあります。

結論:

私が見つけた例のどれも、C ライブラリの printf を使用せずにレジスタの内容値を 10 進数形式で表示する方法を示していませんでした。アセンブリでこれを行う方法を知っている人はいますか?

4

5 に答える 5

19

2 進数から 10 進数への変換ルーチンを作成し、10 進数を使用して「数字文字」を生成して印刷する必要があります。

どこかの何かが、選択した出力デバイスに文字を出力すると仮定する必要があります。このサブルーチンを「print_character」と呼びます。EAXで文字コードを取り、すべてのレジスタを保存すると仮定します..(そのようなサブルーチンがない場合は、別の質問の基礎となる追加の問題があります)。

レジスタ(EAXなど)に数字のバイナリコード(たとえば、0〜9の値)がある場合、「ゼロ」文字のASCIIコードを追加することで、その値を数字の文字に変換できますレジスターへ。これは次のように簡単です。

       add     eax, 0x30    ; convert digit in EAX to corresponding character digit

その後、print_character を呼び出して、数字の文字コードを出力できます。

任意の値を出力するには、数字を取り出して出力する必要があります。

数字を選ぶには、基本的に 10 のべき乗で作業する必要があります。10 自体など、10 の 1 乗で作業するのが最も簡単です。EAX で値を取り、EDX で商を生成し、EAX で剰余を生成する 10 で割るルーチンがあるとします。このようなルーチンを実装する方法を理解するための演習として残します。

次に、正しいアイデアによる単純なルーチンは、値が持つ可能性のあるすべての桁に対して 1 つの桁を生成することです。32 ビット レジスタは 40 億までの値を格納するため、10 桁の数字が出力される可能性があります。そう:

         mov    eax, valuetoprint
         mov    ecx, 10        ;  digit count to produce
loop:    call   dividebyten
         add    eax, 0x30
         call   printcharacter
         mov    eax, edx
         dec    ecx
         jne    loop

これは機能します...ただし、数字が逆の順序で出力されます。おっとっと!プッシュダウン スタックを利用して、生成された数字を格納し、逆の順序でポップすることができます。

         mov    eax, valuetoprint
         mov    ecx, 10        ;  digit count to generate
loop1:   call   dividebyten
         add    eax, 0x30
         push   eax
         mov    eax, edx
         dec    ecx
         jne    loop1
         mov    ecx, 10        ;  digit count to print
loop2:   pop    eax
         call   printcharacter
         dec    ecx
         jne    loop2

読者への演習として残しておきます: 先頭のゼロを抑制します。また、数字文字をメモリに書き込んでいるので、数字をスタックに書き込む代わりに、バッファに書き込んでバッファの内容を出力することもできます。また、読者への演習として残します。

于 2012-10-31T19:53:19.213 に答える
0

コメントできないので、この方法で返信を投稿します。@Ira Baxter、完璧な答えレジスタcxを値10に設定したと投稿したので、10回割る必要はないことを付け加えたいだけです。「ax == 0」になるまでaxで数値を分割するだけです

loop1: call dividebyten
       ...
       cmp ax,0
       jnz loop1

また、元の番号に何桁あったかを保存する必要があります。

       mov cx,0
loop1: call dividebyten
       inc cx

とにかく、Ira Baxter がコードを最適化する方法をいくつか教えてくれました :)

これは最適化だけでなく、書式設定についても同様です。番号54を印刷したい場合は、0000000054ではなく54を印刷したい:)

于 2015-03-11T13:31:05.880 に答える
0

値を標準出力に出力したいと思いますか?その場合は、システム コール
を 使用してそうする必要があります。システムコールは OS に依存します。

例: Linux: Linux システム コール テーブル

このチュートリアルの hello world プログラムから、いくつかの洞察が得られるかもしれません。

于 2012-10-31T19:49:35.577 に答える