Linux系统调用探究(上)

Linux系统调用探究(上)

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

posted @ 2015-03-31 22:29  current  阅读(828)  评论(0编辑  收藏  举报