标签归档:linux

VMware虚拟机拖放文件

要做一件事总是那么多的插曲。就像我准备安装cadence ic615一样。各种bug一大堆,然后就是debug。不过这也不错,因为让我有东西写。very9s不至于看上去什么都没有。
废话不多说。开始记录我debug的过程。

VMware虚拟机拖放文件

最小化安装Centos,貌似不能够通过鼠标拖放传输文件。可能是因为vmware-tools没有安装吧。
所以就安装呗~

加载虚拟光驱

在VM的安装目录下有几个.ISO文件。这几个文件就是用来安装vmware-tools的。
导入iso虚拟光驱
导入后,记得Connect上虚拟光驱。
连接虚拟光驱

安装

挂载上虚拟光驱。把虚拟光驱里面的压缩包拷贝出来,解压。
安装程序
解压后,里面有个READ.TXT。看看里面都说了啥?
reading-how-to-install
写的很清楚嘛。😆
只要运行vmware-install.pl就好了。
一切都默认设置

大功告成

嗯,看似简单,其实我弄了有点久。因为在安装后的配置过程中,总是提示我配置gcc path。明明配置正确了,还是提示“无效地址”。找了好久资料,始终没有解决办法。随后索性不管,跳过配置path。没想到居然可以。💖
drag and drop
现在可以开始装ic615咯~

/etc/group文件格式说明

今晚折腾在centos搭建nginx。在看group的时候发现文档的格式看不懂,于是get到新知识了。

///////////////////////////////////////////////////////////////////////////

1–Understanding /etc/group File

首先group是用来存储描述组信息的文件。

Users can be either people (meaning accounts tied to physical users) or accounts which exist for specific applications to use.用户可以是人,也可以是为某些特殊应用而设立的。

Groups are logical expressions of organization, tying users together for a common purpose. Users within a group can read, write, or execute files owned by that group.组则是将一些有相同需求的用户联系在一起。

——

Chapter 33. Users and Groups

2–/etc/group格式说明

group有四部分,每部分用分号:分割。

四个部分分别是:

  1. group_name: It is the name of group. If you run ls -l command, you will see this name printed in the group field.
  2. Password: Generally password is not used, hence it is empty/blank. It can store encrypted password. This is useful to implement privileged groups.
  3. Group ID (GID): Each user must be assigned a group ID. You can see this number in your /etc/passwd file.
  4. Group List: It is a list of user names of users who are members of the group. The user names, must be separated by commas.

======================================

查看某用户所在的组:$groups username

USTC001 LINUX操作系统分析 部分期末考试题

想了我好久,却不知道我哪里写错了。后来发现我的是对的。要以16进制的格式写,而我却用10进制的格式。

1# 在Linux系统的一般执行过程中,即用户态进程X切换到用户态进程Y的过程中,分析如下进程切换的关键汇编代码,请问系统执行到标号1(即第50行代码)之前的时间点CPU的寄存器eip的值是?直接填eip存储的数值(立即数以$开头)
答案就是$1f 2# 从运行时的角度(执行视图)来看Linux系统,下列哪些属于Linux系统中的执行实体?

一直以来, linux内核并没有线程的概念. 每一个执行实体都是一个task_struct结构, 通常称之为进程. 进程是一个执行单元, 维护着执行相关的动态资源. 同时, 它又引用着程序所需的静态资源(注意这里说的是linux中的进程).通过系统调用clone创建子进程时, 可以有选择性地让子进程共享父进程所引用的资源. 这样的子进程通常称为轻量级进程.

——

《linux线程浅析》

3# Linux系统中,用户态切换到内核态时,int指令或中断信号会触发CPU自动保存下面哪些信息到内核堆栈中?

#2.Linux系统的一般执行过程

Linux系统的一般执行过程大概可以抽象成:

最一般的情况:正在运行的用户态进程X切换到运行用户态进程Y的过程

  1. 正在运行的用户态进程X
    
  2. 发生中断——save cs:eip/esp/eflags(current) ,
    
    
    load cs:eip(entry of a specific ISR)
    
    
    ss:esp(point to kernel stack). 这一过程由CPU自动完成
    
  3. SAVE_ALL //保存现场
    
  4. 中断处理过程中或中断返回前调用了schedule(),其中的switch_to做了关键的进程上下文切换
    
  5. 标号1之后开始运行用户态进程Y(这里Y曾经通过以上步骤被切换出去过因此可以从标号1继续执行)
    
  6. <a href="http://codelab.shiyanlou.com/s?refs=restore_all&amp;project=linux-3.18.6" rel="nofollow" target="_blank">
     restore_all
    </a>
    //恢复现场
    
  7. iret - pop cs:eip/ss:esp/eflags from kernel stack
    
  8. 继续运行用户态进程Y
    



理解进程调度时机跟踪分析进程调度与进程切换的过程

4# Linux内核中,系统调用处理过程中保护现场使用的宏是 SAVE_ALL 5# 动态连接有两种形式:可执行程序装载时动态连接和运行时动态链接。

——《

linux可执行文件的装载

Linux内核学习总结

文章目录:

  1. 实验:通过反汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的
  2. 实验:完成一个简单的时间片轮转多道程序内核代码
  3. 实验:跟踪分析Linux内核的启动过程
  4. 使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用
  5. 从system_call开始到iret
  6. 分析Linux内核创建一个新进程的过程
  7. linux可执行文件的装载
  8. 理解进程调度时机跟踪分析进程调度与进程切换的过程

1#我对linux系统的理解

linux很难,这8周的学习我对绝对还是不理解Linux的。只能说比学之前更理解它了。很多细节深入到底层硬件方面的问题,所以还需要有计算机组成原理的知识,尤其是在堆栈方面的讨论。

linux的哲学

Linux is built with a certain set of unifying principles in mind. Understanding these principles is very helpful in understanding how the system works as a whole. They are known as the “Linux Way”, which is derived from the philosophy behind the UNIX system.

The Linux Way can be summarized as:

  • Use programs that do only one task, but do it well.
    <br/>
    
  • To accomplish complex tasks, use several programs linked together.
    
  • Store information in human-readable plain text files whenever it is possible.
    
  • There is no "one true way" to do anything.
    
  • Prefer commandline tools over graphical tools.
    

Most traits of Linux are a consequence of these principles. In accordance with them, a Linux system is built out of small, replaceable components. We will examine the most important of them in more detail. Those are: the boot loader, the kernel, the shell, the X window server, the window manager and the desktop environment. After that, we will have a look at the file system in Linux. Finally, we will discuss the security of a computer running Linux.

——

Linux Guide/How Linux Works

简单总结就是KISS(keep it simple and stupid)原则

  • 用程序来完成一项任务,然后把任务做好。

  • 复杂的任务用多个程序来完成。

  • 把信息存在更人性化的文本中。

  • 没有唯一的方法。

  • 命令行能做的事就不用图形工具来完成。

这些原则使linux保持简单且高效。

用户通过交互程序与内核打交道,而内核则与硬件直接打交道。这样就把用户、内核、硬件分离开。因此内核就是理解linux的关键。

在内核与用户之间并不是直接关联的,而是通过系统调用来把用户和内核隔离开。这样既安全又方便程序员进行编程,而不是深入到内核中去操作。

内核中又分为多个模块,各各模块管理者不同的任务

通过这些模块与硬件进行打交道
整体框架大概就是这样。我并不是程序员,从我学习的目的来说我并不需要深入到每个模块是如何实现的一些具体细节。就像程序员编程不需要知道每个轮子是怎么制造的一样。 Kernel (operating system)
2#反思实验都做了些什么?

八周下来,周周有实验。再把每周标题串起来,构建一条思路。


###先整体:1~3周

1.计算机只能读懂机器代码,因此我们编程后还要将代码转换成机器代码

2.计算机要高效,就必须多个进程进行轮转。因此就产生了切换时机问题,上下文保存切换问题。

###再系统:4~5周

所谓三层皮目的就是将用户与内核分隔开。用户程序调用API,API调用系统调用,系统调用调用内核

###最后细节:6~8周

三层皮之间的相互调用必然涉及到不用的程序执行,也就是进程切换。进程又可分为用户空间和内核空间进程。进程进行切换,又设计到上下文的保存于切换,于是又回到底层的堆栈操作上。实际上我认为,在这里程序员就不再需要讨论堆栈操作了,将堆栈操作留给系统去做就可以了。否则就会陷入到无限的细节中。这也就是为什么对内核进行层层封装了。

#3.总结课程

这门课让我对linux有了一个感性的认识,这些认识对我日后学习嵌入式必然有帮助。我学习这门课的目的也大体达到。剩下的一些问题,或者说缺乏的理性认识,则可以在实践中慢慢摸索。

《Linux内核分析》课程后最大的遗憾?好吧,那就是缺乏对细节的把握。这单单看视频是不够的。

==================================================

sunfy + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

理解进程调度时机跟踪分析进程调度与进程切换的过程

理解Linux系统中进程调度的时机

Linux的调度程序是一个叫Schedule()的函数,这个函数被调用的频率很高,由它来决定是否要进行进程的切换,如果要切换的话,切换到哪个进程等等。

Linux调度时机主要有:

  1. 中断处理过程(包括时钟中断、I/O中断、系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule():
  2. 内核线程可以直接调用schedule()进行进程切换,也可以在中断处理过程中进行调度,也就是说内核线程作为一类的特殊的进程可以主动调度,也可以被动调度;
  3. 用户态进程无法实现主动调度,仅能通过陷入内核态后的某个时机点进行调度,即在中断处理过程中进行调度。

不同类型的进程有不同的调度需求

第一种分类:

  1. I/O-bound:频繁的进行I/O通常会花费很多时间等待I/O操作的完成
  2. CPU-bound:计算密集型需要大量的CPU时间进行运算

第二种分类:

  1. 批处理进程(batch process):不必与用户交互,通常在后台运行不必很快响应典型的批处理程序:编译程序、科学计算

  2. 实时进程(real-time process):有实时需求,不应被低优先级的进程阻塞响应时间要短、要稳定典型的实时进程:视频/音频、机械控制等

  3. 交互式进程(interactive process):需要经常与用户交互,因此要花很多时间等待用户输入操作响应时间要快,平均延迟要低于50~150ms典型的交互式程序:shell、文本编辑程序、图形应用程序等Linux 进程调度+Linux系统一般执行过程 笔记

进程上下文包含了进程执行需要的所有信息:

用户地址空间:包括程序代码,数据,用户堆栈等

控制信息:进程描述符,内核堆栈等

硬件上下文(注意中断也要保存硬件上下文只是保存的方法不同)

2.schedule()函数

schedule()函数选择一个新的进程来运行,并调用context_switch进行上下文的切换,这个宏调用switch_to来进行关键上下文切换
关键函数
__schedule();

next = pick_next_task(rq, prev);包装了使用某种进程调度策略,但不管使用什么调度策略,它总是选择下一个进程

选完下一个进程后,就要完成进程上下文的切换。
进程上下文的切换主要是通过context_switch(rq, prev, next)实现。

## context_switch(rq, prev, next) 是如何实现上下文切换的?

1-prepare_task_switch(rq,prev,next);//提前做准备

2-context_tracking_task_switch(prev,next);//切换寄存器的状态和堆栈

3-switch_to(prev,next,prev);

switch_to(prev, next, prev);的汇编

switch_to利用了prev和next两个参数:prev指向当前进程,next指向被调度的进程

42  asm volatile(“pushfl\n\t”      /* save    flags */

43           “pushl %%ebp\n\t”        /* save    EBP   */ \

44           “movl %%esp,%[prev_sp]\n\t”  /* save    ESP   */ \这两步实际上完成了内核 45           “movl %[next_sp],%%esp\n\t”  /* restore ESP   */ \堆栈的切换

46           “movl $1f,%[prev_ip]\n\t”    /* save    EIP   */ \

47           “pushl %[next_ip]\n\t”   /* restore EIP   */    \将NEXT进程的起点压入堆栈

48           __switch_canary                   \

49           “jmp __switch_to\n”  /* regparm call  */ \

50           “1:\t”                        \

51           “popl %%ebp\n\t”     /* restore EBP   */    \

52           “popfl\n”         /* restore flags */  \

53                                  \

54           /* output parameters */                \

55           : [prev_sp] “=m” (prev->thread.sp),     \

56             [prev_ip] “=m” (prev->thread.ip),        \

57             “=a” (last),                 \

58                                  \

59             /* clobbered output registers: */     \

60             “=b” (ebx), “=c” (ecx), “=d” (edx),      \

61             “=S” (esi), “=D” (edi)             \

62                                       \

63             __switch_canary_oparam                \

64                                  \

65             /* input parameters: */                \

66           : [next_sp]  “m” (next->thread.sp),        \

67             [next_ip]  “m” (next->thread.ip),       \

68                                       \

69             /* regparm parameters for __switch_to(): */  \

70             [prev]     “a” (prev),              \

71             [next]     “d” (next)               \

72                                  \

73             __switch_canary_iparam                \

74                                  \

75           : /* reloaded segment registers */           \

76          “memory”);                  \

Linux系统的一般执行过程

Linux系统的一般执行过程大概可以抽象成:

最一般的情况:正在运行的用户态进程X切换到运行用户态进程Y的过程

  1. 正在运行的用户态进程X

  2. 发生中断——save cs:eip/esp/eflags(current) ,

    load cs:eip(entry of a specific ISR)

    ss:esp(point to kernel stack). 这一过程由CPU自动完成

  3. SAVE_ALL //保存现场

  4. 中断处理过程中或中断返回前调用了schedule(),其中的switch_to做了关键的进程上下文切换

  5. 标号1之后开始运行用户态进程Y(这里Y曾经通过以上步骤被切换出去过因此可以从标号1继续执行)

  6. restore_all //恢复现场
  7. iret – pop cs:eip/ss:esp/eflags from kernel stack

  8. 继续运行用户态进程Y

几种特殊情况

  • 通过中断处理过程中的调度时机,用户态进程与内核线程之间互相切换和内核线程之间互相切换,与最一般的情况非常类似,只是内核线程运行过程中发生中断没有进程用户态和内核态的转换;

  • 内核线程主动调用schedule(),只有进程上下文的切换,没有发生中断上下文的切换,与最一般的情况略简略;

  • 创建子进程的系统调用在子进程中的执行起点及返回用户态,如fork;

  • 加载一个新的可执行程序后返回到用户态的情况,如execve;

Linux系统架构和执行过程概览

  • 内核(进程管理,进程调度,进程间通讯机制,内存管理,中断异常处理,文件系统,I/O系统,网络部分)
  • 其他程序(例如函数库、shell程序、系统程序等等)

从用户的角度来看:
从CPU的角度来看: #4.gdb跟踪分析一个schedule()函数
qemu -kernel ../linux-3.18.6/arch/x86/boot/bzImage -initrd ../rootfs.img -s -S

打开GDB

gdb

file …/linux-3.18.6/vmlinux

target remote:1234

设置断点:

b schedule

b context_switch

b switch_to

b pick_next_task


==================================================

似乎明白了一点点。

sunfy + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

linux可执行文件的装载

  1. 什么是库? 《linux中的动态链接库,和静态链接库是干什么的?——郭无心的回答》

    库是写好的现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。

    本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态库(.a、.lib)和动态库(.so、.dll)。 windows上对应的是.lib .dll linux上对应的是.a .so

  2. 什么叫做.so?

    .so file is a compiled library file. It stands for “Shared Object”

  3. 什么是动态链接 《Linux 动态库剖析》

    动态链接的共享库是 GNU/Linux® 的一个重要方面。

    该种库允许可执行文件在运行时动态访问外部函数

    ,从而(通过在需要时才会引入函数的方式)减少它们对内存的总体占用。

    库用于将相似函数打包在一个单元中。然后这些单元就可为其他开发人员所共享,并因此有了

    模块化编程

    这种说法 — 即,从模块中构建程序。

    Linux 支持两种类型的库:1.动态库

    2.静态库

    静态库包含在编译时静态绑定到一个程序的函数。动态库则不同,它是在加载应用程序时被加载的,而且它与应用程序是在运行时绑定的。


    动态使用共享库的方法有两种:您既可以在运行时动态链接库,也可以动态加载库并在程序控制之下使用它们。

    对于需要多个库的应用程序来说,则适合使用共享库,因为它们可以减少应用程序对内存(包括运行时中的磁盘占用和内存占用)的占用。这是因为多个应用程序可以同时使用一个共享库;因此,每次只需要在内存上复制一个库。要是静态库的话,每一个运行的程序都要有一份库的副本。

  4. 什么是静态链接

    在链接阶段,会将汇编生成的目标文件与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。

    静态库较适宜于较小的应用程序,因为它们只需要最小限度的函数。

  5. 动态与静态的关系
  6. 目标文件格式 《目标文件的格式》

    目标文件从结构上讲,它是已经编译后的可执行文件格式,只是还没有经过链接的过程,其中可能有些符号或有些地址还没有被调整。其实它本身就是按照可执行文件格式存储的,只是跟真正的可执行文件在结构上稍有不同。

    可执行文件格式涵盖了程序的编译、链接、装载和执行的各个方面。

    现在PC平台流行的可执行文件格式(Executable)主要是:

    Windows下的PE(Portable Executable) Linux的ELF(Executable Linkable Format)

    目标文件就是源代码编译后但未进行链接的那些中间文件(Windows的.obj和Linux下的.o)。从广义上看,目标文件与可执行文件的格式其实几乎是一样的。

    立马编写一个hello world


    用file命令来查看相应的文件格式

    用nm查看ELF信息


    目标文件有三种类型:

    1. 可重定位文件(Relocatable File) 包含适合于与其他目标文件链接来创建可执行文件或者共享目标文件的代码和数据。 (Linux的*.o 文件 Windows的 *.obj文件)

    2. 可执行文件(Executable File) 包含适合于执行的一个程序,此文件规定了 exec() 如何创建一个程序的进程映像。(比如/bin/bash文件;Windows的*.exe)

    3. 共享目标文件(Shared Object File) 包含可在两种上下文中链接的代码和数据。首先链接编辑器可以将它和其它可重定位文件和共享目标文件一起处理,生成另外一个目标文件。其次,动态链接器(Dynamic Linker)可能将它与某个可执行文件以及其它共享目标一起组合,创建进程映像。

    目标文件全部是程序的二进制表示,目的是直接在某种处理器上直接执行(Linux的.so,如/lib/ glibc-2.5.so;Windows的DLL)

    《linux,windows 可执行文件(ELF、PE)》

  7. 什么是ABI

    ABI(application binary interface)描述了应用程序(或者其他类型)和操作系统之间或其他应用程序的低级接口。 一个BINARY(EXEC, LIB)必需符合ABI才能在相应的系统上运行.

  8. ABI和目标文件格式是什么关系

    目标文件格式要符合ABI才能运行。

  9. 装载可执行程序之前的工作

    1. 可执行程序的文件格式

    2. 可执行程序的执行环境

    模拟实验:

准备.so文件

shlibexample.h (1.3 KB) – Interface of Shared Lib Example

shlibexample.c (1.2 KB) – Implement of Shared Lib Example

编译成libshlibexample.so文件

$ gcc -shared shlibexample.c -o libshlibexample.so -m32


dllibexample.h (1.3 KB) – Interface of Dynamical Loading Lib Example

dllibexample.c (1.3 KB) – Implement of Dynamical Loading Lib Example

编译成libdllibexample.so文件

$ gcc -shared dllibexample.c -o libdllibexample.so -m32


分别以共享库和动态加载共享库的方式使用libshlibexample.so文件和libdllibexample.so文件

main.c  (1.9 KB) – Main program

编译main,注意这里只提供shlibexample的-L(库对应的接口头文件所在目录)和-l(库名,如libshlibexample.so去掉lib和.so的部分),并没有提供dllibexample的相关信息,只是指明了-ldl

$ gcc main.c -o main -L /home/muggle/SharedLibDynamicLink/ -lshlibexample -ldl -m32

$ export LD_LIBRARY_PATH=$PWD #将当前目录加入默认路径,否则main找不到依赖的库文件,当然也可以将库文件copy到默认路径下。


跟新menu

新的menu增加了exec代码

make rootfs


gdb调试

还是有些地方模模糊糊的~

sunfy + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

折腾一天的jekyll

今天突然对jekyll很感兴趣,恨不得马上放弃lofter投入jekyll的怀抱。于是开始折腾了。中午不睡都不头疼了~

再联想到我荒废的SAE应用,于是决定把原来SAE上的wordpress删了换成jekyll。

于是。。。

sudo apt-get install subversion


安装完SVN就开始checkout了

svn checkout https://svn.sinacloud.com/appname

删了全部

svn del *

提交下

svn ci -m “del all”


看下SAE状况
嗯,确实删了。

然后就是把_site里面的生成的静态页面上传上去


这样SAE方面送算是告一段落。

要在本地写文章,难免就要测试。测试如果每次都用SAE直接访问,有风险又浪费云豆。所以就要在本地测试。

可是在虚拟机里面打开网页我闲麻烦,浪费资源。虚拟机主要是用来做代码管理的。

于是就要让主机能够访问虚拟主机。

所有装个apache2

sudo apt-get install apache2


看下虚拟机IP

ifconfig

在主机上访问,测试

没问题。

但是要访问我的blog地址不是默认地址,所以有两种方法

  1. 修改jekyll
  2. 更改apache的配置

方法一:

根据官网的介绍,修改_config


换了目的地址,权限就不够了

sudo 下

OK,主机上测试下


大功告成。
方法二:

修改/etc/apache2/apache2.conf

把原来的/var/www/改成想要的地址


修改/etc/apache2/sites-available/000-default.config

重启apache2

sudo /etc/init.d/apache2 restart

Ok,现在不用再使用管理员权限了

可以把jekyll的_config.yml中的destination删了,使用默认值

现在只要使用 Jekyll build命令就可以了。

===========================================================================================================================================================================

总结:

折腾了一整天,最终的发现markdown的效果不是很理想。也许还要进行设置。但是经过这样一天下来我觉得很麻烦。也许是我还太菜了吧。所以我放弃了从lofter转jekyll的想法了。因为要转不是仅仅只要换一个空间就可以了。

所以以后转的话一定一定要想好用什么平台,免得又想转博客。现在如果我换的话,之前的文章的图片是最大的麻烦。lofter虽然很不适合blog,但是也有一个很大的好处就是不用担心图片的问题。

当我准备结束的时候,我居然看到一条广告,着实让我心动不已,又有开始折腾的兴奋了。


于是我开始实验SAE是否可以完全使用wordpress了。。。

分析Linux内核创建一个新进程的过程

task_struct数据结构

linux进程管理分析

In user space, the process is the process identifier (PID) said. From the user’s perspective, a PID is a numeric value, can uniquely identify a process. A PID does not change during the whole life process, but PID can be re used in the process is destroyed, so they are not always ideal cache.

In user space, to create the process can be used in several ways. You can execute a program (which leads to create a new process), also can be in within the program, called a fork or Exec System Call. Fork calls will lead to create a child process, and the exec call will use the new program instead of the current process context.

在用户空间中,每个进程都有一个独一无二的PID。从用户的角度来看,PID在整个进程过程中都不能够改变,但当进程被回收后,PID则可以再次被利用。

在用户态中创建一个进程有多种方法。

  1. 你可以运行一个程序,而程序就会自动创建一个进程。

  2. 也可以在一个进程中庸系统调用创建一个进程。例如:Fork可以创建一个子进程。

精简的task_struct:

Task_struct 在/linux/include/linux/sched.h.

Task_struct

{

  • Volatile long state;
    
  • Long counter;
    
  • Long priority
    
  • Unsigned long signals;  // pending sigs
    
  • Unsigned long blocked; //masked sigs
    
  • Int pid, pgrp, uid, euid, gid, egid;
    
  • Struct linux_binfmt;
    
  • Struct task_struct p_opptr;    // ptr to original parent
    
  • Struct task_struct p_pptr;     // ptr to immediate parent
    
  • Struct task_struct p_cptr;     // ptr to most recent child
    
  • Struct task_struct p_ysptr;    // ptr to following sibling
    
  • Struct task_struct p_osptr;    // ptr to previous sibling
    
  • Struct task_struct *next_task;  // in process list
    
  • Struct task_struct *prev_task;  // in process list
    
  • Struct task_struct *next_run; // in ready queue
    
  • Struct task_struct *prev_run; //in ready queue
    
  • Struct mm_struct  mm[1];
    
  • Unsigned long kernel_stack_page;
    
  • Unsigned long saved_kernel_stack;
    
  • Struct fs_struct fs[1];
    
  • Long utime, stime, cutime, cstime, start_time;
    
  • Struct sem_queue *semsleeping;
    
  • Struct wait_queue *wait_chldexit;
    
  • Struct sigaction sigaction[32];
    
  • Struct rlimit rlim[RLIM_NLIMITS];
    
  • Struct thread_struct tss;  // includes saved registers
    
  • Unsigned long policy;  // SCHED_FIFO,SCHED_RR,SCHED_OTHER
    
  • Unsigned long rt_priority;
    
  • // for SMPs
    
  • Int processor, last processor;
    
  • Int lock_depth;
    
  • }

进程的状态:

task_struct field:

long state;

5 States (see include/linux/sched.h):

  • #define TASK_RUNNING            0
    
  • #define TASK_INTERRUPTIBLE      1
    
  • #define TASK_UNINTERRUPTIBLE    2
    
  • #define TASK_ZOMBIE             4
    
  • #define TASK_STOPPED            8
    

进程的创建:

从该图可以看出do_fork是创建进程的基本函数。do_fork在/linux/kernel/fork.c,包括copy_process().

所以我们主要来看看do_fork:

在 Linux 内核中,供用户创建进程的系统调用fork()函数的响应函数是 sys_fork()、sys_clone()、sys_vfork()。这三个函数都是通过调用内核函数 do_fork() 来实现的。根据调用时所使用的 clone_flags 参数不同,do_fork() 函数完成的工作也各异。

Clone flags = CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND, CLONE_PID

/

/do_fork中的主要函数调用

do_fork(clone_flags, unsigned long usp, struct pt_regs *regs)

{

  • p = copy_process();//调用该函数用来设置进程的信息,包括进程描述、其他数据等
    
    
    :
    
  • wake_up_new_task(p, clone_flags);
    

}

参数说明:

clone_flags:这和 clone( )的flags参数相同。

stack_start:这也和clone()中的child_stack参数一样。

regs:Pointer to the values of the general purpose registers saved into the Kernel Mode stack when switching from User Mode to Kernel Mode.

stack_size:我查到的资料并不太明确知道这个参数具体是做什么的。通常将它设置为0.

parent_tidptr, child_tidptr:这和clone()中的ptid and ctid参数一样。

clone主要的flags:

CLONE_PTRACE:P.S.: If CLONE_PTRACE is specified, and the calling process is being traced, then trace the child also.

CLONE_STOPPED:强制子进程从TASK_STOPPED状态开始。

CLONE_UNTRACED:Set by the kernel to override the value of the CLONE_PTRACE flag

CLONE_VM:Shares the memory descriptor and all page tables

所调用到的clone()函数是为了复制进程的描述。而该函数的主要功能是:

The copy_process( ) function sets up

  • the process descriptor

  • any other kernel data structure required for a child’s execution.

  • Its parameters are the same as do_fork( ), plus the PID of the child.

static task_t *copy_process( )

{       :

p = dup_task_struct(current);

:

retval = copy_thread(0,clone_flags,…, regs);

:

sched_fork§;

:

}

==================================================================================================================

==================分割线==============================

好乱,我自己都看的好乱。。。

不管了,直接上实验截图了。一知半解的。

cd LinuxKernel

rm -rf menu

git clone https://github.com/mengning/menu.git

cd menu

mv test_fork.c test.c

make

结合之前查的资料,虽然实验有些失败,但是还是可以得出这样一个过程:

fork() -> sys_clone() -> do_fork() -> dup_task_struct() -> copy_process() -> copy_thread() -> ret_from_fork()

好吧不得不承认,这章我不懂。。。为了证书只能在这里瞎掰了。

sunfy + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

从system_call开始到iret

自己搭建了实验环境,逃离实验楼,实在是太卡了。自己的环境就是爽!

实验开始:

先加如getuid和getuidAsm代码:


运行系统:


实验下,添加的功能是否可以
效果没问题。

用GDB调试,设置断点

一步一步执行


实验目的达到了。

===========================================================================================================================这里是分割线========================================

从system_call开始到iret

网上有几张图很好的说明了这个过程。

能力不足,不足以详细的说明从system_call到iret的详细过程。在查阅了些资料后,发现有几张图还是解释的不错的,于是就把他们贴出来了。其实也是一种偷懒啦~

下图引用

《linux系统调用原理分析(下)》

下图引用

《system_call中断处理过程》

经过《扒开系统调用的三层皮》2周的学习,对系统调用有些感性的认识,但是没有书看啊,总感觉还是挺乱的。

sunfy + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://www.xuetangx.com/courses/course-v1:ustcX+USTC001+_/about ”