|
发表于 2006-2-10 16:30:57
|
显示全部楼层
lu wei wrote:
> 1)struct pt_regs *pt直接放在处理函数的参数里就可以用pt.eip、pt.esp等吗?不需要初始化?
系统调用是由 int 0x80 进入内核空间,安装的中断处理器是 system_call (arch/i386/kernel/entry.S),此汇编函数中的宏段落 SAVE_ALL 将所有用户空间寄存器值压入内核栈上,后续的 call *sys_call_table(,%eax,4) 过程中,内核栈上的参数排列刚好与 struct pt_regs 形成一致,于是所有真正的系统调用函数(sys_ 形状的函数)都可以认为栈上有一个 struct pt_regs
- /* from arch/i386/kernel/entry.S */
- #define SAVE_ALL \
- cld; \
- pushl %es; \
- pushl %ds; \
- pushl %eax; \
- pushl %ebp; \
- pushl %edi; \
- pushl %esi; \
- pushl %edx; \
- pushl %ecx; \
- pushl %ebx; \
- movl $(__USER_DS), %edx; \
- movl %edx, %ds; \
- movl %edx, %es;
- ...
- # system call handler stub
- ENTRY(system_call)
- pushl %eax # save orig_eax
- SAVE_ALL
- GET_THREAD_INFO(%ebp)
- # system call tracing in operation / emulation
- /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
- testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
- jnz syscall_trace_entry
- cmpl $(nr_syscalls), %eax
- jae syscall_badsys
- syscall_call:
- call *sys_call_table(,%eax,4)
- movl %eax,EAX(%esp) # store the return value
- syscall_exit:
- cli # make sure we don't miss an interrupt
- # setting need_resched or sigpending
- # between sampling and the iret
- movl TI_flags(%ebp), %ecx
- testw $_TIF_ALLWORK_MASK, %cx # current->work
- jne syscall_exit_work
- restore_all:
- movl EFLAGS(%esp), %eax # mix EFLAGS, SS and CS
- # Warning: OLDSS(%esp) contains the wrong/random values if we
- # are returning to the kernel.
- # See comments in process.c:copy_thread() for details.
- movb OLDSS(%esp), %ah
- movb CS(%esp), %al
- andl $(VM_MASK | (4 << 8) | 3), %eax
- cmpl $((4 << 8) | 3), %eax
- je ldt_ss # returning to user-space with LDT SS
- restore_nocheck:
- RESTORE_REGS
- addl $4, %esp
- 1: iret
- ...
- /* from include/asm-i386/ptrace.h */
- struct pt_regs {
- long ebx;
- long ecx;
- long edx;
- long esi;
- long edi;
- long ebp;
- long eax;
- int xds;
- int xes;
- long orig_eax;
- long eip;
- int xcs;
- long eflags;
- long esp;
- int xss;
- };
复制代码
> 2)2.6内核中,使用sysenter的系统调用,用户态的EIP和ESP什么时候压入内核栈的?如何访问压入栈的用户态EIP和ESP等等?
用户态的 eip esp 是由 Intel 硬件特性压入内核栈的, Intel 出版的四本书上写过当中断,调用或是任务门等引起跨特权级的指令转移时,从低级到高级的转移过程中,硬件依次压入栈:ss, esp, eflags, cs, ip, 而普通的 far call 只压入 cs, eip,用户态EIP和ESP等等同样从 struct pt_regs 访问。
- /* from arch/i386/kernel/entry.S */
- # sysenter call handler stub
- ENTRY(sysenter_entry)
- movl TSS_sysenter_esp0(%esp),%esp
- sysenter_past_esp:
- sti
- pushl $(__USER_DS)
- pushl %ebp
- pushfl
- pushl $(__USER_CS)
- pushl $SYSENTER_RETURN
复制代码
> 3)copy_from_user拷贝栈的时候,起始地址和结束地址是什么(x86中好像不是ss —>ss+sp)?
copy_from_user 时只知道起始地址是 esp ,结束地址就要从栈上已取得的数据去分析了,一般来说用户态程序进入 main 函数,再进入系统调用,用户态栈上至少有几十个 Bytes 的内容,可以先 copy 一段,然后根据已 copy 的内容去分析离栈顶大概还有多远,当然也可 |
|