原创 2017年03月17日 21:31:20
  • 标签:
  • linux /
  • 嵌入式汇编 /
  • 简单系统调用

杨金龙 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

  本周是Linux系统分析课程的第四周课程,本周主要讲Linux系统调用的过程,具体知识点和实验结果总结如下。

系统调用的相关知识

  系统调用:系统调用只是一个特殊的中断。我们通过库函数和系统调用打交道,库函数把系统调用封装起来。
1、储备知识——内核态和用户态
  内核态:在高执行级别下,代码可以执行特权指令,访问任意的物理内存,这种CPU执行级别就对应着内核态。
  用户态:在用户态级别下,代码的掌控范围会受到限制,只能在对应级别允许的范围内活动。
注:Intel x86CPU有四种不同的执行级别0-3,Linux只使用了其中的0级和3级分别来表示内核态和用户态。
2、为什么有权限级别的划分?
  若没有用户态和内核态的划分,用户写的不健壮的程序就可以执行特权指令时,就很容易是系统崩溃。操作系统发展过程中划分了用户态和内核态,是系统更稳定的机制。
3、寄存器在系统调用中的作用
  Cs寄存器的最低两位表明了当前代码的特权级。CPU每条指令的读取都是通过CS:EIP这两个寄存器:其中CS是代码段选择寄存器,EIP是偏移量寄存器。
4、内存地址空间
  一般在Linux中,地址空间是一个显著的标志:0xc0000000以上的地址空间只能在内核态下访问,0x0000000–0xbfffffff的地址空间在两种状态下都可以访问。
注:产生中断是从用户态进入内核态的主要方式。
5、寄存器上下文:
 5.1从用户态切换到内核态时:
  必须保存用户态的寄存器上下文;
  同时把内核态的寄存器的值放到寄存器中。
 5.2中断/int指令会在堆栈上保存一些寄存器的值:
  如用户态栈顶地址;
  当前的状态字;
  当时的CS:EIP的值。
 5.3中断发生后的第一件事就是保存现场:
  保存现场:就是进入中断程序,保存需要用到的寄存器的数据。
 5.4中断处理结束前最后一件事就是恢复现场:
  恢复现场:就是退出中断程序恢复保存寄存器的数据。
  注:Iret指令和中断信号(包括int指令)发生时的CPU做的动作整好相反。

中断处理的完整过程

如下图所示

  中断指令interrupt(ex:int 0x80)开始进行系统调用;
  保存当前CS:EIP,SS:ESP,eflags的值到内核堆栈,同时加载了中断服务程序的地址到CS:EIP以及内核堆栈栈顶指针到SS:ESP中。Int指令完成上述操作过程。
  内核代码,完成中断服务:
  发生进程调度,则保存调度时的现场,进行调度,完成调度后再恢复现场;
  不发生进程调度,则恢复之前的保存现场:iret - pop cs:EIP/SS:ESP/eflags from kernel stack.

系统调用的意义

1、操作系统为用户态进程与硬件设备进行交互提供了一组接口——系统调用。
  把用户从底层的硬件编程中解放出来;
  极大的提高了系统的安全性;
  使用户程序具有可移植性。
2、操作系统提供的API和系统调用的关系。
  应用编程接口(Application program interface,API)和系统调用时不同的;
  API只是一个函数定义;
  系统调用通过软中断向内核发出一个明确的请求。
  Libc库定义的一些API引用了封装例程(wrapper routine,唯一的目的就是发布系统调用):一般每个系统调用对应一个封装例程。库再用这些封装例程定义给出用户的API。
3、不是每个API都对应一个特定的系统调用:
  API可能直接提供用户态的服务;
  一个单独的API可能调用几个系统调用;
  不同的API可能调用了同一个系统调用。
4、返回值
  大部分封装例程返回一个整数,其值的含义依赖于相应的系统调用;
  -1在多数情况下表示内核不能满足进程的请求;
  Libc中定义的errno变量包含特定的出错码。
  

注:系统调用的三层皮:API,中断向量,中断服务程序

5、系统调用的服务例程:
  5.1 当用户态进程调用一个系统调用时,CPU切换内核态并开始执行一个内核函数。
  在Linux中是通过执行int $0x80来执行系统调用的,这条汇编指令产生向量为128的编程异常;
  Inter Pentium II中引入了sysenter指令(快速系统调用),2,6已经支持。
5.2 传参:
  内核实现了很多不同的系统调用;
  进程必须指明需要哪个系统调用,这需要使用EAX寄存器传递一个名为系统调用号的参数
5.3 系统调用也需要输入输出参数,例如:
  实际的值;
  用户态进程地址空间的变量的地址;
  甚至包含指向用户态函数的指针的数据结构的地址。
  System call是Linux中所有系统调用的入口点,每个系统调用至少有一个参数,即由eax
5.3 传递的系统调用号;
  系统调用号将xyz和sys_xyz关联起来;用eax寄存器来传递参数;
  一个应用程序调用fork()封装例程,那么在执行int $0x80之前就把EAX寄存器的值置为2(即 NR fork);
  这个寄存器的设置是libc库中的封装例程进行的,因此用户一般不关心系统调用号;
  进入sys,call之后,立即将EAX的值压入内核堆栈;
5.4 寄存器参数具有如下限制:
  每个参数的长度不能超过寄存器的长度,即32位;
  在系统调用号(EAX)之外,参数的个数不能超过6个(ebx,ecx,edx,esi,edi,ebp)。

实验代码

  实验过程中调用mkdir系统函数,mkdir调用号为39,函数原型如下:
  

int mkdir(const char *path, mode_t mode);
参数:
 path是目录名
 mode是目录权限
返回值:
 返回0 表示成功, 返回 -1表示错误,并且会设置errno值。

通过C代码调用

mkdir.c

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>int main()
{int ret = 0;ret = mkdir("./test", 0777);if(ret == 0){printf("Mkdir success!\n") ;   }else printf("Mkdir failed!\n");return 0;
}

通过嵌入式汇编调用

mkdir_asm.c

#include <stdio.h>int main()
{int ret = 0;char *dir = "./test_asm";int mode = 0777;asm volatile("movl $39, %%eax\n\t""int $0x80\n\t""movl %%eax, %0\n\t": "=m"(ret): "b"(dir), "c"(mode)                                                       );if(ret == 0)printf("Mkdir through asm success!\n");else printf("Mkdir through asm failed!\n");return 0;
}

实验总结

  通过对系统调用的两种代码实现方法的分析,我们可以知道C语言的API只不过是对Linux底层系统调用的一次封装而已,本质上是通过系统中断实现的。

Linux下简单的系统调用相关推荐

  1. Linux下简单的邮件服务器搭建

    Linux下简单的邮件服务器搭建 电子邮件服务简介 电子邮件是因特网上最为流行的应用之一,而邮件服务器是一种用来负责电子邮件收发管理的设备,它构成了电子邮件系统的核心. 电子邮件系统的组成  MUA( ...

  2. linux下简单的备份的脚本 2 【转】

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26807463&id=4577034 之前写过 linux下简单 ...

  3. Linux下简单socket编程

    Linux下简单socket编程 socket的英文翻译是接口.插座的意思,很形象,就相当于将两个台电脑用一根线连起来,线的两头分别是插头,插在两台电脑上,借此实现通信. 两台电脑通信,实际上是这两台 ...

  4. linux下阻塞的系统调用,Linux下文件的阻塞与非阻塞对部分系统调用的影响

    1.基本概念 所谓的阻塞,即内核在对文件操作I/O系统调用时,如果条件不满足(可能需要产生I/O),则内核会将该进程挂起.非阻塞则是发现条件不满足就会立即返回.此外需要注意的是非阻塞并不是轮询,不然就 ...

  5. LINUX下简单实现ISP图像处理从RAW到RGB,BMP算法、RGB到JPEG库的使用(一)

    在这里分享一下相关的ISP的一些基本简单图像处理算法.在一般的市面上,相关的ISP算法都是非常复杂,且经过不同serson设备的情况进行固定参数并且固化在芯片内来实现.所以硬件ISP的效率会比软件算法 ...

  6. linux下简单的批处理文件,LINUX下SHELL批处理(SSH批处理命令写法)

    Linux下的SSH类似于windows下的DOS,算是一种便捷版的远程桌面系统,可以让我们直接远程管理LINUX服务器,DOS下有批处理命令,LINUX的SHELL也有远程SSH批处理命令,SSH批 ...

  7. linux下阻塞的系统调用,Linux下socket设置为非阻塞方式和fcntl系统调用.pdf

    Linux 下 socket 设置为非阻塞方式和 fcntl 系统调用 [ 日期: 2011-04-16] 来源: Linux 社区 作者: Linux 用以下方法将 socket 设置为非阻塞方式 ...

  8. JDK+TOMCAT在LINUX下简单的配置

    今天写一个JDK+TOMCAT在LINUX下的配置 JDK是JAVA的类库.运行于JVM之上, 是整个Java的核心,包括了Java运行环境  TOMCAT是WEB服务软件,是为运行JSP提供一个平台 ...

  9. linux网卡入流速,linux下简单限制网卡速度与

    Linux下限制网卡的带宽,可用来模拟服务器带宽耗尽,从而测试服务器在此时的访问效果. 1.安装iproute yum -y install iproute 2.限制eth0网卡的带宽为50kbit: ...

最新文章

  1. RESTful API 设计规范精讲
  2. facebox目标检测改进
  3. 设某链表中最常用的操作是在链表的尾部_Redis系列(二)底层数据结构之双端链表...
  4. 消息已读未读的模型设计_阿里云技术专家分享:现代 IM 系统中消息推送和存储架构的实现...
  5. OpenCV中直方图均衡化
  6. win10配置SSH连接Github
  7. 为什么你写的文字没人看,没人赞?
  8. OpenGL 获取当前屏幕坐标对应的三维坐标
  9. java四舍五入自己写_java提高篇-----详解java的四舍五入与保留位
  10. python有哪些用途-Python是什么 Python的用处
  11. 计算一个连通分量中节点的个数的两种方法
  12. python酷q机器人_NoneBot+酷Q,打造QQ机器人
  13. HDU:2188悼念512汶川大地震遇难同胞——选拔志愿者 (威佐夫博弈)
  14. SpeechSynthesisUtterance实现语音播报
  15. Win系统蓝牙设备删除失败 - 解决方案
  16. 软件设计的哲学:第十六章 修改现有代码
  17. SUMO/检测器设置(E3)学习总结
  18. Android 图形系统概述
  19. 一阶RC和二阶RC低通滤波器
  20. 如果卸载android系统更新,系统将会卸载此android系统应用的所有相关更新,是什么意思,是不是以...

热门文章

  1. 【转】volatile关键字。编译器不优化,多线程会改。防止随时变动的
  2. IPv6网络协议的安全疑云
  3. python安装pymssql
  4. Bash中的whereis
  5. 工信部副部长刘利华:推动5G全球统一标准 加强国际合作
  6. Navicat for MySQL设置备份路径
  7. Silverlight如何与JS相互调用
  8. 创业者的关键词:坚持、忍耐、积累
  9. 【蓝桥杯】算法提高 7-2求arccos值
  10. 最短路之 SPFA(判环+负权)