1.linux的的用户态与内核态
Intel x86架构的CPU有0~3四种执行级别,0级最高,3级最低, linux只使用0级和3级,分别表示内核态和用户态。linux中,只有内核态能访问逻辑地址为0xc0000000以上的空间。执行一个程序时,大部分时间是运行在用户态下的,在其需要操作系统帮助完成某些它没有权力和能力完成的工作时就会切换到内核态。程序由用户态进入内核态的方式是中断。
系统调用的核心是使用操作系统为用户特别开放的一个中断,例如linux的int 80h中断,系统中断是由用户态主动切换到内核态。
图来自http://blog.chinaunix.net/uid-28458801-id-3468966.html
上图展示的是程序在用户态和内核态切换的大概过程。
(1)xyz()是API,就是一个函数定义。
(2)每个系统调用对应一个封装例程, libc库用这些封装例程定义出用户的API。(API在libc库中的实际程序是包含软中断的各个步骤?)系统调用是通过软中断向内核发出的明确请求,由libc库中的int 80h中断,进入系统调用。
(3)此时进入内核态,执行系统调用处理程序,先保存
2.用户态到内核态的切换的具体过程
int 80h
saveall
3.c代码对应的汇编代码
getuid.c
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include <sys/types.h> 4 #include <pwd.h> 5 #include <stdio.h> 6 #include <unistd.h> 7 int main() 8 { 9 uid_t uid; 10 uid = getuid(); 11 printf("User IDs: uid=%d\n", uid); 12 exit(0); 13 }
uid_t是用宏定义的,是用户ID的专用类型,用来表示用户id。数据类型是unsigned long或者unsigned int。
getuid-asm.c
7 int main() 8 { 9 uid_t uid; 10 asm volatile( 11 "mov $0,%%ebx\n\t"//ebx保存参数,置为null 12 "mov $0x18,%%eax\n\t"//getuid的系统调用号是24,传给eax 13 "int $0x80\n\t"//系统调用 14 "mov %%eax,%0\n\t"//返回值用eax保存 15 : "=m"(uid) 16 ); 17 printf("User IDs: uid=%d\n", uid); 18 return 0; 19 }
getuid-asm.c与getuid.c不同的是,把uid = getuid()变成了汇编语言。先把系统调用号传给eax,进行系统调用,再把函数返回值传给eax。这里第11行是参数传递,这个函数没有参数,这一句可以去掉。
编译运行结果如图
---恢复内容结束---
时间: 2024-10-13 14:26:39