linux实验四

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

一.用户态、内核态和中断处理过程
在高级别的状态(内核状态)下,代码可以执行特权指令,访问任意的物理地址;
在相应的低级别执行状态(用户态)下,代码的掌控范围会受到限制。
Intel x86 CPU有四种不同的执行级别0-3,Linux只使用了0级和3级分别表示内核态和用户态。
为什么会有这种级别划分?
没有访问权限划分容易使得系统混乱(毕竟普通程序员写的函数可能会有明显的疏漏)。
如何区分用户态和内核态:
CPU每条指令都是通过cs:eip这两个寄存器读取的(代码段选择寄存器:偏移量寄存器)。一般在Linux中,0xc0000000以上的地址(指的是逻辑地址)空间只能在内核态下访问(即全部的4G内存都可以访问)。
中断处理是从用户态进入内核态的主要方式。系统调用是一种特殊的中断。

二.系统调用概述
1.系统调用的意义
操作系统为用户态进程与硬件设备进行交互提供了一组接口——系统调用
把用户从底层的硬件编程中解放出来
极大的提高了系统的安全性
使用户程序具有可移植性
2.API和系统调用
应用编程接口(application program interface, API)和系统调用是不同的
API只是一个函数定义,系统调用通过软中断向内核发出一个明确的请求
Libc库定义的一些API引用了封装例程(wrapper routine,唯一目的就是发布系统调用)
一般每个系统调用对应一个封装例程
库再用这些封装例程定义出给用户的API
3.系统调用的三层皮:xyz、system_call和sys_xyz

linux实验四_第1张图片
744838-20160315131313381-924010107.png

(1)当用户态进程调用一个系统调用时,CPU切换到内核态并开始执行一个内核函数

在Linux中通过int$0x80来执行系统调用——产生向量为128的编程异常

(2)传参:内核实现了很多不同的系统调用,进程需要通过传递一个名为系统调用编号的参数来指明需要哪个系统调用(通过eax寄存器来实现传递)——系统调用号将xyz和sys_xyz关联起来

(3)系统调用的参数传递方法

a.系统调用也需要输入输出参数,如实际值、用户态进程地址空间的变量的地址、包含指向用户态函数的指针的数据结构的地址

b.system_call是Linux中所有系统调用的入口点,每个系统调用至少有一个参数,即由eax传递的系统调用号

c.寄存器传递参数的限制:

每个参数的长度不能超过寄存器的长度,即32位

在系统调用号(eax)之外,参数的个数不能超过6个(ebx、ecx、edx、esi、edi、ebp),如果超过6个,就把其中某一个寄存器作为一个指针,指向一块内存,进入内核态可以访问所有的地址空间,通过内存传递数据。

实验部分 :使用库函数API和C代码嵌入汇编代码触发同一个系统调用

一、使用库函数API获取当前进程的进程号(getpid())
程序源代码如下:

linux实验四_第2张图片
源代码.JPG

运行结果如下:

linux实验四_第3张图片
运行结果.JPG

使用getpid()获取当前进程的进程号。

二、使用C代码嵌入汇编代码触发系统调用获取当前进程的进程号
程序源代码如下:

linux实验四_第4张图片
源代码.JPG

运行结果如下:

运行结果.JPG

你可能感兴趣的:(linux实验四)