orange's学习--第十章:为自己的操作系统编写应用程序

可无论Init进程fork出多少进程,它也都只是Init而已。所以我们还需要一个系统调用,它就是exec( )。exec的语义很简单,它将当前的进程映像替换成另一个。也就是说,我们可以从硬盘上读取另一个可执行的文件,用它替换掉刚刚被fork出来的子进程,于是被替换的子进程摇身一边,就成了彻头彻尾的新鲜进程了。

以shell中常见的echo命令为例。我们输入“echo  hello  world”,shell就会fork出一个子进程A,这时A跟shell一模一样,fork结束后父进程和子进程分别判断自己的fork(  )返回值,如果是0则表明当前进程为子进程A,这时A马上执行一个exec(),于是进程A的内存映像被echo替换,它就变成echo了。

echo将以操作系统中普通应用程序的身份出现,它跟操作系统的接口是系统调用。其实本质上,一个应用程序只能调用两种东西:属于自己的函数,以及中断(系统调用其实就是软中断)。可是根据我们写程序的经验,一个应用程序通常都会调用一些现成的函数,很少见写程序时里面满是中断调用的。这是因为编译器偷偷地为我们链接了C运行时库(CRT),库里面有已经编译好的库函数代码。这样两者链接起来,应用程序就能正确运行了。

假如我们要写一个echo,最笨的办法就是将send_recv(  )、printf(  )、write(  )等所有用到的系统调用的代码都复制到源文件中,然后编译一下。这肯定是能成功的,但更优雅的做法是制作一个类似C运行时库的东西。我们把之前已经写就的应用程序可以使用的库函数单独链接成一个文件,每次写应用程序的时候直接链接起来就好了。

orange's学习--第十章:为自己的操作系统编写应用程序_第1张图片

orange's学习--第十章:为自己的操作系统编写应用程序_第2张图片

千万不要小看_start,虽然只有寥寥几行,但它肩负三项使命:
为main( )函数准备参数:argc和argv;
调用main( );
将main( )函数的返回值通过exit( )传递给父进程;

orange's学习--第十章:为自己的操作系统编写应用程序_第3张图片

这里使用0x1000入口地址,因为init进程使用的kernel.bin的内存分布,所以必须保持一致。

 

你可能感兴趣的:(orang's,于渊著)