はじめに
だれでも64ビットのコンピュータを所有する時代になってきました。最近の PC では WindowsXP や WindowsVistaといった32ビットのOSが使われているものの、Core2Duo を代表として、すべて amd64 や intel64 といった 64bitに対応した CPU が搭載されています。昔、インテルの 80386 や 80486 という 32bit の CPU は10年近く MS-DOS や Windows3.x といった16bitのOSを使うための高速な8086として使われていました。Windows95の時代になって、やっと32bitの機能が一般的に使われ始めました。2009年現在でも64bitに対応した Windows はサーバ用として一部で活躍しているだけではないでしょうか。Linux という無料で使える OS でも、すでに64bit版が安定して使えるようになっていますが、やはり32bit版を使っている人が多いように思います。64bitのOSを使っても大量のメモリ(例えば32GB)を搭載したPCで、大量のメモリを使用するプログラムを使うのでなければなければ 64ビットのメリットが感じられないことが理由になっているのだと思います。しかし、せっかく64bitに対応したCPUが手元にあるのですから、使ってみないともったいないと思いませんか。
C や C++ でプログラミングすることを含めても、普通に使う限りは「64bit は long型の数値が扱える範囲が広くなった」といった程度の感触しか得られません。まして文章作成や表計算、ブラウザやメールでインターネットという使い方では32ビットで十分です。 そこで、アセンブラの登場です。64ビットCPU の機能を直接確かめることができます。
64ビットのCPUとは、1命令で扱うことのできる整数の大きさが最大64ビットのCPUです。64ビットで表すことができる整数は約±900京、±9,223,372,036,854,775,807 の10進数で約20桁という非常に大きな値になります。32ビットのCPUでは、数値を 0 から 4294967295 (約40億) まで表すことができます。そのためメモリも40億個の番地(4GB)を指定することが限界でした。64ビットあれば最大18,446,744,073,709,551,616バイト(18EB) のメモリを扱うことができます。実際に搭載できるメモリは現在のところ 64GB とか 1TB が上限となっていますが、当分メモリ空間が狭いと感じることはなさそうです。
ほとんどの Linux ディストリビューションも amd64 アーキテクチャをサポートしているため、誰でも簡単に64ビットのCPUを使ったアセンブリプログラミングができるようになっています。Windows XpもWindowsVista も64ビット版を販売していますが、わざわざ購入してインストールするのも大変なため、無料でダウンロードして使うことのできるLinux の 64bit版を使ったアセンブリプログラミングで64ビットの世界を探検してみることにしましょう。Linux の 64bit版でも 32ビット用のプログラムをまったく問題なく使うことができます。Core2などのCPUを積んだ最近のPCを使っている人は、せっかくですから64bit版のLinuxをインストールしてみましょう。私は ubuntu-8.10-desktop-amd64.iso を Core2Duo(E6750, 2.66GHz)のデスクトップPCにインストールしています。
また、VirtualBox を使って Windows上で 64bit Linux を使うこともできます。
Linux の 64bit版を使ったアセンブリプログラミングということで64ビットモードに限定して説明します。
64ビットCPU x86-64
1986年にインテルが発売したIntel80386 (i386) という32ビットのCPUで使われた命令セットアーキテクチャは、20年以上たった今でもIA-32として使われ続けています。しかし、最近のCPUは2003年4月にAMDが発売したOpteronで採用された64ビットの命令セットアーキテクチャ(x86-64, AMD64) をインテルのプロセッサでもIntel64 として採用しています。Intel64の前の名称はEM64T (Extended Memory 64-bit Technology) です。インテルのXeon、Core2、Atom、Celeronなど最近のCPUはすべて64ビットモードを使うことができます。AMDのOpteron、Phenom、Athlon、Sempron、Turion 64などもすべて64ビットモードを使うことができます。Intel64とAMD64はいくつかの微妙な違いはあるもの同じ64ビットのCPUとして使うことができます。
このようにIA-32 の64ビット拡張はx64、x86_64、amd64など色々な呼び方がされています。実際にGoogleで検索したときの件数を表にしてみました。
名称 | 検索件数 | 1年以内 |
---|---|---|
x64 | 21,600,000 | 380,000 |
amd64 | 12,500,000 | 273,000 |
x86_64 | 7,590,000 | 316,000 |
x86-64 | 2,670,000 | 314,000 |
EM64T | 1,880,000 | 247,000 |
intel64 | 127,000 | 10,800 |
"x64" はWindowsの64bit版の名称に使われているので多くなっていますが、IA-32の64bitアーキテクチャの名称という面では決定的な差はないように思われます。Linuxのカーネルソースでは x86_64が使われていますが、Linuxのコマンドのオプションや表示には x86-64 が使われているようです。この解説では x86-64 に統一することにします。
x86-64 は 1978年に発売された16ビットのCPU (8086) から30年以上にわたって上位互換を維持してきたため、非常に複雑で高機能なCPUになっています。すべてを解説しようとするとインテルやAMDのマニュアルのように数千ページが必要となると思います。ここではアセンブリ言語の初心者でも困らないように、32ビットモード (IA-32) の知識がなくても 64ビットモードでユーザ空間で動作するアセンブリプログラムが書けるように解説していきます。
32ビットモードと64ビットモードの違い
IA-32をすでに知っている人のために、32ビットモードと64ビットモードの違いの主なものは次のようになります。
- レジスタのビット数が64bitに倍増
- レジスタ本数が16本に倍増
- SSE2を標準搭載し、XMMレジスタの数が16個に倍増
- 80386以降に追加された多くの命令(CMOVなど)が標準搭載
- オペランドサイズが64 ビットの時、即値は64 ビットに符号拡張される。
- mov 命令は64ビット即値を64ビットレジスタに設定できる
機能が増えた分、犠牲となって無くなった命令もいくつかあります。pusha、popa というすべてのレジスタを1バイトの命令で一括してスタックに退避/復帰する命令が使えなくなっています。アセンブラでプログラムする場合には、レジスタの退避のための行数が増えてちょっと面倒です。またレジスタの本数を増やすためREXプリフィックスバイトが必要になった影響で、レジスタの値を1つ増減する1バイト命令形式の INC/DEC が使えなくなり、2バイトの命令を使う必要があって、プログラムサイズが少し大きくなります。また 10進演算命令(DAA、DAS、AAA、AAS、AAM、AAD)が 64bit モードでは使用できません。
参考資料
AMD64、Intel64 CPU のマニュアルはメーカの Web サイトから簡単に入手できます。以下のリストだけでトータル70MB程のPDFとなり、詳細すぎることが問題でしょうか。
最初に x86 の 64ビット拡張を開発したAMDのマニュアル(10MB)は次のサイトから入手できます。
https://amd-ad.bandrdev.com/documentation/guides/Pages/default.aspx
- AMD64 Architecture Programmer's Manual
- Volume 1: Application Programming
- Volume 2: System Programming
- Volume 3: General-Purpose and System Instructions
- Volume 4: 128-Bit Media Instructions
- Volume 5: 64-Bit Media and x87 Floating-Point Instructions
インテルのマニュアル(全体で30MB)は次のサイトから入手できます。
https://www.intel.com/products/processor/manuals/ 64ビットモードの範囲では AMD と インテルの CPU は互換と考えて問題ないと思います。
- Intel(R) 64 and IA-32 Architectures Software Developer's Manual
- Volume 1: Basic Architecture
- Volume 2A: Instruction Set Reference, A-M
- Volume 2B: Instruction Set Reference, N-Z
- Volume 3A: System Programming Guide
- Volume 3B: System Programming Guide
- IntelR 64 and IA-32 Architectures Optimization Reference Manual
日本語の資料はちょっと古くなりますが以下のマニュアル(全体で30MB)がダウンロードできます。
https://www.intel.co.jp/jp/download/index.htm
- IA-32 インテル アーキテクチャー・ソフトウェア・デベロッパーズ・マニュアル
- 上巻: 基本アーキテクチャー
- 中巻 A: 命令セット・リファレンス A-M
- 中巻 B: 命令セット・リファレンス N-Z
- 下巻: システム・プログラミング・ガイド
- インテル エクステンデッド・メモリー64 テクノロジー・ソフトウェア・デベロッパーズ・ガイド
- 第 1 巻
- 第 2 巻
AMD64 ABI (Application Binary Interface) は x86-64 の Linux における関数呼び出し、システムコール呼び出しのレジスタの使い方、ELFヘッダの情報などの仕様書です。 https://www.x86-64.org/documentation/abi.pdf
- System V Application Binary Interface