athrill(アスリル)を使用してC言語ポインタ変数を理解する

#概要
C 言語のポインタ変数はよく難しいと言われています．ポインタ変数を理解するには，RAM 上のメモリ配置と CPU レジスタの動きをイメージできるかどうかが大切だと思います．

そこで，今回は仮想マシン([athrill](https://qiita.com/kanetugu2018/items/1f2ef93c9e1fa7a29f97) )を使用して，ポインタ変数の理解を深めてみたいと思います※．
※もうすぐ新入社員が入社する時期なので，新人さん向けの内容です．
※athrillは，教育目的にも使うことができます．

#ポインタ変数とは

ポインタ変数は，通常の変数と同じように値を格納する変数です．
ポインタ変数が通常の変数と異なるのは，「メモリのアドレス」を専門的に扱う点です．

#ポインタ変数の定義方法
たとえば，通常の int 型変数を定義する場合は，以下のようになります．

```
int global_value;
```
これに対して，int 型のポインタ変数を定義する場合は，以下のようになります．

```
int *global_value_pointer;
```

型のあとに 「*(アスタリスク)」をつけます．

#ポインタ変数のアドレス配置
athrill で上記変数のアドレス配置を調べてみます．

まずは，「p コマンド」を使用して，通常変数(global_value)を調べてみましょう．

```
[DBG> p global_value
global_value = 0 (int:4) @ 0x5ff7408(0x0)
```

上記結果はこう読みます．

|表記|意味|
|---|---|
|0|本変数に入っている値は0(10進表記)|
|(int:4)|データ型はintでサイズは4バイト|
| @ 0x5ff7408|本変数のメモリ配置場所は0x5ff7408|
※最後の(0x0)は，構造体の場合しか意味のない値ですので，無視してください．

次に，ポインタ変数(global_value_pointer)を調べてみましょう．

```
[DBG>p global_value_pointer
global_value_pointer = (int *: 4 ) 0x0  @ 0x5ff7000(0x0)
```

|表記|意味|
|---|---|
|0x0|本変数に入っている値は0(16進表記)|
|(int *: 4 )|データ型はintのポインタ型でサイズは4バイト|
| @ 0x5ff7000|本変数のメモリ配置場所は0x5ff7000|


上記結果を，メモリイメージ化するとこうなります．

|アドレス|アドレス割り当て変数|値|
|---|---|---|
|0x5ff7000|global_value_pointer|0x0|
|0x5ff7408|global_value|0|

メモリイメージの視点で見ると，global_value と global_value_pointer には，
それぞれ同じようにアドレスが割り当てられており，値が格納されています．

#ポインタ変数にアドレスを代入する

ここで，ポインタ変数にアドレスを代入してみましょう．

```
global_value_pointer = &global_value;
```
上記例は，global_value のアドレス(※)を global_value_pointerに代入しています．
(※) &を変数の前に付すと変数アドレスがとれます.

athrill で代入後の global_value_pointer の値を見てみましょう．

```
[DBG>p global_value_pointer
global_value_pointer = (int *: 4 ) 0x5ff7008  @ 0x5ff7000(0x0)
```
上記結果を，メモリイメージ化するとこうなります．

|アドレス|アドレス割り当て変数|値|
|---|---|---|
|0x5ff7000|global_value_pointer|0x5ff7008|
|0x5ff7008|global_value|0|

global_value_pointerの領域に，global_value のアドレスの値が設定されていることがわかりますね．

ちなみに，新人さんがよくやるミスとして，こんなのがあります．

```
global_value_pointer = global_value;
```

この場合は，global_value のアドレスではなくて，値そのものを代入していますので，結果は以下のようになってしまいますのでご注意を．

```
p global_value_pointer
global_value_pointer = (int *: 4 ) 0x0  @ 0x5ff7000(0x0)
```
#ポインタ変数で値代入する
それでは，ポインタ変数を使用して，値を代入してみましょう．

```
*global_value_pointer = 999;
```

ポインタ変数の前に「*(アスタリスク)」を付けると，ポインタ変数が格納しているアドレスの領域に値を設定します．
結果は，こうなります．

```
[DBG>p global_value
global_value = 999 (int:4) @ 0x5ff7408(0x0)
[DBG>p global_value_pointer
global_value_pointer = (int *: 4 ) 0x5ff7408  @ 0x5ff7000(0x0)
```

メモリイメージ化するとこうなります．

|アドレス|アドレス割り当て変数|値|
|---|---|---|
|0x5ff7000|global_value_pointer|0x5ff7408|
|0x5ff7008|global_value|999|

global_value_pointer に格納されているアドレスが global_value ですので，
global_value のアドレス位置が結果として書き換わるわけです．

#一連の流れをアセンブラ命令で読む
さて，ここまでくれば，ポインタ変数のメモリイメージがついてきたと思います．
次は，C言語レベルのポインタ変数操作が，CPU命令としてどのように扱われるのか理解を深めていきましょう．

以下の２行は，

```
	global_value_pointer = &global_value;
	*global_value_pointer = 999;
```

CPU命令(V850)になると，以下のようになります(最適化していません)．


１行目：global_value_pointer = &global_value;

```
 87a:	2a 06 00 70 	mov	0x5ff7000, r10 /* global_value_pointerのアドレスを r10 に代入(mov) */
 87e:	ff 05 
 880:	2b 06 08 74 	mov	0x5ff7408, r11　/* global_valueのアドレスを r11 に代入(mov) */
 884:	ff 05 
 886:	6a 5f 01 00 	st.w	r11, 0[r10] /* global_valueのアドレス(r11)を 
                                             * global_value_pointer が指すアドレス位置(r10)に格納(st.w)
                                             */
```

CPU の演算処理は，CPU レジスタを通して行われますので，メモリ上に格納されている値は一旦，CPU レジスタに格納する必要があるため，上記のような命令になります．

今回の場合は，CPUの汎用レジスタに変数のアドレスを設定しています．

|汎用レジスタ|割り当て|
|---|---|
|r10|global_value_pointerのアドレス|
|r11|global_valueのアドレス|

２行目：*global_value_pointer = 999;

```
 88a:	2a 06 00 70 	mov	0x5ff7000, r10 /* global_value_pointerのアドレスを r10 に代入(mov) */
 88e:	ff 05 
 890:	2a 57 01 00 	ld.w	0[r10], r10 /* global_value_pointer のアドレス(r10) が指すアドレス位置の値(0[r10])を
                                             * r10 にロード(ld.w)
                                             */
 894:	20 5e e7 03 	movea	999, r0, r11 /* 即値(999) を r11 に代入(movea) */
 898:	6a 5f 01 00 	st.w	r11, 0[r10] /* 999(r11) を 
                                             * global_value_pointer が指すアドレス位置(r10)に格納(st.w)
                                             */
```

以上のように，C 言語レベルのプログラムも，CPUが扱える命令に落とし込みすると，１行のプログラムも複数の命令に展開されることがわかります．

#一連の流れを athrill でデバッグする

最初に，以下のプログラム実行直前で，ブレークを張り，CPUレジスタ状態を確認しましょう．

```
	global_value_pointer = &global_value;
```

上記プログラムのアドレス位置は 0x87a ですので，ここでブレークポイントを設定し,「cpu コマンド」でレジスタ状態を参照します(関係する箇所のみ抜粋)．r10 と r11 はいずれも 0 が入っていることがわかります．

```
[DBG>b 0x87a
break 0x87a
[DBG>c
[CPU>
HIT break:0x87a main(+0x8)
[NEXT> pc=0x87a main.c 22
l
[DBG>cpu
PC              0x87a main(+0x8)
R0              0x0
R1              0x0
R2              0x0
R3              0x5ff7400 stack_data(+0x3fc) Stack Pointer
R4              0x0
R5              0x0
R6              0x0 Arg1
R7              0x0 Arg2
R8              0x0 Arg3
R9              0x0 Arg4
R10             0x0 Return Value
R11             0x0
R12             0x0
　：
```

次に，次の行の手前まで CPU のプログラムカウンタを進めます．

```
	*global_value_pointer = 999;
```

次の行のプログラムのアドレス位置は 0x88a ですので，ここでブレークポイントを設定し,「cpu コマンド」でレジスタ状態を参照します(関係する箇所のみ抜粋)．r10 と r11 値が書き換わっていることがわかります．

```
[DBG>b 0x88a
break 0x88a
[DBG>c
[CPU>
HIT break:0x88a main(+0x18)
[NEXT> pc=0x88a main.c 24
cpu
PC              0x88a main(+0x18)
R0              0x0
R1              0x0
R2              0x0
R3              0x5ff7400 stack_data(+0x3fc) Stack Pointer
R4              0x0
R5              0x0
R6              0x0 Arg1
R7              0x0 Arg2
R8              0x0 Arg3
R9              0x0 Arg4
R10             0x5ff7000 global_value_pointer(+0x0) Return Value　★
R11             0x5ff7408 global_value(+0x0)　★
R12             0x0
　：
```

ここまでくると，global_value_pointerのアドレス領域(0x5ff7000)にglobal_valueのアドレスが格納されているはずですので，「print コマンド」で確かめてみましょう．

```
[DBG>p 0x5ff7000 4
size=4 byte
0x5ff7000 0x5ff7408
```

確かに入ってますね．

最後に，「 *global_value_pointer = 999;」の結果を確認しましょう．

```
[DBG>b 0x89c
break 0x89c
[DBG>c
[CPU>
HIT break:0x89c main(+0x2a)
[NEXT> pc=0x89c main.c 28
cpu
PC              0x89c main(+0x2a)
R0              0x0
R1              0x0
R2              0x0
R3              0x5ff7400 stack_data(+0x3fc) Stack Pointer
R4              0x0
R5              0x0
R6              0x0 Arg1
R7              0x0 Arg2
R8              0x0 Arg3
R9              0x0 Arg4
R10             0x5ff7408 global_value(+0x0) Return Value
R11             0x3e7　★999
R12             0x0
　：
```

global_value_pointerが指すアドレス位置は 「0x5ff7408」であり，その領域に格納する値(999)は，
r11 に一時的に格納されています．

そして，global_value_pointerが指すアドレス領域にも 999(0x3e7)が入っていますね！

```
[DBG>p 0x5ff7408 4
size=4 byte
0x5ff7408 0x3e7　★999
```

#ポインタ演習用ソースコードの配置場所

ここでご説明したプログラム一式は [athrill プロジェクト](https://github.com/tmori/athrill)で公開しています．

場所は，以下になります．

```
https://github.com/tmori/athrill/tree/master/sample/barmetal/step1
```

main.c が，ポインタ演習用のプログラムです．
ビルドおよび athrill によるデバッグは，以下のコマンドを叩くことで簡易化しています．

```
tmori@tmori-vaio:~/project/athrill/sample/barmetal/step1$ ../build/run.sh
Elf loading was succeeded:0x0 - 0x980 : 2.384 KB
Elf loading was succeeded:0x980 - 0x980 : 0.0 KB
ELF SYMBOL SECTION LOADED:index=15
ELF SYMBOL SECTION LOADED:sym_num=41
ELF STRING TABLE SECTION LOADED:index=16
[DBG>
HIT break:0x0
[NEXT> pc=0x0 vector.S 6
```

上記メッセージ出力後，main 関数でブレークポイントを設定すれば，ポインタ変数のデバッグができます．

#関連記事
* [athrill(アスリル) を使用して TOPPERS OS(ASP3) をデバッグ](https://qiita.com/kanetugu2018/items/1f2ef93c9e1fa7a29f97)
* [マルチコア対応仮想環境(athrill)を使用して TOPPERS/ATK2 を実行する](https://qiita.com/kanetugu2018/items/b43c5715124f42a0393d)
* [メモリ保護対応版 athrill(アスリル) のご紹介](https://qiita.com/kanetugu2018/items/f2205475c4a4eae699c0)
* [今さらなぜCPUエミュレータを自作しようとおもったのか？](https://qiita.com/kanetugu2018/items/d692e612c3d4d715c0ad)
* [athrill(アスリル)機能マニュアル](https://qiita.com/kanetugu2018/items/cf3dea16710a3f0737e8)
* [athrill(アスリル) を使用してベアメタル・プログラミング(１回目：main関数が動き出すまで)](https://qiita.com/kanetugu2018/items/7d2ce8def53cb9bda06b)
* [athrill(アスリル) を使用してベアメタル・プログラミング(2回目：割り込みがソフトウェアに通知されるまで)](https://qiita.com/kanetugu2018/items/8cb411717511ca96bc64)
* [TOPPERS/ATK2カーネル向け実機レス環境(athrill2)](https://qiita.com/kanetugu2018/items/75dadc340f3db2a344ab)