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

ゴリ押しでgccにてMakeを通す

id:higepon氏が発足し今尚開発が行われている、自作OS界隈では云わずと知れたMonaOS - Free Operating Systemですが、そのLinux上におけるtoolchainにはMINGWが使用されています。
そこで、GNU toolchainによってMakeを無理やり通してみた結果、何とか起動し動作が確認できたので、ざっくばらんに手順を記録しておきたいと思います。

はじめに

前提として以下の緩いルールを設けました。

実行形式
PEフォーマット、圧縮形式はナシ(.BIN と .ELF のみ)
ライブラリ
共有ライブラリはナシ(全てstaticリンク)
アセンブラ
nasmを使用する(gasへの変換はしない)

また、今回の環境は以下の通りです。

Mona mona-0.3.0alpha9
Host colinux-2.6.12-co-default
GCC 4.1.2(Debian 4.1.1-21)

share/configs

GNUのldのリンカスクリプト取得(User用)
  • --verboseオプションにて。ファイル名はmonapi.ldsとする
  • syntax errorになるような先頭数行と最終行は削除、またはコメントアウト
  • __executable_start と SIZEOF_HEADERS への値をカレントアドレス(.)へと修正
    • PROVIDE (__executable_start = .); . = SIZEOF_HEADERS;
  • .ctorセクションに、__CTOR_LIST__、__CTOR_END__とフラグ(0xFFFFFFFF/0)を定義
__CTOR_LIST__ = .;
LONG(-1);
 …コンストラクタの定義…
LONG(0);
__CTOR_END__ = .;
  • .dtorセクションも同様に__DTOR_LIST__、__DTOR_END__とフラグ(0xFFFFFFFF/0)を定義
MINGWのldのリンカスクリプト取得(Kernel用)
  • ファイル名はkernel.ldsとする
  • syntax errorになるような行は削除、またはコメントアウト
  • OUTPUT_FORMAT/OUTPUT_ARCH/SEARCH_DIRをGNUのものと同じにする
  • __section_alignment__ = 0x1000; を定義
Makefile.inc

Makefile.incはconfigureスクリプトにて生成されるので一旦、MINGWとしてconfigureスクリプトをトップディレクトリにて実行します。

% ./configure --mingw-prefix=/usr/bin/i586-mingw32msvc-

生成されたMakefile.incを以下のように修正しました。

  • BUILD_TARGET=ELF を追加
  • USER_START_FUNCTION のprefix(_)を削除
    • _user_start → user_start
  • SYMPREFIX を空指定に(_を削除)
  • NFLAGS
    • 出力フォーマットを"win32"から"elf"へ
    • -DBUILD_ON_LINUXを追加
monapi-bin.inc
  • .cppサフィックスルール
    • g++へのオプションに -fno-use-cxa-atexitを追加
  • TARGETルール
    • ldに-Tオプションでmonapi.ldsを指定
      • -T $(SHAREDIR)/configs/monapi.lds

-fno-use-cxa-atexit指定しない場合、__static_initialization_and_destruction_0関数がリンクされて、その関数内で参照している __dso_handletと__cxa_at_exitが無いと文句を言われてしまうためです。
2007-02-03 - memologueにて詳細な解説がなされています。

monapi-elf.inc
  • .cppサフィックスルール
    • g++へのオプションに -fno-use-cxa-atexitを追加
  • TARGETルール
    • ldに-Tオプションでmonapi.ldsを指定
      • -T $(SHAREDIR)/configs/monapi.lds
    • monaelfコマンドラインを削除

core/kernel

Makefile
  • ldに-Tオプションでkernel.ldsを指定
    • -T $(SHAREDIR)/configs/kernel.lds
apm_bios.asm
  • シンボルの _ プレフィックス削除

core/monalibc

Makefile
  • TARGET変数定義 に += で $(CRT_OBJECT)を追加
    • BUILD_TARGET=ELFだと追加されてないため
  • LINK変数定義の-lmonapi-imp を -lmonapi に変更
  • g++のオプションに以下を追加
-nostdinc -nostdlib -fno-exceptions -fno-rtti -fno-strict-aliasing
    • gxx_personarity_v0エラーが出るため

core/monapi

Makefile
  • installターゲットに$(CRT_OBJECT)を追加
_alloca.asm
  • シンボルの _ プレフィックス削除
messages.cpp
  • server_names の ".BN5"、".EX5" を ".BIN"、".ELF" に変更

core/shell_server

Makefile
  • BUILD_TARGET=ELF であった場合のinclude文を monapi-el5.inc から monapi-elf.inc へ
main.cpp
  • LookupMainThread("SCREEN.EX5")の引数を"SCREEN.ELF"に指定
Shell.cpp
  • commandExecuteでコマンドライン処理している辺りの name + ".EX5" や command + ".EX5" を ".ELF" に

core/monitor_server

main.cpp
  • すべての ".BN5" と ".EX5" を ".BIN"、".ELF"に

core/keyboard_server

Makefile
  • BUILD_TARGET=ELF であった場合のinclude文を monapi-el5.inc から monapi-elf.inc へ
  • ADDLINK変数定義の-lmonalibc-imp を -lmonalibc に変更

core/screen_server

Makefile
  • BUILD_TARGET=ELF であった場合のinclude文を monapi-el5.inc から monapi-elf.inc へ

core/mouse_server

  • screen_serverと同様

core/pe_server

Makefile
  • include文を monapi-bn5.inc から monapi-bin.inc へ

core/test

Makefile
  • $(TARGET).EX5:(INSTFILES) → $(TARGET).ELF:(INSTFILES)
  • ADDLINK/ADDLINKDEP変数を変更
  • include文を monapi-ex5.inc から monapi-elf.inc へ
test.h
  • TEST_SUCCESS マクロでprintfがある方を有効にする
    • 動作確認のため

tool/mkimg

MONITOR.CFG
  • すべての ".BN5" と ".EX5" を ".BIN"、".ELF"に
  • PEサーバとSCHEMEサーバの行をコメントしそれ以外は有効に
AUTOEXEC.MSH
  • testプログラム自動実行文を追加(バナー出力後あたりに)
    • @EXEC /APPS/TEST.APP/TEST.ELF

include/sys

types.h
  • 以下の定義を追記
#define __fastcall 	__attribute__((__fastcall__))
#define __declspec(x)	/*  */


Makeと実行

ソーストップディレクトリで以下を実行

% make
% cd tool/mkimg
% qemu -L /usr/share/qemu -m 128 -fda mona.img -no-kqemu -nographic -cdrom mona.iso -boot d -serial stdio

すると、printfしている内容が文字単位で<>で囲まれて出力されると思います。
グラフィック出力のないcolinuxでの動作確認のためグラフィック出力を無効(-nographic)にしています。*1
出力可能な環境であれば、-nographicを外すとシェルが動くはずです…。


まとめ

GNU/Linux初心者のため、コンパイラオプションの追加等はエラーを消すためにとりあえずなことろや、MonaOSの内部構造を全く知らないで無理やり変更しているので、いろいろ動かしてみると問題ありありだとおもいます。
完全に対応するためにはまだまだ課題が山積みですが、いろいろと勉強になりました。

*1:-nographic指定時、Ctrl-a c でコンソールをQEMUモニタに切り替え可能です