一 Linux内核分析博客简介及其索引
1 通过反汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的
本次实验简单的分析了计算机如何进行工作,并通过简单的汇编实例进行解释分析
在本次实验中 通过听老师的视频分析,和自己的学习,初步了解了进程切换的原理。操作系统通过保存当前pcb的ebp esp,把下一个进程的esp赋予esp寄存器,把下一个进程的eip赋给ip寄存器(不能直接赋值,需要一定的处理)设置实现中断处理和进程切换。
从老师的视频,网上查找的资料。再通过做实验,已经对linux内核从开始初始化到init进程的建立有一个初步的概念,说道idle进程就不得不提到init_task.init_task进程在Linux中属于一个比较特殊的进程,它是内核开发者人为制造出来的,而不是其他进程通过do_fork来完成。init_task对象的初始化在内核代码来完成.Linux在无进程概念的情况下将一直从初始化部分的代码执行到start_kernel,然后再到其最后一个函数调用rest_init。从rest_init开始,Linux开始产生进程,因为init_task是静态制造出来的,pid=0,在rest_init函数中,内核将通过下面的代码产生第一个真正的进程(pid=1):
4.使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用
在本次实验中初步了解了什么是系统调用和它运行的方式,一般来说,完成系统调用需要3层,第一层是用户函数,第二层库函数,第三层是内核。三层之间的关系是,用户函数调用库函数提供的API API中封装了调用sysem_call的代码。最后才是执行内核。第二层会把系统调用号放在eax寄存器中,这时进程会跳到的内核叫做sysem_call的位置。这个过程检查系统调用号(系统调用号告诉内核进程请求哪种服务),ebx、ecx、edx、esi和edi 来依次传递服务所需要的参数(最多五个参数),当系统调用返回时,返回值存放在 eax 中。
通过学习视频分析出了system_call 大概的处理过程,制作出下面的流程图,流程图大体上描述了system_call到irq_return的过程,在系统调用system_call 后 ,需要先保存现场SAVE_ALL 然后调用 system_call_table 和eax用以确定调用的系统函数,陷入系统内核。在内核处理完后需要判断要不要调用syscall_exit_work然后调用work_pending,然后判断是否有消息需要处理,如果需要就调用work_notifysig,如果不需要就调用work_resched ,在此函数会调用call schedule 进行进程调度(此处为关键步骤),然后会判断是否还需要调度,如果需要进行自循环,如果不需要这执行retore_all,最后执行irq_return.此过程充分体现了进程间切换的思路,保存现场,切换到其他进程,再切换回来,恢复现场。
本次实验分析fork系统函数来呈现Linux内核创建一个新进程的过程.在执行fork函数后,调用copy_process,用以创建进程描述符以及子进程所需要的数据结构,在copy_process中调用dup_task_struct,用以分配一个新的 task_struct,以及复制父进程的task_struct,在dup_task_struct,后 调用copy_thread,用于初始化子进程的内核栈,在copy_thread中会设置子进程的eip。在执行完 copy_thread后回到do_fork函数执行wake_up_new_task把进程添加到调度器队列,等待调度器调度,这样调度器在调用子进程时会自动执行ret_from_fork,真正执行子进程
本次实验通过分析exec的执行过程以呈现Linux内核装载和启动一个可执行程序的过程.exec的执行流程为:sys_execve -> do_execve -> do_execve_common -> exec_binprm -> search_binary_handler -> load_binary ->load_elf_binary -> start_thread。我们调用execve的可执行程序时,当执行到exceve时,系统调用exceve陷入内核,创建一个新的用户态堆栈,把命令行参数的内容和环境变量传递给系统调用内核处理函数的,然后内核处理函数会通过start_thread把这些拷贝到用户新的可执行程序的执行上下文环境.在exceve返回用户态的时候,就变成了被exceve加载的可执行程序。
linux一般的执行过程:
最一般情况:正在运行的用户态进程X切换到运行用户态进程Y的过程
1.正在运行的用户态进程X
2.发生中断——save cs:eip/esp/eflags(current) to kernel stack,then load cs:eip(entry of a specific ISR) and ss:esp(point to kernel stack)
SAVE_ALL //保存现场
中断处理过程中或中断返回前调用了schedule(),其中的switch_to做了关键的进程上下文切换
标号1之后开始运行用户态进程Y(这里Y曾经通过以上步骤被切换出去过因此可以从标号1继续执行)
restore_all //恢复现场
iret - pop cs:eip/ss:esp/eflags from kernel stack
继续运行用户态进程Y
二.总结
最大的收获
熟悉了linux操作系统 进程,汇编相关方面知识.亲身体验了一把linux内核源码,在学习期间学习了很多以前不所熟悉的编程技巧,思想.通过阅读内核代码潜移默化的提高了自身水平,对于大型项目能更好的适应.
找到了一个很好的学习平台网易MOOC课堂,以后可以自学很多东西
最大的遗憾
对一些课程讲解的内容,还不能深入理解.浮于表面.还需要继续加深学习,进一步研究linux内核代码
感想
老师讲解的方式很是幽默,,对l一些知识点深入浅出.举的例子甚是形象.对我的学习提供了很大的帮助.感谢孟老师,感谢网易MOOC课堂这个平台