意外に簡単? x64アプリケーション開発環境の構築(2/2 ページ)

» 2005年07月07日 03時15分 公開
[ch3,C MAGAZINE]
前のページへ 1|2       

x64のアドレス空間

 プロセッサが64ビット対応になって何がうれしいかというと、まず広大なアドレス空間を利用できるようになったことでしょう。試しに32ビットシステムと64ビットシステム用の同じプログラムで、どれだけのメモリを利用できるかという点をList1のプログラムで確認してみることにします。

List.1 仮想メモリのサイズを取得するプログラム
void main()
{
    MEMORYSTATUS status;

    status.dwLength = sizeof(MEMORYSTATUS);
    GlobalMemoryStatus( &status );
    _tprintf( TEXT("Total Virtual Space: %u MB\n"),
                status.dwTotalVirtual / (1024 * 1024) );
}

 実行結果はTable4のとおりで(付録CD-ROMに実行画面のスクリーンショットを収録)、32ビットシステムでは2Gバイトまでしか仮想アドレスがサポートされていなかったのに対し、64ビットシステムでは8Tバイトもの仮想アドレスを利用できることが分かります。しかし、ちょっと待ってください。8Tバイトというと、プロセッサが使用できる最大仮想アドレスサイズには達していません。これはx64版のWindowsの仕様によるものです。しかし、32ビットシステムで利用可能だった2Gバイトのアドレス空間に比べるとはるかに大きな値となっていることがわかります。Table5にメモリの仕様を示します。

Table4 GlobalMemoryStatusの実行結果
(利用可能な仮想アドレスを取得)
  32ビットシステム上で実行 64ビットシステム上で実行
32ビットプログラム 2047Mバイト[※1] 2047Mバイト[※2]
64ビットプログラム
8191Gバイト
[※1]/3Gバイトスイッチで約3Gバイトまで利用可
[※2]/LARGEADDRESSAWAREスイッチで約4Gバイトまで利用可



Table5 x64とx64版Windowsのメモリ空間
  物理アドレス空間 仮想アドレス空間
x64 52ビット(1Pバイト)[※1] 48ビット(256Tバイト)
x64版Windows 35ビット(32Gバイト)
または40ビット(1Tバイト)
43ビット(8Tバイト)[※2]
[※1]現時点では40ビット(1Tバイト)に制限
[※2]ユーザーの1プロセスの空間。システムを含めると16Tバイト

ネイティブ64ビット型

 汎用レジスタが64ビットに拡張され、数も増えたということは前述したとおりですが、ロングモード(IA-32eモード)では、このレジスタをネイティブな64ビットデータ型として利用できます(ユーザーアプリケーションは64ビットモードのみ)。

 64ビットのデータ型をネイティブで利用しているかどうかを、List2に示すような単純な64ビット値の乗算プログラムで確認してみましょう。

List2 64ビット型がネイティブで使われているかどうかを確認する
__int64 A = 0x7fffffff;

void main()
{
    _tprintf( TEXT("Answer: %016I64lx\n"), A * A );
}

 List2を32ビットアプリケーションとしてビルドしたあと、その逆アセンブルしたものがList3です[注2]。それぞれの命令が何をしているか、分かりやすいように各行にコメントをつけておきました。32ビットシステムでは64ビットの値を計算するのに桁上がりや符号拡張が必要になるために、かなり長い命令が生成され、さらに関数コールまで行われていることが分かります。

List.3 32ビットバージョンで生成(64bit.asm)
mov eax, DWORD PTR ?a@@3_JA+4 ;eaxレジスタにグローバル変数Aの下位32ビットをロード
mov ecx, DWORD PTR ?a@@3_JA   ;ecxレジスタにグローバル変数Aの上位32ビットをロード
push    eax                   ;
push    ecx                   ;
push    eax                   ;次に呼ぶ関数のためにデータをスタックに格納する
push    ecx                   ;
call    __allmul              ;64ビットの乗算を行う関数をコール
push    edx                   ;結果の上位をスタックに格納
push    eax                   ;結果の下位をスタックに格納
push    OFFSET FLAT:...       ;出力フォーマットのオフセットをスタックに格納
call    _printf               ;表示
add     esp, 12

 一方、64ビットアプリケーションとしてビルドしたあと、逆アセンブルしたものがList4です。List3と比較して、とてもシンプルな形になっています。64ビットシステムでは64ビットの値をネイティブでサポートしているため、たった1つの命令で計算が完了するのです。

List.4 64ビットバージョンで生成(64bit.asm)
mov     rdx, QWORD PTR ?a@@3_JA ;rdxレジスタに64ビットのグローバル変数Aをロード
lea     rcx, OFFSET FLAT:...    ;出力フォーマットのオフセットを計算
imul    rdx, rdx                ;乗算
call    printf                  ;表示

 また、関数コールやスタックの利用もなく、よりシンプルな形になったということは、当然処理速度の向上も期待できることになります。64ビットのネイティブ化によって、より大きな値を扱う計算がいかに改善されるかは、この例で見てとることができるかと思います。

注2
VS2005はインラインアセンブラをサポートしないので、逆アセンブルリストから実行コードを生成できない。

前のページへ 1|2       

Copyright(C) 2010 SOFTBANK Creative Inc. All Right Reserved.

注目のテーマ