实验内容实验环境实验步骤1.编译Linux5.0内核
2.制做根目录3.启动MenuOs
4.跟踪系统调用
首先查看自己学号对应的系统调用号。我的是ftruncate函数
ftruncate函数目的是更改文件的大小,
函数原型:inttruncate(constchar*path,off_tlength)
参数:path为文件名,length为为文件的最终大小。off_t为长整型,longint。
(1)最终大小比原先大,向后扩充。
(2)最终大小比原先小,删掉后面的部份。
在menu上面的test.c中加入下边两个函数,并在主函数更新。
重新编译menu中的test.c文件,开启qemu,输入update,与update-asm函数,执行成功。
输入update命令,执行Update函数linux开发培训,更改文件大小为500字节
输入update-asm命令,执行UpdateAsm函数,更改文件大小为200字节
【文章福利】小编自己整理了一些个人认为比较好的linux内核学习书籍、视频资料共享在群文件上面,有须要的可以私信【内核】免费发放哦!!!(含视频教程、电子书、实战项目及代码)
接出来使用gdb逐渐跟踪系统调用
5.剖析
通过上图可以发觉,在使用int0x80中断以后,CPU会运行arch/x86/entry/entry_32.S中的指令
剖析entry_32.S代码
1 #这段代码就是系统调用处理的过程,其它的中断过程也是与此类似
2 #系统调用就是一个特殊的中断,也存在保护现场和回复现场
3 ENTRY(system_call) #这是0x80之后的下一条指令
4 RING0_INT_FRAME # can't unwind into user space anyway
5 ASM_CLAC
6 pushl_cfi %eax # save orig_eax
7 SAVE_ALL #保护现场
8 GET_THREAD_INFO(%ebp)
9 # system call tracing in operation / emulation
10 testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
11 jnz syscall_trace_entry
12 cmpl $(NR_syscalls), %eax
13 jae syscall_badsys
14 syscall_call:
15 # 调用了系统调用处理函数,实际的系统调用服务程序
16 call *sys_call_table(,%eax,4)#定义的系统调用的表,eax传递过来的就是系统调用号,在例子中就是调用的systime
17 syscall_after_call:
18 movl %eax,PT_EAX(%esp) # store the return value
19 syscall_exit:
20 LOCKDEP_SYS_EXIT
21 DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
22 # setting need_resched or sigpending
23 # between sampling and the iret
24 TRACE_IRQS_OFF
25 movl TI_flags(%ebp), %ecx
26 testl $_TIF_ALLWORK_MASK, %ecx # current->work
27 jne syscall_exit_work #退出之前,syscall_exit_work
28 #进入到syscall_exit_work里边有一个进程调度时机
29
30 restore_all:
31 TRACE_IRQS_IRET
32 restore_all_notrace: #返回到用户态
33 #ifdef CONFIG_X86_ESPFIX32
34 movl PT_EFLAGS(%esp), %eax # mix EFLAGS, SS and CS
35 # Warning: PT_OLDSS(%esp) contains the wrong/random values if we
36 # are returning to the kernel.
37 # See comments in process.c:copy_thread() for details.
38 movb PT_OLDSS(%esp), %ah
39 movb PT_CS(%esp), %al
40 andl $(X86_EFLAGS_VM | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax
41 cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax
42 CFI_REMEMBER_STATE
43 je ldt_ss # returning to user-space with LDT SS
44 #end
46 RESTORE_REGS 4 # skip orig_eax/error_code
47 irq_return:
48 INTERRUPT_RETURN #iret(宏),系统调用过程到这里结束
实验总结
Linux内核中设置了一组用于实现各类系统功能的子程序,称为系统调用。用户可以通过系统调用命令在自己的应用程序中调用它们。从某种角度来看linux 调用内核函数,系统调用和普通的函数调用十分相像。区别仅仅在于,系统调用由操作系统核心提供,运行于核态度;而普通的函数调用由函数库或用户自己提供,运行于用户态。
系统调用是如何工作的?
其原理是进程先用适当的值填充寄存器,之后调用一个特殊的指令linux下载工具,这个指令会跳到一个事先定义的内核中的一个位置。在IntelCPU中,这个由中断0x80实现。硬件晓得一旦你跳到这个位置,你就不是在限制模式下运行的用户linux 调用内核函数,而是作为操作系统的内核--由用户态转为内核态。
进程可以跳转到的内核位置称作sysem_call。这个过程检测系统调用号,这个号码告诉内核进程恳求哪种服务。之后,它查看系统调用表(sys_call_table)找到所调用的内核函数入口地址。接着,就调用函数,等返回后,做一些系统检测,最后返回到进程(或到其他进程,假如这个进程时间耗尽)。
进程号是由eax寄存器储存的,参数通常是由ebx、ecx、edx、esl、edl、ebp来储存的。
来源;https://www.cnblogs.com/hhachi/p/10553938.html