2017-04-20 5 views
0

これは簡単な問題ですが、頭が回転しています。私は文字列(負の10進数として入力)を符号なし整数に変換する必要があります。 rdiレジスタは、変換される文字列を保持します。 raxレジスタは結果を保持します。x86 NASMは文字列を整数に変換します

xor rsi, rsi 
    xor rax, rax 
    xor dl, dl 
    xor rdx, rdx 
convert: 
    mov dl, [rdi+rsi] ;+rsi causes segmentation fault 

    cmp dl, "-" 
    jz increment 

    cmp dl, "." 
    jz dtoi_end 

    sub dl, "0" 

    mov rdx, 10 
    mul rdx 

    add rax, dl   ;invalid combination 

    inc rsi 
    jmp convert 

increment: 
    inc rsi 
    jmp convert 

convert_end: 
    ret 
  1. 私は、各文字を反復する必要がある、と私はRSIレジスタを使用してこれを使用しようとしています。しかし、私がこれを試すたびに、私はセグメンテーション違反を取得します。

  2. 無効な組み合わせエラーです。私はこれがレジスタが異なるサイズであることを知っていますが、私は変換されたascii値をraxに追加し続ける方法については迷っています。

私はより良いプロセスを理解する助けたが、私は壁を直撃している、ここで同様の質問があります: Convert string to int. x86 32 bit Assembler using Nasm

+0

'DL'は' RDX'の一部です。あなたが 'DL'にすることは、あなたは' RDX'にやります。次に、 'mul rdx'はオペランドと' 'RAX'をとり、それらを乗算して結果を' RDX:RAX'に格納します。これは明らかにあなたが望むものではありません。あなたはレジスタの使用を再考する必要があります。 – rkhb

+0

あなたがアクセスしてはならないメモリにアクセスすると 'mov dl、[rdi + rsi]'がクラッシュします。 rdiはどこに向いていますか?私は1つの目的のために2つのレジスタを使用するので、個人的にはrdiとrsiを追加しません。 rsiを "string"を指すように初期化し、代わりに 'mov dl、[rsi]' + 'inc rsi'でバイトをロードしてください – Tommylee2k

答えて

1

が、私は、各文字を反復処理する必要がある、と私はしようとしていますこれを使用するには、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, dlxor 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::ちょうど楽しみのため


が、ここでのコードの一つの可能​​な実装です!これのロジックがテストされていない私はせずに、より最適な方法で、既存のコードを書き直しましたバグ)

関連する問題