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書いてみません!?