实现一个系统调用来进行系统调用计数

来源:互联网 发布:.top新网域名有哪些 编辑:程序博客网 时间:2024/05/24 20:07

基础知识:

中断:是为了设备与 CPU 之间通信,中段是异步的,它的发生与系统处在用户模式还是在内核

模式无关,只决定于 EFLAGS 寄存器的一个标志位。中断的产生与当前正在执行的进程无关。

异常:是由当前正在执行的进程产生的。异常包括很多方面,有 fault,有 trap,有

programmable exception。fault 和 trap 最重要的一点区别是他们发生时所保存的 EIP 不

同。Fault 保存的 EIP 指向触发异常的那条指令;陷入保存的 EIP 指向触发异常的那条指令的下

一条指令。

系统调用:是用户程序与内核的接口,通过系统调用进程可以由用户模式转入内核模式,在内

核模式下完成相应的服务之后再返回到用户模式。

系统调用的过程:

1.系统调用初始化:在traps.c中,系统在初始化程序trap_init()中,通过调用

set_system_gate(0x80,&system_call)函数,在中断描述符表(idt)里面填入系统调用的处

理函数system_call,这就是每次用户执行指令int 0x80的处理函数

2.系统调用执行:根据system_call传入的系统调用号,在system_call_table中查到相应的

内核处理函数,执行。

3.系统调用的返回:通过ret_from_sys_call返回。返回之前会检测一些变量,根据这些变量跳

转到相应的地方去处理。

简述堆栈变化

int 0x80 :

pushl 用户ss

pushl 用户esp

pushl EFLAGS

pushl cs

pushl eip

SAVE_ALL:

pushl %es

pushl %ds

pushl %eax

pushl %ebp

pushl %edi

pushl %esi

pushl %edx

pushl %ecx

pushl %ebx

RESTORE_ALL:

popl %ebx

popl %ecx

popl %edx

popl %esi

popl %edi

popl %edp

popl %eax

popl %ds

popl %es

addl $4,%esp

程序调用的参数传递:

通过宏_syscallx来实现,比如_syscall0

_syscall0(int,pause)

经过宏替换后:

int pause()

{

   long __res;

   __asm__ volatile (“int $0x80”

               :”=a”(__res)

               :”” (__NR_pause));

   __syscall_return(int,__res);

}

同理

_syscall1(type,name,type1,arg1),_syscall2(type,name,type1,arg1,type2,arg2)...

 

 

 

基本思路:

1.linux­2.6.xx.x/arch/x86/kernel/syscall_table_32.S 中添加.long sys_countsyscalls

2.linux­2.6.xx.x/arch/x86/include/asm/unistd_32.h 添加一个 NR_countsyscalls 定义,注意将

__NR_syscalls 往下调整,这个宏为下界。

3.linux­2.6.xx.x/include/linux/syscalls.h 添加 asmlinkage long sys_countsyscalls();

4.linux­2.6.xx.x/kernel/sys.c 下添加

SYSCALL_DEFINE0(countsyscalls)

{

...

}

关于系统调用的统计:在 entry_32.S 中对系统调用进行劫持。

 

 

实验代码:

       1.  linux­2.6.xx.x/arch/x86/kernel/syscall_table_32.S 中添加.long sys_countsyscalls

      2. linux­2.6.xx.x/arch/x86/include/asm/unistd_32.h 添加一个

           #define NR_countsyscalls  338

      3. linux­2.6.xx.x/include/linux/syscalls.h 添加 asmlinkage long sys_countsyscalls();

      4. linux­2.6.xx.x/kernel/sys.c 下添加

           int call_table[NR_syscalls];

1604  void inc_count(int no) 

1605  { 

1606               call_table[no]++; 

1607 } 

1609  SYSCALL_DEFINE0(countsyscalls) 

1610     { 

1611     int i; 

1612     printk("­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­"); 

1613     for(i=0;i<NR_syscalls;i++) 

1614     { 

1615         printk("sys no. %d : %d/n",i,call_table[i]); 

1616     } 

1617     printk("­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­"); 

1618     return 0; 

1619     } 

           5. 对系统调用的入口进行劫持

           6.

529 ENTRY(system_call) 

 530     RING0_INT_FRAME         # can't unwind into user space anyway 

 531     pushl %eax          # save orig_eax 

 532     call inc_count     #此处调用计数函数

 533     CFI_ADJUST_CFA_OFFSET 4 

 534     SAVE_ALL 

 535     GET_THREAD_INFO(%ebp) 

 536                     # system call tracing in operation / emulation 

 537     testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp) 

 538     jnz syscall_trace_entry 

 539     cmpl $(nr_syscalls), %eax 

 540     jae syscall_badsys 

 541 syscall_call: 

     6. 测试代码

 4  int main() 

  5 { 

  6     syscall(338);

  7     return 0; 

  8 }