アドレスレジスタとは?役割・種類(PC/SP/MAR)からアーキテクチャ別の使い方、性能・セキュリティ対策まで
アドレスレジスタとは
アドレスレジスタ(address register)とは、CPUやプロセッサ内部で「メモリや周辺装置のアドレス(番地)」を保持・操作するためのレジスタを指します。データそのものを保持するデータレジスタ(汎用レジスタ)と対比され、アドレス演算、間接参照、スタック操作、プログラムの流れ(次に実行する命令の番地)など、メモリ位置を扱う処理で中心的な役割を果たします。
基本的な役割と分類
- メモリアクセスの指定:読み書きしたいメモリの番地を示す。例えば「この番地から値を読み取る」「この番地へ値を書き込む」といった命令で使われます。
- プログラムカウンタ(PC)/命令ポインタ:次に実行する命令のアドレスを示す特殊なアドレスレジスタ。命令フェッチに必須です。
- スタックポインタ(SP):スタックの現在位置(トップ)を示す。関数呼び出しやローカル変数の確保で重要です。
- ベース/インデックス/オフセット用レジスタ:配列アクセス、構造体オフセット、ポインタ演算で使用されます。アーキテクチャによっては「アドレス専用レジスタ」として明確に分離されています。
- メモリアドレスレジスタ(MAR):マイクロアーキテクチャ上で、実際にメモリコントローラへ渡す物理アドレスを保持する内部レジスタ。
アーキテクチャ別の例
各プロセッサ設計でアドレスレジスタの扱い方は異なります。以下は代表的な例です。
- Motorola 68000 系:A0〜A7 の8つのアドレスレジスタ(A7 はスタックポインタ)と D0〜D7 の8つのデータレジスタを明確に分けている点が特徴的です。アドレス演算やアドレス間接参照では A レジスタ群が利用されます。
- x86(IA-32 / x86-64):古典的には SI/DI(インデックス)、BP(ベース)、SP(スタック)などの役割を持つレジスタがありましたが、近年は汎用レジスタを柔軟に使います。命令ポインタは EIP/RIP、セグメントレジスタはセグメント方式の際にベースとして用いられます(保護モードや64ビットモードでは使い方が変化)。
- ARM(ARMv7/ARMv8):汎用レジスタ R0–R12(ARMv7)を多目的に使い、R13 が SP、R14 が LR(戻りアドレス)、R15 が PC(命令ポインタ)です。R15(PC)を直接操作して分岐やサブルーチン呼び出しを制御します。
命令セットとアドレッシングモード
アドレスレジスタは各種アドレッシングモード(addressing modes)で使われます。主なモードには次のようなものがあります:
- レジスタ間接(register indirect):レジスタが示す番地を介してメモリにアクセスする(例:LDR R0, [R1])。
- ベース+オフセット(base + offset):ベースレジスタに固定オフセットを足してアクセス(配列や構造体フィールドのアクセスで多用)。
- インデックス(indexing):インデックスレジスタを用いて可変オフセットを加える。
- PC相対(PC-relative):命令ポインタ(PC)を基準にオフセットを足してアドレス指定。位置独立コード(PIC)や分岐で有用。
- 間接オペレータや間接自動更新(auto-increment / auto-decrement):ポインタ操作やスタック操作で頻出。
マイクロアーキテクチャ上の位置 — MAR とレジスタファイル
CPU内部で「メモリへ渡すアドレス」を直接保持するのが MAR(Memory Address Register)です。プログラマブルなレジスタ(レジスタファイル)で保持されたアドレスは、ロード/ストア命令の実行時に MAR に転送され、メモリコントローラへ物理アドレス(あるいは仮想アドレス)として提示されます。現代のCPUでは仮想アドレスと物理アドレスの区別が重要で、MMU によるアドレス変換(ページテーブル、TLB キャッシュ)を経て実際の物理アドレスへ翻訳されます。
仮想メモリ・MMU・TLB とアドレスレジスタ
ソフトウェア(プログラム)が操作するのは通常「仮想アドレス(論理アドレス)」であり、これを物理アドレスに変換するのが MMU(Memory Management Unit)です。CPU レジスタや MAR に置かれた仮想アドレスは、TLB(Translation Lookaside Buffer)で迅速に変換され、ページテーブルを参照して物理アドレスへマッピングされます。アドレスレジスタが指す番地がアクセス可能か、ページ保護や権限チェックもここで行われます(アクセス違反は例外/フォルトを発生)。
プログラミング、コンパイラ、OS における観点
- 言語レベルでは「ポインタ」はアドレスを表現する主要な抽象であり、コンパイラはポインタをレジスタに割り当てたりメモリへ書き出したりして最適化を行います。
- コンパイラ最適化では「レジスタ割り当て」がパフォーマンスに直結します。アドレスをレジスタに保持できればメモリアクセス回数を減らせますが、レジスタ数が限られるためトレードオフが生じます。
- OS はコンテキストスイッチ時にレジスタの状態(アドレスレジスタを含む)を保存/復元します。プロセス間でアドレス空間が異なるため、PC や SP などのレジスタ値はプロセス固有です。
パフォーマンスと設計上の注意点
アドレス計算やメモリアクセスは CPU のパフォーマンスに大きく影響します。ポイントは以下のとおりです。
- レジスタ内アドレス参照はメモリアクセスより圧倒的に速い。可能な限りループでベースアドレスをレジスタに保持することが望ましい。
- キャッシュミス(キャッシュラインの未取得)は致命的に遅いため、ポインタ追跡(pointer chasing)やランダムアクセスは性能低下を招きやすい。
- アドレスのアライメント(境界揃え)やデータレイアウトの最適化によりキャッシュ効率を高められる。
- 分岐予測と命令パイプラインにおいて、PC(命令ポインタ)の変更頻度や不可予測なジャンプは性能に影響する。
セキュリティ的観点
アドレスは攻撃の対象にもなります。代表例はバッファオーバーフローによるリターンアドレス(スタック上のアドレス)改ざんです。これに対する対策として、ASLR(Address Space Layout Randomization)や実行不可ビット(NX)、スタックカナリアなどが使われます。ASLR はプロセス内のアドレス配置をランダム化し、固定的なアドレスへの依存を困難にします。
具体的なアセンブリ例
簡単なアセンブリ表現で、どのようにレジスタがアドレス指定に使われるかを示します。
- x86(32-bit)の例:
mov eax, [ebx] ; EBX がメモリアドレスを示し、その位置の値を EAX に読み込む - ARM の例:
ldr r0, [r1] ; R1 がアドレスを示し、その場所の値を R0 に読み込む - Motorola 68k の例:
MOVE.L (A0), D0 ; A0 が示すアドレスから 32-bit 値を D0 に移動
まとめ
アドレスレジスタは、メモリやデバイスの番地を扱うための主要なレジスタ群であり、CPU、コンパイラ、OS、セキュリティ、性能最適化のあらゆるレイヤーに関わります。アーキテクチャごとに専用のアドレスレジスタを持つ設計や、汎用レジスタで柔軟に対応する設計などさまざまですが、共通するのは「どの番地を参照・演算するか」を決めるという点です。仮想メモリや MMU、TLB と組み合わせた理解が現代システムを正しく設計・解析するうえで不可欠です。
参考文献
- Memory Address Register — Wikipedia
- Addressing mode — Wikipedia
- Registers of the x86 architecture — Wikipedia
- ARM architecture — Wikipedia
- Intel 64 and IA-32 Architectures Software Developer’s Manual — Intel
- ARM Developer Documentation — ARM
- Virtual memory — Wikipedia


