2016-12-19 19 views
0

私はアセンブリで特定のタスクを達成する方法を自分自身で教えようとしています。トラブル理解レジスタx86

今、私は回文を検出しようとしています。私は、スタックを使用するか、おそらくアーバインのライブラリを使用して文字列を比較することができます知っているが、私はレジスタを介してそれをやろうとしている。

問題は、レジスタを使用する場合、私はちょっと混乱しています。

以下のコンパイルが、私はCMPラインを取得、プログラムブレークと私にこのメッセージを与える:Project.exeで0x004033FCで

未処理の例外:0xc0000005で:アクセス 違反読み取り場所0x0000000Fを。

私はレジスタをどのように設定するかとは関係がありますが、デバッグ中はレジスタを使用していてもそれほど助けにはならないと思います。

ご協力いただければ幸いです。

INCLUDE Irvine32.inc 

.data 

enteredWord BYTE "Please enter the string to check: ", 0 
presetWord BYTE "Step on no pets", 0 

isAPalindrome BYTE "The word is a palindrome. ", 0 
isNotAPalindrome BYTE "The word is not a palindrome. ", 0 

.code 
main proc 
mov ecx, SIZEOF presetWord - 1 
mov esi,OFFSET presetWord 

checkWord: 
MOV eax,[esi] 
CMP [ecx],eax 
JNE NOTPALIN 

inc esi 
dec ecx 
loop checkWord 
mov edx, offset isAPalindrome 
call WriteString 
jmp _exit 
main endp 

NOTPALIN PROC 
mov edx, offset isNotAPalindrome 
call WriteString 
ret 
NOTPALIN endp 


_exit: 
exit 


end main 
+4

'ecx'をポインタとして使用しましたが、代わりに長さを指定してロードしました。また、1バイトではなく4バイトずつ操作します。 'mov al、[esi];を使用します。 cmp [presetWord + ecx]、代わりにalです。 – Jester

+0

'ECX'を*文字数*に設定すると、それをメモリへのポインタとして使用します。それは妥当な何かを指摘しませんので、もちろんクラッシュします。長さだけでなく、長さをオフセットするために 'ECX'を設定する必要があります。 –

+0

@Jesterそれで、私はまだ 'mov ecx、OFFSET presetWord + SIZEOF presetWord - 1'をしなければならないでしょうか? –

答えて

0

CPUレジスタは、CPUコアの内部に直接配置されたコンピュータメモリです。コンピュータメモリの一部はあるビット量(0/1)を意味します.64b x86 CPUの場合、汎用レジスタは名前がrax, rcx, rdx, rbx, ..の64ビット "ワイド"です。

rcxの下位32bの部分です(上位32bの部分は特別な名前でアクセスできません。rcxを使用した場合のみ)。そして、下部16b部分はcxによってアクセス可能であり、これは2つの8b部分ch(上)とcl(下)から構成されています。

もしecxを使用しているように、あなたは0から2 -1(ヘキサ0 .. 0xFFFFFFFFで)、又は符号付き数としてより-2符号なし数値として解釈することができ、0または1のいずれかに32ビットを設定することができ~ + 2 -1(0x80000000 .. 0x7FFFFFFF)。あるいは、あなたが望む方法でそれらのビットの意味を解釈し、コードを書くことができます。

あなたのコードでは、いくつかのCPUレジスタのビット値をどのように解釈するかという3つの一般的な方法を利用できます。あなたの例では

; EBX as memory address: 
mov ebx,OFFSET presetWord ; some address into memory (32b unsigned number) 
; ECX as numeric value ("unsigned long" in C++) 
mov ecx,SIZEOF presetWord - 1 ; 15 
; AL as ASCII character (extended 8 bit) 
mov al,[ebx]  ; also shows how memory is referenced by address 
; AL == 83 == 'S' => value of memory at address "presetWord" 

それがクラッシュしないよう、あなたのための幸い違法であるアドレス15、でメモリを参照するためにcmp [ecx],eax手段をやって。あなたのプロセスにいくつかの法的アドレスを偶然使用したいのであれば(実際に使用したいアドレスではない)、それは黙って進んで予期せぬ結果を続けるでしょう。

presetWord+15(文字列の最後の文字)のメモリを参照することを意味するcmp [esi+ecx],eaxをしたかったかもしれませんが、それは最初の繰り返しにのみ当てはまります。次にinc esiを実行し、presetWord+1アドレス(2番目の文字)を指します。

eaxalに変更すると、文字列がASCIIエンコード(8ビット/文字)でエンコードされるため、一度に1バイトだけをフェッチ/比較する必要があります。 eaxはUTF-32エンコーディングで動作します。


あなたが最初の文字のアドレスで1つのレジスタ(「R1」)をロードすることが回文をチェックし、1つのレジスタのアドレスの(「R2」)(!)最後の文字の、そしてこのループを行うには:

  • (R2 < = R1)場合 - >真(比較して、すべての重要な文字)と出口が
  • がここにアドレスR1 < R2(符号なしの数値としてアドレスを確認してください) - >今の文字を比較
  • 場合(バイト[r1]!=バイト[r2])終了偽
  • ++ R1、--r2 - >

始めに2つ目の最後の文字

  • ループにおける第二/ポイントするアドレスを調整これは'S' != 's'として、presetWordのために「偽」を生成しますので、あなたが望むことif (byte [r1]...部分に大文字と小文字を区別しないようにしていますが、最初はそれがなくても動作します。


    デバッグ中に、レジスタ内のいくつかの数の「クラス」を認識できる必要があります。サイズをレジスタにロードすると、0000000F(15)のように小さい数字になる可能性が非常に高くなります。住所は8040506Eのような大きな数字の可能性が非常に高いでしょう。 ASCII文字の場合、通常は20 - 7Fのようになりますが、mov al,...を実行すると、デバッガにはeaxの全体が表示されるため、上位3バイトは以前の値のままです。 eax12345678に設定すると、eaxの値が12345620(ASCIIではスペース' ' == 0x20)に変更されます。

    メモリビューを使用して、メモリ内の特定のアドレスの内容をチェックすることもできます。たとえば、cmpcmp [esi+ecx],eaxに変更し、そのアドレスをメモリビューで確認すると、2番目の最後の文字ではなく、最後の文字で2番目の繰り返しを再度指すことがわかります。

    デバッガをチェックインすることができます。時にはちょっと面倒なことがあります。また、SOを尋ねたり、ソースコードについて考えているよりも簡単です。


    最後に、なぜ登録しますか?コンピュータのメモリは別のチップなので。そして無邪気に見えるかもしれませんが、mov al,[presetWord]のような命令は実際に何百ものCPUサイクルをストールしますが、CPUチップはメモリチップがメモリの内容を読み込み、バスワイヤを介してCPUチップに送るのを待ちます。 alecxはCPUの内部に直接アクセスしますが、CPUが必要なときに同じサイクルでアクセスできます。

    計算で頻繁に使用する場合は値をレジスタに格納し、メモリを使用して速度を落とさないようにすることもできます(メモリの内容がL0/1/2/3キャッシュでキャッシュされると、 CPUチップ上に直接キャッシュレベルを持つ0サイクルでさえも)になります。しかし、予測可能なパターンでメモリにアクセスしたいので(キャッシュは先読みできます)、合理的な量でキャッシュします(キャッシュは、通常、レベルによって16〜32Bのサイズで最大4〜8kまで動作します)。 16個の異なる8Kメモリページのような命令でアクセスすると、使用可能なキャッシュラインが使い果たされ、フルメモリストールを伴う少なくとも1つのアクセスが発生し、実際のメモリ読み出しを待つことになります。

  • +0

    補足として、アセンブリでは、変数の「型」などはありません。あなたのコードで、これらのビットに意味/構造を与えます。だからあなたは、あなたが作業しているデータのサイズを常に意識しなければなりません。例えば、ASCII charは8ビットです。したがって、コードを1バイトだけ読み込み、ポインタを+ -1で調整します。あなたのデータが16b以上で動作するならば、単語を読み込み、ポインタを+ -2で調整するか、 'mov ax、[esi + ecx * 2]'のようにアドレス指定に* 2を使いたいでしょう。したがって、8/16/32ビットが何を意味しているのか、バイト/ワード/ワードが何であるのかを理解し、C++で一般的な型がどのようにエンコードされているかを確認してください(インスピレーションとして)。 – Ped7g

    +0

    私が前のコメントに書いたように、私は文字列 "banab"をテストしていますが、まだ失敗します。また、私のコードは更新されて以来のものです:http://imgur.com/a/pUJYa –

    +0

    また、サイズに関しては、私は 'mov ax、[esi + ecx * TYPEプリセットワード] '? –

    関連する問題