当前位置:  技术问答>linux和unix

挥泪大甩分,关于系统函数fork函数定义的具体实现

    来源: 互联网  发布时间:2016-05-29

    本文导语:  内核是linux0.11版本,里面的fork()用于创建子进程。 但我现在在找这个函数的具体定义时遇到了一些困难。 先把我的查找过程说下: 1、init里的main.c中有static inline _syscall0 (int, fork); 2、在unistd.h中找到_syscall0是个宏...

内核是linux0.11版本,里面的fork()用于创建子进程。
但我现在在找这个函数的具体定义时遇到了一些困难。
先把我的查找过程说下:
1、init里的main.c中有static inline _syscall0 (int, fork);
2、在unistd.h中找到_syscall0是个宏,定义如下
#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;}
进行参数替换
感觉是int fork(void){....};
具体实现主要是:
__asm__ volatile ( "int $0x80"  // 调用系统中断0x80。
:"=a" (__res)  // 返回值??eax(__res)。
:"" (__NR_
##name)); 其中的__NR_##name是2,用来在一个指针函数的数组中作为索引号用的
这个数组定义如下:
typedef int (*fn_ptr) ();
在sys.h中
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_##name的值为2感觉正好对应着上面那个数组里的sys_call_table[2](也就是sys_fork)
感觉有点眉目了
3、继续解释这个指令
__asm__ volatile ( "int $0x80" 	// 调用系统中断0x80。
:"=a" (__res)  // 返回值??eax(__res)。
:"" (__NR_
##name));

感觉主要是调用系统中断0x80
4、在汇编代码system_call.s中找到该中断的中断处理函数
大概如下
#### int 0x80 --linux 系统调用入口点(调用中断int 0x80,eax 中是调用号)。
.align 2
_system_call:
cmpl $nr_system_calls-1,%eax # 调用号如果超出范围的话就在eax 中置-1 并退出。
ja bad_sys_call
5.5 system_call.s 程序
push %ds # 保存原段寄存器值。
push %es
push %fs
pushl %edx # ebx,ecx,edx 中放着系统调用相应的C 语言函数的调用参数。
pushl %ecx # push %ebx,%ecx,%edx as parameters
pushl %ebx # to the system call
movl $0x10,%edx # set up ds,es to kernel space
mov %dx,%ds # ds,es 指向内核数据段(全局描述符表中数据段描述符)。
mov %dx,%es
movl $0x17,%edx # fs points to local data space
mov %dx,%fs # fs 指向局部数据段(局部描述符表中数据段描述符)。

# 下面这句操作数的含义是:调用地址 = _sys_call_table + %eax * 4。参见列表后的说明。
# 对应的C 程序中的sys_call_table 在include/linux/sys.h 中,其中定义了一个包括72 个
# 系统调用C 处理函数的地址数组表。
call _sys_call_table(,%eax,4)
如果上面的eax放的是__NR_##name,即2
那么call _sys_call_table(,%eax,4)
相当于call sys_fork()
在该文件的下面一点找到该函数的定义
#### sys_fork()调用,用于创建子进程,是system_call 功能2。原形在include/linux/sys.h 中。
# 首先调用C 函数find_empty_process(),取得一个进程号pid。若返回负数则说明目前任务数组
# 已满。然后调用copy_process()复制进程。
.align 2
_sys_fork:
call _find_empty_process # 调用find_empty_process()(kernel/fork.c,135)。
testl %eax,%eax
js 1f
push %gs
pushl %esi
pushl %edi
pushl %ebp
pushl %eax
call _copy_process # 调用C 函数copy_process()(kernel/fork.c,68)。
addl $20,%esp # 丢弃这里所有压栈内容。
1: ret
里面的_find_empty_process和copy_process()就是fork的主要子函数了.

问题1:请问我这个思路是不是对的。
问题2:汇编调用C函数为什么名字不一样啊
汇编里是_find_empty_process 而在fork.c里该函数名字是find_empty_process()
汇编这样调用能找到这个函数么????
问题3:__asm__ volatile ( "int $0x80"  // 调用系统中断0x80。
:"=a" (__res)  // 返回值??eax(__res)。
:"" (__NR_
##name));这个内嵌汇编里的__NR_##name值是怎么传给eax的?以让后面的call _sys_call_table(,%eax,4)正确调用sysfork;
希望能给我详细讲解这条指令:__asm__ volatile (仅这条)调用中断int $0x80的具体操作
谢谢了
80分
闲少还可以继续加!

|

问题1:请问我这个思路是不是对的。

貌似大家都是这么干的!


问题2:汇编调用C函数为什么名字不一样啊

gcc编译器在生成汇编代码,其函数名及变量名前都会都会加_,所以汇编在使用时必须在其前面加_


问题3:__asm__ volatile ( "int $0x80"  // 调用系统中断0x80。 
:"=a" (__res)  // 返回值??eax(__res)。 
:"" (__NR_ ##name));这个内嵌汇编里的__NR_##name值是怎么传给eax的?以让后面的call _sys_call_table(,%eax,4)正确调用sysfork; 
希望能给我详细讲解这条指令:__asm__ volatile (仅这条)调用中断int $0x80的具体操作 

貌似这个属于早期的gcc版本形式的嵌入式汇编: 
__asm__ volatile ( "int $0x80"      // 告诉编译器不要优化这条指令,其内容为调用系统中断0x80 
:"=a" (__res)                     // 输出部:中断调用的返回值 eax 与变量 _res 保持一致 
:"" (__NR_ ##name));                // 输入部:用__NR_##name对应的值来初始化寄存器eax 

|
帮up

|
真是好贴!

|
问题1:请问我这个思路是不是对的。
---------------------------------------------------------------------------
差不多,但是有一個地方需要強調一下。static inline _syscall0 (int, fork),這個實際上隱含指出了系統調用的參數個數,注意這裡是以0結尾的,也就是說這個系統調用不需要傳遞參數。你應該還能從代碼中看到_syscall1,_syscall2這樣的定義。

问题2:汇编调用C函数为什么名字不一样啊
---------------------------------------------------------------------------
gcc的C編譯器compile的時候,會在函數名字前面加上一個下劃綫,所以在彙編裏面調用C的函數的時候,要手動的加上這個下劃綫。注意:這裡說的是C編譯器,不包括C++的,C++的編譯器和C的有很多的不同,所以才會有extern "C"的存在。

汇编里是_find_empty_process 而在fork.c里该函数名字是find_empty_process()
汇编这样调用能找到这个函数么????
---------------------------------------------------------------------------
這個已經在問題2中回答了。

问题3:__asm__ volatile ( "int $0x80"  // 调用系统中断0x80。
:"=a" (__res)  // 返回值??eax(__res)。
:"" (__NR_
##name));这个内嵌汇编里的__NR_##name值是怎么传给eax的?以让后面的call _sys_call_table(,%eax,4)正确调用sysfork;
----------------------------------------------------------------------------
__asm__          這個是關鍵字,C裏面內嵌AT&T的彙編需要這個關鍵字
volatile         這個關鍵字的含義是是說,不要對內嵌的彙編語句做任何的優化
int $0x80        彙編指令。調用0x80中斷,linux下的軟中斷
"=a" (__res)     返回值保存在%eax寄存器中,然後轉存到變數res裏面去
:"" (__NR_##name)這裡是系統終端號,在unistd.h裏面定義了

|
帮顶

|
学习!

|

客气了,大家互相学习,呵呵

|
貌似还没结贴?。。我也来说下吧。最近也刚开始研究这些东西,有说的不对的地方请指正。

前面的问题大家都说了,我只说下最后一个吧。


问题3:__asm__ volatile ( "int $0x80"  // 调用系统中断0x80。 
:"=a" (__res)  // 返回值??eax(__res)。 
:"" (__NR_ 
##name));这个内嵌汇编里的__NR_##name值是怎么传给eax的?以让后面的call _sys_call_table(,%eax,4)正确调用sysfork; 
希望能给我详细讲解这条指令:__asm__ volatile (仅这条)调用中断int $0x80的具体操作 
谢谢了 
80分 
闲少还可以继续加!
~~~~~~~~~~~~~~~~
__asm__ volatile ( "int $0x80"     // 调用系统中断0x80。
:"=a" (__res)         // 返回值??eax(__res)。
:"" (__NR_
##name));

开头你自己也说了NR_name 是定义的好的值。具体在unistd.h>头文件里。怎么传给eax的?:"" (__NR_ 
##name) 这条语句就是传给eax的意思。引号中省略表示用和输出一样的寄存器,也就是输出中的a(eax)。gcc嵌入汇编的格式你应该了解吧。int $0x80就是调用系统中断了,设置系统中断的操作在sched.c 最后一行 set_system_gate(0x80,&system_call); set_system_gate是一个嵌入式宏汇编语句,设置中断描述符表表项。具体实现在system.h.这样调用0x80系统中断后,执行的是system_call  eax中存放的是定义好的NR_name的值,以后处理过程你都说了。

    
 
 

您可能感兴趣的文章:

 
本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • 挥泪大送分
  • 超级菜鸟挥泪(是热泪)进军Linux,决定明天安装Redhat Linux9!向各位前辈请教。


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3