Skip to content

Latest commit

 

History

History
75 lines (65 loc) · 4.31 KB

linux系统调用.md

File metadata and controls

75 lines (65 loc) · 4.31 KB

634756f3-779a-4595-a799-22d8c1ca8f16

系统调用是内核提供的一个接口,是应用程序访问内核功能的入口点,而非具体某个函数,应用程序一般是通过系统提供的API来进行编程而非直接使用系统调用,但并非不行。 一个应用程序的用户态到内核的过程是这样的:

系��������

  1. 程序本身使用了getpid()函数,这个是glibc提供的一个函数,实际上是getpid这个系统调用的一个封装,也就是一个系统调用的API。
  2. c函数将封装好的系统调用号圧入EAX寄存器中,系统调用号才是系统调用的具体表现,是每个系统调用唯一的标识,getpid系统调用号_NR_getpid,其中为了syscall函数还为系统调用号创建了索引,通常格式为SYS_常量符号,比如_NR_getpid的索引是SYS_getpid
  3. 后调用一个软中断(0x80中断)进入内核态
  4. 内核中执行system_call根据系统调用号system_call_table(系统调用表)中查找到相应的内核函数,专业点说就是系统调用服务例程,这是一个汇编程序
  5. 执行这个内核函数

4,5两个步骤是真正的系统调用

  1. 返回值后执行syscall_exit再调用resume_userspace返回到用户态,继续在C库中执行。

系统调用方式

一. glibc库函数 这种方式也就是常用的API方式,即调用封装好的C函数

  1. 此种方式下可以一个API封装一个系统调用,如open
  2. 也可以一对多封装如printf
  3. 也可以多对一封装,比如maloccaloc等都是封装了brk

二. syscall调用 这是一个封装好的系统调用,函数原型是

#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <unistd.h>
#include <sys/syscall.h> /* For SYS_xxx definitions */
long syscall(long number, ...);

其中传入的number就是系统调用号,也就是<sys/syscall.h>中的宏定义,就是调用号的索引,后续参数则依照对应内核函数的需要传入

三. int指令 用户态程序进入内核态关键的一个步骤就是int 0x80,然后eax寄存器存的是系统调用号,之后ebxecxedxesiedi依次传递至多5个参数,这个可以看系统调用约定最下面的表。 程序通过内联的汇编代码直接操作寄存器。 例:

#include <stdio.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <errno.h>

int main()
{
        long rc;
        char *file_name = "/etc/passwd";
        unsigned short mode = 0444;
        asm(
                "int $0x80"
                : "=a" (rc)
                : "0" (SYS_chmod), "b" ((long)file_name), "c" ((long)mode)
        );
        if ((unsigned long)rc >= (unsigned long)-132) {
                errno = -rc;
                rc = -1;
        }
        if (rc == -1)
                fprintf(stderr, "chmode failed, errno = %d\n", errno);
        else
                printf("success!\n");
        return 0;
}

如果 eax 寄存器存放的返回值(存放在变量 rc 中)在 -1~-132 之间,就必须要解释为出错码(在/usr/include/asm-generic/errno.h 文件中定义的最大出错码为 132),这时,将错误码写入 errno 中,置系统调用返回值为 -1;否则返回的是 eax 中的值。

结语:

系统调用用户态请求内核服务一种有效的方法,但是控制上也较为严谨,因此更简单的方式是增加一个新的/proc文件系统项来提供交互,就比如ps之类的。

参考