X64 移行ノート
                                                                                   Jan.19.2012

概要 
 32bitシステムから、64ビットシステムに移行するときの注意点について、VeritakSV6464の開発の経験から述べます。開発環境は、VC10++です。
VPI/DPIの開発時の参考になると思います。

1.32ビットからの注意点
1.1 アドレス空間が変わる
 64ビットで変わるのは、ポインタが4バイトから8バイトに変わることです。アドレス空間が、以下のようになります。

x86 (32ビット) x64 (64ビット)
ユーザ空間  2GB  8TB
物理メモリ(Windows7 Proffetional)  4GB  *128GB

仮想アドレス空間が64-bitとなっていませんが、これは実装上のサイズであって、ポインタは、あくまで8バイトになります。int のサイズは、4バイトのままですので、ポインタをキャストしている部分が、移行時の注意箇所になります。

*物理メモリの最大値は、OSのVersionで変わります。メモリを32GB積んでもOSが対応していないと意味がないのでご注意ください。

1.2 開発環境

VisualStudio10で開発したWIN32(x86)プロジェクトをX64に移行します。

構成マネージャをクリックすると下のようなダイアログが現れます。



新規作成をクリックします。






X64 が現れますので、OKを押します。

このとき、「新規に作成できない..」というエラーが出た場合、新しいプロジェクトフォームを作成するのチェックを外してトライしてみください。


以上で、プロジェクトは作成されました。このプロジェクト下では、#define _WIN64 が暗黙に宣言されています。

後は、通常通り、ビルドしてください。

1.3 注意点
1.3.1 ポインタのサイズに纏わる問題
1.3.1.1 ハンドルは、64ビット
  
 ハンドルは、一般的に、void* という内部宣言になっていることが多いです。
 実際SVの

   共、実体は、void* ですので、64ビットになります。


  hSharedMap = CreateFileMapping(
(HANDLE)0xffffffff, //-1のつもりだが、64ビット環境では、0xffff_ffff_ffff_ffffでなければならない
NULL,
PAGE_READWRITE | SEC_COMMIT,
0, MAX_SHARED_FILE_SIZE,
MAPPED_FILE_NAME);

このコードは、64ビット環境では、エラーです。

1.3.1.2 string::npos 、STLメソッド.size()に注意

    STLのstring::npos及び.size()は、size_t で宣言されており、64ビット環境では、64ビットサイズになります。

   string name=get_file_name();
    size_t end_pos=name.find_last_of("\\/");// unsigned end_posでは、意図したようには動かない
   if (end_pos !=std::string::npos) {
     name=name.substr(end_pos+1);
    }

まとめ

   #ifdef _WIN64
       #define INVALID_HANDLE (-1L)
   #else
       #define INVALID_HANDLE(-1)
   #endif



以上を注意すれば、64ビットへの移行は、完了です。

2 64ビットアーキテクチャ
 DPIを開発する場合には、64ビットアーキテクチャの理解は、必要と思います。うまくインターフェースできている(すなわちデバッグの必要がない場合は)
場合はよいのですが、デバッグするなら呼び出し規約の理解が必要です。

ポイントは、最初の4つまでのパラメータは、スタック渡しではなく、RCX、RDX,R8,R9浮動小数の場合はSSE2のXMMレジスタ渡しになることです。
(GCCとは、すでにこの部分で違います。)



3 x64用コンパイラ開発について

 VeritakSV6464においては、x64nativeコードを生成しています。これに纏わるトピックです。

3.1 インラインアセンブラは、使えない
    masm64で代用します。
3.2 下位32ビットのアサイン時は、上位32ビットがクリアされる
    mov rax,0よりも、
    mov eax,0
    の方がコード長が短い。さらに、xor eax,eaxの方が短い。
3.3 呼び出し時にパラメータのスペースを空けておく必要がある
    レジスタ渡しであっても、従来のスタック渡しの空間は空けて呼ばれます。呼び出された側は、この空間を使用してもしなくても
    よいのです。(VC++の実装では、デバッグモードでは、書き込んでいるようです。) 言い換えると、この領域がcallee によって破壊される可能性があるということです。 
3.4 RSPのアライメントは、常に16である必要がある
    これは、SSE2の要請でもあるようです。この規則を破ると 例えば、C-Runtimeで、xmmレジスタのセーブ命令fxsaveでクラッシュします。 

3.5.例外のハンドリングが32ビットとは異なる
    例外処理機構が変更されています。例外発生時、スタックを巻き戻す必要がありますが、X64の例外処理は、例外が発生しない場合の(つまり通常時)オーバヘッドが最小になるような設計がされています。この要請として、各関数の

  を一つの構造体として、コード領域とは別に、EXEファイルのなかに情報を埋め込む必要があります。VeritakSVの場合、ダイナミックにコード生成しますので、
 この情報は、別な形で与えています。(rtladdfunctiontable) unwind構造体というのが、各関数のunwind情報をもっている不定サイズの構造体です。
 masm64でも、このunwind情報を与えることができます。

.code
align 8
vthread_run PROC FRAME
; public vthread_run
; vthread_run:



; mov [RSP + 8], RCX
push R15
.pushreg r15
push R14
.pushreg r14
push R13
.pushreg r13
; sub rsp,fixed_allocation_size
push r12
.pushreg r12
push rdi
.pushreg rdi
push rsi
.pushreg rsi
push rbx
.pushreg rbx
push rbp
.pushreg rbp


mov rbp,rsp
.setframe rbp, 0h
sub rsp,fixed_allocation_size
.allocstack fixed_allocation_size

.endprolog
mov rdx,rcx
mov rdi,[rcx+offset_module_ptr]

call qword ptr [rcx+offset_start_address] ;
leave

pop rbx
pop rsi
pop rdi
pop r12

; add rsp,fixed_allocation_size

pop R13
pop R14
pop R15
ret
vthread_run ENDP


unwind情報は、dumpbinでダンプすることが出来ます。

dumpbin" /unwindinfo veritak_sv.exe >unwind.txt


00000000 00001000 0000102C 009FF7B0 vthread_run
Unwind version: 1
Unwind flags: None
Size of prologue: 0x16
Count of codes: 11
Frame register: rbp
Frame offset: 0x0
Unwind codes:
16: PUSH_NONVOL, register=rbx
15: PUSH_NONVOL, register=rsi
14: PUSH_NONVOL, register=rdi
13: PUSH_NONVOL, register=r12
11: PUSH_NONVOL, register=r13
0F: PUSH_NONVOL, register=r14
0D: PUSH_NONVOL, register=r15
0B: ALLOC_LARGE, size=0xC0
04: SET_FPREG, register=rbp, offset=0x00
01: PUSH_NONVOL, register=rbp


さらに、rawdataは、dumpbinの次のコマンドでダンプできます。
dumpbin /rawdata:4 veritak_sv.exe >rawdata.txt

構造体のメンバーは、領域節約のため、32ビットオフセット単位になっているために、その範囲内に構造体データが存在する必要があります。


参考Links:
http://uninformed.org/?v=4&a=1&t=txt
http://web17.webbpro.de/index.php?page=windows-exception-handling
http://www.nynaeve.net/?p=11
http://www.microsoft.com/msj/0197/Exception/Exception.aspx
http://blogs.msdn.com/b/freik/archive/2006/01/04/509372.aspx