x64プログラムでアドレスが32bitになる理由

このQ&Aのポイント
  • x64プログラムにおいて、アドレスが32bitになる理由について説明します。
  • 64bitOSで4GBを超えるメモリを使いたい場合やWin32APIにポインタを渡したい場合の技術についても考えています。
  • しかし、具体的な理解ができないため、詳しい方に教えていただきたいと思っています。
回答を見る
  • ベストアンサー

x64プログラムでアドレスが32bitになる理由

はじめまして。 私は趣味で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以内に制限されているのでしょうか? いろいろ調べ、考えてみましたが、納得の行く理解ができません。 浅学ですが、詳しい方がいましたら教えていただければ助かります。 よろしくお願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

lea や call のアドレス指定において 33ビット目の 1 が落ちているのは, おそらく 冗長な情報だから だと思います. 命令フォーマットの都合上, ここの 4000B000h は 14000B000h しかありえません.

takaki6211
質問者

補足

確かに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はイメージベースでした

その他の回答 (4)

  • chie65535
  • ベストアンサー率43% (8526/19383)
回答No.5

>調べてみたところ、HWNDは構造体へのポインタらしいのですが >その構造体の実体をOSが管理しているのならば、メモリのどこかにまとめられているから大丈夫なのかもしれませんね。 64ビットの動作環境に対応したコンパイラなら、ポインタに near * far * など「アドレスが何ビットのポインタなのか?」を修飾する、オプションの修飾子がある筈です。 たぶん、HWNDは「32ビットアドレスのポインタ」として定義されていると思われます。 もちろん、通常のポインタ(オプションの修飾子が無いポインタ)は、64ビットのポインタになると思います。

takaki6211
質問者

お礼

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

  • chie65535
  • ベストアンサー率43% (8526/19383)
回答No.4

>1つ疑問がありますが、r9dはr9の下位32bitのことですね?NULLで下位32bitのみをゼロにしても大丈夫でしょうか? NULLに指定しているパラメータはHWND型だから、多分「OS管理のウィンドゥハンドルは下位32ビットのみ有効で、上位32ビットは無視される」っていう仕様になっているんじゃないかな? 詳しく調べてないから判らないけど、ウィンドゥハンドルの実体って、常にOSが管理するメモリの上に居るから、そこを指すポインタって、常に上位32ビットが固定になると思います。上位32ビットが固定なら「上位32ビットは要らない」ですよね?

takaki6211
質問者

お礼

調べてみたところ、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が埋められるかもしれません。 解決しました!皆様ありがとうございます。 これからさらに勉強していきます。

  • chie65535
  • ベストアンサー率43% (8526/19383)
回答No.2

>このうち、最後から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ビットで渡されてる。何も問題無し。

takaki6211
質問者

補足

分かりやすい説明、ありがとうございます! 引数の順番について、STDCALLに慣れすぎてまた混合してしまいました。すみません。 1つ疑問がありますが、r9dはr9の下位32bitのことですね?NULLで下位32bitのみをゼロにしても大丈夫でしょうか?

回答No.1

これって http://msdn.microsoft.com/ja-jp/library/ms173505(v=vs.90).aspx をしたと言う事ですか? それともデータ形で64bit の指定という話ですか?  http://msdn.microsoft.com/ja-jp/library/7kcdt6fy(v=vs.90).aspx にその説明があるようですが・・

takaki6211
質問者

補足

混乱してしまったようで申し訳ないです。 下の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

関連するQ&A

  • これらの文を意味のわかる分にしてください

    アドレス          ダンプ    逆アセコード 00551A90 31C9 XOR ECX,ECX 00551A92 51 PUSH ECX 00551A93 E8 68575000 CALL 00A57200 00551A98 59 POP ECX 00551A99 41 INC ECX 00551A9A 83F9 02 CMP ECX,2 00551A9D 75 F3 JNZ SHORT 00551A92 00551A9F 31C0 XOR EAX,EAX 00551AA1 C2 0400 RETN 4 00551AA4 90 NOP 00551AA5 ゞ 00551AA6 ゞ 00551AA7 ゞ 00551AA8 ゞ 00551AA9 90 NOP 00551AAA 8B4424 04 MOV EAX,[ESP+4] 00551AAE 8B48 04 MOV ECX,[EAX+4] 00551AB1 8B10 MOV EDX,[EAX] 00551AB3 8B40 08 MOV EAX,[EAX+8] 00551AB6 51 PUSH ECX 00551AB7 52 PUSH EDX 00551AB8 50 PUSH EAX 00551AB9 E8 12BB2B00 CALL 0080D5D0 00551ABE 83C4 0C ADD ESP,C 00551AC1 33C0 XOR EAX,EAX 00551AC3 C2 0400 RETN 4

  • 配列変数のポインターが勝手に変わる

    下記の2個のファイルを持つプログラムでインラインアセンブラのcall命令で配列変数のポインター(アドレス)が勝手に変わる現象をおしえてください。 但し、配列の最初のポインターのみが変わる。 開発環境はWin7(64bit)、VC++2010無償版です。 main.cpp int *disp; int data[3]; WinMain() { _asm mov disp,offset disp_top ・ ・ ・ メッセージループへ _asm{ disp_top://下記move()からcallされた時 lea eax,data//下記のmove()関数のeaxの値より16番地少ない lea ebx,data+4//下記のmove()関数のebxの値と同じ lea ecx,data+8//下記のmove()関数のecxの値と同じ ・ ・ ・ ret   } } move.cpp extern int *disp; extern int data[3]; void move() { _asm{ lea eax,data lea ebx,data+4 lea ecx,data+8 call disp   } }

  • VC2008のアセンブラ出力

    Visual C++ 2008 Express Editionで勉強をしています。 Cで簡単なプログラムを作り、そのアセンブラ出力を見ているのですが、下のアセンブラリストの###部のようなCの記述と関係ないコードが追加されます。この行を削除してアセンブルしても動作に問題ないように見えます。 このコードが追加される意味を教えて下さい。名前からセキュリティに関係しそうですが…… またプログラムによって追加される場合と、されない場合があります。何故でしょう? ご教示いただければ幸いです。 ----scanf.c #include <stdio.h> #include <stdlib.h> int main(void) { int i; char buf[256]; scanf("%s",buf); i = atoi(buf); printf("%d\n",i); return 0; } ----- -----scanf.asm ; Listing generated by Microsoft (R) Optimizing Compiler Version 15.00.30729.01 TITLE D:\vc_asm\scanf.c .686P .XMM include listing.inc .model flat INCLUDELIB LIBCMT INCLUDELIB OLDNAMES _DATA SEGMENT $SG3702 DB '%s', 00H ORG $+1 $SG3703 DB '%d', 0aH, 00H _DATA ENDS PUBLIC __$ArrayPad$ PUBLIC _main EXTRN _printf:PROC EXTRN _atoi:PROC EXTRN _scanf:PROC EXTRN ___security_cookie:DWORD EXTRN @__security_check_cookie@4:PROC ; Function compile flags: /Odtp _TEXT SEGMENT _buf$ = -264 ; size = 256 __$ArrayPad$ = -8 ; size = 4 _i$ = -4 ; size = 4 _main PROC ; Line 5 push ebp mov ebp, esp sub esp, 264; 00000108H mov eax, DWORD PTR ___security_cookie ###この行 xor eax, ebp ###この行 mov DWORD PTR __$ArrayPad$[ebp], eax ###この行 ; Line 8 lea eax, DWORD PTR _buf$[ebp]  (中略  Cで記述した内容の動作が記載) ; Line 11 xor eax, eax ; Line 12 mov ecx, DWORD PTR __$ArrayPad$[ebp] ###この行 xor ecx, ebp ###この行 call @__security_check_cookie@4 ###この行 mov esp, ebp pop ebp ret 0 _main ENDP _TEXT ENDS END -----

  • 機械語に直すことについて。

    (機械語データ) (アセンブリ言語) b8 57 61 6b 61 mov $0x616b6157,%eax 53 push %ebx 50 push %eax ba 04 00 00 00 mov $0x4,%edx bb 01 00 00 00 mov $0x1,%ebx b8 04 00 00 00 mov $0x4,%eax 89 e1 mov %esp,%ecx cd 80 int $0x80 58 pop %eax 31 c0 xor %eax,%eax 5b pop %ebx c3 ret これのintと movとxor の機械語が分かりません。後、retの機械語が、farなのかnearなのかも分かりません。教えていただけないでしょうか?すみません。

  • ページ違反

    IEXPLORE のページ違反です。 モジュール : KERNEL32.DLL、アドレス : 015f:bff9d9f9 Registers: EAX=c003010c CS=015f EIP=bff9d9f9 EFLGS=00010212 EBX=0064ecdc SS=0167 ESP=0054ff2c EBP=005501c8 ECX=00000000 DS=0167 ESI=00550318 FS=42c7 EDX=bff768d5 ES=0167 EDI=0064ecc8 GS=0000 Bytes at CS:EIP: 53 8b 15 dc 9d fc bf 56 89 4d e4 57 89 4d dc 89 Stack dump: 上記の表示が頻繁に出て通常のネットサーフィンすらできません。 WIN98  IE6.0  cpu226MHZ 64MB 4GBで空き1.2GBです。 どうかご助言を下さい。

  • アセンブリ言語について。

    これが何をしているのか教えていただけないでしょうか?すみません。 これの事です。 (機械語データ) (アセンブリ言語) b8 57 61 6b 61 mov $0x616b6157,%eax 53 push %ebx 50 push %eax ba 04 00 00 00 mov $0x4,%edx bb 01 00 00 00 mov $0x1,%ebx b8 04 00 00 00 mov $0x4,%eax 89 e1 mov %esp,%ecx cd 80 int $0x80 58 pop %eax 31 c0 xor %eax,%eax 5b pop %ebx c3 ret

  • 16バイトアライメントで配置された要素へのポインタ

    非常にトリッキーな質問です。標準のC言語で記述可能かもわかりません。もし可能なら教えてください。 16バイトアライメント配置された要素の先頭アドレスは下位4ビットが0となっています。 そこで、1MBの範囲にある要素へのポインタは本来20ビット必要ですが、下位4ビットが常に0なので、上位16ビットを記憶するだけで十分のはずです。アセンブラで記載すれば可能ですが、Cで、「使うときは、4ビット右シフト」「記憶するときは、上位16ビット」となるようなコードを出力するような記載がわかりません。具体的には、以下のようなアセンブラ結果が希望です。 struct ABC {  struct ABC *next;  int x,y,z;   : } *p,*q; のとき、 q = p->next; は mov ecx,dword ptr p mov eax,word ptr [ecx] slr eax,4 // 使うときは4ビット右シフト mov q, eax q->next = p; は mov ecx,dword ptr q mov eax,p slr eax,4 // 構造体ABCに保存する場合には4ビット左シフト mov word ptr [ecx],eax となってほしいです。

  • メモリデータ比較中にハング

    メモリデータ比較中にハング A領域のデータとB領域のデータを先頭から比較するプログラムをアセンブラで組んでおります。 しかしかなりの頻度でプログラムがハングし、困っております。 ソースを眺めていても、どこが悪いのかわかりません。ハングの原因をうまく調べる方法はあるでしょうか? 動作環境:MS-DOS アセンブラ:MASM32 MOV ECX, srcAddr;Aのメモリアドレス PUSH ECX POP ESI MOV ECX, dstAddr;Bのメモリアドレス PUSH ECX POP EDI MOV ECX, CmpByte;比較するバイト数(比較するのは100000Hexバイト) XOR EAX, EAX CALL ENTER_PROTECT;プロテクトモードに移行 CALL GET_SORC_SEL;SORC_SELのBASE AddressとLimitを変更 CALL GET_DEST_SEL;DEST_SELのBASE AddressとLimitを変更 ; DWORD単位で比較するので2で割る SHR ECX, 2 @@compare: CLD ;CMPS*でのESI,EDIの変化を増加方向に @@cmp4: CMPSD DS:[ESI], ES:[EDI] ;4Byteずつ比較 jne @@err4 dec ECX jnz @@cmp4 ; 4で割った余り分のチェック MOV ECX, CmpByte AND ECX, 3 or ecx, ecx jz @@exit jmp @@cmp1 @@err4: ; 1Byteずつチェックしてコンペアエラーしたオフセットを割り出す LEA ESI,[ESI-4] ; コンペアエラー前のオフセットに戻す LEA EDI,[EDI-4] shl ecx, 2 @@cmp1: ;1Byteずつ比較 CMPSB DS:[ESI], ES:[EDI] jne @@exit dec ECX jnz @@cmp1 @@exit: ; コンペアしたByte数を計算(EAX <- CmpByte - ECX) MOV EAX, CmpByte SUB EAX, ECX PUSH EAX CALL FREE_SORC_SEL CALL FREE_DEST_SEL CALL LEAVE_PROTECT POP AX POP BX MOV DX, BX RET _MemCmp2 ENDP

  • 32bit処理はメモリ使用量に制限ある?

    Win7の64bitを使用しています 32bit処理のゲームをするときにかくかくする事があるんです その時にタスクマネージャーを見ると ゲームのプロセスがメモリを2GBぐらい使用していることが多くあります ですが、PCに搭載するメモリは8GBなのでまだ余裕があるはずなんです 裏で大したプログラムは動かしていないので でそこで思ったのですが、32bit処理されていると 32bitOS同様に2GBまでしかメモリを割り当てできないなんて事はありますか? もしそのような事があるなら32bitOSの3GBスイッチのような対策手段はありますか?

  • 毎回「このプログラムは不正な処理~強制終了」

    パソコンを起動する度にデスクトップに上記の警告が出て困っています。OSはWin98です。原因・解決方法はありますか?詳細は以下の通りです。 ATIUPDPL のページ違反です。 モジュール : KERNEL32.DLL、アドレス : 015f:bff8b6be Registers: EAX=00000000 CS=015f EIP=bff8b6be EFLGS=00010246 EBX=004121b9 SS=0167 ESP=0064fe40 EBP=77f70000 ECX=c1585380 DS=0167 ESI=004047d8 FS=0f37 EDX=bffc9490 ES=0167 EDI=00401178 GS=0f1e Bytes at CS:EIP: 89 45 d8 eb 1a ff 75 ec e8 01 23 01 00 c3 8b 65 Stack dump: 00000000 816368f4 00000000 75697441 6c706470 45584500 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000