HIT CSAPP 大作业 程序人生

                                                                   计算机系统

                                              题     目  程序人生-Hello’s P2P 

                                              专       业  未来技术人工智能模块 

                                               学  号     2022112257        

                                               班   级      WL021           

                                               学       生      董子宁           

                                               指 导 教 师       刘宏伟           

计算机科学与技术学院

2024年5月

摘  要

本文通过探索hello.c的一生,细致了解其从.C文件到执行到结束的过程,.C文件经过预处理,编译,汇编,链接成为可执行文件,在执行过程中又涉及进程管理,存储管理等内容,hello.c的生命历程将其串联在一起,我们将深入理解这一过程。

关键词:hello;P2P;020;汇编;链接;进程管理;存储管理    

第1章 概述

1.1 Hello简介

运行hello.c程序时,是由编译器读取并启动程序,将程序转换为一个名为hello的可执行目标文件。第一步,cpp根据以字符#开头的命令修改hello.c,即预处理生成一个hello.i文件。第二步,ccl将hello.i文件编译,得到汇编语言程序的文件hello.s。第三步,as将hello.s翻译成机器语言指令,并将机器语言指令打包成可重定位目标文件hello.o。第四步,ld进行链接,得到可执行目标文件:hello。在shell中加载运行hello程序,系统会为hello创建(fork)一个子进程,这样,就完成了P2P的过程。

程序从无到有,形成可执行文件,在shell中产生子进程,通过execve加载hello,系统分配资源并执行。执行完成后,父进程将回收hello进程,内核将清除hello所有的痕迹,就完成了020的过程。

1.2 环境与工具

12代酷睿i7 CPU;2GHz;2G RAM;256GHD Disk 以上

Windows7/10 64位以上;VirtualBox/Vmware 11以上;Ubuntu 22.1 LTS 64位/优麒麟 64位;

Visual Studio 2010 64位以上;CodeBlocks 64位;vi/vim/gedit+gcc

1.3 中间结果

hello.c:源程序

hello.i:预处理后的文件

hello.s:编译后汇编程序文件

hello.o:汇编后的可重定位目标文件

hello:链接后的可执行目标文件

elf.txt:ELF格式下的hello.o

1.4 本章小结

本章介绍了hello.c的P2P和020过程。介绍了实验的硬软件环境、开发和测试工具,以及中间结果文件。

第2章 预处理

2.1 预处理的概念与作用

概念:预处理指的是程序在编译之前进行的处理,是计算机在处理一个程序时所进行的第一步处理,可以进行代码文本的替换工作,但是不做语法检查。 预处理是为编译做的准备工作,能够对源程序.c 文件中出现的以字符“#”开头的命令进行处理,包括宏定义# define、文件包含# include、条件编译# if def 等,最后将修改之后的文本进行保存,生成.i文件,预处理结束。

作用:预处理可以在在将c程序转化为s的汇编程序之前进行文本替换和宏扩展,方便后续的代码转化,并且对于在汇编中无用的注释进行处理,删去无用部分对后续操作做准备。

2.2在Ubuntu下预处理的命令

在终端中输入cpp hello.c  > hello.i,得到预处理后的文件

2.3 Hello的预处理结果解析

图中包含hello.c中涉及到的所有头文件名称

除此之外

1.开头的文字注释被删除

2.头文件stdio.h、unist.h和stdlib.h都被替换成了相应的完整的库中的内容。

3.#+数字 代表编译器中原始代码的行号

hello.c的代码在文件最后

2.4 本章小结

预处理后的文件相较于源文件多了几千行,预处理器对hello.c进行了大量的展开操作,我们查看并比较了其中的差异。

第3章 编译

3.1 编译的概念与作用

概念:编译器将高级语言转换为汇编语言的过程,将hello.i翻译为hello.s

作用:将抽象的高级语言(C语言)翻译成汇编语言,同时gcc还会检查代码是否规范,是否有语法错误,编译器还能起到优化代码的作用。       

3.2 在Ubuntu下编译的命令

gcc -S hello.c -o hello.s(使用ccl要进行下载,所以用该命令)

3.3 Hello的编译结果解析

3.3.1数据

常量:

字符串常量位于.rodata数据段。

根据UTF-8编码原则,汉字被编码为三个字节,其余字符与ASCII码规则相同,除汉字外字符保持原形式。

变量(全局/局部/静态):

局部变量有i,argc,argv[]

i先被初始化为零,每次迭代加一,与9比较,小于等于则继续循环

argc被放在了寄存器%edi中,然后放入栈中-20(%rbp)的位置,而argv的的地址放在了寄存器%rdi中,然后将数据放入栈中-32(%rbp)的位置。

3.3.2赋值

“=”赋值进行了一次

-4(%rbp)中储存的是i,即让i=0.

对于逗号操作符,只在函数的传参过程中出现,造成相邻的两次参数赋值

i在第一次执行时是没有被赋初值的,只有在argc第一次与5比较后,才被赋初值为0.

3.3.3类型转换

函数atoi将输入的字符串转换为int型

3.3.4 sizeof

以数组argv[]为例,内存中该数组占了32个字节的空间

3.3.5算数操作

只进行了i+1的操作

3.3.6 逻辑/位操作

该程序中不存在逻辑操作

3.3.7 关系操作

程序中有两处关系操作

第一处,5和变量argc的比较

第二处,循环变量i和9的比较,小于等于则继续循环,在机器语言中,小于等于则跳转至.L4.

3.3.8 数组/指针/结构操作

该程序中只有数组操作,且只有一个数组argv[],数组的地址被储存在栈中,一开始作为参数从%rsi转入栈中

从上图中可以看出数组的首地址存在栈中,寻址时,先将首地址放入寄存器%rax中,再分别加一定的偏移量,再从内存中取出相应的字符串。

3.3.9 控制转移

if的条件转移,argc=5则跳转至.L2

for循环中,i<=9则跳转至.L4

3.3.10 函数操作

main函数:

参数:argc,argv[],argc储存在%edi中,argv[]首地址储存在%rsi中

返回:主函数返回则程序结束,argc!=5时,call exit,退出,或是调用函数后,返回%rax中的值0.

printf函数和puts函数

参数:printf在for循环中调用时传入argv[1],argv[2],argv[3],puts无参数传入

调用:printf在for循环中调用,puts在if分支中

sleep函数

参数:转换为整型数的argv[4]

无返回值,作用是睡眠

exit函数

无参数传入

退出

3.4 本章小结

本章详细介绍了C语言程序转换为汇编语言后,程序的各个组成部分的表示,即C语言中的操作在汇编语言中如何体现,介绍了编译器如何处理C语言的各个数据类型以及各类操作。

第4章 汇编

4.1 汇编的概念与作用

概念:汇编器as将汇编语言的hello.s文件翻译成机器语言的可重定位目标文件hello.o的过程称为汇编

作用:汇编可以将汇编代码转换为计算机可执行的二进制代码,生成可重定位目标文件。

4.2 在Ubuntu下汇编的命令

gcc -c hello.s -o hello.o

4.3 可重定位目标elf格式

使用readelf命令,将elf结果保存到elf.txt中

  1. ELF头

ELF头有一个16字节的序列,该序列表示生成该文件的系统的字的大小和字节顺序。ELF头剩下的部分包含帮助链接器语法分析和解释目标文件的信息。其中包括ELF头的大小、目标文件的类型(如可重定位、可执行或者共享的)、机器类型(如x86-64)、节头部表(section header table) 的文件偏移,以及节头部表中条目的大小和数量。在上述表中,可以看出关于ELF header的长度这里也给出了,一共是64个字节。

  1. 节头表

描述了.o文件中每一个节出现的位置,大小,目标文件中的每一个节都有一个条目。

本程序中没有程序头

  1. 重定位节

本程序需要重定位的信息有:.rodata中的模式串,putsexitprintfatoi, sleepgetchar

重定位节包含了在代码中使用的一些外部变量等信息,在接下来的链接中,需要利用重定位节的信息修改一些变量符号,链接器会利用重定位节的信息,如偏移量等,计算外部变量符号的正确地址。

重定位节中各项符号的信息:

Offset偏移量:需要被修改的引用节的偏移

Info信息:包括符号和类型两个部分,符号在前面四个字节,类型在后面四个字节

Sym.Value符号值:标识被修改引用应该指向的符号,

Type类型:重定位的类型

Addend加数:一个有符号常数,一些重定位要使用它对被修改引用的值做偏移调整

Sym.Name符号名称:重定向到的目标的名称。

文件中自动进行了翻译

  1. 符号表

符号表存放在程序中定义和引用的全局变量和函数等信息,在本程序中如getchar,puts,atoi等函数都存放在其中

4.4 Hello.o的结果解析

代码基本相同,但反汇编后的的每行前面都有一串16进制的编码。hello.s是由汇编语言组成的文件,反汇编得到的不仅有汇编语言,还有机器语言代码。

1.分支转移时,hello.s中是跳到如.L3等的代码段,给出的是代码段的名字,反汇编代码中,由于每一行都已经分配了地址,因此跳转命令后跟着的是要跳转部分的目标地址。

2.数字的进制不同:hello.s的数字用十进制表示,反汇编文件中数字是16进制的。

3.全局变量访问不同:在 hello.s 中,直接通过段名称加 %rip 寄存器访问 .rodata 段。然而在 hello.asm 中,初始阶段是不知道 .rodata 段的数据地址的,所以只能先写成 0(%rip) 进行访问。而在重定位和链接后,链接器会更新确定的地址以正确访问 .rodata 段中的数据。

4.5 本章小结

本章对汇编过程进行了详细的介绍,汇编处理将hello.s处理后生成一个可重定位目标文件hello.o,然后我们比较了hello.s和反汇编后的代码,展示了两者的区别。

第5章 链接

5.1 链接的概念与作用

概念:将一个或多个目标文件和库文件组合在一起,生成最终的可执行文件,这个文件可以被加载到内存并执行。

作用:通过将多个预编译的目标文件合并成为一个可执行文件,实现重定位,使分离编译成为可能。

5.2 在Ubuntu下链接的命令

ld -o hello -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o hello.o /usr/lib/x86_64-linux-gnu/libc.so /usr/lib/x86_64-linux-gnu/crtn.o

5.3 可执行目标文件hello的格式

ELF头部表

节表

程序头

重定位表

符号表

5.4 hello的虚拟地址空间

使用命令edb –run hello

data dump显示虚拟地址从0x401000开始,到0x402000结束。与5.3对照,我们可以根据5.3中每一节对应的起始地址在edb中找到相应信息。

5.5 链接的重定位过程分析

输入命令objdump -d -r hello,得到可执行文件hello的反汇编结果。与hello.o的反汇编结果相比,hello的反汇编结果增加了很多函数代码,增加了程序执行main前的准备工作,以及一些库函数的定义。一些虚拟的地址操作数被设置成了真正的虚拟地址。

重定位节和符号定义链接器将相同类型的节合并,生成ELF节,形成可执行文件的虚拟空间,分配内存地址,再将重定位条目指向的位置设置为真实的地址。

5.6 hello的执行流程

0x401000 _init

0x401030 puts@plt

0x401040 printf@plt

0x401050 getchar@plt

0x401060 atoi@plt

0x401070 exit@plt

0x401080 sleep@plt

5.7 Hello的动态链接分析

动态链接中,编译器没有办法预测共享库函数的运行地址,因为共享模块在运行时会加载到任意位置。因此会为共享库函数的引用生成一条重定位记录,由动态链接器来解析。

PLT:PLT是一个数组,其中每个条目是16字节代码。PLT[0]是一个特殊条目,它跳转到动态链接器中。每个被可执行程序调用的库函数都有它自己的PLT条目。每个条目都负责调用一个具体的函数。

GOT:GOT是一个数组,其中每个条目是8字节地址。和PLT联合使用时,GOT[O]和GOT[1]包含动态链接器在解析函数地址时会使用的信息。GOT[2]是动态链接器在1d-linux.so模块中的入口点。其余的每个条目对应于一个被调用的函数,其地址需要在运行时被解析。每个条目都有一个相匹配的PLT条目。

查看hello的ELF文件,发现GOT起始表位置:

执行init前

执行init后got.plt地址

5.8 本章小结

本章对链接过程进行了详细介绍,链接指令可将hello.o转换为可执行目标文件,分析了hello的格式,虚拟空间,链接的重定位过程,和hello的执行过程,并且分析了动态链接过程。

6章 hello进程管理

6.1 进程的概念与作用

概念:计算机中正在运行的一个程序的实例,它是一个动态的实体,包含了程序代码以及程序执行时的当前活动,包括程序计数器、寄存器内容和变量。

作用:每个进程都有自己的文件描述,内存,地址空间等,操作系统通过进城来管理这些资源,使多个程序可以有效运行。

操作系统可以实现多个进程并发执行,提高系统的性能和效率。

6.2 简述壳Shell-bash的作用与处理流程

shell-bash是一个C语言程序,代表用户执行进程(一个命令行解释器)。它交互的解释和执行用户输入的命令,能够通过调用系统级的函数或功能执行程序、建立文件等。同时它还会协调程序间的运行冲突,保证程序能够以并行的形式高速执行。除此之外,bash还提供了一个图形化的界面,提高了交互的速度。

Shell的处理流程大致如下:

从Shell终端读入输入的命令。

切分输入字符串,获得并识别所有的参数

若输入参数为内置命令,则立即执行

若输入参数并非内置命令,则调用相应的程序为其分配子进程并运行

若输入参数非法,则返回错误信息

处理完当前参数后继续处理下一参数,直到处理完毕

6.3 Hello的fork进程创建过程

当Shell运行一个程序时,父进程通过fork函数生成这个程序的进程。新创建的子进程几乎但不完全与父进程相同,包括代码、数据段、堆、共享库以及用户栈。父进程和新创建的子进程之间最大的区别在于它们有不同的PID。

6.4 Hello的execve过程

execve函数在当前进程的上下文中加载并运行一个新程序。它会加载指定的可执行文件,并接受参数列表和环境变量列表。execve只有在出现错误时才会返回到调用程序。与fork函数一次调用会返回两次不同,execve只会调用一次并且从不返回。

一旦可执行文件被加载,execve会启动启动代码。启动代码负责设置栈,将可执行文件中的代码和数据从磁盘复制到内存中,然后通过跳转到程序的入口点或第一条指令来执行该程序,从而将控制权交给新程序的主函数。

6.5 Hello的进程执行

输入./hello,shell为hello fork一个子进程,execve函数在当前子进程的上下文中加载并运行hello,加载指定的可执行文件,并接受参数列表和环境变量列表,输出2022112257 dongzining 187****5007,执行sleep函数,休眠2s,内核转而执行其他进程,2s后回复hello的上下文,继续执行。

    执行9次输出后,执行getchar函数,发生一个上下文切换,读取数据到缓存区后,发生中断,再次上下文切换执行hello进程。

6.6 hello的异常与信号处理

程序运行时使用CTRL+Z,进程收到SIGSTP信号,hello进程挂起并向父进程发送SIGCHLD.

ps查看程序进程状态

jobs查看已停止的程序

pstree,显示进程的分支图

调用kill杀死进程

按CTRL+C,向进程发送SIGINT信号,终止hello

异常种类:

中断:收到键盘输入 处理:处理器读取异常号,调用中断处理程序

陷阱:shell执行syscall fork一个进程 处理:陷阱处理程序在内核中执行后返回。

故障:缺页异常等 处理:从磁盘加载相应的页到主存。

终止:硬件损坏 处理:终止程序

6.7本章小结

本章详细介绍了进程,介绍了shell为hello fork进程,execve执行程序以及程序运行过程中异常的处理等,并探索了CTRL+Z后使用多种指令查看进程状态,以及向进程发送信号等。

7章 hello的存储管理

7.1 hello的存储器地址空间

逻辑地址:程序直接使用的,机器语言中用来指定一个操作数或一条指令的地址,由段和偏移量组成。

线性地址:由逻辑地址到物理地址变换之间的中间层。在分页机制下可以变换形成物理地址,不采用分页机制,直接就是物理地址。

虚拟地址:虚拟内存空间的地址,逻辑地址经过计算后得到的结果,需要经过MMU翻译后才能得到物理地址。hello中,反汇编代码中就是经过计算后的虚拟地址。

物理地址:计算机中真正的内存地址,每个字节都有自己的物理地址,物理地址决定了数据在内存中真正的存储位置。hello中寻找数据需要根据其物理地址。

7.2 Intel逻辑地址到线性地址的变换-段式管理

逻辑地址由两个部分组成:段选择子和偏移量。段式内存管理方式就是直接将逻辑地址转换成物理地址,也就是CPU不支持分页机制。其地址的基本组成方式是段号+段内偏移地址。

段标识符:由16位长的字段组成,称为段选择符。其中,前13位是一个索引号,索引号是段描述符的索引,段描述符具体地址描述了一个段,段描述符数组称为段描述符表,因此可以通过段标识符的前13位在表中找到一个具体的段描述符,每个段描述符由8字节组成。后3位包括一些硬件细节,表示该段寄存器的属性。

段描述符的构成:

1.Base字段:表示包含段的首字节的线性地址,即一个段开始位置的线性地址;

2.全局段描述符:放在全局段描述符表(GDT中);

3.局部段描述符:放在局部段描述符表(LDT中)。

CPU将会通过其中的16位段选择子定位到GDT/LDT中的段描述符,通过这个段描述符得到段的基址,与段内偏移地址相加得到的64位整数就是线性地址。这就是CPU的段式管理机制,其中,段的划分,也就是GDT和LDT都是由操作系统内核控制的。

                       

7.3 Hello的线性地址到物理地址的变换-页式管理

页式管理是一种操作系统内存管理技术,它将内存和进程的地址空间划分为固定大小的页,以实现对物理内存和逻辑地址之间的映射。其核心原理包括将主存储器分割为固定大小的页,并通过页表将线性地址映射到物理地址。此外,页目录存储指向页表的指针,页表将线性地址映射到物理地址,偏移量用于定位页内具体地址。处理器通过高位找到页目录项,中间位找到页表项,加上偏移量得到物理地址。TLB缓存用于加速地址翻译,存储最近的页表项以提高性能。整体而言,页式管理实现了高效的地址映射和内存管理,为多任务操作系统提供了良好的支持。

7.4 TLB与四级页表支持下的VA到PA的变换

TLB(Translation Lookaside Buffer)是一个硬件缓存,用于存储最近的一些虚拟地址到物理地址的映射。在四级页表结构中,虚拟地址通常划分为索引1、索引2、索引3和偏移量这四个部分,共同构成层级结构,用于访问页表。

当CPU需要将虚拟地址转换为物理地址时,首先会在TLB中查找映射。若在TLB中找到对应映射,则称为TLB命中,CPU可直接使用TLB中存储的物理地址;若未在TLB中找到映射,则称为TLB未命中。此时,CPU需要通过多级页表查找地址映射,先使用索引1找到第一级页表项,再使用索引2找到第二级页表项,依此类推,直至找到最终的页表项,并获取物理地址。

TLB的作用在于加速地址翻译的速度,因为其存储了最近使用过的虚拟地址到物理地址的映射,减少了对页表的频繁访问,从而提高了内存访问的效率。

7.5 三级Cache支持下的物理内存访问

为了提高 CPU的访存速度,计算机采用三级Cache缓存。低一级是高一级的缓存。

L1缓存:L1缓存是距离处理器核心最近的缓存,速度最快。当处理器需要访问内存中的数据时,首先会访问L1缓存。如果数据在L1缓存中找到了对应的数据,则可以立即访问这个数据,这被称为L1缓存命中。

L2缓存:如果在L1缓存中未找到需要的数据,处理器会继续检查L2缓存。L2缓存通常比L1缓存更大,但速度稍慢一些。如果数据在L2缓存中找到了对应的数据,则处理器会从L2缓存中读取这个数据,这称为L2缓存命中。

L3缓存:如果在L2缓存中也未找到需要的数据,处理器会继续检查L3缓存。L3缓存通常更大,但速度可能比L2缓存稍慢。如果数据在L3缓存中找到了对应的数据,则处理器会从L3缓存中读取这个数据,这称为L3缓存命中。

主存储器:如果在处理器的各级缓存中都未找到需要的数据,则处理器需要从主存储器中读取这个数据。这将导致一个内存访问周期,处理器从主存中读取数据并将其加载到适当的缓存层中。

这些缓存层级的存在可以极大地提高内存访问速度,因为较高级别的缓存通常速度更快,而且更接近处理器核心。只有在缓存中未命中时,才会导致对较慢的主存储器的访问。

7.6 hello进程fork时的内存映射

当shell使用fork创建子进程时,内核为新的子进程创建各种数据结构,并分配给子进程一个唯一的PID,为了给它创建虚拟内存空间,内核创建了当前进程的mm_struct、区域结构和页表的原样副本,将两个进程的页面都标记为只读,并将两个进程中的每个区域结构都标记为私有的写时复制。当fork在新进程中返回时,新进程现在的虚拟内存刚好和调用fork时存在的虚拟内存相同。当着两个进程中的任一个后来进行写操作时,写时复制机制就会创建新页面,因此,也就为每个进程保持了私有地址空间的抽象概念。

7.7 hello进程execve时的内存映射

Execve函数在Shell中加载并运行名为hello的可执行目标文件中的程序,以hello程序有效地替代当前程序。该过程包括以下几个步骤:

1.清除已存在的用户区域。删除当前进程(Shell)虚拟地址空间中已存在的区域结构。

2.创建私有区域映射。为hello程序的代码、数据、bss和栈区域创建新的区域结构。所有这些新区域均为私有且采用写时复制方式。代码和数据区域映射到hello文件中的.text和.data段。.bss段被映射为请求二进制零值,连接到匿名文件中,其大小信息包含在hello中。栈和堆区域也映射为请求二进制零值,且初始长度为零。

3.映射共享区域。若hello程序链接了共享对象(如标准C库libc.so),这些对象会被动态链接到该程序,并映射到用户虚拟地址空间中的共享区域。

4.设置程序计数器(PC)。执行execve的最后一步是设置当前进程上下文中的程序计数器,将其指向代码区域的入口点。下次调度hello进程时,程序将从该入口点开始执行。Linux会根据需要换入代码和数据页面。

7.8 缺页故障与缺页中断处理

缺页故障指DRAM缓存不命中,此时会触发缺页中断

  1. CPU转交控制权给操作系统内核,执行缺页中断处理程序。
  2. 操作系统分析引起缺页的原因
  3. 处理缺页:

未分配页面:如果地址对应的页面尚未分配,在MMU中注册相关页的物理地址。

页面被交换到磁盘:如果页面在磁盘上,则执行页面置换算法将一个页面从磁盘换入到物理内存中。

页面错误:如果是其他类型的页面错误,例如权限错误或无效访问,则相应地处理。

  1. 将相应的页放入物理内存。
  2. 恢复执行程序

7.9动态存储分配管理

动态内存分配器负责管理堆的分配和释放,维护内存的使用情况,并提供接口供程序员进行内存管理。堆是程序运行时用于动态分配内存的区域,动态分配器根据程序的请求在堆中分配内存空间,并在适当时机释放。动态内存分配器可以根据需要动态调整堆的大小,以便更有效地利用内存资源。对于内存的分配和释放,动态内存分配器可以分为两种类型:显式分配器和隐式分配器。

1)显式分配器:程序员显式地分配和释放内存。在这种情况下,程序员负责跟踪内存的分配和释放,并通过特定的API手动请求分配内存和释放不再使用的内存。

2)隐式分配器:由编程语言或者运行时环境自动处理内存的分配和释放。在这种情况下,内存的分配和释放是由语言或者环境的机制隐式完成的,程序员无需手动进行内存管理。例如,在一些高级语言中,有自动的垃圾回收机制,负责自动释放不再使用的内存。

7.10本章小结

本章详细介绍了hello的存储管理,intel 的段式管理、hello 的页式管理, VA 到PA 的变换、物理内存访问,hello进程fork、execve 时的内存映射、缺页故障与缺页中断处理、动态存储分配管理。虚拟内存空间能够使得程序在表面上独占整个内存。

结论

  1. hello.c经过预处理后,库函数,宏定义的内容被插入到文本中,得到hello.o
  2. hello.o经过编译器编译变为汇编语言文件得到hello.s
  3. hello.s经过汇编器变成二进制可重定位目标文件hello.o
  4. hello.o经过链接器链接得到可执行文件hello
  5. shell为hello fork一个子进程,execve在子进程上下文中加载并运行hello
  6. hello在执行过程中可能遇到各种异常,有各种异常处理机制
  7. 在hello中的地址为虚拟地址,要经历虚拟地址映射为线性地址,再由线性地址计算得到物理地址。
  8. hello执行printf函数时会调用malloc向动态内存分配器申请堆中的内存
  9. hello执行完毕,由父进程回收终止的子进程,结束自己的一生。

附件

hello.c:源程序

hello.i:预处理后的文件

hello.s:编译后汇编程序文件

hello.o:汇编后的可重定位目标文件

hello:链接后的可执行目标文件

elf.txt:ELF格式下的hello.o

参考文献

[1]  林来兴. 空间控制技术[M]. 北京:中国宇航出版社,1992:25-42.

[2]  辛希孟. 信息技术与信息服务国际研讨会论文集:A集[C]. 北京:中国科学出版社,1999.

[3]  赵耀东. 新时代的工业工程师[M/OL]. 台北:天下文化出版社,1998 [1998-09-26]. http://www.ie.nthu.edu.tw/info/ie.newie.htm(Big5).

[4]  谌颖. 空间交会控制理论与方法研究[D]. 哈尔滨:哈尔滨工业大学,1992:8-13.

[5]  KANAMORI H. Shaking Without Quaking[J]. Science,1998,279(5359):2063-2064.

[6]  CHRISTINE M. Plant Physiology: Plant Biology in the Genome Era[J/OL]. Science,1998,281:331-332[1998-09-23]. http://www.sciencemag.org/cgi/ collection/anatmorp.

[7]  深入理解计算机系统

[8]CSDNhttps://blog.csdn.net/daocaokafei/article/details/116207148?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165235562016781683965613%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=165235562016781683965613&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_click~default-1-116207148-null-null.142^v9^pc_search_result_control_group,157^v4^new_style&utm_term=%E8%99%9A%E6%8B%9F%E5%9C%B0%E5%9D%80&spm=1018.2226.3001.4187

  • 9
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值