Linux中1号进程是由0号进程来创建的,因此必须要知道的是如何创建0号进程,由于在创建进程时,程序一直运行在内核态,而进程运行在用户态,因此创建0号进程涉及到特权级的变化,即从特权级0变到特权级3,Linux是通过模拟中断返回来实现特权级的变化以及创建0号进程,通过将0号进程的代码段选择子以及程序计数器EIP直接压入内核态堆栈,然后利用iret汇编指令中断返回跳转到0号进程运行。
相关阅读:Linux中1号进程的创建剖析 http://www.linuxidc.com/Linux/2013-07/87010.htm
代码如下:
move_to_user_mode();//创建0号进程,开始进入0号进程,切换到特权级3运行
if (!fork()) {init();}//创建1号进程
跟踪代码:
#define move_to_user_mode() \
__asm__ ("movl %%esp,%%eax\n\t" \//将esp寄存器的内容存入eax中
"pushl $0x17\n\t" \//压入0号任务的数据段选择符
"pushl %%eax\n\t" \//压入堆栈指针
"pushfl\n\t" \//压入标志寄存器
"pushl $0x0f\n\t" \//压入0号任务的代码段选择符
"pushl $1f\n\t" \//压入EIP,即切换到0号任务后CPU运行的位置
"iret\n" \//中断返回指令
"1:\tmovl $0x17,%%eax\n\t" \//由于发生了切换,需要更改各段寄存器
"movw %%ax,%%ds\n\t" \//更改段寄存器ds
"movw %%ax,%%es\n\t" \//更改段寄存器es
"movw %%ax,%%fs\n\t" \//更改段寄存器fs
"movw %%ax,%%gs" \//更改段寄存器gs
:::"ax")
分析如下,注释已经很清楚:
代码为嵌入汇编语句的C程序,::”ax”表示的是输出为空,输入为空,在这个宏定义的执行过程中可以发生改变的是ax寄存器,这属于GNU的gas语法,不作解释
0x17与0x0f的真实意义,跟踪查看前先写成二进制形式
0x17=0000 0000 0001 0111
0x0f=0000 0000 0000 1111