Linux系统调用探究(上)

:first-child {
margin-top: 0;
}
blockquote > :last-child {
margin-bottom: 15px;
}
h1 {
text-transform: uppercase;
font-weight: bold;
border-bottom: 1px solid;
}
h2 {
border-bottom: 1px solid;
}
h3,
h4,
h5,
h6 {
border-bottom: none;
}
html * {
color: #657b83;
}
html body {
background-color: #fdf6e3;
}
html h1,
html h2,
html h3,
html h4,
html h5,
html h6 {
color: #586e75;
border-color: #657b83;
}
html a,
html a:active,
html a:visited {
color: #586e75;
}
html a:hover {
background-color: #eee8d5;
}
html pre {
color: #586e75;
background-color: #eee8d5;
}
html a,
html a:active,
html a:visited,
html code.url {
color: #b58900;
}
html h1 {
color: #b58900;
}
html h2,
html h3,
html h4,
html h5,
html h6 {
color: #b58900;
}

@media print {
body {
margin: 0;
}
* {
color: #000 !important;
}
}
-->
code[class*="language-"],
pre[class*="language-"] {
background: #2d2d2d;
}

/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
}

.token.comment,
.token.block-comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #999;
}

.token.punctuation {
color: #ccc;
}

.token.tag,
.token.attr-name,
.token.namespace,
.token.deleted {
color: #e2777a;
}

.token.function-name {
color: #6196cc;
}

.token.boolean,
.token.number,
.token.function {
color: #f08d49;
}

.token.property,
.token.class-name,
.token.constant,
.token.symbol {
color: #f8c555;
}

.token.selector,
.token.important,
.token.atrule,
.token.keyword,
.token.builtin {
color: #cc99cd;
}

.token.string,
.token.char,
.token.attr-value,
.token.regex,
.token.variable {
color: #7ec699;
}

.token.operator,
.token.entity,
.token.url {
color: #67cdcc;
}

.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}

.token.entity {
cursor: help;
}

.token.inserted {
color: green;
}
-->

Linux系统调用探究(上)

Linux系统提供了一系列系统调用,用户可以通过这些系统调用与Linux内核进行交互,对于一个典型的C程序来说,调用一次系统调用经历了如下三层

  1. C库API,这是由C库提供的对中断向量的wrapper,也是直接面向用户的一层
  2. 中断向量,中断向量是一个用户态进程进入内核态执行内核代码的途径,通过中断向量中的中断号,进程会被相应的陷阱门截获并转入内核态
  3. 中断服务程序,也就是真正执行的内核态代码

1,2运行在用户态,3才真正进入内核态

以简单的getpid系统调用来说,典型做法就是调用POSIX接口getpid(),代码如下

#include <unistd.h>
#include <stdio.h>

int main()
{
    int pid = getpid();
    printf("pid: %d\n", pid);
    return 0;
}

这个过程非常简单,但是有必要探究一下系统调用在用户态真正的执行流程,于是我们使用内联汇编来调用getpid系统调用,代码如下

#include <unistd.h>
#include <stdio.h>

int main()
{
    int pid = 0;
    __asm__ __volatile__ (
            "mov $0, %%ebx\n\t"
            "mov $0x14, %%eax\n\t"
            "int $0x80\n\t"
            "mov %%eax, %0\n\t"
            : "=m" (pid)
            );
    printf("pid-asm: %d\n", pid);
    return 0;
}

我们要关注的部分主要在于内联汇编部分

            "mov $0, %%ebx\n\t"
            "mov $0x14, %%eax\n\t"
            "int $0x80\n\t"
            "mov %%eax, %0\n\t"
            : "=m" (pid)

最后一行声明了导入导出参数pid,不多说

第一行: mov $0, %%ebx ebx用于传递系统调用的第一个参数,getpid不需要参数,所以这儿就是立即数0,相当于NULL 系统调用的传参规则如下:

  • 当系统调用的参数少于五个时,依次使用ebx,ecx,edx,esi,edi传递参数
  • 当系统调用的参数多余五个是,参数应当储存在一段连续内存中,ebx指向该内存区域的起始地址

第二行:mov $0x14, %%eax 触发软中断时,具体调用哪个系统调用是由系统调用号决定的,系统调用号需要储存在eax中,随后使用int $0x80触发中断

第三行:int $0x80 int 0x80触发中断,没啥说的

第四行:mov %%eax, %0 系统中断的返回值储存在eax中,这儿是将eax的值写进了pid变量的内存区域

这个过程也比较简单,但是已经阐明了系统调用在用户态的触发过程

运行结果如图

![实验截图](http://images.cnblogs.com/cnblogscom/current/613723/o7C%60YR(5QP53M18F07GYPU.jpg)

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

时间: 2024-12-26 20:21:36

Linux系统调用探究(上)的相关文章

使用 Linux 系统调用的内核命令【转】

转自:http://www.ibm.com/developerworks/cn/linux/l-system-calls/ 探究 SCI 并添加自己的调用 Linux® 系统调用 —— 我们每天都在使用它们.不过您清楚系统调用是如何在用户空间和内核之间执行的吗?本文将探究 Linux 系统调用接口(SCI),学习如何添加新的系统调用(以及实现这种功能的其他方法),并介绍与 SCI 有关的一些工具. 1 评论: M. Tim Jones ([email protected]), 顾问工程师, Em

Linux系统调用列表(转)

以下是Linux系统调用的一个列表,包含了大部分常用系统调用和由系统调用派生出的的函数.这可能是你在互联网上所能看到的唯一一篇中文注释的Linux系统调用列表,即使是简单的字母序英文列表,能做到这么完全也是很罕见的. 按照惯例,这个列表以man pages第2节,即系统调用节为蓝本.按照笔者的理解,对其作了大致的分类,同时也作了一些小小的修改,删去了几个仅供内核使用,不允许用户调用的系统调用,对个别本人稍觉不妥的地方作了一些小的修改,并对所有列出的系统调用附上简要注释. 其中有一些函数的作用完全

linux平台学x86汇编(十七):在汇编中使用linux系统调用

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 在前面章节我们已经看到,启动系统调用需要使用INT指令.linux系统调用位于中断0x80,执行INT指令时,所有操作转移到内核中的系统调用处理程序,完成后执行转移到INT指令之后的下一条指令. linux的系统调用在如下文件(32位系统)可以查看: $ cat /usr/include/asm/unistd_32.h #ifndef _ASM_X86_UNISTD_32_H

添加新的linux系统调用

上一篇详细解释了linux系统调用的原理,接下来根据上一篇的原理简单介绍如何创建新的linux系统调用 向内核中添加新的系统调用,需要执行3个步骤: 1. 添加新的内核函数 2. 更新头文件unistd.h 3. 针对这个新函数更新系统调用表calls.S 1. 在kernel/sys.c中添加函数: asmlinkage int sysMul(int a, int b) { int c; c = a*b; return c; } 2.在arch/arm/include/asm/unistd.h

Linux on Power 上的调试工具和技术

简介: 调试是一项主要的软件开发活动,作为应用程序开发人员,您无法避免对程序进行调试.有效的调试不仅能缩短软件开发周期,而且可以节省成本.本文简要介绍了在用户空间的 C/C++ 和 Java? 应用程序中查找 bug 的技术,并介绍了一些可以在 Linux? for POWER? 架构上使用的调试技术. 简介 调试程序有很多方法,例如向屏幕上打印消息,使用调试器,或者只需仔细考虑程序如何运行,并对问题进行有根有据的猜测. 在修复 bug 之前,首先要确定在源程序中的位置.例如,当一个程序产生崩溃

[Linux]Linux系统调用列表

本文列出了大部分常见的Linux系统调用,并附有简要中文说明. 以下是Linux系统调用的一个列表,包含了大部分常用系统调用和由系统调用派生出的的函数.这可能是你在互联网上所能看到的唯一一篇中文注释的Linux系统调用列表,即使是简单的字母序英文列表,能做到这么完全也是很罕见的. 按照惯例,这个列表以man pages第2节,即系统调用节为蓝本.按照笔者的理解,对其作了大致的分类,同时也作了一些小小的修改,删去了几个仅供内核使用,不允许用户调用的系统调用,对个别本人稍觉不妥的地方作了一些小的修改

[Linux]系统调用理解(1)

本文是Linux系统调用专栏系列文章的第一篇,对Linux系统调用的定义.基本原理.使用方法和注意事项大概作了一个介绍,以便读者对Linux系统调用建立一个大致的印象. 什么是系统调用? Linux内核中设置了一组用于实现各种系统功能的子程序,称为系统调用.用户可以通过系统调用命令在自己的应用程序中调用它们.从某种角度来看,系统调用和普通的函数调用非常相似.区别仅仅在于,系统调用由操作系统核心提供,运行于核心态:而普通的函数调用由函数库或用户自己提供,运行于用户态.二者在使用方式上也有相似之处,

Linux系统调用--getrlimit()与setrlimit()函数详解

http://www.cnblogs.com/niocai/archive/2012/04/01/2428128.html 功能描述:获取或设定资源使用限制.每种资源都有相关的软硬限制,软限制是内核强加给相应资源的限制值,硬限制是软限制的最大值.非授权调 用进程只可以将其软限制指定为0~硬限制范围中的某个值,同时能不可逆转地降低其硬限制.授权进程可以任意改变其软硬限制.RLIM_INFINITY的 值表示不对资源限制. 用法: #include <sys/resource.h>int getr

Linux系统调用列表

以下是Linux系统调用的一个列表,包含了大部分常用系统调用和由系统调用派生出的的函数.这可能是你在互联网上所能看到的唯一一篇中文注释的Linux系统调用列表,即使是简单的字母序英文列表,能做到这么完全也是很罕见的. 按照惯例,这个列表以man pages第2节,即系统调用节为蓝本.按照笔者的理解,对其作了大致的分类,同时也作了一些小小的修改,删去了几个仅供内核使用,不允许用户调用的系统调用,对个别本人稍觉不妥的地方作了一些小的修改,并对所有列出的系统调用附上简要注释. 其中有一些函数的作用完全