備忘録やめた

備忘録として使用していたけどやめた.このブログに載せてあるコードのライセンスは別途記載がない限りWTFPL OR NYSLです.

「はりぼてOS」をC++で書く時の注意点

このブログを大体2/3年放置していたようだけど,なんか勿体無いし,アウトプットはいいことなのでまた書くことにした.

30日でできる! OS自作入門

30日でできる! OS自作入門

この有名な自作OS本を数ヶ月前に購入した.購入した直後ははじめの機械語をポチポチ入力したり,アセンブリ言語で書くことに嫌気が差してそのまま幾許か放置していたけどやる気が戻ってきたので再開した.

この本はアセンブリ言語で書くのはなるべく少なく,できるだけC言語で書こうという方針である.コンパイルなどのツールは付属のCD-ROMにあるソフトを用いることが想定されているが,別に用いることなくGCCGNU Makeを使用することもできる1

C言語導入直後は楽しくなってきたけど,キューを自作したりマウスポインタを扱ってきたところでクラスを使用したくなった.そうだ,C++で書こう,と決心してもう一度はじめからC++で書き直すことにした.その時にいくつかトラブったところがあったのでそれを書き連ねる.

オブジェクトファイルのリンク

『30日でできる!OS自作入門』のメモリンカスクリプトを使用すると,C言語ではリンクに成功するが,C++ではリンクに失敗する.

マングリング

C++には関数のオーバーロードを行うため,マングリング2という処理が行われる.この処理のために,リンカスクリプトでいわゆるmain関数(あるいはこの本の場合HariMain関数)のアドレスを指定したり,アセンブリファイルで割り込み処理の時にC++で定義されたハンドラを呼び出したり,C++のコードからアセンブリファイル内の関数を呼び出したりすることが単純にはできない.これらの原因は,マングリングによってオブジェクトファイル内で関数名がそのままの名前では登録されず,修飾された名前が登録されてしまうためである.従っていわゆるmain関数やハンドラなどに関してはマングリングをしてはならない.

これらの関数でマングリングを行わない場合,extern "C"{ ... }で関数プロトタイプ宣言を囲う必要がある.

extern "C" {
void IoHlt();
void IoCli();
void IoSti();
void IoStiHlt();
void IoOut8(int port, int data);
int IoIn8(int port);
int IoLoadEflags();
void IoStoreEflags(int eflags);

void LoadGdtr(int limit, int addr);
void LoadIdtr(int limit, int addr);

void AsmInterruptHandler21();
void AsmInterruptHandler27();
void AsmInterruptHandler2c();

int LoadCr0();
void StoreCr0(int cr0);

unsigned AsmCheckMemorySize(unsigned start, unsigned end);
}

このようにすることで,囲いの中で定義された関数はマングリングが行われない.

あるいは,関数定義の際に頭にextern "C"をつける.

extern "C" void OSMain()
{
    MousePointer mouse_pointer;
    MouseDevice mouse_device;
    InitOS(mouse_device, mouse_pointer);

    while (1) {
        MainLoop(mouse_device, mouse_pointer);
    }
}

こうすることで,例えばこの場合はOSMain関数のみマングリングを回避することができ,リンクエラーを回避できる.

リンカスクリプト

先程のリンカスクリプトの18行目の以下の記述

.text : { *(.text) }

C言語ではこれでリンカに成功するが,C++だと例えばクラス関係はは.text.(装飾されたクラス名やメソッド)に配置されたり,.text.startupなるものが登場し,アドレスの重複でリンクに失敗する.

これを解決するには,ワイルドカードを使用してすべて.textに突っ込めば良い.

.text : { *(.text*) }

僕が突っかかったのはここらへん.ただ,僕自身まだ最後まで完成していないどころか10日目すら到達していないので,ここから新たな問題が発生するかもしれない.

現在制作中のOS.My C++ OSとかいう適当な名前だけど,いい名前が思いつかない.世の中に出回っているOSやプログラミング言語は本当に素晴らしい名前を持っていると実感する.本の内容をすべて実装し終えたら,自作コンパイラをこのOSの中に実装したい(フラグではない).


  1. 30日でできる!OS自作入門(3日目)[Ubuntu16.04/NASM]C言語導入の項を参照してください.

  2. マングリングについてはC++のマングルとextern “C” {を参照してください.