OS自作入門 -Advent10-

OS自作入門 -Advent10-

Step3 静的変数の読み書き 後半

Step3の前半ではメモリの仕組み、どこに何を配置すべきなのか、リンカとローダーの違い辺りの知識が深まった。今回はそれに対応するようにプログラムを書き直していくことになりそう。

変数の初期値が配置されるアドレス(PA)とプログラムが変数にアクセスする際のアドレス(VA)を別に割り当てるという作業。これをVA ≠ PAにするというらしい。

静的変数の書き換えの対応

今回変更を加えるのは以下のファイル

  • ld.scr
  • main.c
  • startup.s

順にやっていこう。


ld.scrの修正

MEMORYという定義を追加する。定義そのままMEMORYはメモリ領域を定義するもの。

  romall(rx)        : o = 0x000000, l = 0x080000 /* 512kb */
  vectors(r)        : o = 0x000000, l = 0x000100 /* top of ROM */
  rom(rx)           : o = 0x000100, l = 0x07ff00

こんな感じで書く。oはoriginの略、lはlengthの略。

前回のメモリ構成図を引っ張ってくると

|——————- 0x000000
| 割り込みベクタ
|——————- 0x0000ff
| 内臓ROM(512KB)
|——————- 0x07ffff
|——————- 0xffbf20
| 内臓RAM(16KB)
|——————- 0xffff1f
|——————- 0xffff20
| 内臓I/Oレジスタ
|——————- 0xffffe9

こうなっている部分の512kbの領域を定義して、rxはread, executeが可能であることを示している(wがあればwriteも可能)。vectorsは割り込みベクタ、romは残りの領域。なのでこのように領域が被るように書くことができる。

同じようにRAMの方の設定もする。Githubに編集後のファイルを置いておいた。

次はセクション定義の修正を行う。

  .vectors : {
    vector.o(.data)
  } > vectors

このような感じで修正を行なっていく。末尾の> vectorsはMEMORYコマンドで定義したどの領域にセクションを配置するのかを指定している。これによってちゃんとROMメモリ内に配置することができる。

dataセクションに関しては次のような修正を行う。

  .data : {
    _data_start = . ;
    *(.data)
    _edata = . ;
  } > data AT> rom

この末尾にあるAT > romがVA≠PAにしている処理である。まずは> dataによって.dataセクションはMEMORYコマンドで定義されたdata領域(RAM)に配置される。AT > romの指定が物理アドレスの指定になるらしい。なので、.dataセクションの物理アドレスはROM内に設定されることになる。これで

.dataセクションは、リンクはRAM上のアドレスをベースにして行われるが、ロードはROM上に行われる

ようになる。リンカとローダーの違いがこの辺りに出てくるようだ。なるほどー。


main.cの修正

これだけだと不十分で結局プログラム状で静的変数の初期値を設定するために「プログラムの起動時にROM上の静的変数の初期値をRAM上にコピーする」という処理が必要になるとのこと。

  extern int erodata, data_start, edata, bss_start, ebss;

init関数の中でこれらを使って初期化するが、この変数はリンカ・スクリプト中で定義されており、cには突然出てきたように見えるかもしれない。これらは結局のところメモリの特定のアドレスを持っているだけなので以下のような書き方でアドレスを知ることができる。

int *p;
p = &data_start;

これらを駆使して、ROM上のデータをRAMにコピーして、bssセクションのメモリ領域をゼロクリアする処理を書いている。main.cの今回分はここに置いておいた。


startup.sの修正

さらに今回のリンカ・スクリプトの中にはstack領域を設けるための修正が入っている。元々はstartup.sでベタ書きで初期化していたらしい(全然気づいてなかったけど)

mov.l #0xffff00,sp

メモリの配置に関してはリンカ・スクリプトに任せているのでリンカ・スクリプトで定義しているシンボルを参照するように修正する。

mov.l #_stack,sp

確認

できたプログラムを確認する。

make
make image
readelf -a kzload.elf

これで取得できた結果はGitubに置いておいた。修正前と比較してみると面白いかもしれない。

こんな感じで変わっている ↓

  • .bssセクションが加わった
  • .textと.rodataセクションはROM上に配置されている(00000100000004c8
  • .dataと.bssセクションはRAM上に配置されている(00fffc2000fffc24
  • セグメントが増えて、ROM領域の上の二つは仮想Addrと物理Addrが等しくなっている
  • bss領域のためのセグメントが追加されている
  • bss領域のセグメントの仮想Addrと物理Addrが異なっている(VA≠PAということ)
  • bss領域のようのセグメントは.bssと連続しておりFileSiz ≠ MemSizになっている

FileSizは実行ファイル中のサイズ、MemSizはメモリ上に展開される時のサイズらしい。

各シンボルの値はこの辺りに載っている。_start系のシンボルはセクションの開始アドレスと同値になっているのとか確かに。という感じ。

あとはいつも通り書き込みモードにして書き込み、読み込みモードにしてシリアル接続してreset連打。

今日の文はこれまで!