如何进入linux系统的内核,linux 系统调用如何进入内核模式

linux下的系统调用如何从用户态进入内核态?这个问题一直以来都是模模糊糊,最近阅读了《程序员的自我修养》第十二章:系统调用与API,终于对此有了一个算是比较清醒和深刻的认识:总结了一下,画了一个图大致如下(注:没有内核态返回内核态流程):

564d7aa4aa8b5b73e87119912f272013.png

其中x86有两种方式从用户态陷入内核态:int 0x80系统调用以及新型的sysenter指令。本文暂且基于经典的int 0x80方式。对于用户态,地球人都知道我们写的C程序要调用到glibc库,与我们所理解的库调用并没有多大差异。但是对于glibc库如何陷入内核态,就需要详细的了解一下。

首先,glibc对系统调用做了一系列的封装,典型如fork()函数,比如我们所调用的fork()函数,在glibc中实际上定义的是如下一个宏:

_syscall0(pid_t, fork);

这里有一系列的__syscallN宏定义,其中的N范围从0-6,这是因为x86在linux下支持的最多的参数个数为6个。每个宏对应着相应个数的参数。fork()没有参数,所以是_syscall0。这个宏的参数pid_t是返回值的类型,fork是函数的名字,用于下一步的扩展。其中i386版本的_syscall0宏定义如下:

#define _syscall0(type,name)     \

{   long __res;                          \

__asm__ volatile("int 0x80"    \

: "=a" (__res)                  \

: "0"   (__NR_##name));  \

__syscall_return(type, __res);\

}

这就是采用gcc内联汇编的形式编写的_syscall0宏,通过这个宏,可以很明显的看出来是通过int 0x80方式触发中断,进入内核态中断处理。并指明使用eax来传递参数和返回值。而此处的参数就是系统调用号,所以由此可知,触发中断进入内核时,所有的系统调用号都是通过eax传递,这样在内核态,想知道是什么系统调用,直接查询eax寄存器就可以得到系统调用号了。

进入中断,查询中断号,根据安装的中断处理程序就可以得到这是一个系统调用,于是查询系统调用表,根据eax中传递的系统调用号就可以得到对应的系统调用。

内核处理完成之后,最后通过__syscall_return从用户态返回内核态。当然,返回值还是通过eax传递返回的。

至于用户态和内核态的堆栈的切换,记住其中最重要的一个宏SAVE_ALL,就可以查询到其中的切换了,此处也就不讲述。

阅读(515) | 评论(0) | 转发(0) |

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值