Linux系统调用详细全过程

上传人:m**** 文档编号:569375087 上传时间:2024-07-29 格式:PPT 页数:43 大小:422KB
返回 下载 相关 举报
Linux系统调用详细全过程_第1页
第1页 / 共43页
Linux系统调用详细全过程_第2页
第2页 / 共43页
Linux系统调用详细全过程_第3页
第3页 / 共43页
Linux系统调用详细全过程_第4页
第4页 / 共43页
Linux系统调用详细全过程_第5页
第5页 / 共43页
点击查看更多>>
资源描述

《Linux系统调用详细全过程》由会员分享,可在线阅读,更多相关《Linux系统调用详细全过程(43页珍藏版)》请在金锄头文库上搜索。

1、LinuxLinux系统调用系统调用- -详细全过详细全过程程LinuxLinux系统调用系统调用_ _详细全过程详细全过程u系统调用系统调用( (SYSTEM CALL)SYSTEM CALL) nOSOS内核中都有一组实现系统功能的过程,内核中都有一组实现系统功能的过程,系统调用就是对上述过程的调用。系统调用就是对上述过程的调用。编程人编程人员利用系统调用,向员利用系统调用,向OSOS提出服务请求,由提出服务请求,由OSOS代为完成。代为完成。u一般情况下,进程是不能够存取系统内核的。一般情况下,进程是不能够存取系统内核的。它不能存取内核使用的内存段,也不能调用它不能存取内核使用的内存段,

2、也不能调用内核函数,内核函数,CPUCPU的硬件结构保证了这一点。的硬件结构保证了这一点。只有系统调用是一个例外。只有系统调用是一个例外。 Linux系统调用系统调用- -功能功能u系统调用是用户态进入内核态的唯一入口系统调用是用户态进入内核态的唯一入口:一夫一夫当关,万夫莫开。常用系统调用:当关,万夫莫开。常用系统调用:n控制硬件控制硬件: :如如write/readwrite/read调用。调用。n设置系统状态或读取内核数据设置系统状态或读取内核数据getpid()getpid()、getprioritygetpriority()()、setpriority()setpriority()、

3、sethostname()sethostname()n进程管理进程管理: :如如 fork()fork()、clone()clone()、execve()execve()、exitexit()()等等u优点优点 n编程容易,从硬件设备的低级编程中解脱出来编程容易,从硬件设备的低级编程中解脱出来n提高了系统的安全性,可以先检查请求的正确性提高了系统的安全性,可以先检查请求的正确性5.1 Linux系统调用系统调用- -功能功能5.2 Int 5.2 Int 0x800x80指令指令uLinuxLinux中实现系统调用利用了中实现系统调用利用了i386i386体系结体系结构中的软件中断。即调用了构

4、中的软件中断。即调用了int $0x80汇汇编指令。编指令。u这条汇编指令将产生向量为这条汇编指令将产生向量为128128的编程异的编程异常,常,CPUCPU便被切换到内核态执行内核函数,便被切换到内核态执行内核函数,转到了系统调用处理程序的入口:转到了系统调用处理程序的入口:system_callsystem_call()()。uint $0x80int $0x80指令将用户态的执行模式转变为内核指令将用户态的执行模式转变为内核态,并将控制权交给系统调用过程的起点态,并将控制权交给系统调用过程的起点system_callsystem_call()()处理函数。处理函数。system_call

5、()system_call()函数函数usystem_cal()system_cal()检查系统调用号,该号码告诉内核检查系统调用号,该号码告诉内核进程请求哪种服务。进程请求哪种服务。u内核进程查看系统调用表内核进程查看系统调用表(sys_call_table)(sys_call_table)找到找到所调用的内核函数入口地址。所调用的内核函数入口地址。u接着调用相应的函数,在返回后做一些系统检查,接着调用相应的函数,在返回后做一些系统检查,最后返回到进程。最后返回到进程。系统调用和普通函数调用系统调用和普通函数调用uAPIAPI是用于某种特定目的的函数,供应用程序调用,是用于某种特定目的的函数

6、,供应用程序调用,而系统调用供应用程序直接进入系统内核。而系统调用供应用程序直接进入系统内核。uLinuxLinux内核提供了一些内核提供了一些C C语言函数库,这些库对系统语言函数库,这些库对系统调用进行了一些包装和扩展,因为这些库函数与系调用进行了一些包装和扩展,因为这些库函数与系统调用的关系非常紧密,所以习惯上把这些函数也统调用的关系非常紧密,所以习惯上把这些函数也称为系统调用。称为系统调用。u有的有的APIAPI函数在用户空间就可以完成工作,如一些函数在用户空间就可以完成工作,如一些用于数学计算的函数,因此不需要使用系统调用。用于数学计算的函数,因此不需要使用系统调用。u有的有的API

7、API函数可能会进行多次系统调用。函数可能会进行多次系统调用。u不同的不同的API API 函数也可能会有相同的系统调用。比如函数也可能会有相同的系统调用。比如mallocmalloc()(),calloc()calloc(),free()free()等函数都使用相同的方法分等函数都使用相同的方法分配和释放内存。配和释放内存。系统命令、内核函数系统命令、内核函数u系统调用与系统命令系统调用与系统命令n系统命令相对系统命令相对APIAPI来说,更高一层。每个系统命令都来说,更高一层。每个系统命令都是一个执行程序,如是一个执行程序,如lsls命令等。这些命令的实现调命令等。这些命令的实现调用了系统

8、调用。用了系统调用。u系统调用与内核函数系统调用与内核函数n系统调用是用户进入内核的接口层,它本身并非内系统调用是用户进入内核的接口层,它本身并非内核函数,但是它由内核函数实现。核函数,但是它由内核函数实现。n进入内核后,不同的系统调用会找到各自对应的内进入内核后,不同的系统调用会找到各自对应的内核函数,这些内核函数被称为系统调用的核函数,这些内核函数被称为系统调用的“服务例服务例程程”。如系统调用。如系统调用getpidgetpid实际调用的服务例程为实际调用的服务例程为sys_getpidsys_getpid()(),或者说系统调用,或者说系统调用getpid()getpid()是服务例程

9、是服务例程sys_getpidsys_getpid()()的封装例程。的封装例程。封装例程封装例程(wrapper routine)(wrapper routine)u由于陷入指令是一条特殊指令,依赖操作系统实现由于陷入指令是一条特殊指令,依赖操作系统实现的平台,如在的平台,如在i386i386体系结构中,这条指令是体系结构中,这条指令是int int $0x80($0x80(陷入指令陷入指令) ),不是用户在编程时应该使用的,不是用户在编程时应该使用的语句,因为这将使得用户程序难于移植。语句,因为这将使得用户程序难于移植。u在标准在标准C C库函数库函数中,为每个系统调用设置了一个中,为每个

10、系统调用设置了一个封封装例程装例程,当一个用户程序执行了一个系统调用时,当一个用户程序执行了一个系统调用时,就会调用到就会调用到C C函数库中的相对应的封装例程。函数库中的相对应的封装例程。系统调用过程系统调用过程系统调用过程系统调用过程xyz()system_call:sys_xyz()ret_from_sys_call:iretxyz()int0x80sys_xyz()在应用程序在应用程序 在标准库在标准库 系统调用系统调用 系统调用系统调用调用中的调用中的 中的封装例程中的封装例程 处理程序处理程序 服务例程服务例程系统调用系统调用用户态用户态内核态内核态system_call()片段n

11、 n pushl %eax /* pushl %eax /* pushl %eax /* pushl %eax /*将系统调用号压栈将系统调用号压栈* */ /SAVE_ALLSAVE_ALLSAVE_ALLSAVE_ALL.cmpl$(NR_syscalls), %eax /*cmpl$(NR_syscalls), %eax /*cmpl$(NR_syscalls), %eax /*cmpl$(NR_syscalls), %eax /*检查系统调用号检查系统调用号Jb nobadsysJb nobadsysJb nobadsysJb nobadsysMovl $(-ENOSYS), 24(%

12、esp) /*Movl $(-ENOSYS), 24(%esp) /*Movl $(-ENOSYS), 24(%esp) /*Movl $(-ENOSYS), 24(%esp) /*堆栈中的堆栈中的eaxeaxeaxeax设置为设置为- - - -ENOSYSENOSYSENOSYSENOSYS, 作为返回值作为返回值Jmp ret_from_sys_callJmp ret_from_sys_callJmp ret_from_sys_callJmp ret_from_sys_callsystem_call片段(续)nobadsys:nobadsys:call *sys_call_table(,

13、%eax,4) #call *sys_call_table(,%eax,4) #call *sys_call_table(,%eax,4) #call *sys_call_table(,%eax,4) #调用系统调调用系统调用表中调用号为用表中调用号为eaxeaxeaxeax的系统调用例程的系统调用例程movl %eax,EAX(%esp) #movl %eax,EAX(%esp) #movl %eax,EAX(%esp) #movl %eax,EAX(%esp) #将返回值存入将返回值存入堆栈堆栈堆栈堆栈中中Jmp ret_from_sys_callJmp ret_from_sys_call

14、Jmp ret_from_sys_callJmp ret_from_sys_callsystem_call()system_call()函数(见教材函数(见教材P234P234页)页)u首先将系统调用号首先将系统调用号(eax)(eax)和可以用到的所有和可以用到的所有CPUCPU寄存寄存器保存到相应的堆栈中(由器保存到相应的堆栈中(由SAVE_ALLSAVE_ALL完成);完成);u对用户态进程传递过来的系统调用号进行有效性检对用户态进程传递过来的系统调用号进行有效性检查查(eax(eax是系统调用号,它应该小于是系统调用号,它应该小于 NR_syscallsNR_syscalls)u如果是

15、合法的系统调用,再进一步检测该系统调用如果是合法的系统调用,再进一步检测该系统调用是否正被跟踪;是否正被跟踪;u根据根据eaxeax中的系统调用号调用相应的服务例程。中的系统调用号调用相应的服务例程。u服务例程结束后,从服务例程结束后,从eaxeax寄存器获得它的返回值,并寄存器获得它的返回值,并把这个返回值存放在堆栈中,让其位于用户态把这个返回值存放在堆栈中,让其位于用户态eaxeax寄寄存器曾存放的位置。存器曾存放的位置。u然后跳转到然后跳转到ret_from_sys_call()ret_from_sys_call(),终止系统调用程,终止系统调用程序的执行。序的执行。SAVE_ALLSA

16、VE_ALL宏定义宏定义 #define SAVE_ALL #define SAVE_ALL cld; cld; pushl %es; pushl %es; pushl %ds; pushl %ds; pushl %eax; pushl %eax; pushl %ebp; pushl %ebp; pushl %edi; pushl %edi; pushl %esi; pushl %esi; pushl %edx; pushl %edx; pushl %ecx; pushl %ecx; pushl %ebx; pushl %ebx; movl $(_KERNEL_DS),%edx; movl $

17、(_KERNEL_DS),%edx; movl %edx,%ds; movl %edx,%ds; movl %edx,%es;movl %edx,%es;将寄存器中的参数压入到将寄存器中的参数压入到核心栈中核心栈中( (这样内核才能使这样内核才能使用用户传入的参数。用用户传入的参数。) )因为在不同特权级之间控因为在不同特权级之间控制转换时,制转换时,INTINT指令不同于指令不同于CALLCALL指令,它不会将外层指令,它不会将外层堆栈的参数自动拷贝到内堆栈的参数自动拷贝到内层堆栈中。层堆栈中。所以在调用系所以在调用系统调用时,必须把参数指统调用时,必须把参数指定到各个寄存器中定到各个寄存器

18、中图10.2 调用总控程序(system_call)执行流程图系统调用表与调用号u这样系统调用处理程序一旦运行,就可以从这样系统调用处理程序一旦运行,就可以从eaxeax中中得到系统调用号,然后再去系统调用表中寻找相得到系统调用号,然后再去系统调用表中寻找相应服务例程。应服务例程。u 一个应用程序调用一个应用程序调用fork()fork()封装例程,那么在执行封装例程,那么在执行int $0x80int $0x80之前就把之前就把eaxeax寄存器的值置为寄存器的值置为2(2(即即_NR_fork)_NR_fork)。u这个寄存器的设置是这个寄存器的设置是libclibc库中的封装例程进行的,

19、库中的封装例程进行的,因此用户一般不关心系统调用号因此用户一般不关心系统调用号系统调用表与调用号u核心中为每个系统调用定义了一个唯一的编号,这个编号核心中为每个系统调用定义了一个唯一的编号,这个编号的定义在的定义在linux/include/asm/unistd.hlinux/include/asm/unistd.h中(最大为中(最大为NR_syscallNR_syscall)u同时在内核中保存了一张同时在内核中保存了一张系统调用表,该表中保存了系统系统调用表,该表中保存了系统调用编号和其对应的服务例程地址调用编号和其对应的服务例程地址。第第n n个表项包含系统个表项包含系统调用号为调用号为n

20、 n的服务例程的地址。的服务例程的地址。u系统调用陷入内核前,需要把系统调用号一起传入内核。系统调用陷入内核前,需要把系统调用号一起传入内核。而该标号实际上是系统调用表而该标号实际上是系统调用表( ( sys_call_tablesys_call_table) )的下标的下标u在在i386i386上,这个传递动作是通过在执行上,这个传递动作是通过在执行int $0x80int $0x80前前把调把调用号装入用号装入eaxeax寄存器寄存器实现。实现。u这样系统调用处理程序一旦运行,就可以从这样系统调用处理程序一旦运行,就可以从eaxeax中得到系统中得到系统调用号,然后再去系统调用表中寻找相应

21、服务例程。调用号,然后再去系统调用表中寻找相应服务例程。系统调用号系统调用号u#define _NR_exit 1u#define _NR_fork 2u#define _NR_read 3u#define _NR_write 4u#define _NR_open 5u#define _NR_close 6u#define _NR_waitpid 7u#define _NR_creat 8u#define _NR_link 9u#define _NR_unlink 10u#define _NR_execve 11u#define _NR_chdir 12u#define _NR_time 13

22、系统调用表系统调用表 (arch/i386/kernel/entry.s)udataENTRY(sys_call_table).long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_exit).long SYMBOL_NAME(sys_fork).long SYMBOL_NAME(sys_read).long SYMBOL_NAME(sys_write).long SYMBOL_NAME(sys_open) .long SYMBOL_NAME(sys_close).long SYMBOL_NAME(sys_waitpid).long SY

23、MBOL_NAME(sys_creat).long SYMBOL_NAME(sys_link).long SYMBOL_NAME(sys_unlink) .long SYMBOL_NAME(sys_execve).long SYMBOL_NAME(sys_chdir).long SYMBOL_NAME(sys_time).long SYMBOL_NAME(sys_mknod)1.1.系统调用表系统调用表记录了各个记录了各个系统调用的服务例程的系统调用的服务例程的入口地址。入口地址。2.2.以系统调用号为偏移量以系统调用号为偏移量能够在该表中找到对应能够在该表中找到对应处理函数地址。处理函数地址

24、。3.3.在在linux/include/linux/linux/include/linux/sys.hsys.h中定义的中定义的NR_syscallsNR_syscalls表示该表表示该表能容纳的最大系统调用能容纳的最大系统调用数,一般数,一般NR_syscalls NR_syscalls = 256= 256。系统调用表(sys_call_table)系统调用的返回系统调用的返回u当服务例程结束时,system_call( ) 从eax获得系统调用的返回值,并把这个返回值存放在曾保存用户态 eax寄存器栈单元的那个位置上,然后跳转到ret_from_sys_call( ),终止系统调用处理

25、程序的执行。u当进程恢复它在用户态的执行前,RESTORE_ALL宏会恢复用户进入内核前被保留到堆栈中的寄存器值。其中eax返回时会带回系统调用的返回码(负数说明调用错误,0或正数说明正常完成)ret_from_sys_callcli cli cli cli # # # # 关中断关中断cmpl $0,need_resched(%ebx) cmpl $0,need_resched(%ebx) cmpl $0,need_resched(%ebx) cmpl $0,need_resched(%ebx) jne reschedule jne reschedule jne reschedule jne

26、 reschedule # # # #如果进程描述符中的如果进程描述符中的 need_reschedneed_reschedneed_reschedneed_resched位不为位不为0 0 0 0,则重新调度,则重新调度cmpl $0,sigpending(%ebx)cmpl $0,sigpending(%ebx)cmpl $0,sigpending(%ebx)cmpl $0,sigpending(%ebx)jne signal_return jne signal_return jne signal_return jne signal_return # # # #若有未处理完的信号,则处若有

27、未处理完的信号,则处理理restore_all:restore_all:restore_all:restore_all:RESTORE_ALL RESTORE_ALL RESTORE_ALL RESTORE_ALL # # # #堆栈弹栈,返回用户态堆栈弹栈,返回用户态系统调用的返回值系统调用的返回值u所有的系统调用返回一个整数值。所有的系统调用返回一个整数值。n正数或正数或0 0表示系统调用成功结束表示系统调用成功结束n负数表示一个出错条件负数表示一个出错条件u这里的返回值与封装例程返回值的约定不同这里的返回值与封装例程返回值的约定不同n内核没有设置或使用内核没有设置或使用errnoerrn

28、o变量变量n封装例程在系统调用返回取得返回值之后设置这封装例程在系统调用返回取得返回值之后设置这个变量个变量n当系统调用出错时,返回的那个负值将要存放在当系统调用出错时,返回的那个负值将要存放在errnoerrno变量中返回给应用程序变量中返回给应用程序5.3 5.3 系统调用系统调用- -实例分析实例分析假设源文件名为假设源文件名为getpid.cgetpid.c,内容是:,内容是:#include #include #include #include #include #include #include #include int main(void) int main(void) long

29、 ID; long ID; ID = getpid(); ID = getpid(); printf (getpid()=%ldn, ID); printf (getpid()=%ldn, ID); return(0); return(0); 系统调用系统调用- -实例分析实例分析1.1.该程序调用封装例程该程序调用封装例程getpid()getpid()。该封装例程将。该封装例程将系统调用号系统调用号_NR_getpid_NR_getpid(第(第2020个)压入个)压入EAXEAX寄存寄存器器2.2.CPUCPU通过通过int $0x80 int $0x80 进入内核,找到进入内核,找到s

30、ystem_callsystem_call()(),并调用它,并调用它 (以下进入内核态)(以下进入内核态)3. 3. 在内核中首先执行在内核中首先执行system_call()system_call(),接着执行根,接着执行根据系统调用号在调用表中查找到的对应的系统据系统调用号在调用表中查找到的对应的系统调用服务例程调用服务例程sys_getpid()sys_getpid()。4 4执行执行syssys_ _getpid()getpid()服务例程。服务例程。5 5执行完毕后,转入执行完毕后,转入ret_from_sys_call()ret_from_sys_call()例程,例程,系统调用

31、返回到用户态。系统调用返回到用户态。5.4 5.4 系统调用的参数传递系统调用的参数传递u很多系统调用需要不止一个参数很多系统调用需要不止一个参数n普通普通C C函数的参数传递是通过把参数值写入堆栈函数的参数传递是通过把参数值写入堆栈( (用用户态堆栈或内核态堆栈户态堆栈或内核态堆栈) )来实现的。但因为系统调来实现的。但因为系统调用是一种特殊函数,它由用户态进入了内核态,所用是一种特殊函数,它由用户态进入了内核态,所以以既不能使用用户态的堆栈也不能直接使用内核态既不能使用用户态的堆栈也不能直接使用内核态堆栈堆栈用户态堆栈用户态C函数内核态堆栈内核态C函数系统调用的参数传递系统调用的参数传递n

32、在在int $0x80int $0x80汇编指令之前,系统调用的参数被写汇编指令之前,系统调用的参数被写入入CPUCPU的的寄存器寄存器。然后,在进入内核态调用系统调。然后,在进入内核态调用系统调用服务例程之前,内核再把存放在用服务例程之前,内核再把存放在CPUCPU寄存器中的寄存器中的参数拷贝到内核态堆栈中。因为毕竟服务例程是参数拷贝到内核态堆栈中。因为毕竟服务例程是C C函数,它还是要到堆栈中去寻找参数的函数,它还是要到堆栈中去寻找参数的用户态堆栈用户态C函数内核态堆栈内核态C函数寄存器系统调用的参数传递系统调用的参数传递系统调用系统调用使用寄存器来传递参数使用寄存器来传递参数,要传递的参

33、数有:,要传递的参数有:系统调用号系统调用号系统调用所需的参数系统调用所需的参数用于传递参数的寄存器有:用于传递参数的寄存器有:eaxeax:用于保存系统调用号和系统调用返回值:用于保存系统调用号和系统调用返回值系统调用参数保存在:系统调用参数保存在:ebx,ecx,edx,esiebx,ecx,edx,esi和和ediedi中中进入内核态后,进入内核态后,system_callsystem_call通过使用通过使用SAVE_ALLSAVE_ALL宏把这宏把这些寄存器的值保存在内核态堆栈中。些寄存器的值保存在内核态堆栈中。n用寄存器传递参数必须满足两个条件:用寄存器传递参数必须满足两个条件:n

34、 每个参数的长度不能超过寄存器的长度每个参数的长度不能超过寄存器的长度n 参数的个数不能超过参数的个数不能超过6 6个个( (包括包括eaxeax中传递中传递的系统调用号的系统调用号););否则,需要用一个单独的否则,需要用一个单独的寄存器指向进程地址空间中这些参数值所寄存器指向进程地址空间中这些参数值所在的一个内存区即可在的一个内存区即可n返回值必须写到返回值必须写到eaxeax寄存器中寄存器中 系统调用的参数传递系统调用的参数传递参数传递举例参数传递举例u处理处理writewrite系统调用的系统调用的sys_writesys_write服务例程声明如下服务例程声明如下u该函数期望在栈顶找

35、到该函数期望在栈顶找到fdfd,bufbuf和和countcount参数参数在封装在封装sys_write()sys_write()的封装例程中,将会在的封装例程中,将会在ebxebx、ecxecx和和edxedx寄存寄存器中分别填入这些参数的值,然后在进入器中分别填入这些参数的值,然后在进入system_callsystem_call时,时,SAVE_ALLSAVE_ALL会把这些寄存器保存在堆栈中,进入会把这些寄存器保存在堆栈中,进入sys_writesys_write服务例服务例程后,就可以在相应的位置找到这些参数程后,就可以在相应的位置找到这些参数asmlinkage使得编译器不通过寄

36、存器(x=0)而使用堆栈传递参数SAVE_ALLSAVE_ALLSys_write需要的参数系统调用的参数传递系统调用的参数传递- -举例设设C库中封装的系统调用号为库中封装的系统调用号为3的函数原形如下:的函数原形如下: int sys_func(int para1, int para2)C编译器产生的汇编伪码如:编译器产生的汇编伪码如:movl 0x8(%esp),%ecx /*将用户态堆栈中的将用户态堆栈中的para2放入放入ecxMovl 0x4(%esp),%ebx /*#将用户态堆栈中的将用户态堆栈中的para1放入放入ebxMovl $0x3,%eax /*系统调用号保存在系统调

37、用号保存在eax中中int$0x80 #引发系统调用引发系统调用Movl %eax,errno /*将结果存入全局变量将结果存入全局变量errno中中Movl $-1,%eax /*eax置为置为-1,表示出错注,表示出错注5.5 5.5 练习:练习:添加一个系统调用添加一个系统调用mysyscallmysyscallu功能要求功能要求 首先,自定义一个系统调用首先,自定义一个系统调用mysyscallmysyscall ,它的功,它的功能是使用户的能是使用户的uiduid等于等于0 0 。然后,编写一段测试程。然后,编写一段测试程序进行调用。序进行调用。u执行步骤如下执行步骤如下n添加系统调

38、用号添加系统调用号n在系统调用表中添加相应的表项在系统调用表中添加相应的表项n实现系统调用服务例程实现系统调用服务例程n重新编译内核,启动新内核重新编译内核,启动新内核n编写一段测试程序检验实验结果编写一段测试程序检验实验结果添加一个系统调用添加一个系统调用mysyscallmysyscall(1 1)添加系统调用号:)添加系统调用号:它位于它位于unistd.hunistd.h,每个系统调用号都,每个系统调用号都以以“_NR_NR_开头开头”,u系统调用的编号命名为系统调用的编号命名为 _NR_mysyscall_NR_mysyscallu改写改写/usr/include/asm/unist

39、d.h/usr/include/asm/unistd.h240240 #define #define _NR_llistxattr_NR_llistxattr 233233241241 #define #define _NR_flistxattr_NR_flistxattr 234234242242 #define #define _NR_removexattr_NR_removexattr 235235243243 #define #define _NR_lremovexattr_NR_lremovexattr 236236244244 #define #define _NR_fremove

40、xattr_NR_fremovexattr 237237245245 #define #define _NR_mysyscall238238添加一个系统调用添加一个系统调用mysyscallmysyscall(2 2)在系统调用表中添加相应的表项)在系统调用表中添加相应的表项u内核中实现该系统调用的例程的名字内核中实现该系统调用的例程的名字 sys_mysyscallsys_mysyscallu改写改写arch/i386/kernel/entry.Sarch/i386/kernel/entry.S398398 ENTRY(sys_call_table) ENTRY(sys_call_table

41、)399399 .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_ni_syscall) 636636 .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_ni_syscall) 637 637 .long SYMBOL_NAME(sys_mysyscall).long SYMBOL_NAME(sys_mysyscall)638 638 639 .rept NR_syscalls-(.-sys_call_table)/4639 .rept NR_syscalls-(.-sy

42、s_call_table)/46 640 .long 40 .long SYMBOL_NAME(sys_ni_syscall)SYMBOL_NAME(sys_ni_syscall)64641 .endr 1 .endr 添加一个系统调用添加一个系统调用mysyscallmysyscall(3 3)实现实现系统调用服务例程系统调用服务例程 把一小段程序添加在把一小段程序添加在kernel/sys.ckernel/sys.casmlinkage int sys_mysyscall(void)asmlinkage int sys_mysyscall(void) current-uid = curre

43、nt-euid = current-suid = current-current-uid = current-euid = current-suid = current-fsuid = 0;fsuid = 0;return 0;return 0; (4 4)重新编译内核,启动新内核)重新编译内核,启动新内核添加一个系统调用添加一个系统调用mysyscallmysyscall(5 5)编写一段测试程序检验实验结果)编写一段测试程序检验实验结果#include #include _syscall0_syscall0(int,mysyscall)/* (int,mysyscall)/* 注意这里没有

44、分号注意这里没有分号 * */ /int main()int main() mysyscall(); mysyscall();printf(printf(“This is my uid: %d. nThis is my uid: %d. n”, getuid();, getuid(); u_syscall1(int,print_info,int,testflag)u如果要在用户程序中使用系统调用函数,那么在主函数main前必须申明调用_syscall,其中1 表示该系统调用只有一个入口参数,第一个int 表示系统调用的返回值为整型,print_info为系统调用函数名,第二个int 表示入口参

45、数的类型为整型,testflag为入口参数名。系统调用执行系统调用执行- -小结小结u1 1、程序调用库的封装函数、程序调用库的封装函数 u2 2、调用软中断、调用软中断 int $0x80 int $0x80 进入内核。进入内核。 u3 3、在内核中首先执行、在内核中首先执行system_call()system_call()函数,接着函数,接着根据系统调用号在系统调用表中查找到对应的系根据系统调用号在系统调用表中查找到对应的系统调用服务例程统调用服务例程 u4 4、执行该服务例程、执行该服务例程 u5 5、执行完毕后,转入、执行完毕后,转入ret_from_sys_callret_from_sys_call例程,例程,从系统调用返回从系统调用返回 作业作业u什么是系统调用?它与普通函数调用有何区别?什么是系统调用?它与普通函数调用有何区别?u什么是系统调用号和系统调用表?什么是系统调用号和系统调用表?u系统调用的参数如何传递到内核?系统调用的参数如何传递到内核?u简述添加系统调用的大致流程。简述添加系统调用的大致流程。结束语结束语谢谢大家聆听!谢谢大家聆听!43

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 资格认证/考试 > 自考

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号