くっそ!アカン!どうも理解が甘い!以下は間違ってます!(お勉強&再整理開始・・・)
- 桁指定の考え方は、基本は全て指定しよ!ってことでいいのかな・・・
- たとえばレジスタ相手。これだって、「指定して間違い」ってわけじゃないはず。ええと・・・
MOV AX,0x11 ←まあ問題ないよね?相手がAXなんだからイヤでも16ビット MOV AX, WORD 0x11 ←無駄ではあるが、これは「間違い」だろうか??
・・・ふむ・・・実験の結果、少なくとも「間違いではない」ようだ・・・
こういうのはおかしくなるかな???
MOV WORD AX,WORD 0x11
あれれれ?? これも正常にコンパイルできたなぁ。これも、「別に間違いではない」って理解でいいのかな??
たとえばこうしたとするよね?
MOV [0x00ff],0x11
これが間違いなのは分る。正解は
MOV [0x00ff],WORD 0x11
これでコンパイルが通る。・・・しかし疑問だ。
- 最初の、アドレスを指定している部分。ここ、0x00ffって言うけど、これが0xffなのか、0x00ffなのか、0x000000ffなのか・・・って、おい!!!
あ〜! そっか!なるほどなるほど!。そうだよ!アドレス指定の場合は、[0xff]も[0x00ff]も[0x000000ff]も同じことじゃないか!!!
ん?じゃあもしかして・・・・
MOV WORD [0x00ff],WORD 0x11
これもいいの???
あっちゃぁ〜。いいんじゃん!(エラーないし、同じバイナリが出てくる)
うーん。しかしそうなると分らん。P37の、 MOV BYTE [678],123 。これはどう理解すれば・・・
あーーー!! まってまって??。勘違いしてたかも!?
値の桁数はわからないってのがおかしいのか。だって、0x11も0x0011も0x00000011も値としてはまったく同じことなんだよね???
メモリのほうに桁指定を入れるってのはようするに、「メモリ素子何個使う?」っていう理解でいいのかな????
・・・そうすると、たとえば
MOV BYTE [678],0x11223344
こんなことしたらどうなるの????
あー・・・エラーになる。じゃ、これは?
MOV BYTE [678],0x00000044
おーーーー!! エラー出ない!!!!!!
こんな実験もしてみた。
MOV AX,0x00000044 ←エラーなし MOV AX,0x11223344 ←エラー!!
おぉ!予測どおり!しかも、 MOV AX,0x11223344 と MOV BYTE [678],0x11223344 は、同じエラー(data range error.)が出る!! 分ってきたぞ!!!
じゃあこれはどうなる?
たとえば0x10番地に0x11、0x11番地に0x22を入れておいたとして・・・ MOV AX, [0x10] ← これは分る。AXには、0x2211が代入されるはず。 MOV AX, BYTE [0x10] ← こうやればAXには0x0011が入るのか? おーー! エラー!
さらにこんなの・・・
MOV AL,BYTE 0x11223344
うほ!エラーだよ!!!。しかもデータレンジのエラー!
・・・わかってきたぞ・・・。NASK(あるいはアセンブラ?)では、とにもかくにも、「切捨ては決してしない」ってことなんじゃないのか???
こういう法則かなぁ・・・
- アセンブラでは、全ての代入に桁指定をする
- 補完はするが、決して切り捨てをしない
相手がレジスタだろうがなんだろうが、とにかく全て桁を指定する!
当たり前だが、桁指定と指定された物が矛盾してはいけない。
MOV WORD AX,WORD 0x1122 MOV BYTE [0x0043],BYTE 0x11 MOV WORD [0x0044],WORD DX ※どれも問題ない。とにかく全て桁を指定する。
問題がある指定
指定と矛盾する MOV BYTE AX,BYTE 0x13 ← AXは16bitのレジスタ。BYTE指定はおかしい
切捨ては決してしてくれない MOV BYTE AL,BYTE 0x11223344 ←たとえBYTE指定しても、0x11223344は8bitデータじゃない。 (自動で0x11223344を0x44に切り捨てしたりしてくれない)
以下は問題がない(補完) MOV WORD AX, WORD 0x11 ←0x11と0x0011は同じこと。WORD指定で頭00を補完してくれる MOV WORD AX,WORD 0x00000011 ←一見切り捨てに見えるが、0x00000011と0x11はまったく同じこと。 なので、「元々0x11だった」と理解すれば、補完になる
以上の単純な法則で全てOK。これで少なくとも「間違いである!」ということは起きなくなる
実際の書き方(省略)
上記の簡単な法則が全て。後は、「省略しても特定できるかどうか」だけとなる。
省略しても特定できるのでエラーにならない例
MOV WORD AX,WORD 0x1122 ←本来の書き方 MOV AX,WORD 0x1122 ←AXは16bitレジスタと解りきっているので省略可 MOV AX,0x1122 ←但し注意。これは0x1122が16bitと特定できるのではない。 ・AXが16bitなんだから、当然値も16bitだろう ・うん、4桁だし、問題もないよね? と、こう理解しているに過ぎない。 MOV WORD DX,WORD 0x11 ←本来の書き方 MOV DX,WORD 0x11 ←DXは16bitに特定できる。0x11も0x0011と同じ なのでWORD指定しても矛盾しない(補完) MOV DX,0x11 ←上の例と同じで、0x11を見て判断しているのではない。 あくまでもDX(本来ならWORD DX)によって16bitに 特定され、0x11は16bit化しても矛盾しないので エラーにならないに過ぎない。 MOV BYTE [0x0041],BYTE 0x22 ←本来の書き方(エラーにならない) MOV BYTE [0x0041],0x22 ←・メモリに対しBYTE指定。当然値もBYTEだろう。 ・0x22はBYTE指定と矛盾しないな。OK! ・エラーにならない。 MOV [0x0041],BYTE 0x22 ←・メモリにバイト指定がないなぁ。何バイトだ? ・うん、値にはBYTE指定か。じゃあメモリをBYTEと 決め付けても問題ないだろう。 ・エラーにならない
- 下2例のメモリへのMOV。メモリ側と値側。とにかくどちらか一方でも指定があれば他方は特定できる。・・・じゃ、どっちを省略するのが正しい??
- 少なくともどちらを省略してもエラーにはならない。それどころかどちらを省略しても、また省略しなくても、出てくるバイナリはまったく同一である。
MOV BYTE [0x0041],BYTE 0x22 ←┐ MOV BYTE [0x0041], 0x22 ←┼── 全て同じこと。バイナリも同一 MOV [0x0041],BYTE 0x22 ←┘
特定ができない例:(エラーになる)
MOV [0x0041],0x11 ←・ん?何バイト?メモリにも値にも指定がないぞ? ・え?値が0x11だからBYTE指定だろうって? ・それは解らんぞ?もし0x0011なら0x0041番地と0x0042番地 にも書かなくちゃいけない。どっちだ? ・エラーになる(特定しきれない) MOV [0x0041],0x1122 ←・これならいいだろう?値は16bit。WORD指定だ! ・値が0x001122っていう可能性はないの?それ次第 では0x0043にも書かなくちゃいけない。どっち? ・エラーになる(特定しきれない) MOV [0x0041],0x11223344 ←・これならどうだ!お前DWORDまでだろう? 値が32bitなんだから、値から32bit(DWORD指定)と 特定できるはずだ! ・この値がさ、0x000000000011223344じゃないって 保障ある?。ないよね?。やっぱり特定できない。 ・エラーになる(特定しきれない)
- 省略していいのか悪いのか、ごっちゃになってわからなくなっちゃった!
- そういう場合はなまじっか考えず、全部指定しちゃうのがいい。そうすれば少なくともエラーにはならないし、正解の省略と出てくるバイナリは変わらない。それでもエラーになるっていうなら、矛盾・切捨て違反のどちらかだと、間違いの特定もできるし。
実際の挙動(メモリへの代入)
- 8ビット指定
MOV BYTE [0x0042],0x11 : ├────┤ : ├────┤ 0x40番地 │ 0x32 │ 0x40番地 │ 0x32 │ ├────┤ ├────┤ 0x41番地 │ 0xA1 │ 0x41番地 │ 0xA1 │ ├────┤ ├────┤ 0x42番地 │ 0x4F │ ⇒ 0x42番地 │ 0x11 │ ←ここだけ変化 ├────┤ ├────┤ 0x43番地 │ 0x96 │ 0x43番地 │ 0x96 │ ├────┤ ├────┤ 0x44番地 │ 0xEF │ 0x44番地 │ 0xEF │ ├────┤ ├────┤ 0x45番地 │ 0x89 │ 0x45番地 │ 0x89 │ ├────┤ ├────┤ 0x46番地 │ 0xFF │ 0x46番地 │ 0xFF │ : ├────┤ : ├────┤
- 16ビット指定
MOV WORD [0x0042],0x11 : ├────┤ : ├────┤ 0x40番地 │ 0x32 │ 0x40番地 │ 0x32 │ ├────┤ ├────┤ 0x41番地 │ 0xA1 │ 0x41番地 │ 0xA1 │ ├────┤ ├────┤ 0x42番地 │ 0x4F │ ⇒ 0x42番地 │ 0x11 │ ←値は16ビットの0x0011と ├────┤ ├────┤ 解釈される。値が16ビット 0x43番地 │ 0x96 │ ⇒ 0x43番地 │ 0x00 │ ←なのだから0x43も変化する ├────┤ ├────┤ (リトルエンディアンで値が 0x44番地 │ 0xEF │ 0x44番地 │ 0xEF │ 逆さまになるのに注意) ├────┤ ├────┤ 0x45番地 │ 0x89 │ 0x45番地 │ 0x89 │ ├────┤ ├────┤ 0x46番地 │ 0xFF │ 0x46番地 │ 0xFF │ : ├────┤ : ├────┤
- 32ビット指定
MOV DWORD [0x0042],0x11 : ├────┤ : ├────┤ 0x40番地 │ 0x32 │ 0x40番地 │ 0x32 │ ├────┤ ├────┤ 0x41番地 │ 0xA1 │ 0x41番地 │ 0xA1 │ ├────┤ ├────┤ 0x42番地 │ 0x4F │ ⇒ 0x42番地 │ 0x11 │ ←値は32ビットの0x00000011と ├────┤ ├────┤ 解釈される。値が32ビット 0x43番地 │ 0x96 │ ⇒ 0x43番地 │ 0x00 │ ←なのだから0x43、0x44、0x45 ├────┤ ├────┤ まで変化する 0x44番地 │ 0xEF │ ⇒ 0x44番地 │ 0x00 │ ←(リトルエンディアンで値が ├────┤ ├────┤ 逆さまになるのに注意) 0x45番地 │ 0x89 │ ⇒ 0x45番地 │ 0x00 │ ← ├────┤ ├────┤ 0x46番地 │ 0xFF │ 0x46番地 │ 0xFF │ : ├────┤ : ├────┤