Linux下简单的系统调用
- 标签:
- 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下简单的系统调用相关推荐
- Linux下简单的邮件服务器搭建
Linux下简单的邮件服务器搭建 电子邮件服务简介 电子邮件是因特网上最为流行的应用之一,而邮件服务器是一种用来负责电子邮件收发管理的设备,它构成了电子邮件系统的核心. 电子邮件系统的组成 MUA( ...
- linux下简单的备份的脚本 2 【转】
转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26807463&id=4577034 之前写过 linux下简单 ...
- Linux下简单socket编程
Linux下简单socket编程 socket的英文翻译是接口.插座的意思,很形象,就相当于将两个台电脑用一根线连起来,线的两头分别是插头,插在两台电脑上,借此实现通信. 两台电脑通信,实际上是这两台 ...
- linux下阻塞的系统调用,Linux下文件的阻塞与非阻塞对部分系统调用的影响
1.基本概念 所谓的阻塞,即内核在对文件操作I/O系统调用时,如果条件不满足(可能需要产生I/O),则内核会将该进程挂起.非阻塞则是发现条件不满足就会立即返回.此外需要注意的是非阻塞并不是轮询,不然就 ...
- LINUX下简单实现ISP图像处理从RAW到RGB,BMP算法、RGB到JPEG库的使用(一)
在这里分享一下相关的ISP的一些基本简单图像处理算法.在一般的市面上,相关的ISP算法都是非常复杂,且经过不同serson设备的情况进行固定参数并且固化在芯片内来实现.所以硬件ISP的效率会比软件算法 ...
- linux下简单的批处理文件,LINUX下SHELL批处理(SSH批处理命令写法)
Linux下的SSH类似于windows下的DOS,算是一种便捷版的远程桌面系统,可以让我们直接远程管理LINUX服务器,DOS下有批处理命令,LINUX的SHELL也有远程SSH批处理命令,SSH批 ...
- linux下阻塞的系统调用,Linux下socket设置为非阻塞方式和fcntl系统调用.pdf
Linux 下 socket 设置为非阻塞方式和 fcntl 系统调用 [ 日期: 2011-04-16] 来源: Linux 社区 作者: Linux 用以下方法将 socket 设置为非阻塞方式 ...
- JDK+TOMCAT在LINUX下简单的配置
今天写一个JDK+TOMCAT在LINUX下的配置 JDK是JAVA的类库.运行于JVM之上, 是整个Java的核心,包括了Java运行环境 TOMCAT是WEB服务软件,是为运行JSP提供一个平台 ...
- linux网卡入流速,linux下简单限制网卡速度与
Linux下限制网卡的带宽,可用来模拟服务器带宽耗尽,从而测试服务器在此时的访问效果. 1.安装iproute yum -y install iproute 2.限制eth0网卡的带宽为50kbit: ...
最新文章
- RESTful API 设计规范精讲
- facebox目标检测改进
- 设某链表中最常用的操作是在链表的尾部_Redis系列(二)底层数据结构之双端链表...
- 消息已读未读的模型设计_阿里云技术专家分享:现代 IM 系统中消息推送和存储架构的实现...
- OpenCV中直方图均衡化
- win10配置SSH连接Github
- 为什么你写的文字没人看,没人赞?
- OpenGL 获取当前屏幕坐标对应的三维坐标
- java四舍五入自己写_java提高篇-----详解java的四舍五入与保留位
- python有哪些用途-Python是什么 Python的用处
- 计算一个连通分量中节点的个数的两种方法
- python酷q机器人_NoneBot+酷Q,打造QQ机器人
- HDU:2188悼念512汶川大地震遇难同胞——选拔志愿者 (威佐夫博弈)
- SpeechSynthesisUtterance实现语音播报
- Win系统蓝牙设备删除失败 - 解决方案
- 软件设计的哲学:第十六章 修改现有代码
- SUMO/检测器设置(E3)学习总结
- Android 图形系统概述
- 一阶RC和二阶RC低通滤波器
- 如果卸载android系统更新,系统将会卸载此android系统应用的所有相关更新,是什么意思,是不是以...