张雨梅   原创作品转载请注明出处

《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-10000

1.linux的的用户态与内核态

Intel x86架构的CPU有0~3四种执行级别,0级最高,3级最低,  linux只使用0级和3级,分别表示内核态和用户态。linux中,只有内核态能访问逻辑地址为0xc0000000以上的空间。执行一个程序时,大部分时间是运行在用户态下的,在其需要操作系统帮助完成某些它没有权力和能力完成的工作时就会切换到内核态。程序由用户态进入内核态的方式是中断。

系统调用的核心是使用操作系统为用户特别开放的一个中断,例如linux的int 80h中断,系统中断是由用户态主动切换到内核态。

上图展示的是程序在用户态和内核态切换的大概过程。

(1)xyz()是API,就是一个函数定义。

(2)每个系统调用对应一个封装例程, libc库用这些封装例程定义出用户的API。执行到int 80h时,产生系统调用,是通过软中断向内核发出的明确请求。

(3)system_call是linux所有系统调用的入口点,此时进入内核态,执行系统调用处理程序,执行内核函数sys_xyz。

(4)执行完成后返回到系统调用处理程序中的ret_fromsys_call,通过iret返回到封装例程中,又回到用户态封装例程执行完回到发生系统调用的位置,继续执行下面的程序。

每个系统调用对应一个封装实例,从而产生可给用户使用的API。但是API与系统调用不是一一对应的,有的API可能提供的都是用户态的服务,有的API可能调用多个系统调用,可能多个API调用同一个系统调用。

2.c代码与汇编代码

可以通过c代码和汇编代码的对应关系,观察系统调用的发生过程,这里用geituid函数。

getuid.c

 #include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <pwd.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
uid_t uid;
uid = getuid();
printf("User IDs: uid=%d\n", uid);
exit();
}
       uid_t是用宏定义的,是用户ID的专用类型,用来表示用户id。数据类型是unsigned long或者unsigned int。

getuid-asm.c

 int main()
{
uid_t uid;
asm volatile(
"mov $0,%%ebx\n\t"//ebx保存参数,置为null
"mov $0x18,%%eax\n\t"//getuid的系统调用号是24,传给eax
"int $0x80\n\t"//系统调用
"mov %%eax,%0\n\t"//返回值用eax保存
: "=m"(uid)
);
printf("User IDs: uid=%d\n", uid);
return ;
}
getuid-asm.c与getuid.c不同的是,把uid = getuid()变成了汇编语言。汇编语言的执行步骤是:
(1)把参数传递给ebx,这个函数没有参数,这一句去掉以后执行结果是一样的。
(2)把系统调用号传给eax,系统调用号标志具体的系统调用函数。
每个系统调用至少有一个参数,系统调用号,用eax传递。除了系统调用号,参数不能超过6个,分别存入ebx,ecx,edx,esi,edi,ebp。如果参数超过6个,会用一个单独的寄存器指向进程地址空间中这些参数所在的内存区。
(3)int 80h,进入system_call,在内核堆栈中保存现场
push cs
push eip
push EFLAGS
push ss
push esp
push eax
push es
push ds
push eax
push ebp
push edi
push esi
push edx
push ecx
push ebx

然后执行内核函数sys_getuid()。

(4)执行完sys_getuid后,返回到system_call,恢复现场。

pop ebx
pop ecx
pop edx
pop esi
pop edi
pop ebp
pop eax
pop ds
pop es
add $,esp//相当于pop eax
iret//返回到用户堆栈
与一般中断一样,函数返回值传递给eax。
iret执行之后,弹出esp,ss,eflags,cs,eip,进入用户堆栈,程序回到用户态进程。

编译运行结果如图

可以看出c代码与汇编代码的执行结果一样。

Linux下的系统调用的更多相关文章

  1. 浅析基于ARM的Linux下的系统调用的实现

    在Linux下系统调用是用软中断实现的,下面以一个简单的open例子简要分析一下应用层的open是如何调用到内核中的sys_open的. t8.c 1: #include <stdio.h> ...

  2. (转)linux下的系统调用函数到内核函数的追踪

    转载网址:http://blog.csdn.net/maochengtao/article/details/23598433 使用的 glibc : glibc-2.17使用的 linux kerne ...

  3. linux下的系统调用函数到内核函数的追踪

    http://blog.csdn.net/maochengtao/article/details/23598433

  4. Linux下缓冲区溢出攻击的原理及对策(转载)

    前言 从逻辑上讲进程的堆栈是由多个堆栈帧构成的,其中每个堆栈帧都对应一个函数调用.当函数调用发生时,新的堆栈帧被压入堆栈:当函数返回时,相应的堆栈帧从堆栈中弹出.尽管堆栈帧结构的引入为在高级语言中实现 ...

  5. LINUX下FD_SET介绍

    刚刚了解了linux下select系统调用,函数原型是 #include <sys/select.h> #include <sys/time.h> int select(int ...

  6. Linux下端口复用(SO_REUSEADDR与SO_REUSEPORT)

    freebsd与linux下bind系统调用小结:    只考虑AF_INET的情况(同一端口指ip地址与端口号都相同) freebsd支持SO_REUSEPORT和SO_REUSEADDR选项,而l ...

  7. Linux下函数调用堆栈帧的详细解释【转】

    转自:http://blog.chinaunix.net/uid-30339363-id-5116170.html 原文地址:Linux下函数调用堆栈帧的详细解释 作者:cssjtuer http:/ ...

  8. Linux下缓冲区溢出攻击的原理及对策

    前言 从逻辑上讲进程的堆栈是由多个堆栈帧构成的,其中每个堆栈帧都对应一个函数调用.当函数调用发生时,新的堆栈 帧被压入堆栈:当函数返回时,相应的堆栈帧从堆栈中弹出.尽管堆栈帧结构的引入为在高级语言中实 ...

  9. linux下C++修改文件内容

    C fwrite在任意位置写入文件,并可修改文件内容 想实现类似迅雷那样下载时可以从文件半中间写入的功能 #include<stdio.h> int main() { FILE *fp; ...

随机推荐

  1. Windows Phone 三、样式和资源

    定义样式和引用资源 <Page.Resources> <!-- 向资源字典中添加一个键为ButtonBackground值为SolidColorBrush对象 --> < ...

  2. 约在CBD,吃饭

    午饭当然是外卖. CBD上班的同仁们不用约,都去了一间叫“大食堂”的餐厅. 它在商业街繁华地段的二楼,有1000平米.你不知道么,餐馆们都躲到找不着的角落,变成了厨房,这里的租金便宜得很.但它不做饭, ...

  3. Azure VM上传小文件

    因为需要传一些脚本到Azure的VM里,有个简单方法可以实现,如下 编辑这个rdp文件 点击确定,连接远程计算机 可以在我的电脑里看到本地硬盘

  4. mvc 中的 [ChildActionOnly] 和 [NonAction]

    首先,NonAction表示它不是一个真正的Action,而是一个普通方法, 就像我们定义一个普通的方法那样,返回值可以任意定义; 而  ChildActionOnly表示它只能在View中通过Htm ...

  5. Asp.net在IE10、IE11下事件丢失经验总结

    asp.net4.0出生得比IE10早,所以asp.net4.0以前版本不认识IE10 的 User-Agent 标头,导致的后果就是ASP.NET 特定功能失效,例如:页面报错__doPostBac ...

  6. C# 获取当前路径7种方法

    //获取模块的完整路径. string path1 = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName; //获取 ...

  7. ODBC简介

    加载驱动 1 oracle Class.forName("oracle.JDBC.driver.OracleDriver") 2 DB2 Class.forName("c ...

  8. MYSQL中replace into的用法

    新建一个test表,三个字段,id,title,uid,  id是自增的主键,uid是唯一索引: 插入两条数据 '); ');执行单条插入数据可以看到,执行结果如下: [SQL]insert into ...

  9. App前后台判断

    http://blog.csdn.net/vpractical/article/details/51034360 需求是计算app在后台的时间,当返回前台时,根据时间差来做相应的操作. 思路是让app ...

  10. 自定义控件(View的绘制流程源码解析)

    参考声明:这里的一些流程图援引自http://a.codekk.com/detail/Android/lightSky/%E5%85%AC%E5%85%B1%E6%8A%80%E6%9C%AF%E7% ...