が、私は、各文字を反復処理する必要がある、と私はしようとしていますこれを使用するには、rsiレジスタを使用します。しかし、私がこれを試すたびに、私はセグメンテーション違反を取得します。
あなたが示されたコード、およびRDI
は、文字列の先頭のアドレスを保持していることを声明に基づき、私はあなたがその負荷にセグメンテーションフォールトを得ることがなぜ異なる理由のカップルを見ることができます。
RDI
には、文字列(参照渡し)を含むメモリ位置のアドレスではなく、8文字のASCII文字列(値渡し)が含まれている可能性があります。
もう1つの可能性は、ループの最初の数回の繰り返しがうまくいくということですが、ループを正しく終了していないため、文字列の最後を読み取るようになります。表示されたコードにはdtoi_end
というラベルはなく、実際にconvert_end
というラベルにジャンプする場所はありません。これらは同じラベルであるはずですか?文字列 "-2"を渡すとどうなりますか?ループはいつ終了するのですか?それがそうでないように私に見える!
文字列全体が処理されたことを示す方法が必要です。一般的な方法がいくつかあります。 1つは、文字列の終わりにセンチネルターミネーター文字を使用しています。これは、CがASCII NUL文字を使用するのと同じです。ループの内部では、処理中の文字が0(NUL)かどうかを確認し、そうであればループから飛び出します。もう1つのオプションは、Pascalがカウントされた長さの文字列のように、関数の追加パラメータとして文字列の長さを渡すことです。その後、十分な文字をまだ処理していないかどうかを調べるループ内のテストを行い、そうであればループから飛び出します。
私はこれについてあまり説得しないようにしようとしますが、デバッガを使用してこの問題を自分で検出できるはずです。行ごとにコードを実行し、変数/レジスタの値を見て、何が起きているのかを確認します。これは基本的に私があなたのコードを分析するときに行ったことですが、自分の頭をデバッガとして使い、私の心の中でコードを「実行」します。それは、コンピュータにそれをさせることはずっと簡単です(そしてエラーを起こしにくい)、それがデバッガが発明された理由です。動作していないコードがあり、それをデバッガで行単位で実行していない場合は、まだ問題を解決するために十分な努力をしていません。実際には、をシングルステップ実行すると、すべての機能がになります。これは、(A)あなたが書いたことの論理を理解できるようにすること、(B)バグ。
無効な組み合わせエラーです。私はこれがレジスタが異なるサイズであることを知っていますが、私は変換されたascii値をraxに追加し続ける方法については迷っています。
サイズを一致させる必要があります。 add al, dl
を実行できますが、結果を8ビットのBYTEに限定します。それはおそらくあなたが望むものではありません。したがって、rax
のように、dl
を64ビットQWORDにする必要があります。これを実行する明白な方法は、ゼロ拡張を行うMOVZX
命令を使用することです。言い換えると、値をより大きなサイズに「拡張」し、上位ビットを0で埋めます。これは、符号なしの値に対して必要なものです。符号付きの値の場合は、符号付き拡張を行う(つまり、符号ビットを考慮する)必要があります。これを行うには、MOVSX
命令を使用します。コードで
:それは、このよう
| 63 - 32 | 31 - 16 | 15 - 8 | 7 - 0 |
--------------------------------------
| DH | DL |
--------------------------------------
| EDX |
--------------------------------------
| RDX |
:コメント投稿の一つはDL
は単にRDX
レジスタの最下位8ビットであることを、指摘したように
movzx rdx, dl
add rax, rdx
は、注意してくださいxor dl, dl
とxor rdx, rdx
に冗長です。後者は前者を達成する。また、dl
を変更するたびに、rdx
の下位8ビットを実際に変更しているため、結果が正しくありません。ヒント、ヒント:これは、デバッガを使用してシングルステッピングすることで、あなたがキャッチしたことのあるものです(理由はわかりませんが)。
さらに、xor rdx, rdx
を行う必要はありません。 xor edx, edx
を実行して同じタスクmore efficientlyを実行することもできます。
; Parameters: RDI == address of start of character string
; RCX == number of characters in string
; Clobbers: RDX, RSI
; Returns: result is in RAX
xor esi, esi
convert:
; See if we've done enough characters by checking the length of the string
; against our current index.
cmp rsi, rcx
jge convert_end
; Get the next character from the string.
mov dl, BYTE [rdi + rsi]
cmp dl, "-"
je increment
cmp dl, "."
je convert_end
; Efficient way to multiply by 10.
; (Faster and less difficult to write than the MUL instruction.)
add rax, rax
lea rax, [4 * rax + rax]
sub dl, "0"
movzx rdx, dl
add rax, rdx
; (fall through to increment---no reason for redundant instructions!)
increment:
inc rsi ; increment index/counter
jmp convert ; keep looping
convert_end:
ret
(WARNING::ちょうど楽しみのため
が、ここでのコードの一つの可能な実装です!これのロジックがテストされていない私はせずに、より最適な方法で、既存のコードを書き直しましたバグ)
'DL'は' RDX'の一部です。あなたが 'DL'にすることは、あなたは' RDX'にやります。次に、 'mul rdx'はオペランドと' 'RAX'をとり、それらを乗算して結果を' RDX:RAX'に格納します。これは明らかにあなたが望むものではありません。あなたはレジスタの使用を再考する必要があります。 – rkhb
あなたがアクセスしてはならないメモリにアクセスすると 'mov dl、[rdi + rsi]'がクラッシュします。 rdiはどこに向いていますか?私は1つの目的のために2つのレジスタを使用するので、個人的にはrdiとrsiを追加しません。 rsiを "string"を指すように初期化し、代わりに 'mov dl、[rsi]' + 'inc rsi'でバイトをロードしてください – Tommylee2k