crt*.oに頼らないHello, world!!プログラム
crt*.oに頼らないHello, world!!プログラムを書いてみました(ちょっとパディングの入れ方が自信ないですけど…)。
ただHello, world!!を出力するだけなんてたいしたことないじゃんと思うかもしれませんが、このプログラムをよくよく見ると、プログラム内で直にソフトウェア割込みを発生させてカーネルに制御を移しているのがわかると思います。普段はlibcの層に隠蔽されているのであまり意識しないと思いますが、システムコールの正体はソフトウェア割込みだというのを知っておいた方がいいと思います。
ちなみにNetBSDでシステムコールを呼ぶ場合には、システムコールの引数をスタックに積んで、システムコールの番号をeaxレジスタにおいてソフトウェア割込みを発生させます。Linuxの場合は、確かシステムコールの引数も(数個までは)レジスタを使っていたと記憶しています。
そうそう、NetBSDでは.note.netbsd.identセクションがないとexec(3)がENOEXECで失敗します。このことを知らずにはまりました。
ファイル: tiny_hello.s
.text .globl sys_exit sys_exit: mov $0x1,%eax int $0x80 .globl sys_write sys_write: mov $0x4,%eax int $0x80 ret .globl _start _start: pushl $15 pushl $.LC0 pushl $1 call sys_write pushl $123 call sys_exit .section ".rodata" .LC0: .string "Hello, world!!\n" .section ".note.netbsd.ident", "a" .p2align 2 .long 7 .long 4 .long 1 .ascii "NetBSD\0\0" .long 200000200
コンパイルは、以下のように行います。-nostdlibを付けてcrt*.oなどをリンクしないように、-sでシンボルを付けないようにしています。
$ gcc -Wall -nostdlib -s -o tiny_hello tiny_hello.s
できたプログラムのサイズは、564バイトでした。これ以上ダイエットするには、リンカを使わずに自分でELFの構造を出力する必要があると思います。さすがにそこまでは…
参考: http://www.netbsd.org/ja/Documentation/kernel/elf-notes.html