-277

binary - よりポータブルな無限ループという記事があったので,Plan9で試してみた.

コンパイル通ったと思ったら,ファイルは空で,実行できなかった.

cpu% cat infinite.c
int main=-277;
cpu% 8c infinite.c
cpu% 8l infinite.8
cpu% 8.out
8.out: '/bin/8.out' file does not exist
cpu% ls -l 8.out
--rwxrwxr-x M 1832969 oraccha oraccha 0 Dec 24 18:48 8.out

アセンブリをみると,mainがテキストじゃなくてデータセクションになっているね.

cpu% 8c -S infinite.c
	DATA	main+0(SB)/4,$-277
	GLOBL	main+0(SB),$4
	END	,

上の実行例で奇妙なのは,ファイルが空だけど,存在するのに,"file does not exist"になること.次のように,"./"をプレフィックスすると予想通りのエラーメッセージを返す.

cpu% ./8.out
./8.out: exec header invalid

不思議だけど,ここでシステムコールのエラー処理について横道にそれる.システムコールがエラーで終了した場合,UNIXではerrnoという整数値にその原因がセットされるが,Plan9では,文字列でセットされる.errnoはライブラリが保持するグローバル変数だけど,Plan9の場合は,カーネルのプロセス構造体(struct Proc)の中にエラー文字列を保持する領域(syserrstrの先のerrbuf0かerrbuf1に格納されている)があって,errstr(2)システムコールによってその文字列を取り出す.

9/port/portdat.h:
  612: struct Proc
  613: {

  697:         char   *syserrstr;       /* last error from a system call, errbu\f0 or 1 */
  698:         char   *errstr;  /* reason we're unwinding the error stack, errb\uf1 or 0 */
  699:         char   errbuf0[ERRMAX];
  700:         char   errbuf1[ERRMAX];

UNIXでもおなじみのperror()の実装は次のようになっている.10行目でerrstr()を呼んでいる.

libc/port/perror.c:
    4: void
    5: perror(char *s)
    6: {
    7:         char buf[ERRMAX];
    8:
    9:         buf[0] = '\0';
   10:         errstr(buf, sizeof buf);
   11:         if(s && *s)
   12:                 fprint(2, "%s: %s\n", s, buf);
   13:         else
   14:                 fprint(2, "%s\n", buf);
   15: }

(追記 2007-01-06) Cがダメなら,アセンブリで書けばいいんだけど,やるだけ野暮ってもんか.

cpu% cat infinite.s
TEXT _main(SB),$0
     WORD $-277;
cpu% 8a infinite.s
cpu% 8l -o infinite infinite.8
cpu% infinite