プロが教えるわが家の防犯対策術!

はじめまして。

私は趣味でCPUや機械語の勉強をしているのですが、
非常に初歩的な部分でどうしても分からないことがあったので質問させて下さい。

WindowsのVisual C++ 64ビットコンパイラで

MessageBox(NULL, "message", "caption", MB_OK);

をコンパイルすると、以下のコードが出力されます。

 0000000140001004: 45 33 C9      xor  r9d,r9d
 0000000140001007: 4C 8D 05 F2 9F 00 lea  r8,[4000B000h]
            00
 000000014000100E: 48 8D 15 F3 9F 00 lea  rdx,[4000B008h]
            00
 0000000140001015: 33 C9       xor  ecx,ecx
 0000000140001017: FF 15 F3 71 00 00 call  qword ptr [40008210h]
 000000014000101D: 33 C0       xor  eax,eax

このうち、最後から3行目のxor(NULLに該当するところ)がecxになっている理由が分かりません。rcxではないのでしょうか?
戻り値もeaxなのが気になります。

他のパラメータも見ると、64bitのレジスタを使っているのはmessageとcaptionへのポインタのみで、それもleaに渡すRVAは32bitです。
エントリーポイントも140000000のはずなのに、leaの[4000B008h]では33bit目の1が抜けています。

64bitとは具体的にどこがどう64bitなのでしょうか?

それとも64bitOSになってもWin32APIはWin32APIのままなのでしょうか?
64bitOSで4GBを超えるメモリを使いたいときはどういう技術を使えばよいのでしょうか?Win32APIにそのポインタを渡したい時は?
実行ファイルのサイズは2GBまでということですが、全てのセクションが持てる仮想アドレス領域の合計も4GB以内に制限されているのでしょうか?

いろいろ調べ、考えてみましたが、納得の行く理解ができません。
浅学ですが、詳しい方がいましたら教えていただければ助かります。
よろしくお願い致します。

A 回答 (5件)

lea や call のアドレス指定において 33ビット目の 1 が落ちているのは, おそらく


冗長な情報だから
だと思います.

命令フォーマットの都合上, ここの 4000B000h は 14000B000h しかありえません.

この回答への補足

確かにcaptionが7文字なのでNULLのことを考えると先ほど説明を頂きました8バイトと一致しましたので、

MessageBox (NULL, "Message", "Caption Title", MB_OK);

としてコンパイルすると、本当に以下のように変わりました。

 0000000140001007: 4C 8D 05 F2 9F 00 lea  r8,[4000B000h]
            00
 000000014000100E: 48 8D 15 FB 9F 00 lea  rdx,[4000B010h]
            00

冗長な情報というのは、leaニモニックにおいて、33~64ビット目が一致している領域間でのやり取りには
32ビットオペランドを指定することで、これを省略することができるということでしょうか?

先ほどNo.2の補足に書いたNULLはxorですが、これについてはどうなるのでしょうか?


追伸:エントリーポイントは140001000でしたm(__)m 140000000はイメージベースでした

補足日時:2013/11/01 16:06
    • good
    • 0

>調べてみたところ、HWNDは構造体へのポインタらしいのですが


>その構造体の実体をOSが管理しているのならば、メモリのどこかにまとめられているから大丈夫なのかもしれませんね。

64ビットの動作環境に対応したコンパイラなら、ポインタに

near *

far *

など「アドレスが何ビットのポインタなのか?」を修飾する、オプションの修飾子がある筈です。

たぶん、HWNDは「32ビットアドレスのポインタ」として定義されていると思われます。

もちろん、通常のポインタ(オプションの修飾子が無いポインタ)は、64ビットのポインタになると思います。
    • good
    • 0
この回答へのお礼

ご指摘ありがとうございます!勉強不足でした。

行き違いで回答を締めきってしまいましたが、あとは専門書探して勉強してみようと思います。
ありがとうございまいsた。

お礼日時:2013/11/01 17:53

>1つ疑問がありますが、r9dはr9の下位32bitのことですね?NULLで下位32bitのみをゼロにしても大丈夫でしょうか?



NULLに指定しているパラメータはHWND型だから、多分「OS管理のウィンドゥハンドルは下位32ビットのみ有効で、上位32ビットは無視される」っていう仕様になっているんじゃないかな?

詳しく調べてないから判らないけど、ウィンドゥハンドルの実体って、常にOSが管理するメモリの上に居るから、そこを指すポインタって、常に上位32ビットが固定になると思います。上位32ビットが固定なら「上位32ビットは要らない」ですよね?
    • good
    • 0
この回答へのお礼

調べてみたところ、HWNDは構造体へのポインタらしいのですが
その構造体の実体をOSが管理しているのならば、メモリのどこかにまとめられているから大丈夫なのかもしれませんね。


先ほどのLEA33ビット目以降についてIntel資料のLEA項目に以下の記述がありました。

(Operand Size 32、Address Size 64の場合)
>64-bit effective address is calculated (default address size) and the lower 32 bits of the
>address are stored in the requested 32-bit register destination.

今回の結果も考慮すると、64bitの実効アドレスが計算された後、下位32bitが埋められるかもしれません。


解決しました!皆様ありがとうございます。
これからさらに勉強していきます。

お礼日時:2013/11/01 17:00

>このうち、最後から3行目のxor(NULLに該当するところ)がecxになっている理由が分かりません。

rcxではないのでしょうか?

NULLは、一番最初の

xor  r9d,r9d

だよ。

xor  ecx,ecx

は「MB_OK」だよ。

MB_OKの引数は「UINT」だから、32ビットで0クリアすれば問題無し。

>エントリーポイントも140000000のはずなのに、leaの[4000B008h]では33bit目の1が抜けています。

命令のオペランドを良く見て下さい。

lea  r8,4000B000h

ではなくて

lea  r8,[4000B000h]

だよね?

lea  r8,[4000B000h]

は「4000B000番地に格納されている64bitアドレスのアドレスをr8に入れろ」です。

この時に参照される4000B000番地は、セグメントレジスタにより64bit拡張されます。

4000B000~4000B007の8バイトに、64ビットのアドレスが入っているから、その次の命令は

lea  rdx,[4000B008h]

のように「8バイト先」になってます。

>戻り値もeaxなのが気になります。

MessageBoxの戻り値は「int」です。

「64ビット環境でも、intの大きさが32ビットなら、戻り値も32ビット」ですよ。

戻り値が32ビットなら、eaxで問題ありません。

sizeof(int)ってやったら、4になりますよね?8ではなく。

だから、NULLはちゃんと64ビットでNULLになってるし、他の文字列も64ビットで渡されてる。何も問題無し。

この回答への補足

分かりやすい説明、ありがとうございます!

引数の順番について、STDCALLに慣れすぎてまた混合してしまいました。すみません。

1つ疑問がありますが、r9dはr9の下位32bitのことですね?NULLで下位32bitのみをゼロにしても大丈夫でしょうか?

補足日時:2013/11/01 15:36
    • good
    • 0

これって



http://msdn.microsoft.com/ja-jp/library/ms173505 …

をしたと言う事ですか? それともデータ形で64bit の指定という話ですか? 

http://msdn.microsoft.com/ja-jp/library/7kcdt6fy …

にその説明があるようですが・・

この回答への補足

混乱してしまったようで申し訳ないです。

下のURIの「イメージ形式」によると

>実行可能イメージの形式は、PE32+ です。
>実行可能イメージ (DLL、EXE の両方) は、最大 2 GB までに制限されるため、静的イメージ データをアドレス指定するには 32 ビットの変位による相対アドレス指定を使用できます。
>このデータには、インポート アドレス テーブル、文字列定数、静的なグローバル データなどが含まれます。

とのことですが、

・最大 2 GBというのは実行可能イメージのファイルとしての物理的なサイズで、確保できる物理メモリのサイズとは関係ない
→当然仮想メモリは物理メモリ以上の量を予約できる
→仮想メモリはファイルサイズに関係なく 2 GBや 4 GBを超える量を自由に予約できるのでは?
→ということはRVAが 32 bitを超えることも有り得るのでは?
→そのことを考慮すると、RCXではなくECXを渡すのは問題あるのでは?leaについても同様

と考えましたら分からなくなったのです。この考えのどこかに間違いがあるのでは。
もし 2 GBがヒープ領域を除く仮想メモリの最大サイズだとしても、mallocなどで返される64ビットポインタを関数に渡すときに問題が起こるのでは?と。


コマンドラインには、以下を入力しました。cl.exe、dumpbin.exeは、amd64フォルダのものを使用しました。
user32.libはWindows Kits内のものです。
cl test64.c /link /defaultlib:user32.lib
dumpbin test64.exe /disasm

補足日時:2013/11/01 15:14
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!