中断:是为了设备与 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.linux2.6.xx.x/arch/x86/kernel/syscall_table_32.S 中添加.long sys_countsyscalls
2.linux2.6.xx.x/arch/x86/include/asm/unistd_32.h 添加一个 NR_countsyscalls 定义,注意将
__NR_syscalls 往下调整,这个宏为下界。
3.linux2.6.xx.x/include/linux/syscalls.h 添加 asmlinkage long sys_countsyscalls();
4.linux2.6.xx.x/kernel/sys.c 下添加
SYSCALL_DEFINE0(countsyscalls)
{
...
}
关于系统调用的统计:在 entry_32.S 中对系统调用进行劫持。
1. linux2.6.xx.x/arch/x86/kernel/syscall_table_32.S 中添加.long sys_countsyscalls
2. linux2.6.xx.x/arch/x86/include/asm/unistd_32.h 添加一个
#define NR_countsyscalls 338
3. linux2.6.xx.x/include/linux/syscalls.h 添加 asmlinkage long sys_countsyscalls();
4. linux2.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 }