现在的位置: 首页 > 综合 > 正文

Linux0.11内核–系统中断处理程序int 0×80实现原理 .

2013年04月26日 ⁄ 综合 ⁄ 共 14840字 ⁄ 字号 评论关闭

 

系统调用是一个软中断,中断号是0x80,它是上层应用程序与Linux系统内核进行交互通信的唯一接口。通过int 0x80,就可使用内核资源。不过,通常应用程序都是使用具有标准接口定义的C函数库间接的使用内核的系统调用,即应用程序调用C函数库中的函数,C函数库中再通过int 0x80进行系统调用。
    所以,系统调用过程是这样的:
    应用程序调用libc中的函数->libc中的函数引用系统调用宏->系统调用宏中使用int 0x80完成系统调用并返回

下面是sys_call_table的定义文件

位于./include/sys.h

 

其中sys_call_table的类型是fn_ptr类型,其中sys_call_table[0]元素为sys_setup,它的类型是fn_ptr类型,它实际上是函数sys_setup的

入口地址。

它的定义如下:

typedef int (*fn_ptr) (); // 定义函数指针类型。

下面的实例代码有助于理解函数指针:

  1. #include<stdio.h>   
  2. typedef int (*MyFunc)();  
  3. MyFunc Func1;  
  4. int Func2()  
  5. {  
  6.     printf("This is a sample output!/n");  
  7.     return 0;  
  8. }  
  9. int main()  
  10. {  
  11.     Func1=Func2;  
  12.     //Func2();   
  13.     //(*Func1)();   
  14.     printf("%x/n",(*Func1));  
  15.     printf("%x/n",Func2);  
  16.     return 0;  
  17. }  

 

 

system_call系统调用入口函数

  1. #### int 0x80 --linux 系统调用入口点(调用中断int 0x80,eax 中是调用号)。  
  2. .align 2  
  3. _system_call:  
  4. cmpl $nr_system_calls-1,%eax # 调用号如果超出范围的话就在eax 中置-1 并退出。  
  5. ja bad_sys_call  
  6. push %ds # 保存原段寄存器值。  
  7. push %es  
  8. push %fs  
  9. pushl %edx # ebx,ecx,edx 中放着系统调用相应的C 语言函数的调用参数。  
  10. pushl %ecx # push %ebx,%ecx,%edx as parameters  
  11. pushl %ebx # to the system call  
  12. movl $0x10,%edx # set up ds,es to kernel space  
  13. mov %dx,%ds # ds,es 指向内核数据段(全局描述符表中数据段描述符)。  
  14. mov %dx,%es  
  15. movl $0x17,%edx # fs points to local data space  
  16. mov %dx,%fs # fs 指向局部数据段(局部描述符表中数据段描述符)。  
  17. # 下面这句操作数的含义是:调用地址 = _sys_call_table + %eax * 4。参见列表后的说明。  
  18. # 对应的C 程序中的sys_call_table 在include/linux/sys.h 中,其中定义了一个包括72 个  
  19. # 系统调用C 处理函数的地址数组表。
      
  20. call _sys_call_table(,%eax,4)  
  21. pushl %eax # 把系统调用号入栈。  
  22. movl _current,%eax # 取当前任务(进程)数据结构地址??eax。  
  23. # 下面97-100 行查看当前任务的运行状态。如果不在就绪状态(state 不等于0)就去执行调度程序。  
  24. # 如果该任务在就绪状态但counter[??]值等于0,则也去执行调度程序。  
  25. cmpl $0,state(%eax) # state  
  26. jne reschedule  
  27. cmpl $0,counter(%eax) # counter  
  28. je reschedule  
  29. # 以下这段代码执行从系统调用C 函数返回后,对信号量进行识别处理。  
  30. ret_from_sys_call:  
  31. # 首先判别当前任务是否是初始任务task0,如果是则不必对其进行信号量方面的处理,直接返回。  
  32. # 103 行上的_task 对应C 程序中的task[]数组,直接引用task 相当于引用task[0]。  
  33. movl _current,%eax # task[0] cannot have signals  
  34. cmpl _task,%eax  
  35. je 3f # 向前(forward)跳转到标号3。  
  36. # 通过对原调用程序代码选择符的检查来判断调用程序是否是超级用户。如果是超级用户就直接  
  37. # 退出中断,否则需进行信号量的处理。这里比较选择符是否为普通用户代码段的选择符0x000f  
  38. # (RPL=3,局部表,第1 个段(代码段)),如果不是则跳转退出中断程序。  
  39. cmpw $0x0f,CS(%esp) # was old code segment supervisor ?  
  40. jne 3f  
  41. # 如果原堆栈段选择符不为0x17(也即原堆栈不在用户数据段中),则也退出。  
  42. cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ?  
  43. jne 3f  
  44. # 下面这段代码(109-120)的用途是首先取当前任务结构中的信号位图(32 位,每位代表1 种信号),  
  45. # 然后用任务结构中的信号阻塞(屏蔽)码,阻塞不允许的信号位,取得数值最小的信号值,再把  
  46. # 原信号位图中该信号对应的位复位(置0),最后将该信号值作为参数之一调用do_signal()。  
  47. # do_signal()在(kernel/signal.c,82)中,其参数包括13 个入栈的信息。  
  48. movl signal(%eax),%ebx # 取信号位图??ebx,每1 位代表1 种信号,共32 个信号。  
  49. movl blocked(%eax),%ecx # 取阻塞(屏蔽)信号位图??ecx。  
  50. notl %ecx # 每位取反。  
  51. andl %ebx,%ecx # 获得许可的信号位图。  
  52. bsfl %ecx,%ecx # 从低位(位0)开始扫描位图,看是否有1 的位,  
  53. # 若有,则ecx 保留该位的偏移值(即第几位0-31)。  
  54. je 3f # 如果没有信号则向前跳转退出。  
  55. btrl %ecx,%ebx # 复位该信号(ebx 含有原signal 位图)。  
  56. movl %ebx,signal(%eax) # 重新保存signal 位图信息??current->signal。  
  57. incl %ecx # 将信号调整为从1 开始的数(1-32)。  
  58. pushl %ecx # 信号值入栈作为调用do_signal 的参数之一。  
  59. call _do_signal # 调用C 函数信号处理程序(kernel/signal.c,82)  
  60. popl %eax # 弹出信号值。  
  61. 3: popl %eax  
  62. popl %ebx  
  63. popl %ecx  
  64. popl %edx  
  65. pop %fs  
  66. pop %es  
  67. pop %ds  
  68. iret  

./include/unistd.h文件中系统调用符号和调用号的对应定义

  1. // 以下是内核实现的系统调用符号常数,用于作为系统调用函数表中的索引值。( include/linux/sys.h )  
  2. #define __NR_setup 0        /* used only by init, to get system going */  
  3. /* __NR_setup 仅用于初始化,以启动系统 */  
  4. #define __NR_exit 1   
  5. #define __NR_fork 2
      
  6. #define __NR_read 3   
  7. #define __NR_write 4
      
  8. #define __NR_open 5   
  9. #define __NR_close 6
      
  10. #define __NR_waitpid 7   
  11. #define __NR_creat 8
      
  12. #define __NR_link 9   
  13. #define __NR_unlink 10
      
  14. #define __NR_execve 11   
  15. #define __NR_chdir 12
      
  16. #define __NR_time 13   
  17. #define __NR_mknod 14
      
  18. #define __NR_chmod 15   
  19. #define __NR_chown 16
      
  20. #define __NR_break 17   
  21. #define __NR_stat 18
      
  22. #define __NR_lseek 19   
  23. #define __NR_getpid 20
      
  24. #define __NR_mount 21   
  25. #define __NR_umount 22
      
  26. #define __NR_setuid 23   
  27. #define __NR_getuid 24
      
  28. #define __NR_stime 25   
  29. #define __NR_ptrace 26
      
  30. #define __NR_alarm 27   
  31. #define __NR_fstat 28
      
  32. #define __NR_pause 29   
  33. #define __NR_utime 30
      
  34. #define __NR_stty 31   
  35. #define __NR_gtty 32
      
  36. #define __NR_access 33   
  37. #define __NR_nice 34
      
  38. #define __NR_ftime 35   
  39. #define __NR_sync 36
      
  40. #define __NR_kill 37   
  41. #define __NR_rename 38
      
  42. #define __NR_mkdir 39   
  43. #define __NR_rmdir 40
      
  44. #define __NR_dup 41   
  45. #define __NR_pipe 42
      
  46. #define __NR_times 43   
  47. #define __NR_prof 44
      
  48. #define __NR_brk 45   
  49. #define __NR_setgid 46
      
  50. #define __NR_getgid 47   
  51. #define __NR_signal 48
      
  52. #define __NR_geteuid 49   
  53. #define __NR_getegid 50
      
  54. #define __NR_acct 51   
  55. #define __NR_phys 52
      
  56. #define __NR_lock 53   
  57. #define __NR_ioctl 54
      
  58. #define __NR_fcntl 55   
  59. #define __NR_mpx 56
      
  60. #define __NR_setpgid 57   
  61. #define __NR_ulimit 58
      
  62. #define __NR_uname 59   
  63. #define __NR_umask 60
      
  64. #define __NR_chroot 61   
  65. #define __NR_ustat 62
      
  66. #define __NR_dup2 63   
  67. #define __NR_getppid 64
      
  68. #define __NR_getpgrp 65   
  69. #define __NR_setsid 66
      
  70. #define __NR_sigaction 67   
  71. #define __NR_sgetmask 68
      
  72. #define __NR_ssetmask 69   
  73. #define __NR_setreuid 70
      
  74. #define __NR_setregid 71  

 

这是一系列宏,它们的定义在unistd.h中,基本形式为#define _NR_name value,name为系统函数名字,value是一个整数值,是name所对应的系统函数指针在sys_call_table中的偏移量。

 

系统调用宏也在本文件内定义,采用内联汇编,如下:

  1. // 以下定义系统调用嵌入式汇编宏函数。   
  2. // 不带参数的系统调用宏函数。type name(void)。   
  3. // %0 - eax(__res),%1 - eax(__NR_##name)。其中name 是系统调用的名称,与 __NR_ 组合形成上面  
  4. // 的系统调用符号常数,从而用来对系统调用表中函数指针寻址。   
  5. // 返回:如果返回值大于等于0,则返回该值,否则置出错号errno,并返回-1。  
  6. #define _syscall0(type,name) /
      
  7. type name(void) /  
  8. { /  
  9. long __res; /  
  10. __asm__ volatile ( "int $0x80" /    // 调用系统中断0x80。  
  11. :"=a" (__res) /     // 返回值??eax(__res)。  
  12. :"" (__NR_##name)); /           // 输入为系统中断调用号__NR_name。  
  13.       if (__res >= 0) /      // 如果返回值>=0,则直接返回该值。  
  14.       return (type) __res; errno = -__res; /    // 否则置出错号,并返回-1。  
  15.       return -1;}  
  16. // 有1 个参数的系统调用宏函数。type name(atype a)
      
  17. // %0 - eax(__res),%1 - eax(__NR_name),%2 - ebx(a)。  
  18. #define _syscall1(type,name,atype,a) /  
  19. type name(atype a) /  
  20. { /  
  21. long __res; /  
  22. __asm__ volatile ( "int $0x80" /  
  23. "=a" (__res) /  
  24. "" (__NR_##name), "b" ((long)(a))); /  
  25. if (__res >= 0) /  
  26. return (type) __res; /  
  27. errno = -__res; /  
  28. return -1; /  
  29. }  
  30. // 有2 个参数的系统调用宏函数。type name(atype a, btype b)  
  31. // %0 - eax(__res),%1 - eax(__NR_name),%2 - ebx(a),%3 - ecx(b)。  
  32. #define _syscall2(type,name,atype,a,btype,b) /  
  33. type name(atype a,btype b) /  
  34. { /  
  35. long __res; /  
  36. __asm__ volatile ( "int $0x80" /  
  37. "=a" (__res) /  
  38. "" (__NR_##name), "b" ((long)(a)), "c" ((long)(b))); /  
  39. if (__res >= 0) /  
  40. return (type) __res; /  
  41. errno = -__res; /  
  42. return -1; /  
  43. }  
  44. // 有3 个参数的系统调用宏函数。type name(atype a, btype b, ctype c)  
  45. // %0 - eax(__res),%1 - eax(__NR_name),%2 - ebx(a),%3 - ecx(b),%4 - edx(c)。  
  46. #define _syscall3(type,name,atype,a,btype,b,ctype,c) /  
  47. type name(atype a,btype b,ctype c) /  
  48. { /  
  49. long __res; /  
  50. __asm__ volatile ( "int $0x80" /  
  51. "=a" (__res) /  
  52. "" (__NR_##name), "b" ((long)(a)), "c" ((long)(b)), "d" ((long)(c))); /  
  53. if (__res>=0) /  
  54. return (type) __res; /  
  55. errno=-__res; /  
  56. return -1; /  
  57. }  

抱歉!评论已关闭.