Linux第四周学习总结——扒开系统调用的三层皮(上)

一、用户态、内核态和中断

系统调用通过库函数。

1.用户态和内核态

区分(不同的指令执行级别):

  • 用户态:在相应的低执行状态下,代码的掌控范围受到限制,只能在对应级别允许的范围内活动
  • 内核态:在高执行级别下,代码可以执行特权指令,访问任意的物理地址。

Intel x86 CPU有四种不同的执行级别0—3,Linux只是用了期中的0级和3级分别表示内核态和用户态。

注意逻辑地址和物理地址的区别。逻辑地址是进程地址空间里面的

2.中断

中断处理是从用户态进入内核态主要的方式

系统调用是只是一种特殊的中断

中断指令或向量发生之后发生中断处理程序,刚一开始执行SAVE ALL,即把其他的寄存器的值push到内核堆栈上去,结束之后,把用户态的寄存器的值在popl出来,最后iret,对应着中断信号(int指令),发生时的CPU动作相反。

  • 保护现场就是进入中断程序,保存需要用到的寄存器的数据;
  • 恢复现场就是退出中断程序,恢复保存寄存器的数据。

中断处理的完整过程:

理解:中断信号(int指令)完成:保存cs:eip的值、当前堆栈段栈顶和当前标志,同时加载了当前中断信号或是系统调用的相关联的中断服务入口到cs:eip里面,把当前对战段和esp也加载到CPU里面。

SAVE ALL完成后若没有发生调度,则接着执行RESTORE_ALL;若发生进程调度,则当前的状态会暂时的保存在系统里面,当下一次发生进程调度切换到当前进程时再接着执行完毕。

二、系统调用概述

1.系统调用的意义:

操作系统为用户态进程与硬件设备进行交互提供的一组接口。可以把用户从底层的硬件变成中解放出来,极大的提高了系统的安全性,使用户程序具有可移植性。

2.API应用程序编程接口:

只是一个函数定义,系统调用通过软中断向内核发出一个明确的请求。

Libc库定义的一些API引用了一些封装例程,目的是发布系统调用,让程序员写代码的时候可以通过函数调用而非汇编指令触发一个系统调用。

3.返回值:

  • 大部分封装例程返回一个整数,其值的含义依赖于相应的系统调用;
  • -1在多数情况下表示内核不能满足进程的请求;
  • Libc中定义的errno变量包含特定的出错码。

4.系统调用的三个层次

应用程序编程接口里封装了一个系统调用,int 0x80中断向量,对应着system_call内核代码的起点,执行完中断服务程序,返回。

系统调用的三个层次依次是:xyz函数(API)、system_ call(中断向量)和 sys_ xyz(中断服务程序)。

5.传参

内核实现了很多不同的系统调用,进程必须指明需要哪个系统调用,这需要传递一个名为系统调用号的参数,使用eax寄存器传递。

系统调用号将xyz和sys_xyz关联起来了。

system_call是linux中所有系统调用的入口点,每个系统调用至少有一个参数,即由eax传递的系统调用号。具体过程:

1.一个应用程序调用fork()封装例程,那么在执行int $0x80之前就把eax寄存器的值置为2(即__NR_fork)。
2.这个寄存器的设置是libc库中的封装例程进行的,因此用户一般不关心系统调用号
3.进入sys_call之后,立即将eax的值压入内核堆栈。

寄存器传递参数具有如下限制:

  • 每个参数的长度不能超过寄存器的长度,即32位
  • 在系统调用号( eax)之外,参数的个数不能超过6个( ebx,ecx, edx, esi, edi, ebp)
  • 参数个数超过6个则把某一个寄存器作为指针指向一块内存,进入内核态之后可以访问所有的地址空间,通过那块内存传递参数。

三、使用库函数API和C代码中嵌入汇编代码触发系统调用

1. 内嵌汇编语法:

__asm__(
汇编语句模板:
输入部分:
输出部分:
破坏描述部分:);

这部分内容前几周已经讲过,这里不再重复。

2. 用汇编方式出发系统调用获取系统当前时间

汇编代码分析:

#include <stdio.h>
#include <time.h>
int main()
{
time_t tt;//int型数值
struct tm *t;
asm volatile(
"mov $0,%%ebx\n\t"//将ebx寄存器清零,系统调用传递第一个参数使用ebx,这里是null
"mov $0xd,%%eax\n\t"//将0xd放入eax中,0xd为13,传递系统调用号13
"int $0x80\n\t"
"mov %%eax,$0\n\t"//通过eax这个寄存器返回系统调用值,和普通函数一样
:"=m"(tt)
);
t = localtime(&tt);
printf("time:%d:%d:%d:%d:%d:%d\n",t->tm_year+1900,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
return 0;
}

用户态进程向内核态传递了系统调用号。

四、实验——使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

本次实验我选择了24号系统调用,获取当前用户uid(用户ID)。

实验过程:

使用库函数API方式:

使用C代码中嵌入汇编代码方式:

编译运行:

汇编代码调用系统调用的工作过程分析:

  • 首先将ebx寄存器清零,表示无参数传入;

  • 然后将0x18放入eax,表示需要调用的系统调用号24;

  • 执行int 0x80来执行系统调用;

  • 之后eax寄存器保存了返回值,将它赋值给输出uid变量。

    完成整个汇编代码的系统调用。

总结:

在Linux系统中是通过激活0x80中断来触发系统调用的,需要调用的系统调用号实现赋值给eax存储器,如果有传入参数可赋值给ebx寄存器,如果多于1个则按顺序赋值给ebx、ecx、edx、esi、edi、ebp,如果超过6个则通过指针变量指向另一片堆栈区,如果无参数传入则赋值为0。

虽然Intel X86 CPU有4种执行级别0~3,但是在Linux系统中仅使用了0和3级,分别表示内核态和用户态。一些涉及底层、硬件、核心的操作必须在内核态下才允许执行,为操作系统程序和驱动程序专享,普通程序仅能执行在用户态下。如果普通程序需要涉及内核态的操作,就需要通过系统调用来实现。这样做的好处是屏蔽平台相关操作降低了软件开发难度,增强了系统安全性,使程序具有更好的移植性(Linux系统及其他Unix系统遵循统一标准,系统调用基本一样)。

另外,我想问一下老师,为什么我的API方法运行结果最后会多出来一个%?

参考资料:

http://www.iteedu.com/os/linux/linuxprgm/linuxcfunctions/user/getuid.php

#Linux第四周学习总结——扒开系统调用的三层皮(上)的更多相关文章

  1. 20135337朱荟潼 Linux第四周学习总结——扒开系统调用的三层皮(上)

    朱荟潼 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课http://mooc.study.163.com/course/USTC 1000029000 知识点梳理 一.用 ...

  2. LINUX内核分析第四周学习总结——扒开系统调用的“三层皮”

    LINUX内核分析第四周学习总结--扒开系统调用的"三层皮" 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>MOOC ...

  3. LINUX内核分析第五周学习总结——扒开系统调用的“三层皮”(下)

    LINUX内核分析第五周学习总结--扒开系统调用的"三层皮"(下) 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>M ...

  4. Linux第五周学习总结——扒开系统调用的三层皮(下

    Linux第五周学习总结--扒开系统调用的三层皮(下) 作者:刘浩晨 [原创作品转载请注明出处] <Linux内核分析>MOOC课程http://mooc.study.163.com/co ...

  5. 《Linux内核分析》第五周学习总结 扒开系统调用的三层皮(下)

    扒开系统调用的三层皮(下) 郝智宇 无转载 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.给Men ...

  6. linux 内核 第四周 扒开系统调用的三层皮 上

    姬梦馨 原创作品 http://mooc.study.163.com/course/USTC-1000029000 一.用户态.内核态和中断处理过程 用户通过库函数与系统调用联系起来:库函数帮我们把系 ...

  7. 20135337朱荟潼 Linux第五周学习总结——扒开系统调用的三层皮(下)

    朱荟潼 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课http://mooc.study.163.com/course/USTC 1000029000 一.学习内容 (一 ...

  8. Linux内核分析 笔记五 扒开系统调用的三层皮(下) ——by王玥

    (一)给MenuOs增加time和time-asm命令 更新menu代码到最新版 在main函数中增加MenuConfig 增加对应的Ttime和TimeAsm函数 make rootfs (二)使用 ...

  9. 《Linux内核分析》第四周学习总结 扒开系统调用的三成皮(上)

    第四周 扒开系统调用的三层皮(上) 郝智宇 无转载 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一. ...

随机推荐

  1. 【PyCharm疑问】在pycharm中带有中文时,有时会导致程序判断错误,是何原因?

    1.会导致程序打印false错误的代码如下: # -*- coding:utf-8 -*- import os import sys from uiautomator import device as ...

  2. python difflib.md

    difflib 此模块提供了用于比较序列的类和函数.它可以用于例如比较文件,并且可以产生各种格式的差异信息,包括HTML和上下文以及统一差异. difflib 模块包含用于计算和处理序列间差异的工具. ...

  3. 敲代码非常难之logstash之file input插件实现分析

    版权声明:本文为横云断岭原创文章,未经博主同意不得转载.微信公众号:横云断岭的专栏 https://blog.csdn.net/hengyunabc/article/details/25665877 ...

  4. BZOJ2095:[POI2010]Bridges(最大流,欧拉图)

    Description YYD为了减肥,他来到了瘦海,这是一个巨大的海,海中有n个小岛,小岛之间有m座桥连接,两个小岛之间不会有两座桥,并且从一个小岛可以到另外任意一个小岛.现在YYD想骑单车从小岛1 ...

  5. QGis C++ 开发之创建临时图层并添加要素

            开发环境:Win10 + VS2010 + Qt 4.8.6 + QGis 2.14.4 其实本文实现的功能类似于QGis中“添加文本数据图层”的一个简化版,本文不会涉及到对话框的使用 ...

  6. python argparse模块:命令行选项及参数解析

    位置参数:给一个例子: import argparse parser = argparse.ArgumentParser() parser.add_argument("echo") ...

  7. excel中散点图和折线图的区别(散点图时间均匀分布)

    折线图可以显示随单位(如:单位时间)而变化的连续数据,因此非常适用于显示在相等时间间隔下数据的趋势.散点图显示若干数据系列中各数值之间的关系,或者将两组数绘制为 xy 坐标的一个系列.-------- ...

  8. 福慧双修&探险 BZOJ4398&BZOJ2407

    分析: 双倍经验(数据范围不同). 我们考虑,我们必定是从1走一条边到节点i,之后从i到j跑最短路,之后再从j到1走另一条边的情况下,不会重复,并且是答案.那么我们考虑预处理出pre[i]表示从1走到 ...

  9. 20155235 《网络攻防》 实验五 MSF基础应用

    20155235 <网络攻防> 实验五 MSF基础应用 实验内容 一个主动攻击实践,如ms08_067; (1分) 一个针对浏览器的攻击,如ms11_050:(1分) 一个针对客户端的攻击 ...

  10. mfc 虚函数

    知识点 类虚函数概念 类虚函数定义virtual 一.虚函数 简单地说,那些被virtual关键字修饰的成员函数,就是虚函数. 二.虚函数定义 定义:在某基类中声明为 virtual 并在一个或多个派 ...