⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄

📁 华中科技大学96级学生linux内核实习报告
💻
📖 第 1 页 / 共 5 页
字号:
<html><head><title>Linux原代码分析 </title></head><body><p><font FACE="宋体" SIZE="2"> </p><p></font><font face="宋体" size="7"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><font FACE="隶书" SIZE="6"> Linux代码分析实验报告 </font><font FACE="宋体" size="4">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ----关于EXECVE系统调用  </font><font FACE="宋体" SIZE="7"></p><p></font><font FACE="宋体" SIZE="5" COLOR="#0000ff"><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 962班 <b>陈浩 </b>(学号:9630043)</i></font><font FACE="宋体" SIZE="5"></p><p>一 <font FACE="隶书" SIZE="6">简介(Introdution):&nbsp;<br></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<strong>&nbsp;</font><font FACE="宋体" size="4">1</strong>,<strong>进程(process)</strong>: &nbsp;&nbsp; 在多道程序批处理系统和分时系统中,程序并不能独立运行。作为资源分配和运行的基本单位是进程。操做系统所具有的四大特征也都是基于进程而形成的。进程对于操做系统具有特别重要的意义。进程是程序的一个执行过程,其运动性质是由其自身的状态变化决定的。通常在操作系统中,进程至少有三种基本状态:运行态,就绪态,等待态。Linux 是一个多任务的分时操作系统</font><font FACE="宋体" SIZE="5">, </font><font FACE="宋体" size="4">在<strong>Linux </strong>中进程被分为如下状态<strong>:Running, &nbsp; Waiting, Stopped, Zombie.</strong> 四种状态。在Linux中,主要的进程的产生之间的关系如下所示:<br><br><br></font><font FACE="宋体" SIZE="5">&nbsp;&nbsp;&nbsp; </font><font FACE="宋体" size="4">init(1)-+-crond(98)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-emacs(387)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-gpm(146) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-inetd(110)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-kerneld(18)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-kflushd(2) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-klogd(87)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-kswapd(3) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-login(160)---bash(192)---emacs(225)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-lpd(121) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-mingetty(161)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-mingetty(162)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-mingetty(163) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-mingetty(164)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-login(403)---bash(404)---pstree(594)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-sendmail(134)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-syslogd(78)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; `-update(166)</font><font FACE="宋体" SIZE="5"><font FACE="宋体" SIZE="6"></p></font><p>&nbsp;&nbsp;&nbsp; </font><font FACE="宋体" size="4"><strong>2,进程和内存分配(memory management)的关系:</strong>因为一个程序必须首先被放在内存中才能运行,而且对每一进程都要有一相应的进程控制块(PCB),所以每一个进程都必须占用一定的存储空间。但因为真正的 physical memory 要比 virtual memory 要小的多,所以操作系统需要对 physical memory 进行最有效的利用。其中的一种办法就是 OS 只把那些正被使用着的页调进内存。这种只有在真正需要访问时才把虚页装进内存的技术被称为 demand paging.当一个进程试图访问一 virtual address 而它当前却不在内存中时,处理器将找不到所须的页表项。这时,处理器将通知操作系统发生了 page fault。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果此 faulting virtual address 是非法的,这就意味着此进程正试图访问一个不属于它的 virtual address,这表明进程已经出现错误,操作系统为保护其他系统中进程将终止此错误进程。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果 faulting virtual address 是合法的但所须的页当前不在内存中,操作系统会把此页从硬盘调进内存中。相对来说,对硬盘的访问需要很长时间,这样此进程就必须</font><font FACE="宋体" size="3">在所</font><font FACE="宋体" size="4">须页被调进内存之前等待相当长的一段时间,如果此时有其它的进程可以运行,操作系统将先让这些进程运行。新调进的页将被写进一个空闲的 physical page frame ,并且一个新的关于此 virtual page 的页表项被加进 processes page table。然后,此进程被选中以继续运行,运行是从 memory fault 发生时的机器指令开始进行下去的。&nbsp; </font><font FACE="宋体" SIZE="5"></p><p></font><font FACE="宋体" size="4">&nbsp;</font><font FACE="宋体" SIZE="5">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; </font><font FACE="宋体" size="4">Linux 使用 demand paging 以把可执行的程序装入进程的 virtual memory。当一个命令被执行时,包含此命令的文件被打开并且它的内容被映射进进程的 virtual memory中。通过修改<strong><u> 描述这些进程的数据结构</u><em>(</font><font FACE="宋体" SIZE="5">memory mapping</font><font FACE="宋体" size="4">)</em></strong>,上面所说的映射是很容易做到的。然而,只有可执行文件的第一部分被真正的放进物理内存。文件的其它部分还是在磁盘上。当此文件(进程)执行时,它会造成 page faults 的出现,Linux 将根据进程的 memory map 决定需要把文件的哪一块调进内存以满足执行的需要。</font><font FACE="宋体" SIZE="5"></p><font FACE="宋体" SIZE="6"><p></font>&nbsp; </font><font FACE="宋体" size="4">&nbsp; exec系统调用从一个指定的程序重新初始化一个进程,当该进程保持不变时程序却有可能改变。另一方面,fork系统调用是用复制指令,用户数据段和系统数据段的办法创建一个新进程,该进程是一个已存在进程的复制品,而不是从一个程序初始化得来的。 </font><font FACE="宋体" SIZE="5"><font FACE="宋体" SIZE="6"></p><p align="left"></font><font FACE="宋体" size="4">&nbsp;&nbsp;&nbsp;&nbsp; 没有fork,exec的使用将受到限制;而没有 exec, fork也无任何实际使用意义。除了引导Linux 核心自身外,exec 系统调用是程续在Linux上获得执行的唯一方式。不仅shell使用 exec 执行用户的程序,而且 shell 和他的祖先也是通过 exec 引用的。而 fork 系统调用则是创建新进程的唯一方式。&nbsp; </font><font FACE="宋体" SIZE="6"></p></font><p><strong>二 Principles</strong></p><p>&nbsp;&nbsp;&nbsp; <strong>(一) 结构</strong>:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><font FACE="宋体" size="4">函数 do_execve()主要完成以下步骤:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <em><strong>1</strong></em>.把页表清 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <em><strong>2</strong></em>.调用函数 open_namei();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <em><strong>3</strong></em>.检查此系统调用本身的参数设置是否正确; &nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <em><strong>4</strong></em>.调用函数 prepare_binprm();此函数主要完成以下工作 :<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><font face="宋体" size="5">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font FACE="宋体" size="4">1.检查文件的类型是否满足执行条件;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;2.检查执行权限;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3.检查文件此是否正在被写入(修改);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4.set user_id, set group_id;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.调用 memset() 和 read_exec();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <em><strong>5.</strong></em>调用函数 copy_strings();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <em><strong>6</strong></em>.调用 search_binary_handler(),</font><font FACE="宋体" size="3">查找可执行</font><font FACE="宋体" size="4">的文件格式; </font><font FACE="宋体" SIZE="5">&nbsp;</font><font FACE="宋体" size="4"></p></font><font><p><strong><big><big>(二) 算法</big></big></font><font FACE="宋体" SIZE="6">:</font> </strong></p><blockquote>  <blockquote>    <blockquote>      <font FACE="宋体" size="3"><p></font><font color="#00FF40" face="宋体" size="3">&nbsp;&nbsp;&nbsp;&nbsp;       </font><font face="宋体" size="3" color="#000000">&nbsp;&nbsp; 由于 Linux 是用       comand-loading 算法,所以 do_execve()       实际所做的工作并不多,不需要把所要执行的程序真正的读入内存,而仅仅把所要的代码头设置好,并把进程的状态设置为“就绪”,等待系统的调度,以运行此进程。<br>      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;       真正的把代码读入内存,要涉及到较复杂的算法,如在首先要内存中寻找一块足够大的空间,然后再把程序从外存读入此空间中。<br>      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exec()所做的和内存有关的工作有以下这些:<br>      </font>&nbsp; <font face="宋体" size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1). 内存空间的获取: <br>      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 page for exec header entire file for omagic <br>      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 page or more for stack (MAX_ARG_PAGES) <br>      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (2).&nbsp;&nbsp;       &nbsp; <tt>clear_page_tables()</tt> used to remove old pages. <br>      <tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (3).&nbsp; change_ldt()</tt>       sets the descriptors in the new <tt>LDT[]</tt> <br>      <tt>&nbsp;&nbsp; </tt>&nbsp;&nbsp;&nbsp; (4). <tt>ldt[1]</tt> = code base=0x00,       limit=TASK_SIZE <br>      <tt>&nbsp;&nbsp; </tt>&nbsp;&nbsp;&nbsp; (5).&nbsp; <tt>ldt[2]</tt> = data base=0x00,       limit=TASK_SIZE<br>      &nbsp;&nbsp;&nbsp;&nbsp; These segments are DPL=3, P=1, S=1, G=1. type=a (code) or 2       (data) <br>      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (6).&nbsp; Up to <tt>MAX_ARG_PAGES</tt>       dirty pages of argv and envp are allocated and stashed at the top of the data segment for       the newly created user stack.</font></p>      <p><font FACE="宋体" size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (7).&nbsp;       Set the instruction pointer of the caller <tt>eip = ex.a_entry</tt> <br>      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (8).&nbsp; Set the stack pointer of the       caller to the stack just created (esp = stack pointer) These will be popped off the stack       when the caller Resumes. <br>      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (9).&nbsp; update memory limits<br>      <tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;       end_code = ex.a_text</tt><br>      <tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;       end_data = end_code + ex.a_data</tt><br>      <tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;       brk = end_data + ex.a_bss</tt> </p>      </font>    </blockquote>  </blockquote>  <blockquote>    <font FACE="宋体" size="3"><p>Interrupts and traps     是在当前任务的环境中被处理的。特别的,地址的转换是用当前任务的页目录进行的。然而,段却是用的内核的。这样,所有的线形地址都指向     &nbsp; kernel memory。<br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -