よもぎのための「レジスタのまとめ」
れじすたっておいしいの?
レジスタと言われても、それがどういうものかを知っている人は人口の1%程度だと思います。*1 もしもあなたの周囲で8割以上が理解しているのなら、人付き合いを見直したほうがいいと思いますね。*2*3
以下はWikipediaからの引用
レジスタ(register)はコンピュータのプロセッサなどが内蔵する記憶回路で、制御装置や演算装置や実行ユニットに直結した、操作に要する速度が最速の、比較的少量のものを指す。
ここで気をつけたほうがいいと思うのは、レジスタは記憶装置というよりも演算装置の一部である、ということ。
記憶装置の説明の比喩として、”本”をデータに見立て、”本棚”がHDDやSSDなどの補助記憶装置、”机”がメモリなどの主記憶装置のようなものである、という説明があると思います。 ここに本を開く”手のひら”という場所を追加してみると、これにはCPU内部のキャッシュのようなもの*4。 そして本を読んでるときの内容を記憶する”脳”。これこそがレジスタ、ではないでしょうか。
ばしょ | ひゆ | はやさ | おおきさ |
---|---|---|---|
レジスタ | 脳 | 速い | 小さい |
キャッシュ | 手のひら | ||
メモリ(主記憶装置) | 机 | ||
HDD/SSD(補助記憶装置) | 本棚 | 遅い | 大きい |
このレジスタに読み込んだものに対して、CPUの演算処理が働く、みたいな感じでしょうか。直接いじることが多いと思われます。
アセンブリ言語でみると使われているのがみえる。*5gccでアセンブリ言語を見たいときには
$ gcc -S hogehoge.c
これでhogehoge.sファイルと言うかたちで出力されるので、これをテキストエディタなどで見ればよし。
x86あーきてくちゃぁ
x86アーキテクチャ、聞いたことあるかと思います。これが今現在一般的なマイクロプロセッサの命令セットアーキテクチャで、一般的には32bitだと思います。これを64bitに拡張したものをx86-64だとかx64とか言います。
もともと、16bit CPUのIntel 8086での命令セットを32bit CPUのIntel 80386*6で32bitに拡張したものです。64bitに拡張したのはAMDさんらしいけど。
この記事では、このx86アーキテクチャ(あるいは、x86-64)に基づいた説明をしていきますね。
れじすたのせつめい
いろいろあるレジスタについて、グループ分けしながら。といってもこの分け方は色々あるので、お世話になっているハリネズミ本*7に従っていきます。
汎用レジスタ
汎用レジスタはどんな使い方でもできるものですが、通例というものがあります。
name | なまえ | つかわれかた |
---|---|---|
EAX | アキュームレータレジスタ | 演算の結果 |
ECX | カウンタレジスタ | カウント(ループ回数など) |
EDX | データレジスタ | 演算に用いるデータ |
EBX | ベースレジスタ | アドレスのベース値 |
ESI | ソースインデクスレジスタ | データの転送元(データ転送命令) |
EDI | デスティネーションインデックスレジスタ | データの転送先(データ転送命令) |
ちなみにこのEっていうのは32bitを表す接頭語みたいに考えるといいと思います。
特殊レジスタ
専用の用途があるということですが、たとえばx64だと汎用レジスタとしてつかえるものもあるみたい
name | なまえ | つかわれかた |
---|---|---|
EBP | ベースポインタレジスタ | 現在のスタックフレームにおける底のアドレスの保持 |
ESP | スタックポインタレジスタ | 現在のスタックトップのアドレスの保持 |
EIP | インストラクションポインタレジスタ | 次に実行するアセンブリ命令のアドレスを保持 |
EFLAGSレジスタ
演算の結果による影響を保持したり、プロセッサの状態に格納するレジスタで、各bitにそれぞれの役割があります。プログラミングでもflagを立てて条件分岐に役立てるとか、やったことあると思う。x64だとRFLAGSレジスタみたい。
x86,x64では18bitのflagがあるけれども、CTFで比較的使うらしいものを選びます。ちなみにflagで用いられないbitは予約されている(reserved)で変更されないべき。
name | なまえ | bit | つかわれかた |
---|---|---|---|
CF | キャリーフラグ | 0 | 演算でキャリー*8|orボロー*9でセット |
ZF | ゼロフラグ | 6 | 演算で0になったときにセット |
SF | 符号フラグ*10 | 7 | 演算で負になったときにセット |
DF | 方向フラグ*11 | 10 | ストリームの方向を制御 |
OF | オーバーフローフラグ | 11 | 符号付き算術演算でオーバーフローしたときにセット |
セグメントレジスタ
メモリ管理のために区切った領域がセグメント*12。セグメントの先頭のアドレスを格納しているみたいです。
name | なまえ | つかわれかた |
---|---|---|
CS | コードセグメントレジスタ | コードセグメントのアドレス |
DS | データセグメントレジスタ | データセグメントのアドレス |
SS | スタックセグメントレジスタ | スタックセグメントのアドレス |
ES | エクストラセグメントレジスタ | エクストラセグメント(1つめの追加セグメント)のアドレス |
FS | Fセグメントレジスタ | エクストラセグメント(2つめの追加セグメント)のアドレス |
GS | Gセグメントレジスタ | エクストラセグメント(3つめの追加セグメント)のアドレス |
Eの次だからF,Gという命名の適当さは好きです。セグメントよくわかっていないのでおいおい
こまかいよびかた
汎用レジスタや特殊レジスタには、そのレジスタ内でも特定の場所にたいして呼び方があります。
具体的には、
- RAX->64bitでの基本長
- EAX->32bitでの基本長。64bitの場合、下位32bitを表す
- AX->下位16bitを表す
- AH->AXの中で上位8bitを表す
- AL->AXの中で下位8bitを表す
こんな感じになっています。x86がもともと16bitを拡張したものと言う感じが伝わってきますね。なお、AHにあたるものがESI,EDI,EBP,ESP,EIPにはないです。
つぎの画像を参考にしてもらえるとわかってもらえるんじゃないかな。
あとがき
だいたいこんな感じで一通りだと思います。間違っている所ありましたら教えてください
追記
追記1: EIPに対して、IPLというのは存在しないみたいです x86 - Wikipedia
参考
X86アセンブラ/x86アーキテクチャ - Wikibooks
Assembly Programming on x86-64 Linux (04)