vx32-gccとlibvxcとvxrun

と、ここでしばらく考えてみる。vx32-gccがどんなバイナリを出力するとかというと、

$ vx32-gcc hello.c 
$ file a.out 
a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped

ELF形式だ。当然、実行はできない。

$ ./a.out
-bash: ./a.out: cannot execute binary file

vx32-gccが普通のgccと何が違うのか、まだわかっていないが、libcにはlibvxcという独自のものが使われている。ベースになっているのはFreeBSDのlibcみたいだけど、システムコール呼び出しはすべてvx32のトラップ(正確にはsyscall命令を実行する)に置き換えられる。例えば、openは、こんな感じ。

int open(const char *path, int flags, int mode)
{
	return syscall(VXSYSOPEN, (int)path, flags, mode, 0, 0);
}

vx32にはこのa.outを実行できる、vxrunというプログラムが同梱されている。これもvxlinuxと同様なループになっていて、vxproc_runがVXTRAP_SYSCALLで中断されたら、システムコール処理をする。(vxlinuxとvxrunの違いは前者がLinuxホストOS上でLinuxの実行バイナリを変更なしで実行できるのに対して、vxrunはOS非依存な仕組みである。)

static void dosyscall(vxproc *proc)
{
    :
	switch (NUM) {
    :
	case VXSYSOPEN:
		addr = ARG1;
		mode = ARG2;
		umode = mode&3;
		if(mode & VXC_O_CREAT)
			umode |= O_CREAT;
		if(mode & VXC_O_EXCL)
			umode |= O_EXCL;
		if(mode & VXC_O_NOCTTY)
			umode |= O_NOCTTY;
		if(mode & VXC_O_TRUNC)
			umode |= O_TRUNC;
		if(mode & VXC_O_APPEND)
			umode |= O_APPEND;
		if(mode & VXC_O_NONBLOCK)
			umode |= O_NONBLOCK;
		if(mode & VXC_O_SYNC)
			umode |= O_SYNC;
		if (!checkstring(proc->mem, m->base, addr))
			goto einval;
		ret = open((char*)m->base+addr, umode, ARG3);
		if(trace)
			fprintf(stderr, "open %s %#x %#o => %d\n", (char*)m->base+addr, ARG2, ARG3, ret);
		break;

見てわかるように、vx32のシステムコールをホストOSへのシステムコール呼出しに書き換えている。

9vxも似たような流れになるんだろう。

こんな感じでユーザレベルOS書いてみません!?