google-site-verification: google3bd66dd162ef54c7.html
FC2ブログ

Arduino の RAM の内容をダンプして、あれこれ考えてみた

まえがき
前回の記事では arduino のメモリーの用途別アドレス、つまり、groval, haeap, free, stack の各領域のアドレスを調べるプログラムを作りました。これを使うとメモリーの使い分けが正確に判って面白いのですが、今回はこれを更に発展させてRAMの内容をダンプするプログラムを追加しました

プログラム
プログラムは関数の形で作りましたが、単独では動かないので使用例の形で公開します。内容としては、0.96インチOLED(SSD-1306)に適当なパターンを描くプログラムになっています。このプログラムは OLED の画像バッファとしてヒープ領域を大量に使うので、事例として面白いと思います。

プログラムはこちら→20190519CoreDump.txt (Shift-JISエンコードになっています)

setup の中の下記の関数呼び出しでメモリーの中身を調べてダンプしています。
  checkMem();    // メモリーの使用状況をチェック
  printMem();    // チェック結果をシリアルに表示
  coreDump();   // コアダンプ(RAM領域の内容を表示)

実行結果
ダミー表示
こんな画像を表示した後で、シリアルにRAM の状態をダンプするようになっています。なお、10グリッドピッチの線を書いているのは、ビット位置がデーターの中で変化するようにしたかったためです。

じっくり眺めるために、紙に印刷してみました。
ダンプリスト
面白いのでもう少し詳しく中身を見てみます。

最初に領域別のアドレスのリスト (RAM allovation table) が出てきますが、これは前回の記事と同じです。

その後が RAM 領域のダンプで、先頭の 0x0000 から 0x00FF までの256バイトは CPU 内部のレジスタで、RAM 領域ではないのですが、同じアドレス空間にあるので一緒にダンプしています。なお、CPU は ATmega328P なので RAM は 2k バイトあり、そのアドレスの範囲は 0x0100 から 0x08FF です。

以下、面白そうなところを見て行きます。

RAMダンプ (先頭)
ダンプ-1b

RAM allocation tabel の値(アドレス)が RAM の中に埋まっている様子がこのリストから見て取れます。プログラムでは RAM の内容を調べて領域別のアドレスを洗い出しているので、当然と言えば当然の結果です。なお、avr はバイトオーダーをリトルエンディアンで扱うので、RAM のダンプの中に出て来る値は下位、上位の順になっています。

アドレスの 0x005D は CPU のスタックポインタのレジスタですが、その値は 0x01EE 番地にコピーされていました。またその前には、ヒープの開始や終了アドレスが入ってる感じです。なお、プログラムの構造によってこの場所(アドレス)は変化しているようです。

プログラムカウンタ (PC) の値がこのダンプの範囲に入っていると面白いのですが、残念ながら発見出来ませんでした。PC (プログラムカウンタ) はソフトにとっては神の領域なので見えなくても当然、というか見ても意味が無いのかも知れません。

話を戻しますが、RAM 領域の先頭 (つまりグローバル変数領域の先頭) から 2バイト目にはヒープ領域の開始アドレスが入っているようで、この位置はプログラムの内容によって変化しない、つまり固定されている感じでした。

RAMダンプ (中間)
ダンプ-2
グローバル変数領域とヒープ領域の様子です。中身の推定データーを赤字で記入しておきました。(かなり怪しいところもあります)

ヒープ領域の大半は OLED の画像メモリーとして使われていました。OLED 画面の左上がアドレスの若い方に相当し、1 バイト 8 ビットのデーターの MSB が画面の上側にマップされているようです。

RAMダンプ (末尾)
RAMダンプ-3
ヒープの終わりからRAMの終わりにあるスタック領域まで見た様子です。

スタックは RAM の末尾の 2 バイトだけが使われていて、その値は 0x05E8 となっています。これは恐らくこの関数 (setup) 終了時の戻りアドレスだと思います。なお、スタックにはアドレス逆順でデーターが積まれていくので、リトルエンディアンなのにビッグエンディアンで記録されたように見えるのが面白いです。

フリー領域には電源を入れた時のノイズのようなデーターが記録されていますが、およそ 0x08A8 以降では値の雰囲気が変わっていてゼロが多くなっています。想像ですが、リセットがかかってシステムの立ち上げ処理が行われていく過程で、このあたりまでスタックとして使われていた痕跡が残っているのではないかと思います。

まとめ
面白いのでいろいろとやってみたのですが、CPU やコンパイラがやっていることの一部を垣間見たようで、なかなか興味深かいです。コンピューターの仕組みを勉強したい人には格好の教材になると思います。

以前の記事に書きましたが、arduino のIDE のメッセージで空きメモリーに関する情報は極めて少ないので、何か問題が発生した時にその原因の切り分けに苦労します。そんな時にこういうツールを使うと原因究明が楽になるかも知れません。

ところで、この OLE Dのライブラリ (adafruits_GFX) は画像メモリーをヒープ領域に確保していることが良く判りました。ここで疑問は何でヒープ領域を使うんだろう?という点です。グローバル変数領域を使っても良さそうな気がしますが、何故かヒープ領域が使われています。

想像ですが、メモリーを開放して別のことに使えるように配慮しているのかも知れません。そうは言っても、OLED の使用を停止する display.end(hoge,, ) なんて関数は用意されていないようなので自信はありません。あと、adafruit が用意するライブラリは多くのCPUやフルカラーの大きなグラフィックデバイスにも対応しているので、そのあたりとの整合性を取るとこういう仕様になるのかも知れません。うん、たぶんそうなん、、かな、、
関連記事

コメントの投稿

管理者にだけ表示を許可する

解析できるスキルが素晴らしい

このような解析できるスキルが有るのは羨ましいです。
私は挑戦しようとする気力すら起きない年になりました。

今回のダンプリストを見ていて、昔PC8001で機械語を入力していたころを思い出しました。
自分でゼロから作る能力は無いので、逆アセンブルして一部改変する程度でしたが、楽しい思い出でした。

re:解析できるスキルが素晴らしい

mytoshi さん、今晩は。

こんなことしなくても、もっとスマートな手、例えばコンパイラの仕様から調べて行く手などがありそうです。

でも貧乏性なもので、自分の手持ちの道具だけで何とか出来ないかと考えてやってます。

プログラムカウンタ

PCのx86とかでもプログラムカウンタって普通には指定できなかったりするんですよね。
でも大丈夫。多くのCPUでは関数呼び出しをすればプログラムカウンタはスタックにプッシュされます。
戻り値用レジスタにポップしてからプッシュしなおしてリターンするアセンブリ関数や、引数リストへのポインタを範囲外アクセスさせてスタックトップを読み取る純C関数やらを作って呼び出せば読めます。
なんだったら0バイト先を相対コールするコール命令がPUSH PCの代わりにできるはずです。
まぁ引数リストの範囲外アクセスが一番無難かな……?

re:プログラムカウンタ

とおりすがりさん、コメントありがとうございます。

そうですよね、プログラムカウンタを直接読み出すことは出来なくても、工夫すれば出来ますよね。

どうすれば出来るか考えるのは、CPUの命令やアーキを調べるような話になって、面白いです。
カレンダー
10 | 2019/11 | 12
- - - - - 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
プロフィール

ラジオペンチ

Author:ラジオペンチ
電子工作を中心としたブログです。たまに近所(東京都稲城市)の話題など。60過ぎて視力や器用さの衰えを感じつつ日々挑戦!
コメントを入れる時にメールアドレスの記入は不要です。なお、非公開コメントは受け付けていません。

記事が気に入ったらクリックを!
最新記事
カテゴリ
最新コメント
リンク
FC2カウンター
検索フォーム
月別アーカイブ
RSSリンクの表示
QRコード
QRコード