Linux下的系统调用

1.linux的的用户态与内核态

Intel x86架构的CPU有0~3四种执行级别,0级最高,3级最低,  linux只使用0级和3级,分别表示内核态和用户态。linux中,只有内核态能访问逻辑地址为0xc0000000以上的空间。执行一个程序时,大部分时间是运行在用户态下的,在其需要操作系统帮助完成某些它没有权力和能力完成的工作时就会切换到内核态。程序由用户态进入内核态的方式是中断。

系统调用的核心是使用操作系统为用户特别开放的一个中断,例如linux的int 80h中断,系统中断是由用户态主动切换到内核态。

图来自http://blog.chinaunix.net/uid-28458801-id-3468966.html

上图展示的是程序在用户态和内核态切换的大概过程。

(1)xyz()是API,就是一个函数定义。

(2)每个系统调用对应一个封装例程, libc库用这些封装例程定义出用户的API。(API在libc库中的实际程序是包含软中断的各个步骤?)系统调用是通过软中断向内核发出的明确请求,由libc库中的int 80h中断,进入系统调用。

(3)此时进入内核态,执行系统调用处理程序,先保存

2.用户态到内核态的切换的具体过程

int 80h

saveall

3.c代码对应的汇编代码

getuid.c

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include <sys/types.h>
 4 #include <pwd.h>
 5 #include <stdio.h>
 6 #include <unistd.h>
 7 int main()
 8 {
 9 uid_t uid;
10 uid = getuid();
11 printf("User IDs: uid=%d\n", uid);
12 exit(0);
13 }

uid_t是用宏定义的,是用户ID的专用类型,用来表示用户id。数据类型是unsigned long或者unsigned int。

getuid-asm.c

 7 int main()
 8 {
 9         uid_t uid;
10         asm volatile(
11             "mov $0,%%ebx\n\t"//ebx保存参数,置为null
12             "mov $0x18,%%eax\n\t"//getuid的系统调用号是24,传给eax
13             "int $0x80\n\t"//系统调用
14             "mov %%eax,%0\n\t"//返回值用eax保存
15             : "=m"(uid)
16             );
17        printf("User IDs: uid=%d\n", uid);
18        return 0;
19 }
    getuid-asm.c与getuid.c不同的是,把uid = getuid()变成了汇编语言。先把系统调用号传给eax,进行系统调用,再把函数返回值传给eax。这里第11行是参数传递,这个函数没有参数,这一句可以去掉。

编译运行结果如图

---恢复内容结束---

时间: 2024-10-13 14:26:39

Linux下的系统调用的相关文章

linux下的系统调用函数到内核函数的追踪

使用的 glibc : glibc-2.17  使用的 linux kernel :linux-3.2.07 系统调用是内核向用户进程提供服务的唯一方法,应用程序调用操作系统提供的功能模块(函数).用户程序通过系统调用从用户态(user mode)切换到核心态(kernel mode ),从而可以访问相应的资源.这样做的好处是:为用户空间提供了一种硬件的抽象接口,使编程更加容易.有利于系统安全.有利于每个进程度运行在虚拟系统中,接口统一有利于移植.             运行模式.地址空间.上

【学习&amp;理解】Linux下的系统调用过程

在应用程序中,很多时候都会调用到系统调用来完成一些操作,可是系统调用是在内核态下才能调用,用户态下的应用程序是无法直接调用到的,那么操作系统是怎么处理这一过程的呢? 本文的环境是基于Linux 0.11,没有查证现代操作系统是否有所变化,不过基本思路应该差不多. 过程: 先来看一张图,有个大概的理解. 首先,应用程序能直接调用的是系统提供的API,这个在用户态(Ring3)下就可做到. 然后相应的API就会将相应的系统调用号保存到eax寄存器中(这一步通过内联汇编实现),之后就是使用int 0x

linux下C++修改文件内容

C fwrite在任意位置写入文件,并可修改文件内容 想实现类似迅雷那样下载时可以从文件半中间写入的功能 1 #include<stdio.h> 2 int main() 3 { 4 FILE *fp; 5 fp=fopen("overwrite.bin","rb+"); //使用rb+模式,可以往半中间插入数据,而且是覆盖插入,若使用"ab+"每次都插入到最后面,调用fseek也没用 6 if(NULL != fp) 7 { 8 i

Linux下C编程-----文件操作(1) 通过系统调用简单操作标准输入、标准输出、标准错误

Linux的 C系统调用操作  ,下面我们就来练习下 简单的系统调用操作 read系统调用测试 /************************************************************************* > File Name: read.c > Author: > Mail: > Created Time: Tue 10 Feb 2015 01:23:58 AM PST **********************************

linux下syscall函数 间接系统调用

NAME              syscall - 间接系统调用 SYNOPSIS              #define _GNU_SOURCE               #include <unistd.h>       #include <sys/syscall.h>                 /* For SYS_xxx definitions */ int syscall(int number, ...); DESCRIPTION           sys

linux下64位汇编的系统调用(3)

背景知识基本交代清楚了,下面我们实际写一个小例子看一下.代码的功能很简单,显示一行文本,然后退出.我们使用了syscall中的write和exit调用,查一下前面的调用号和参数,我们初步总结如下: write(即sys_write)调用号为1,需传递3个参数 unsigned int fd const char *buf size_t count exit(sys_exit)调用号为60,只需传递一个错误码 int error_code 如果该值为0表示程序执行成功. 因为以上两个调用最多的也只

linux下64位汇编的系统调用(5)

看到这里大家都基本知道了如何进行linux下的汇编系统调用:不过有些童鞋可能会问:那些C库中函数里为我们解决的额外汇编代码你是怎么知道的? 好吧,我承认:我是通过逆向知道的,这貌似有点犯规的嫌疑- 比如举个例子,那上一篇里的mmap C库函数来说,首先写一个C代码: #include <stdlib.h> #include <stdio.h> #include <stdbool.h> #include <sys/mman.h> #include <sy

linux下系统调用、API、系统命令,内核函数的区别与联系

1.系统调用: 应用程序和内核间的桥梁,是应用程序访问内核的入口点;但通常情况下,应用程序通过操作系统提供的API进行编程而不是使用系统调用直接编程; linux的全部系统调用加起来大约只有250个左右. 2.API: API常以c库(libc)的形式提供,c库提供了绝大部分API,每个系统调用在c库中都有对应的封装函数(通常封装函数与系统调用的名称相同).系统调用与c库函数并不是一一对应的,有些c库函数可能使用多个系统调用来实现,也有可能多个c库函数使用同一个系统调用来实现,也有些c库函数不使

文件编程之Linux下系统调用

说明: linux下文件编程可使用两种方法: ****linux系统调用 ****C语言库函数 前者依赖于linux系统,后者与操作系统是独立的. 在任何操作系统下,使用C语言库函数操作文件的方法都是相同的. 这里首先记录下Linux下系统调用操作文件编程的学习过程.函数原型: 1.系统调用--创建: int create(const char *filename, mode_t mode); filename为要创建的文件名(包含路径,缺省为当前路径): mode为创建模式. 模式可用数字来表