Linux系统调用及测试

1.系统调用

  • 查询syscall用法:man 2 syscall
  • 系统调用:上层应用程序调用的API
    • eg:printf() --> glibc write() --> kernel write()
  • 系统调用和计算机的体系结构相关
  • 系统调用的指令
    • syscall和init
    • syscall是64bit机器的指令,init是32bit机器的指令
  • 系统调用的返回值
    • 返回值:rax、rdx寄存器
  • 系统调用的参数
    • 支持6个参数,分别对应6个寄存器

2.demo程序

/************************************************************************
    > File Name: test_syscall.c
    > Author: CurryCoder
    > Mail: 1217096231@qq.com 
    > Created Time: 2022年09月18日 星期日 09时42分51秒
************************************************************************/

#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>

int main(){
	int pid = syscall(39); // 39为getpid的系统调用号
	printf("pid=%d\n",pid);
	
	return 0;
}

3.系统调用相关的代码位置

  • 不同体系结构有不同的系统调用
    • arch/x86/entry/syscalls/syscall_64.tbl
  • 系统调用属于内核的一部分,不能作为模块进行编译
    • 对系统调用的修改需要重新编译内核
  • 宏__NR_syscalls
    • 系统调用的个数
    • arch/x86/include/generated/uapi/asm/unistd_64.h
    • 注意:系统调用的编号从0开始的

4.实例:添加系统调用(获取cpu的个数)

  • (1).注册系统调用号
    • arch/x86/entry/syscalls/syscall_64.tbl文件中,eg: 451 common get_cpu_number sys_get_cpu_number
  • (2).声明系统调用函数
    • include/linux/syscalls.h文件中,asmlinkage long sys_get_cpu_number(void)
  • (3).实现系统调用
    • kernel/sys.c文件中
    SYSCALL_DEFINE0(get_cpu_number){
        return num_present_cpus();
    }
    

5.测试系统调用

  • (1).重新编译内核
  • (2).使用busybox制作initramfs
#!/bin/busybox sh

/bin/busybox mkdir -p /proc && /bin/busybox mount -t proc none /proc

/bin/busybox echo "Hello Syscall"

export 'PS1=(kernel) =>'
/bin/busybox sh
  • (3).本地静态编译测试代码gcc -static get_cpu.c -o get_cpu,打包进initramfs
/************************************************************************
    > File Name: get_cpu.c
    > Author: CurryCoder
    > Mail: 1217096231@qq.com 
    > Created Time: 2022年09月18日 星期日 09时42分51秒
************************************************************************/

#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>

int main(){
	int pid = syscall(39);
	printf("pid=%d\n",pid);

	int cpu_number = syscall(451); // 451为get_cpu_number的系统调用号
	printf("cpus=%d\n",cpu_number);
	
	return 0;
}
  • (4).编写Makefile文件
.PHONY: clean initramfs run

${shell mkdir -p build}

initramfs:
	cd initramfs && find . -print0 | cpio -ov --null -H newc | gzip -9> ../build/initramfs.img

clean:
	rm -rf build

run:
	qemu-system-x86_64 \
		-kernel bzImage \
		-m 256M \
		-smp 4 \
		-nographic \
		-initrd build/initramfs.img \
		-append "init=/init earlyprintk=serial,ttyS0 console=ttyS0"
  • (5).用QEMU模拟,可以调整-smp参数观察效果

版权声明:本文为cdlwhm1217096231原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。