X64
x64またはx86-64は、32ビットのx86系命令セットとの互換性を維持したまま64ビットコードの実行を可能にした命令セットアーキテクチャ。AMD64とも。
AMDがx86-64という名称で発表し製品化段階ではAMD64と呼び、それにインテルが追従し(「EM64T」「IA-32e」「Intel 64」などと呼び)、結果として世の主流になった64ビットの命令セットアーキテクチャの総称である。
なお呼び方は、採用時期やマイクロプロセッサベンダーとの関係などにより多様である。具体的にはx86-64, x86_64, x64, AMD64, IA-32e, EM64T, Intel 64などがある。これらは全て、x86-64(AMD64)を源流とする互換命令セットを指しており、基本的には同じものを指していると考えてよい。
この命令セットアーキテクチャは、AMDがx86-64という名前で仕様を発表したものが元になっている。AMDは2003年にAMD64と名前を改めて実装。インテルもAMD64互換命令セットをEM64Tという名で実装した(後で「Intel 64」と改称)。そしてVIAもこれに続き当命令セットアーキテクチャと互換のものをリリース。こうして、64ビット命令セットアーキテクチャの主流として定着した。
大元のAMD64は、AMDのOpteron、Athlon 64、Turion 64など最初に実装されたK8マイクロアーキテクチャとその後継製品に実装されている。
PC用アーキテクチャとして広く普及したx86は、半導体の製造技術とマイクロアーキテクチャの革新とともに性能の向上を続け、サーバやワークステーションといったエントリークラスのエンタープライズ市場でも広く受け入れられるに至った。しかし、IA-32の性能向上によって自社開発の64ビットアーキテクチャであるIA-64との競合を懸念したインテルは、x86の拡張を32ビットアーキテクチャの範囲に留めてIA-64との棲み分けを図った。これに対し、市場からは広く普及したIA-32アーキテクチャと互換性を保ちつつ64ビットに拡張した、よりコストパフォーマンスに優れたエンタープライズ製品の登場が待ち望まれていた。高収益を望めるエンタープライズ市場への進出を図っていたAMDはそうした需要に応えて、x86の64ビット拡張アーキテクチャとして、従来のIA-32のソフトウェアも利用が可能な命令セットとしてx86-64を発表した。その後の実際の製品発表でAMD64と改称された。この計画は、2000年8月に発表され、最初のプロセッサは2003年4月に出荷された。
64ビットの汎用レジスタを持ち、32ビットのx86より広いアドレス空間をサポートするため、大きいデータをより容易に扱うことができる。またx64は32ビットのプログラムコードと完全な後方互換性を持つ。全ての32ビットの命令セットが実装されているため、32ビットのx86実行ファイルは、互換性あるいは性能の損失なしに動作させられる。ただし、アプリケーションソフトウェアがx64の性能を活かすには、x64ネイティブコードを出力するコンパイラを用いることが必要である。
AMDがx86命令セットを64ビット化する際に使ったのは、x86命令の先頭にプリフィックスをつけるという手法である(REXプリフィックスと呼ばれる)。プリフィックスを使うのは、インテルが16ビットCPU 80286を32ビット化(80386)するときに使った手法でもある。
DEC Alpha の設計者の一人 ダーク・メイヤー が AMD64仕様の作成に関わり、彼をはじめとするDEC出身者の経験がこのプロジェクトに活かされた。特筆すべき点は以下のようなものである。
汎用レジスタ (GPR) 数はIA-32の8本 (EAX,EBX,ECX,EDX,ESI,EDI,EBP,ESP) に更にR8〜R15の8本を追加して16本に増やされ、各レジスタのビット幅も32ビットから64ビットに拡張された。IA-32は汎用レジスタが少ないことからコンパイラによる最適化に限界があり、これが最も大きな欠点とされた。AMD64に最適化されたアプリケーションでは、レジスタ本数の増加によって性能向上が見込まれ、特に深いループを持った演算主体のソフトウェアでその傾向が強いと見込まれる。さらに128ビットのXMMレジスタの本数も8本から16本に増やされた(Streaming SIMD命令で使われる)。
AMD64アーキテクチャでは、現状の実装で48ビットのアドレス空間を持ち、256テラバイトまでのメモリを扱うことが出来る。IA-32アーキテクチャにおいて初期のプロセッサでは、アドレス空間は32ビットで表現できる4GiBに制約され、Pentium Pro以降の実装で追加された物理アドレス拡張機能を使用することで64GiBのメモリを接続できるが、1プロセスで利用可能なメモリ空間はやはり4GiBに制約された。32bit版Windowsシリーズにおいては、OSの仕様でアプリケーションが利用可能なメモリはおよそ3GiBに制約される。これに対しAMD64のLongモードでは、IA-32の物理アドレス拡張をベースに、論理アドレス空間を48ビットへ拡張し(現状物理アドレス空間は52ビット)、将来の拡張で4エクサバイトまでの仮想空間をサポートできるようになっている。
関連:2進接頭辞
プログラムカウンタ (RIP) 相対でデータにアクセスすることができ、リロケータブルな共有ライブラリのコードを作成できる。また、共有ライブラリを仮想アドレス空間のどこにでも配置することができる(位置独立コード)。
SSE 命令
AMD64アーキテクチャでは明確にインテルのSSEとSSE2を基本命令セットに組み込んでいる。SSE2はx87の80ビット浮動小数点数から 32ビット/64ビットの浮動小数点数に置き換えたものである。SSE/SSE2命令セットは追加の8本のXMMレジスタを扱えるように拡張された。SSEとSSE2がAMD64命令セットに組み込まれており、それが従来のx87 FPUやMMXや3DNow!の機能をカバーする。x64版Windowsでの64ビットプログラムでは、FPU/MMXレジスタをコンテキストスイッチの際に保存しないようにすると噂されたが、実際には保存されるようになっている。
No-Executeビット
NXビット(ページテーブルエントリのビット63)は仮想アドレス空間のどのページが実行可能か、実行不可かを指定することができる。NXビットがセットされたページにあるコードを実行しようとするとメモリアクセス違反となり、実行できない。これは、リードオンリーページへの書き込みを実行しようとしてもできないことと似ている。No-Execute機能は、ウイルスなどがバッファーオーバランなどを使用して、オペレーティングシステムを乗っ取ろうとすることを難しくする。
類似の機能は、セグメントの属性として80286以降のプロセッサーに存在している。しかし、近代的なオペレーティングシステムではセグメント機能は古いものと見なされ、セグメントのベースを0、リミットを4Gバイト(32ビットOSの場合)に設定することにより、実質的にセグメントを使用していない。
AMDはリニアアドレッシングモードでNo-Execute機能を実装した最初のx86ベンダーである。No-Execute機能は、PAEを有効にすれば、32ビットOSでも使用可能である。
x86アーキテクチャーにある多くのシステムプログラミング機能は近代的なオペレーティングシステムでは使用されておらず、それら古い機能は、AMD64のLongモードにはない。それらは、セグメントアドレッシング、タスクステートセグメントを使用したタスクスイッチ、仮想86モードなどである(ただし、FS, GSセグメントは、オペレーティングシステム構造体へのエクストラベースポインタとして残されている)。これらの古い機能は、Legacyモードでは依然として、完全に実装されているので、これまでの32ビット、16ビットオペレーティングシステムは、修正なしにx64プロセッサー上で動作する。
このアーキテクチャは、LongモードとLegacyモードという二つの動作モードを持つ。
AMD64で拡張された部分に対応する動作モードである。これにはネイティブの64ビットモードと互換のための32ビットモードが含まれる。IA-32でのマイナーな動作モードはサポートされない。このモードは64ビットのOSで使用される。
基本的な命令セットは同じなので、x86コードを実行しても性能が低下することはない。インテルのIA-64では32ビットコードの性能低下が問題となったが、これは命令セットが全く違うためにエミュレート実行していたためである。
Longモードを使うと、64ビットOSは 32ビットアプリケーションと64ビットアプリケーションを並行して実行できる。また、AMD64は 16ビットのアプリケーションも実行することができる。しかし、Windowsの16ビットアプリケーション (Win16) のサポートに欠かせない仮想86モードは使用できないため、マイクロソフトは WOW64サブシステムでの16ビットアプリケーションの実行機能の実装を断念し、Windows XP Professional x64 Edition でのWin16アプリケーション実行をサポートしていない。これはWindows Vista以降のx64版にも引き継がれる制限となっている。
このモードは、16ビットOS(MS-DOS - Windows 3.1等)や32ビットOS(Windows 95 - Windows XP等)で使用される。このモードにおいて、プロセッサは基本的にx86の32ビットプロセッサとして振る舞い、16ビットと32ビットのコードのみが実行可能である。Legacyモードは、仮想アドレス空間の4GB制限のような32ビットの仮想アドレッシング上の上限がある。64ビットのプログラムは、Legacyモードで起動することができない。
次のプロセッサは、AMD64を実装する:
AMD Athlon 64
AMD Athlon 64 X2
AMD Athlon 64 FX
AMD Athlon II (搭載コア数などから、'X2', 'X3', 'X4', XLTモデルに分かれる)
AMD Opteron
AMD Turion 64
AMD Turion 64 X2
AMD Sempron ("Palermo" E6 ステッピングと、"Manila"以降の全モデル)
AMD Phenom (搭載コア数から、'X3', 'X4'に分かれる)
AMD Phenom II (搭載コア数から、'X2', 'X3', 'X4' 'X6'に分かれる)
AMD Bulldozer (マイクロアーキテクチャ) FX
AMD APU
AMD Ryzen
AMD EPYC
Intel 64は、IA-32アーキテクチャの64ビット拡張であり、インテルによるAMD64の実装である。
従来、AMDはインテルがオリジナルであるx86の互換プロセッサを開発・生産していた。しかし、x64では立場が逆転し、インテルはAMDが開発したAMD64アーキテクチャ(x86プロセッサの64ビット拡張アーキテクチャ)を採用した。
当初プロジェクトは、Yamhillという開発コードネームで始まった。このプロジェクトの存在を否定し続けて数年が経ち、2004年2月のIDFで、インテルはプロジェクトが進行中であることを発表した。インテルの当時の会長クレイグ・バレットは、これが重要な機密の一つであったことを認めた。
インテルは、AMD64互換命令セットの名称を数回 変更した。IDFで用いられた名前はCT(Clackamas Technology)、その数週間後にIA-32e(IA-32 extensions)と呼称を変更し、2004年4月にはこれを EM64T(Extended Memory 64 Technology)という名前で公式に発表した。製品リリース後の2006年7月27日には、インテルはEM64TをIntel 64と改称している。
インテルで最初にIntel 64を実装したのは、Noconaというコード名で2004年6月に発表されたマルチソケットのXeonプロセッサである。Xeonはデスクトップ向け Pentium 4 をベースにしているため、同時期のPentium 4もIntel 64を実装しているはずだが、ハイパースレッディング・テクノロジーのときと同様、この機能はPrescottでは最初は動かないようになっていた。これはおそらく初期の実装が完全ではなかったためで、インテルはその後Intel 64を使用可能にしたPrescottのE0バージョンをmodel Fとして販売し始めた。このバージョンではAMD64のNXビットに相当する機能がIntel 64でサポートされた。インテルではこれをeXecute Disable(XD)ビットと呼んでいる。この機能はすぐにNocona(Xeon系列)にも実装された。8xx/6xx/5x6/5x1/3x6/3x1シリーズのCPUは全てIntel 64が使用可能になった。また、Intel Core 2・Intel AtomでもIntel 64が採用された。
Intel 64を実装しているCPUは以下のものがある。
Xeon (Nocona以降、Sossaman除、Xeon MPについてはCranford/Potomac以降)
Intel Atom(model 230/330,N450/D510/D410)
Pentium 4(Prescottはmodel F以降、model 521/531/541/551/561/571)
Celeron D(model 326/331/336/341/346/351/355/356)
Celeron M (model 520/530)
Celeron 200シリーズ(model 220)
AMD64とIntel 64は、ほとんど同じであるが、僅かながら違いはある。これらの違いはオペレーティングシステム、コンパイラなどの開発者のみが意識しなければならない。アプリケーションプログラムの開発者がこれらの違いを意識する必要は、ほぼない。
Intel 64では、SYSCALL, SYSRET命令は64ビットモードにしかない。SYSENTER, SYSEXIT命令は32ビット、64ビットの両方にある。
AMD64では、SYSCALL, SYSRET命令は32ビット、64ビットの両方にあるが、SYSENTER, SYSEXIT命令は32ビットモードにしかない。
Intel 64には、AMD64で定義されたSYSCFG, TOP_MEM, TOP_MEM2がMSR(model-specific registers)にない。
Intel 64では、64ビットモードでニア分岐命令に66h(オペランドサイズ プリフィックス)を付けた場合サポート外となる。AMD64では、仕様書通り16ビットオペランドとして実行される。
BSF, BSR命令はソースが0の場合、Intel 64では元々のx86と同様にデスティネーションは不定(undefined)であるが、AMD64はデスティネーションを変更しない。
Intel 64には、AMDのFast FXSAVE/FXRSTOR機能はない。
初期以外のAMD64は、VMwareでの64ビットゲストOSの仮想化を容易にするために、セグメントリミットを一部に再導入した。ロングモードセグメントリミットと呼ばれる。ただし、AMD-Vがあればロングモードセグメントリミットは必須ではない。
ハードウェア仮想化支援機能のIntel VT-xとAMD-Vは互換性がない。仮想化ソフトウェアはそれぞれに対応する必要がある。
Second Level Address Translation機能のIntel EPTとAMD RVIは互換性がない。仮想化ソフトウェアはそれぞれに対応する必要がある。
AMD64には、元々はCMPXCHG16B命令はなかった。この命令は16バイト(128ビット)のメモリ領域を複数のCPUコアで排他的に共有することに使用される。この命令はWindowsで16TB以上の仮想メモリを使うために必要である。Socket AM2以降のAMD64で対応。
初期のAMD64, Intel 64は、64ビットモードでLAHF, SAHF命令をサポートしていない。この2つの命令はAHレジスタとフラグ間の転送命令で、元々は8ビットCPUである8080のプログラムを8086へ移植するのを容易にするために提供されていた。64ビットモードでは、使い道があまりない命令のように見える。しかし、PUSH/POP命令の組み合わせと比較して、メモリにアクセスせず高速にフラグをコピーできるため、VMwareなどの仮想化ソフトウェアがこの2つの命令に依存している。また、x87のステータスワードをフラグにコピーすることにも使用される。
初期のIntel 64には、PREFETCHW命令はなかった。この命令は、元々はAMDの3DNow!で導入されたキャッシュの最適化命令である。Pentium 4のCedarMillコアからIntel 64はこの命令を単にNOP(No Operation)として処理するようになった。NOPとして処理するIntel 64でもMicrosoft社のCoreinfoツールは、PREFETCHWに対応と表示する。2013年のSilvermont、2014年のBroadwellよりPREFETCHW命令に正式に対応している。 (上記3つは、Windows 8.1、Windows 10の64ビット版が初期のAMD64、Intel 64CPUにインストールできない制約事項となる)
初期のIntel 64は、XDビット(AMD64におけるNXビット)をサポートしていない。したがってWindows 8(32ビット版、64ビット版とも)がインストールできない制約事項となる。
POPFQ命令には、REXプリフィックスは必要ない。Intel社のドキュメントにはこのことが正しく記載されていなかった。
同じオペコードに対するMOVDとMOVQの割り当てがIntel 64のドキュメントとAMD64のドキュメントで異なる。一方のドキュメント通りのアセンブリソースがアセンブルできない、逆アセンブル結果が想定と異なるといったことが起こり得る。
次のような命令にはREXプリフィックスを使用する。
新しいR8〜R15レジスタ、追加されたXMMレジスタなどへのアクセス
64ビットレジスタであるRSP, RBP, RDI, RSIのビット0から7を、8ビットレジスタSPL, BPL, DIL, SILとしてアクセス。一方でREXプリフィックスを付けると8ビットレジスタとして AH, BH, CH, DHにアクセスできない。これにより直交性が高まった。
また、以下の命令は、デフォルトで64ビットのオペランドサイズであり、REXプリフィックスを必要としない。
PUSH, POP命令
ENTER, LEAVE命令
32ビットレジスタにデータを書き込むとその汎用レジスタの上位32ビット(ビット32から63)はゼロになる。
これは、コードサイズの最適化に使用できる。
一方、16ビットレジスタや8ビットレジスタにデータを書き込んでも、このゼロ拡張は起きない。
NOP(No Operation:オペコード 90h)命令は、かつてはXCHG EAX, EAXと等価であったが64ビットモードではこの命令を特別に扱い、暗黙のゼロ拡張を適用せずRAXレジスタは変化しない。
CMOV(Conditional Move)命令では、64ビットモードでオペランドが32ビットの場合、条件が偽でもデスティネーションレジスタの上位32ビットはゼロになる。
64ビットモードであっても、即値(Immediate value)は、32ビットのままであり、64ビットに符号拡張されて使用される。ただし、MOV命令のみ64ビットの即値が使用できる。
64ビットモードであっても、変位(displacement)は、32ビットのままであり、64ビットに符号拡張されて使用される。ただし、RAXレジスタに対してのMOV命令のみ64ビットの変位が使用できる。
以下のx86命令は64ビットモードでは廃止されたため、64ビットモードで実行すると不正命令例外が発生する。
AAA, AAD, AAM, AAS (ASCII Adjust Addtion/Division/Multiply/Subtraction)
BOUND (Check Array Bounds)
CALL far, JMP far (Call far absolute, JMP far absolute)
DAA, DAS (Decimal Adjust Addition/Subtraction)
INTO (Interrupt to Overflow Vector)
LDS, LES (Load Segment Register)
POP DS, POP ES, POP SS, POPA
PUSH CS, PUSH DS, PUSH, ES, PUSH SS, PUSHA
オペコード 82h (Redundant encoding of opcode 80h: undocumented)
SALC (Set AL According to CF: undocumented)
LAHF, SAHF命令は、初期のAMD64, Intel 64では64ビットモードで廃止されたx86命令であった。
ARPL (Adjust Requestor Privilege Level)命令は、64ビットモードでは、新しいMOVSXD命令になった。
1バイトのINC, DEC命令は、64ビットモードでは、REXプリフィックスになった。一方、2バイトのINC, DEC命令は、64ビットモードでも使用可能である。
64ビットモードで廃止されたLDS, LES命令は、のちにインテルによってAVX命令のVEXプリフィックスとして割り当てられた。VEXプリフィックスに続く2バイト目を32ビットモードでは不正であった11xxxxxxという形式にすることにより、AVX命令は32ビットモードでも使用可能である。Windows NTの仮想DOSマシンでは、C4h C4h(LES AX, SPとデコードされる不正命令)を仮想86モードから32ビットプロテクトモードの呼び出しに使用していた。AVXは仮想86モード、リアルモードには対応していない。
64ビットモードで廃止されたBOUND命令は、のちにインテルによってAVX-512命令のEVEXプリフィックスとして割り当てられた。EVEXプリフィックスに続く2バイト目を32ビットモードでは不正であった11xxxxxxという形式にすることにより、AVX-512命令は32ビットモードでも使用可能である。
64ビットモードでは、コードセグメントディスクリプタのP(Present)ビット、D(Default)ビット、DPL(Descriptor Privilege Level)フィールド、C(Conforming)ビット、および、新しく定義されたL(Long)ビットのみが有効である。L=1の場合、64ビットモードでプロセッサーが動作することを意味する。それ以外のベースアドレス、リミットなどは無視される。
64ビットモードでは、データセグメントディスクリプタは、P(Present)ビットのみが有効である。それ以外のベースアドレス、リミットなどは無視される。ただし、FS,GSセグメントレジスタのみベースアドレスは有効で、MSRを使用して64ビットのベースアドレスを指定することもできる。
のちにインテルは、特権レベル0以外でもFS,GSのベースアドレスを操作可能にするRDFSBASE, RDGSBASE, WRFSBASE, WRGSBASE命令を追加した。
正規形(canonical form)
64ビットモードでは、仮想アドレスは64ビットであるものの、実際の実装では、264バイト(16EB)のすべてを使用できるようにはなっていない。ほとんどのオペレーティングシステム、アプリケーションは、近い将来も含めて、そのような大きなアドレス空間を使用しない。フル64ビットという大きなアドレス空間のサポートは、複雑さとアドレス変換のコストを増やすだけでメリットはない。そのため、AMDは最初のAMD64の実装では、48ビットの仮想アドレス空間のみを使用することにした。さらに仮想アドレスのビット48から63は、ビット47の値がコピーされなければならないことにした。そうでない仮想アドレスを使用した場合は、プロセッサーは例外エラーを発生する。このルールに従ったアドレスは、正規形(canonical form)と呼ばれる。正規形のアドレスは、0から00007FFF'FFFFFFFFとFFFF8000'00000000からFFFFFFFF'FFFFFFFFの範囲であり、合計で256TBの仮想アドレス空間が使用可能である。
この仕様は、実際に64ビット仮想アドレスが使用可能になったときに重要な意味を持つ。正規形ではないアドレスを使用した場合、例外エラーが発生するので、アプリケーションやOSが、未使用の上位16ビットを別の用途に使用できない。そのため、将来、仮想アドレス空間が48ビットから拡張されたときに問題が起こらない。
Longモードでのページ変換(page translation)
Longモードでのページ変換には物理アドレス拡張(PAE)が必須である。Longモードに入る前にCR4のPAEビットを1にセットする必要がある。AMD64では、PDPE(page-directory-pointer entry), PDE(page-directory entry), PTE(page-table entry)を拡張し、新たにPML4(page-map level-4)を追加した。PAEが有効になっているため、CR4のPSE(page-size extensions)ビットは無視される。CPUIDのファンクション8000_0001hで、EDXのビット26がセットされていると、そのCPUは、1Gbyteページ変換に対応している。
4Kbyteページ変換:  PML4, PDPE, PDE, PTEによって変換される。ページのサイズは4Kbyteである。
2Mbyteページ変換:  PML4, PDPE, PDEによって変換される。ページのサイズは2Mbyteである。
1Gbyteページ変換:  PML4, PDPEによって変換される。ページのサイズは1Gbyteである。
特権レベルは80286のプロテクトモードでx86に導入され、レベル0,レベル1,レベル2,レベル3の4階層がある。リングプロテクションとも呼ばれる。x64の64ビットモードでも特権レベルは4階層あるが、通常は特権レベル0(カーネルモード)と特権レベル3(ユーザーモード)の2種類しか使用されない。
コールゲートによるシステムコール(CALL far, RET)
コールゲートは80286で特権レベル(0,1,2,3)を切り替える仕組みとして導入された。64ビットモードでは、コールゲートは64bitのオフセットが使用できるように拡張された。
コールゲートの仕組みはRISCには無い。RISCにも対応していたWindows NTではシステムコールにコールゲートを使用せず、INT命令やPentium IIで追加されたSYSENTER, SYSEXIT命令を使用していた。
高速システムコール(SYSCALL, SYSRET)