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. 2017-2018-2 20165318 实验四《Android程序设计》实验报告

    2017-2018-2 20165318 实验四<Android程序设计>实验报告 一.实验报告封面 课程:Java程序设计        班级:1653班        姓名:孙晓暄  ...

  2. oneinstack远程管理数据库

    本篇文章主要内容是本地工具连接数据非网页(网站)连接 如果你想使用网页(网站)连接远程数据库,请看下面的官网教程 OneinStack如何配置MySQL远程连接? 为了安全考虑,OneinStack仅 ...

  3. oracle 批量更新merge语句

    merge into (SELECT * FROM QUERY_DB1.test_MPOS  ) T1 using (SELECT FLAG FLAG1,IN_MNO FROM QUERY_DB1.t ...

  4. 【转】SVN branches trunk 合并 讲解

    转自:http://blog.csdn.net/e3002/article/details/21469437 使用svn几年了,一直对分支和合并敬而远之,一来是因为分支的管理不该我操心,二来即使涉及到 ...

  5. nginx静态文件缓存的解决方案

    nginx的一大功能就是完成静态资源的分离部署,减轻后端服务器的压力,如果给这些静态资源再加一级nginx的缓存,可以进一步提升访问效率. 第一步:添加nginx.conf的http级别的缓存配置 # ...

  6. WorldWind源码剖析系列:代理助手类ProxyHelper

    代理助手类ProxyHelper通过平台调用的互操作技术封送了若干Win32结构体和函数.该类类图如下. 提供的主要处理方法基本上都是静态函数,简要描述如下: 内嵌类型WINHTTP_AUTOPROX ...

  7. Android将日志信息自动发送到指定的邮箱中 邮件的内容以附件形式发送

    今日整合了网上一些大神的例子(具体看了那些大神的?这个真不好意思我忘记了.下次再整合一定给大家补上,这次也只有默默的给那几个大神说声抱歉了.)做了一个“记录android项目中的日志信息,并将日志信息 ...

  8. 【LeetCode21】Merge Two Sorted Lists★

    1.题目描述: 2.解题思路: 本题是要合并两个已经有序的单链表,思路很简单,有两种方法:非递归和递归. 3.Java代码: (1)非递归: 为方便操作,定义一个辅助的头节点,然后比较原来两个链表的头 ...

  9. 20155207 《网络对抗》 Exp9 Web安全基础

    20155207 <网络对抗> Exp9 Web安全基础 实验内容 关于WebGoat Cross-Site Scripting(XSS)练习 Injection Flaws练习 CSRF ...

  10. 20155217《网络对抗》Exp02 后门原理与实践

    20155217<网络对抗>Exp02 后门原理与实践 实验要求 使用netcat获取主机操作Shell,cron启动. 使用socat获取主机操作Shell,任务计划启动. 使用MSF ...