Linuxカーネル学習-システム呼び出し(fork)

5956 ワード

昨日一日かけてLinux 0を見ていました.11のカーネル、mainが表示されます.cのint()関数の時に1つのシステムに呼び出されて倒れにくくなりました(実は筆者のc、アセンブルなどの基礎はあまり強くありません.しかし何らかの原因で、このコアの穴に入って、冷たい水をかけられるのはよくあることです).そこでいろいろな資料をいろいろ検索しましたが、みんなが出した資料は千編一律で、最初からシステム呼び出しとは何かを紹介しているのではなく、一つ一つのシステム呼び出しの原理を確実に分析していないのです.どうせバラバラの言うことは基本的に同じで、见ても何も分からない......ps:笔者は本当にクズなので、理解できないかもしれません.
そこで私は自分で研究したと思います.まずinitのどこから始めますか.fork()というシステム呼び出しについて深く研究を始めました(実はそれほど深くはありませんが、ハハハ).それを実現する過程を追跡して、今やこれからも似たような問題に遭遇する人がいると思います.さらに、身につけた知識をもっと強固にしたいので、手書きでこのブログを書きました.では、本題を始めましょう.
まず、Linux 0についてお話しします.11バージョンのカーネルのfork()システム呼び出しは、システム呼び出しを分析します.
fork()関数を呼び出すとmain.cのinit()関数にfork()の呼び出しが表示されます.
  //   fork()         (   )。         ,fork()   0  ,
  //    (   )          。  180-184           。    
  //      0(stdin),       /etc/rc   ,   /bin/sh   ,     
  //        argv_rc  envp_rc     。       。
  if (!(pid = fork ()))
    {
      close (0);
      if (open ("/etc/rc", O_RDONLY, 0))
	_exit (1);		//         ,   (/lib/_exit.c,10)。
      execve ("/bin/sh", argv_rc, envp_rc);	//   /bin/sh      。
      _exit (2);		//  execve()       (   2,“        ”)。
    }

この関数はよく知られているはずですが、正確にはシステム呼び出しが新しいプロセスを作成するために使用されているはずです.しかし、カーネルにはこの関数の具体的なプロトタイプが見つからないことがわかります.では、どうやって実現したのでしょうか.エディタで定義を表示できます.source Insight 3を使用しています.unistdに関数のプロトタイプ定義があることを発見しました.
      int fork (void);//               。      235 
しかし、この関数のプロトタイプ定義しか見つかりませんが、ソースが見つかりません.このファイルには、次のような関数定義があります.
//                 。
//             。type name(void)。
// %0 - eax(__res),%1 - eax(__NR_##name)。  name         ,  __NR_       
//          ,                 。
//   :         0,     ,      errno,   -1。
#define _syscall0(type,name) \
type name(void) \
{ \
long __res; \
__asm__ volatile ( "int $0x80" \	//       0x80。
:"=a" (__res) \		//    ??eax(__res)。
:"" (__NR_
##name)); \			//           __NR_name。
      if (__res >= 0) \		//      >=0,       。
      return (type) __res; errno = -__res; \	//       ,   -1。
      return -1;}
このアセンブリ文を埋め込んだcプログラムを見たばかりの頃も霧で、何が起こっているのか分からなかったが、注釈によるとシステム呼び出しと大きな関係がある可能性があることが分かった.しかし、このsyscall(後の0,1,2…は持っているパラメータを表しているが、ここではひとまずsyscallと総称しよう)関数とfork関数の関係は不明である.その後、しつこく絡み合った無頼な質問と本をめくってみると、このようなことが分かった.
これらのシステムを使用して呼び出されたファイルには、mainなどの宣言があります.
/*
 *              -          (forking)         (COPY ON WRITE)!!!
 *       execve   。          。       fork()      main()  
 *     。           -     fork          ,      fork()  
 *         。
 *      pause  fork         ,    main()       ,       
 *          。
 */
static inline
_syscall0 (int, fork)		//  unistd.h        。          
	// Linux        0x80。           
	//   。        int fork()        。
	// syscall0       0      ,1   1    。
     static inline _syscall0 (int, pause)	// int pause()    :       ,  
	//       。
     static inline _syscall1 (int, setup, void *, BIOS)	// int setup(void * BIOS)    ,   
	// linux    (          )。
     static inline _syscall0 (int, sync)	// int sync()    :      。
にはstatic inlineがありますSyscall 0(int,fork)、このような声明は、明らかにfork()とsyscall()のつながりである.それでも明らかでなければ、声明、マクロ関数をすべて順番に展開し、
staticinline_Syscall 0(int,fork)をsyscall 0関数に持ち込み、マクロを置き換えると次のような関数になります.
void fork(void) 
{ 
	long __res; 
	__asm__ volatile ( "int $0x80" :"=a" (__res) :"" (__NR_fork)); 
      if (__res >= 0) 
      return (type) __res; errno = -__res; 
      return -1;
}
ハハハ、これがfork()関数です.forkを呼び出す前に、前のmainで宣言します.これがfork関数の作成と呼び出しです.(システムコード量を減らすためかもしれませんが、各システム呼び出しが関数のように宣言されると、60個のシステム呼び出しがあれば60個の関数が必要になります.このような方法では、わずかな関数にいくつかの関数宣言を加えるしかありません.これはそのうちの1つかもしれません).
この関数はどのように機能していますか?
上の埋め込みアセンブリ文では、このような文を見ることができますが、実際には詳細な説明もあります.私はあまり説明しません.システム呼び出しは0 x 80割り込みで実現され、int$0 x 80は0 x 80割り込みを呼び出すことを意味し、戻り値は_res,関数システム割込み呼び出し番号は_NR_nameとのリンク、nameがforkならシステム呼び出し番号は_NR_forkです.システム呼び出し番号はsys.hヘッダファイル中(切り取り):
extern int sys_setup ();	//            。 (kernel/blk_drv/hd.c,71)
extern int sys_exit ();		//     。 (kernel/exit.c, 137)
extern int sys_fork ();		//     。 (kernel/system_call.s, 208)
extern int sys_read ();		//    。 (fs/read_write.c, 55)
extern int sys_write ();	//    。 (fs/read_write.c, 83)
extern int sys_open ();		//     。 (fs/open.c, 138)

//          。            (int 0x80),     。
fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
  sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
  sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,
  sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount,
  sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm,
  sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access,
  sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir,
  sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,
  sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,
  sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
  sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
  sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,
  sys_setreuid, sys_setregid
};
実は_NR_fork対応マクロ定義は2、つまりfn_ptr sys_call_table[]の2番-sys_fork,これによりforkシステム呼び出しの具体的な実装もsys_に移行する.forkという関数に来ました.この関数の位置は
アドレス=sys_call_table + %eax * 4.(確認されていませんが、他のブログで見られます).次に、カーネル状態でのシステム呼び出しが具体的に実装されます.
最も重要なのは理解です
__asm__ volatile ( "int $0x80" :"=a" (__res) :"" (__NR_fork)); 
この言叶の上で、この言叶の中で、最も肝心なのは0 x 80号の中断で、中断処理とアセンブリプログラムに関わることが多いため、筆者は今もカーネルを理解し始めたばかりなので、多くの解釈をしないで、みんなは以下のいくつかの博文によって深く理解することができます:
ps:私は拭いて、突然ハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッハッ
Linuxシステム割込み処理プログラムint 0 x 80実現原理
GCCはC言語にアセンブリcallを埋め込むvolasile_Linuxカーネル——fork()関数作成プロセスLinuxシステム呼び出しの実装技術システム呼び出しの実装原理ここで著者の無私な奉仕に感謝します