kernel——系统调用

1. 系统调用的原理

linux借助硬件实现特权态和用户态运行,应用程序只能通过系统调用进入内核态。
方法是使用系统调用指令。
以arm32环境,打印hello world字符串的汇编为例

.text
.global _start
_start:
        mov r0, #1              /* stdout */
        add r1, pc, #16 /* address of string */
        mov r2, #12     /* string length */
        mov r7, #4      /* syscall of write */
        swi #0          /* software interrupt  */

_exit:
        mov r7, #1      /* syscall for exit */
        swi #0          /* software interrupt */

_string:
.asciz "hello world\n"

2. glibc

glibc对系统调用进行封装,提供c接口给用户使用

3. 系统调用流程分析

4. 添加系统调用

在一个kernel一定会链接的文件中加入系统调用的实现.

asmlinkage void sys_hello(const char __user *ubuf, size_t count)
{
        char kbuf[100] = {0};
        if (ubuf) {
                copy_from_user(kbuf, ubuf, (count < sizeof(kbuf)) ? count : sizeof(kbuf) - 1);
                printk("hello world 2022: %s\n", kbuf);
        }
}

include/uapi/asm-generic/unistd.h 添加声明

void sys_hello(const char __user *str, size_t count);

arch/arm/include/generated/calls-eabi.S 添加系统调用号

__SYSCALL(450, sys_hello)

编译kernel
应用程序

#include <sys/syscall.h>
#include <unistd.h>
#include <sys/syscall.h>   /* For SYS_xxx definitions */

int main()
{
        syscall(450, "aaa bbb");
        return 0;
}

5. 系统调用优化

由于系统调用频繁,所以希望降低开销,方法是:

  • 快速系统调用, fast syscall
    使用硬件专门为系统调用设置的汇编指令,避免一些不需要的操作,如权限检查等,从而降低开销。

  • 虚拟系统调用,vsyscall
    有些系统调用可以不进入内核态完成,只需要少量内核空间映射给应用空间,应用层可以直接读取,如time,可以在应用层实现。

  • 虚拟动态共享对象,VDSO
    由于虚拟系统调用有缺点,分配内存有限,只支持4个系统调用,且分配的内存在进程空间中是静态的,容易被攻击,
    所以使用 VDSO 进行改进。
    VDSO提供超过4个系统调用,且在进程中地址是随机的。

posted on 2022-10-24 16:30  开心种树  阅读(148)  评论(0编辑  收藏  举报