系统调用的两种使用方式
实验准备
首先,在/LinuxKernel/linux-3.18.6/arch/x86/syscalls
目录下查看syscall_32.tbl
文件,获取系统调用号信息。选择getuid进行此次实验,其系统调用号为24,即0x18
:
通过man getuid
查看getuid系统调用相关信息,可以看到getuid的功能是返回当前调用进程的真实用户ID:
对getuid的功能及其头文件等信息有了一定了解之后,开始进行正式的实验过程。
使用库函数API的方式利用系统调用
编写getuid.c
文件,通过getuid()
获取用户ID信息:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
int usr;
usr=getuid();
printf("The user id is %d
",usr);
return 0;
}
编译并执行,结果如下:
在C代码中嵌入汇编使用系统调用
修改getuid.c
文件,嵌入汇编代码。将系统调用号0x18赋给eax寄存器,执行系统调用后将返回值赋给变量usr:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
int usr;
asm volatile(
"mov $0,%%ebx
"
"mov $0x18,%%eax
"
"int $0x80
"
"mov %%eax,%0
"
:"=m"(usr)
);
printf("The user id is %d
",usr);
return 0;
}
编译并执行,结果与前一种方法相同:
实验总结
系统调用的三层皮:API XYZ,中断向量system_call,中断服务程序sys_xyz。系统调用号将xyz和sys_xyz关联起来。
系统调用工作机制:Linux下的系统调用是通过int 0x80
实现的,每个系统调用都有相应的系统调用号作为唯一的标识,通过系统调用号进入相应的系统调用,使用软中断进入内核态。中断发生后会保护现场,将用户的当前栈顶地址,当时的状态字和cs:eip的值进行压栈。之后进入由用户态切换到内核态,处理完中断程序后还原现场,返回用户态。