最初の部分のメモ
内核态:高执行级别,代码可以执行特权指令,访问任意的物理内存,CPU的执行级别对应的就是内核态。
用户态:与内核态相对应的低级别指令,代码能够掌控的范围会受到限制。
Intel x86 CPU有四种不同的执行级别,分别是0,1,2,3其中数字越小,特权越高。Linux操作系统只采用了其中的0和3两个特权级别,分别对 应内核态和用户态.用户态和内核态很显著的区别方法就是CS:EIP的指向范围,内核态CS:EIP的值是任意的,即可以访问所有的地址空间。 用户态只能访问其中的一部分内存地址(0x00000000-0xbbbbbbbf),0xc0000000以上的地址只能在内核态下访问。
CS:代码段选择寄存器 EIP:偏移量寄存器。
中断:由中断触发进入内核态。硬件中断或是由调用系统调用(Trap)引起中断,陷入内核态。从用户态切换到内核态,将用户态寄存器的上下文保存起来,同时将内核态寄存器的值放入当前CPU中。
系统调用的特点:把用户从底层的硬件编程中解放出来;极大的提高了系统的安全性;使用户程序具有可移植性。
系统调用的库函数就是我们使用的操作系统提供的API,系统调用是通过软中断向内核发出中断请求,int指令的执行中触发断请求。
libc函数库内部定义的一些API内部就使用了系统调用的封装历程。每个系统调用对应一个系统调用的封装例程。
- ユーザーモードは、カーネルモードでは、カーネルモードを表し、ユーザ・モードを示します。XYZ()API関数は、その後ret_from_sys_call内部sys_xyz()システムコールハンドラがあるだろう、それは0x80を割り込みベクタ割り込みサービスルーチンのエントリーを対応で、()中断され、開始SYSTEM_CALLカーネルコードに対応するint型$ 0x80をトリガし、されています。
- 3層システムコール機構:XYZ(); SYSTEM_CALL; sys_xyz()。
- システムコール番号:カーネルは、各システムに番号を呼び出すことによって区別します。API関数XYZ()システムコールとカーネル関数sys_xyz()の仲間。
- ユーザプロセスは、パラメータの名前のシステムコール番号を転送し、EAXレジスタを使用して、システムコールを必要とするかを指定しなければなりません。
- ユーザモードから切り替えるときに、異なるスタックシステムコールモードカーネルするために使用される、送信パラメータは、パラメータの押し込みにより渡すことができません。EBX ECX EDX ESI EDI EBP順序パラメータは6つのレジスタを超えないように割り当てられているパラメータの数。パラメータが大きすぎると、ポインタとしてレジスタには、より多くのパラメータを提供するためにメモリを配置します。
実験の第二の部分
- ライブラリ関数、システムコールのAPIを使用します
#include<stdio.h>
#include<time.h>
int main()
{
time_t tt;
struct tm *t;
tt=time(NULL);
t=localtime(&tt);
printf("time:%d:%d:%d:%d:%d:%d:\n",t->tm_year+1900,t->tm_mon,t->tm_mda,t->tm_hour,t->tm_min,t->tm_sec);
return 0;
}
- アセンブラコード組み込みシステムコールのCコード
#include<stdio.h>
#include<time.h>
int main()
{
time_t tt;
struct tm *t;
asm volatile
(
"mov $0,%%ebx\n\t"//把EBX寄存器清0
"mov $0xd,%%eax\n\t"//eax用于传递系统调用号
"int $0x80\n\t"//触发系统调用陷入内核执行13好系统调用的内核处理函数
"mov %%eax,%0\n\t"//系统调用的返回值通过eax返回
:"=m"(tt)
);
t=localtime(&tt);
printf("time:%d:%d:%d:%d:%d:%d:\n",t->tm_year+1900,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
return 0;
}
2つの方法は、システムコールをトリガーがあります-38
- ユニバーサル・トリガ・システムは、システムコールを呼び出します
#include<stdio.h>
#include<sys/syscall.h>
int main()
{
int ret;
char oldname[]="hello.c";
char newname[]="newhello.c";
ret=syscall(38,oldname,newname);
if (ret==0)
printf("Renamed successfully\n");
else
printf("Unable to renam the file\n");
return 0;
}
libcのは、包装システムコールを提供していない、システムコールはlibcのを呼び出す直接機能を提供するために利用することができます