Jun's Homepage

玄箱PRO、Linux ZaurusでARMアセンブリプログラミング

copyright (C) 2003-2009 Jun Mizutani

5. レジスタ-メモリ転送命令(複数レジスタ)

スタックやブロック転送に使用する命令です。複雑そうに思えますが、覚える事は このページの最後の2行です。

LDM / STM 命令

LDM/STM命令は、すべてのレジスタから任意に組み合わせた複数のレジスタ (レジスタリスト) の内容を、 一度にメモリとの間で転送する場合に使用します。 LDM命令で複数ワードをメモリからレジスタに読み込み、STM命令で複数のレジスタの内容をメモリに書き込む ことで大量のデータ転送に使用します。 またスタックデータ構造(Last-In First-Out 型のバッファ)を実現するために、ほとんどのCPUが持つ スタックポインタを任意のレジスタで実現することができます。レジスタの内容をメモリに保存(push)し、 メモリの内容をレジスタに復帰(pop)することで、サブルーチンコールの際の戻り先アドレスや引数を スタックに格納したり、スタックをローカル変数領域とする場合に使用します。

オペコード オペランド 動作 意味
LDM<cd><adm> Rm<!>, {reg list} <reg list>=[Rn+=4] 複数レジスタからロード
STM<cd><adm> Rm<!>, {reg list} [Rm+=4]=<reg list> 複数レジスタのストア
STM<cd><adm> Rm, {reg list}^ 特権モード用 複数レジスタのストア
LDM<cd><adm> Rm, {reg list}^ 特権モード用 複数レジスタからロード
LDM<cd><adm> Rm<!>, {reg list}^ 特権モード用 複数レジスタからロード
STM<cd><adm> Rm<!>, {reg list}^ 特権モード用 複数レジスタのストア

レジスタリストが「 {reg list}^」となっている命令はユーザモードでは使用しません。

<adm>はアドレッシングモードとして4種類のうちの1つを指定します。 オペランドにあるレジスタRmの示すメモリとの間で複数レジスタの内容を転送しますが、 転送前 (Before) にレジスタRmの示すアドレスを更新するか、転送後 (After) に更新するかを 指定します。 また、更新の方向がレジスタの値を増加 (Increment) させるか、減少 (Decrement) させるかを指定します。レジスタRmに「!」を指定した場合は更新後のアドレスをRmに書き戻します。

モード 意味 動作
DA Decrement After メモリアクセス後にポインタを減らす
IA Increment After メモリアクセス後にポインタを増やす
DB Decrement Before メモリアクセス前にポインタを減らす
IB Increment Before メモリアクセス前にポインタを増やす

レジスタRmをスタックポインタとして使用する場合には、スタックの種類で アドレッシングモードを指定するほうがわかり易いため、次のような別名も用意されています。

モード 意味 LDM (pop) STM (push) CPUのスタックの例
FA Full Ascending DA IB  
FD Full Decending IA DB i386,6809,Z80
EA Empty Ascending DB IA  
ED Empty Decending IB DA 6800

それぞれのモードにおけるスタックの動作を次に示します。最初の Full Descending が 最も重要なモードです。

Full Descending

レジスタをメモリに保存する前にメモリアドレスを保持しているレジスタ(通常は r13, sp)の値を 1ワード分(4バイト)減じた後に保存するレジスタの内容をメモリに書き込みます。スタックポインタ が常に保存済みの値を指しているのでFULL、保存時にメモリアドレスの減る方向にポインタが進むので DECENDING (下降) と呼びます。下の図では上がメモリアドレスの小さい方向となっているので、 上に向かって「下降」することに注意して下さい。 このモードをサブルーチン呼び出し、レジスタの退避などのスタックとして使います。

    アドレス小

  ┃   ↑   ┃
  ┣━━━━━━━┫
  ┃   空   ┃
  ┣━━━━━━━┫
  ┃   C   ┃←SP  Full Descending
  ┣━━━━━━━┫    Push : Decrement Before  [stmfd]
  ┃   B   ┃    Pop : Increment After   [ldmfd]
  ┣━━━━━━━┫
  ┃   A   ┃
  ┣━━━━━━━┫
  ┃   ↑   ┃←sp

sp は最初にスタックポインタの示していた位置、SPは3ワード保存後にスタックポインタが示す位置 を表しています。

Empty Descending

レジスタの内容をメモリに書き込んだ後、メモリアドレスを保持しているレジスタ(通常は r13, sp)の値を 1ワード分(4バイト)減じます。スタックポインタが常に次に保存する空のメモリ領域 (EMPTY) を指します。 保存時にメモリアドレスの減る方向にポインタが進むのでDECENDINGとなります。

    アドレス小

  ┃   ↑   ┃
  ┣━━━━━━━┫
  ┃   空   ┃←SP  Empty Descending
  ┣━━━━━━━┫    Push : Decrement After   [stmed]
  ┃   C   ┃    Pop : Increment Before  [ldmed]
  ┣━━━━━━━┫
  ┃   B   ┃
  ┣━━━━━━━┫
  ┃   A   ┃←sp
  ┣━━━━━━━┫
  ┃   ↑   ┃

Full Ascending

レジスタをメモリに保存する前にメモリアドレスを保持しているレジスタ(通常は r13, sp)の値を 1ワード分(4バイト)減じた後に保存するレジスタの内容をメモリに書き込みます。スタックポインタ が常に保存済みの値を指しているのでFULL、保存時にメモリアドレスが増える方向にポインタが進むので ASCENDING (上昇) と呼びます。下の図では上がメモリアドレスの小さい方向となっているので、 下に向かって「上昇」となることに注意して下さい。

    アドレス小

  ┃   ↓   ┃←sp
  ┣━━━━━━━┫
  ┃   A   ┃
  ┣━━━━━━━┫
  ┃   B   ┃
  ┣━━━━━━━┫
  ┃   C   ┃←SP  Full Ascending
  ┣━━━━━━━┫    Push : Increment Before  [stmfa]
  ┃   空   ┃    Pop : Decrement After   [ldmfa]
  ┣━━━━━━━┫
  ┃   ↓   ┃

Empty Ascending

レジスタの内容をメモリに書き込んだ後、メモリアドレスを保持しているレジスタ(通常は r13, sp)の値を 1ワード分(4バイト)減じます。スタックポインタが常に次に保存する空のメモリ領域 (EMPTY) を指します。 保存時にメモリアドレスが増える方向にポインタが進むのでASCENDINGとなります。

    アドレス小

  ┃   ↓   ┃
  ┣━━━━━━━┫
  ┃   A   ┃←sp
  ┣━━━━━━━┫
  ┃   B   ┃
  ┣━━━━━━━┫
  ┃   C   ┃
  ┣━━━━━━━┫
  ┃   空   ┃←SP  Empty Ascending
  ┣━━━━━━━┫    Push : Increment After   [stmea]
  ┃   ↓   ┃    Pop : Decrement Before  [ldmea]

LDM/STM は重要な命令でよく使います。複雑な動きをする命令ですが、 次の形式の2つの命令を覚えておけば十分です。

        stmfd    sp!, { レジスタリスト }  @ 保存
        ldmfd    sp!, { レジスタリスト }  @ 復帰

レジスタリストはレジスタを並べて書いたもので、{r0, r3, r6, lr}、{r0-r10, pc} のようにレジスタ番号の若い方から順に並べたものです。i386の push/pop と pusha/popa の ように「1つ、または全部」よりも柔軟にレジスタをスタックに退避することができます。 レジスタリストの各レジスタはレジスタ番号の小さいほうから順番で転送されます。 レジスタリストのうち最も番号の小さいレジスタは最も低位のメモリアドレスに転送されます。

典型的な使用法はサブルーチンの入り口でリンクレジスタ(r14, lr) と破壊したくない レジスタを保存 (push) し、サブルーチンの出口では保存したレジスタを戻し (pop)、 保存したリンクレジスタをプログラムカウンタ (r15, pc) に戻すことで呼び出し元に 戻ります。

sub:
        stmfd   sp!, {r3, v1-v5, lr}   @ 入り口で保存
          :  何か処理
        ldmfd   sp!, {r3, v1-v5, pc}   @ lr の代わりに pc に戻してリターン

Jun's Homepage

  • HOME に戻る
  • 前のページ
  • 次のページ
  • webg:WebGPU 3Dライブラリ
  • Blender
  • Raspberry Pi メモ
  • rvtl:Tiny Basic
  • ARM64 アセンブリ
  • ARM アセンブリ
  • x86 アセンブリ
  • x86-64 アセンブリ
  • PowerPC アセンブリ

ARM アセンブリ

  • はじめに
  • 1. アセンブラのインストールと実行
  • 2. ARMのレジスタ
  • 3. 演算命令と分岐命令
  • 4. ロード/ストア命令
  • 5. ロード/ストア命令(複数レジスタ)
  • 6. システムコールとその他の命令
  • 7. アセンブラGNU asの基礎知識
  • 8. 標準入出力用のサブルーチンの作成
  • 9. フレームバッファでグラフィックス - その1
  • A. システムコールと引数一覧
  • B. インタプリタの作成

Raspberry Pi メモ

  • Raspberry Pi メモ 目次
  • ★ 逆引き Raspberry Pi メモ ★
  • (1) Raspberry Pi到着
  • (2) ブート用SDカードの作成
  • (3) アセンブリで浮動小数点数表示
  • (4) 軽く三次元
  • (5) ベクトル演算の実力
  • (6) 転んでも泣かない!
  • (7) OpenGL ES2 (1) 概要
  • (8) OpenGL ES2 (2) 初期化
  • (9) 公式オーバークロック
  • (10) OpenGL ES2 (3) シェーダの使い方
  • (11) OpenGL ES2 (4) 三次元で三角形
  • (12) OpenGL ES2 (5) テクスチャ
  • (13) OpenGL ES2 (6) シェーダで照明
  • (14) 新wheezy-raspbian と「まとめ」
  • (15) Tiny BASIC と ASLR
  • (16) 新イメージ 2012-12-16
  • (17) 各種言語のベンチマーク
  • (18) Pi専用の Minecraft の使い方
  • (19) LuaJITでお手軽3D (1)
  • (20) LuaJITでお手軽3D (2) LjESリリース
  • (21) 新 raspbian と Wayland/Weston
  • (22) LuaJITでお手軽3D (3) NodeとShape
  • (23) カメラモジュールの使い方
  • (24) 2013-09-25-wheezy-raspbian と「まとめ」
  • (25) LuaJITでお手軽3D (4) テクスチャマッピング
  • (26) raspbian(2013-12-20)とMathematica
  • (27) RPI Expansion Board (X100)のレビュー
  • (28) 液晶ディスプレイ一体型PC
  • (29) LuaJITでお手軽3D (5) LjES-2 リリース
  • (30) GPIO とシャットダウンボタン
  • (31) Lua でオブジェクト指向
  • (32) 新Raspbianとリアルタイムクロック
  • (33) 2014-09-09-wheezy-raspbian のインストール
  • (34) デスクトップの軽量な日本語化
  • (35) デスクトップのカスタマイズ
  • (36) 2014-12-24-wheezy-raspbian の変更点
  • (37) Java8 プログラミング
  • (38) Raspberry Pi でラムダ式
  • (39) Raspberry Pi 2 始動
  • (40) Raspberry Pi2 の互換性
  • (41) ゲームパッドでシャットダウン
  • (42) Raspberry Pi2 の非互換性とGPIO
  • (43) Node.js で JavaScript
  • (44) ハードディスク起動とヘアピンNAT
  • (45) 2015-05-05版と新しい無線LAN設定方法

アセンブリ言語シリーズ

  • PowerPC アセンブリ
  • ARM アセンブリ
  • ARM64 アセンブリ
  • x86 アセンブリ
  • x86-64 アセンブリ

ARM64 アセンブリ

  • 0. はじめに
  • 1. メモリ、バイト、エンディアン
  • 2. アセンブラのインストール
  • 3. ARM64 のレジスタ
  • 4. ロード命令
  • 5. ストア命令
  • 6. 演算命令
  • 7. シフト命令
  • 8. 条件分岐、システムコール
  • 9. 浮動小数点レジスタと命令
  • 10. 浮動小数点数の表示
  • 11. 浮動小数点数のロード/ストア命令
  • 12. ベクトルのロード/ストア命令
  • 13. 浮動小数点数のレジスタ間移動命令
  • つづく...

  • インタプリタの作成
  • Dragonboard 410C のインストール
  • 仮想 Arm64 マシンの作り方
  • HiKey のインストール
  • Orange Pi PC2 の性能と Ubuntu のインストール
  • Raspberry Pi2、Orange Pi Zero/PC2 の UnixBench

アセンブリ言語シリーズ

  • PowerPC アセンブリ
  • ARM アセンブリ
  • x86 アセンブリ
  • x86-64 アセンブリ

ご意見・ご感想は,こちらの掲示板まで。

64781