読者です 読者をやめる 読者になる 読者になる

ゆとりーなの日記

日記的な事を書いて行くと思はれる

H8のGCCでC++やるときの話

「12ステップで作る組み込みOS自作入門」はC言語の本なんで我々Cぷらーはいろいろとやらなければいけないことがあるんですね。
まずリンカスクリプトに書いてあるシンボルにアクセスするときには

extern "C" {
extern シンボル名の先頭_を取ったもの;
}

としなければ残当しますし、一番厄介なのがグローバルクラス変数のコンストラクタ/デストラクタ周りですね。対策しないと呼ばれなくて悲しみを背負うことになります。コンストラクタに関してはメンバ変数に値を代入する程度のものだと最適化でコンストラクタ呼び出しが消えて?何事もなかったかのように動くので地味に気づきにくかったりする罠もあります。
具体的に何をするかというと、

.tors : {
    _start_ctors = . ;
    *(.ctors)
    _end_ctors = . ;
    _start_dtors = . ;
    *(.dtors)
    _end_dtors = . ;
 } > ram

な感じにリンカスクリプトにグローバルなコンストラクタ/デストラクタ呼び出しの函数ポインタが入る領域を用意します。取り敢えずここ「H8のプログラム開発(Linux C言語 編)」にあったそれっぽい部分を参考にしました。
そんでもって

extern "C" {
extern void (*start_ctors[])(void);
extern void (*end_ctors[])(void);
extern void (*start_dtors[])(void);
extern void (*end_dtors[])(void);
}

int main_no_maeni_yobu() {
  for (auto it = start_ctors; it != end_ctors; ++it) {
    (**it)();
  }
  const int ret = main();
  for (auto it = start_dtors; it != end_dtors; ++it) {
    (**it)();
  }
  return ret;
}

みたいな函数を用意してそこからmain()を呼ぶようにすれば良さげですかね。mainの前後でコンストラクタ/デストラクタの処理をやるわけです。start_ctorsはコンストラクタ函数ポインタの配列の先頭、end_ctorsは最後+1が入っているのでこれを回して函数を呼べばいいっぽいです。デストラクタも同様にすれば良さげでした。この辺は「第1回 基本言語仕様を支えるランタイム | 株式会社きじねこ」を参考にしました。
デストラクタに関して言えば、コンパイルオプションに-fno-use-cxa-atexitをつけておかないと色々なものが足りないとリンカエラーを起こすようで(___dso_handleとか___cxa_atexitのことです)、この辺り「MyOS/singleton2 - おーた('A`)の落書き帳」を見た感じこれらはダイナミックリンクライブラリを使う時に必要なものな雰囲気を受信したのでそんなものは使っていないとばっさり切りました。
で、最後に起動アセンブリで@main_no_maeni_yobuにjsrするようにすれば多分いい感じです。めでたしめでたし。