tsx81429 发表于 2024-8-3 18:46:57

程序人生-Hello’s P2P From Program to Process




计算机体系

大作业

题     目  程序人生-Hello’s P2P 
专       业 将来技能学院人工智能2+X
学     号        2022112767       
班   级         22wl02          
学       生          符爱        
指 导 教 师          刘宏伟      


计算机科学与技能学院
2024年5月
摘  要
本文主要介绍在linux发行版操作体系Ubantu下,C语言程序hello.c从源代码转换为可执行文件的过程,包括预处理、编译、汇编、链接、进程管理、存储管理和IO管理等整个生命周期。旨在通过对hello程序在计算机中运行过程中的分析,总结并深入理解程序在计算机中运行的基本原理。
关键词:C语言、编译过程、进程、存储器布局、操作体系


目  录

第1章 概述
1.1 Hello简介
1.2 环境与工具
1.3 中间结果
1.4 本章小结
第2章 预处理
2.1 预处理的概念与作用
2.2在Ubuntu下预处理的命令
2.3 Hello的预处理结果解析
2.4 本章小结
第3章 编译
3.1 编译的概念与作用
3.2 在Ubuntu下编译的命令
3.3 Hello的编译结果解析
3.4 本章小结
第4章 汇编
4.1 汇编的概念与作用
4.2 在Ubuntu下汇编的命令
4.3 可重定位目的elf格式
4.4 Hello.o的结果解析
4.5 本章小结
第5章 链接
5.1 链接的概念与作用
5.2 在Ubuntu下链接的命令
5.3 可执行目的文件hello的格式
5.4 hello的假造地点空间
5.5 链接的重定位过程分析
5.6 hello的执行流程
5.7 Hello的动态链接分析
5.8 本章小结
第6章 hello进程管理
6.1 进程的概念与作用
6.2 简述壳Shell-bash的作用与处理流程
6.3 Hello的fork进程创建过程
6.4 Hello的execve过程
6.5 Hello的进程执行
6.6 hello的异常与信号处理
6.7本章小结
第7章 hello的存储管理
7.1 hello的存储器地点空间
7.2 Intel逻辑地点到线性地点的变换-段式管理
7.3 Hello的线性地点到物理地点的变换-页式管理
7.4 TLB与四级页表支持下的VA到PA的变换
7.5 三级Cache支持下的物理内存访问
7.6 hello进程fork时的内存映射
7.7 hello进程execve时的内存映射
7.8 缺页故障与缺页中断处理
7.9动态存储分配管理
7.10本章小结
第8章 hello的IO管理
8.1 Linux的IO装备管理方法
8.2 简述Unix IO接口及其函数
8.3 printf的实现分析
8.4 getchar的实现分析
8.5本章小结
结论
附件
参考文献


第1章 概述

1.1 Hello简介

Hello是C语言中最基础的一个程序,可以通过运行hello的过程来了解程序在计算机中的处理、执行过程,大致可以总结为P2P和020两个过程:
P2P:From Program to Process  编译完成的C语言源程序(文本)hello.c经过预处理器(cpp)预处理之后得到hello.i文件,经过编译器(ccl)编译后得到汇编程序hello.s,经过汇编器(as)汇编后得到可重定位目的文件hello.o,末了经由链接器(ld)生成可执行程序hello,在壳(shell)里输入执行命令,进程管理(OS)为hello fork()一个进程(Process),即完成了P2P过程。
020:O2O: From Zero-0 to Zero-0进程管理为hello进行execve操作,然后经过mmap操作将其映射到内存中,给运行的hello分配时间片,让其在Hardware(CPU/RAM/IO)取指译码执行/流水线等,即执行逻辑控制流过程。程序运行竣事后,父进程接纳子进程,内核会删除程序相干数据,即完成了020过程。
1.2 环境与工具

硬件环境:12th Gen Intel(R) Core(TM) i5-12450H  2.00 GHz   16G RAM
软件环境:Windows11 64位,VMware,Ubuntu 18.04
开发和调试工具:Visual Studio 2022 64位  CodeBlocks;vim objump edb gcc readelf等
1.3 中间结果

hello.i
预处理后得到的文本文件
hello.s
编译后得到的汇编语言文件
hello.o
汇编后得到的可重定位目的文件
hello.asm
可重定位文件hello.o的反汇编文件
hello01.asm
可执行文件hello的反汇编文件
hello.elf
hello.o的elf文件
hello01.elf
可执行文件hello的elf文件


1.4 本章小结

本章首先介绍了hello程序的P2P和020过程,通过两过程的详细介绍,阐述了程序在计算机中运行的全过程,然后列出了撰写论文的软、硬件环境和开发、调试工具,末了列写出实现hello运行过程中产生的中间文件结果。
(第1章0.5分)

第2章 预处理

2.1 预处理的概念与作用

预处理的概念:预处理指的是程序在编译之前进行的处理,是计算机在处理一个程序时所进行的第一步处理,可以进行代码文本的替换工作,但是不做语法查抄。预处理是为编译做的准备工作,可以或许对源程序.c文件中出现的以字符“#”开头的命令进行处理,包括宏定义#define、文件包罗#include、条件编译#ifdef等,末了将修改之后的文本进行保存,生成.i文件,预处理竣事。
预处理的作用:
1.处理用#define定义的内容,替换为实际的字符;
2.处理#include预编译指令,将被包罗的文件插入到该预编译指令的位置;
3.删除所有表明,添加行号和文件标志;
4. 处理#if等条件编译指令。
2.2在Ubuntu下预处理的命令

预处理命令:gcc -E hello.c -o hello.i
https://img-blog.csdnimg.cn/direct/e91388945812418b9ba61476cbeb2465.png
图 2-1预处理命令
2.3 Hello的预处理结果解析

打开hello.i文件可以看到
https://img-blog.csdnimg.cn/direct/289a3a0daf324251b158ccf46020a4fd.png
https://img-blog.csdnimg.cn/direct/d89ed49057ec49f69bd6a48a1491dd51.png
图 2-2预处理结果
预处理后,引入了头文件并去除了表明,宏都被替换。添加了行号,编译指令被保留
2.4 本章小结
介绍了hello.c预处理生成hello.i的过程,该过程主要包括:头文件展开、宏定义替换、条件编译和表明删除。预处理器只进行简单的复制和替换操作,不对头文件中的内容进行计算和处理。

(第2章0.5分)

第3章 编译

3.1 编译的概念与作用

编译的概念:编译器(ccl)将文本文件 hello.i 翻译成文本文件 hello.s ,它包罗一个汇编语言程序
编译的作用:将 c语言文件转换成汇编语言文件。
注:这儿的编译是指从 .i 到 .s 即预处理后的文件到生成汇编语言程序

3.2 在Ubuntu下编译的命令

编译命令:gcc -S hello.i -o hello.s
https://img-blog.csdnimg.cn/direct/04351ede87204792b5cb5cd6fbd53d0a.png
图 3-1 编译指令
3.3 Hello的编译结果解析

3.3.1汇编指令
https://img-blog.csdnimg.cn/direct/9c5f84d621624194803947ee5cecd5dd.png
图 3-2汇编指令
.file “hello.c”//源文件
.text
.section   .rodata
.align 8  //声明对数据或者指令地点的对齐方式

3.3.2 数据的处理
(1)字符串
https://img-blog.csdnimg.cn/direct/ddb52534727c4afd9dc18527eba23757.png
图 3-3 字符串
https://img-blog.csdnimg.cn/direct/335acd706e6a41359b27e86cfcee3a14.png
图 3-4 printf() 的表达
main()函数中第一个与第二个printf()语句的内容在hello.s中的表达。
其一为printf("用法: Hello 2022112767 符爱 1998*****14 4!\n");
另一个为printf("Hello %s %s %s\n",argv,argv,argv)。

(2) int i
局部变量保存在栈上,程序中为-4(%rbp)的位置
(3) int argc :
参数,程序中通过访问栈上-20(%rbp)的位置访问。
(4)数组char *argv[]
argv为数组首地点,main()访问数组元素。在hello.s中,%rax表示取地点。argv和argv作为for循环中printf的参数。由argv和argv的取值语句可知argv的首地点是-32(%rbp)。取argv的汇编语句:
movq  -32(%rbp), %rax
addq  $16, %rax
movq  (%rax), %rdx
(5)其他数据以立即数的形式出现。

3.3.2赋值
(1)循环语句中的i = 0,汇编如图
https://img-blog.csdnimg.cn/direct/f0d0b0fd3b154a5e8d47b292d42f707b.png
图 3-5 i=0的赋值语句
(2)MOV类的数据传送指令
指令
效果
形貌
MOVS,D
D< -S
传送
movb

传送字节
movw

传送字
movl

传送双字
movq

传送四字
movabsqI,R
R< -I
传送绝对四字
表3-1 MOV类的数据传送指令
3.3.4. 控制转移的处理
(1)for循环
https://img-blog.csdnimg.cn/direct/3386ba29af134a79bcbaa523bad18689.png
https://img-blog.csdnimg.cn/direct/709dc826c5d34937abc16afb5f0583ee.png
https://img-blog.csdnimg.cn/direct/02876934a758454cae3ab6b8be1ecbb5.png
图3-6 for()循环的编译
.L2为开始前的赋值语句。.L4为for循环的判断语句,.L3之后.L4之前为进入循环体中的循环部分,循环10次。
(2)if(argc!=5) if语句
https://img-blog.csdnimg.cn/direct/24aa1e8894694d63994b745abbfb6dab.png
图3-7 if语句的编译
cmpl比较栈上的argv值和5,je为判断相等条件。如果为0,说明argv==5,跳转去执行for循环,否则执行if中的输出语句,输出提示。
(3)跳转指令
https://img-blog.csdnimg.cn/direct/ddc4a7df16f3452e8898c7c31a10789c.png
图 3-8 跳转指令
3.3.5. 函数操作
(1)main函数
参数传递:外部传入的参数为数组元素,分别存储在寄存器%rdi,%rsi中。
分配和释放内存则使用函数分配栈空间,竣事时恢复栈空间
(2)printf函数
参数传递:第一次将学号姓名字符串的首地点存入%rdi,第二次用%rdi传递“Hello %s %s\n”的首地点,%rsi和%rdx为分别存储。
使用call语句跳转至printf函数:call printf@PLT , call puts@PLT
(3)getchar函数
call getchar@PLT
(4)exit函数
call exit@PLT

3.3.6. 数值操作及比较
(1)i++;
addl $1, -4(%rbp)
(2)i<10
.L3中:cmpl $9, -4(%rbp)
程序中作为循环判断条件,与i<10等价。
3.4 本章小结

总结了编译的概念、作用和部分编译命令。联合hello.i的编译结果,就C语言中的数据与操作怎样被翻译成汇编语言进行了分析。
(第3章2分)
第4章 汇编

4.1 汇编的概念与作用

汇编的概念:
汇编指的是汇编器(as)将hello.s翻译成呆板语言指令,把这些指令打包成一种叫做可重定位目的程序的格式,并将结果保存在目的文件hello.o中。hello.o文件是一个二进制文件,包罗hello程序执行的呆板指令。
汇编的作用:
实现将汇编代码转换为呆板指令,使之在链接后可以或许被计算机直接执行。
注:这儿的汇编是指从.s 到.o,即编译后的文件到生成呆板语言二进制程序的过程。
4.2 在Ubuntu下汇编的命令

汇编指令:gcc -O hello.s -o hello.o
https://img-blog.csdnimg.cn/direct/d8626e84790f4b2d94c6a5e6fc0226bb.png
图 4-1汇编指令
4.3 可重定位目的elf格式

命令:readelf -a hello.o > hello.elf
(1)ELF头:
ELF头以一个16字节的序列开始,这个序列形貌了生成该文件的体系的字的巨细和字节顺序。ELF头剩下的部分包罗帮助链接器语法分析和表明目的文件的信息,此中包括ELF头的巨细、目的文件的范例、呆板范例、节头部表的文件偏移,节头部表中条目的巨细和数目等信息。
https://img-blog.csdnimg.cn/direct/f7d7931f6a1d434ab3ed7b78c04f8fce.png
图 4-2ELF头
(2)节头
节头记载每个节的名称、范例、属性、在ELF文件中所占的长度、对齐方式和偏移量等。
https://img-blog.csdnimg.cn/direct/d4bc16351c234978a7a3b4c98f0ff807.png
图 4-3节头
(3)重定位节
重定位条目告诉链接器在将目的文件合并成可执行文件时怎样修改这个引用。如图,偏移量是需要被修改的引用的节偏移,符号标识被修改引用应该指向的符号。范例告知链接器怎样修改新的引用,加数是一个有符号常数,一些范例的重定位要用它对被修改引用的值做偏移调整。
https://img-blog.csdnimg.cn/direct/e9b3103086874118857e814888218c07.png
图 4-4重定位节
(4)符号表https://img-blog.csdnimg.cn/direct/5100e103d4f54bd98ff57bf8f829bdd8.png
图 4-5符号表
.dynsym节中包罗ELF符号表,这张符号表包罗一个条目的数组,存放一个程序定义和引用的全局变量和函数的信息。
4.4 Hello.o的结果解析

命令:objdump -d -r hello.o > hello.sam
https://img-blog.csdnimg.cn/direct/b9c4063766e04fee90cc2cf993f3a298.png
图 4-6 hello.o的反汇编代码
分析hello.o的反汇编代码,并请与第3章的 hello.s进行对照分析,发现反汇编代码与hello.s差异不大,只是有几处不同:

[*]呆板指令
hello.o的反汇编代码在左侧增添了呆板指令的十六进制代码和地点

[*]分支转移
在hello.s中,代码由不同的段构成,每次跳转会跳到其他段的位置,如L1,L2,L3;hello.o的反汇编文件为跳转指令分配了地点。下一条指令的地点为地点寄存器的中的值加上指令操作数的结果。

[*]函数调用
在hello.o的反汇编代码中有很多函数调用,这些函数源自库或者其他的文件,必须在经过链接后才能调用。hello.o的反汇编文件为这些函数留下了地点以便链接后重定向。

[*]全局变量:
hello.s中使用段名称+%rip访问,反汇编代码中使用0+%rip访问。呆板语言中待访问的全局变量地点为全0。在重定位节中有对应的重定位条目,链接之后确定地点。
4.5 本章小结

本章报告了汇编语言的基本含义和功能,以hello.s的汇编文件为例,说明怎样将其汇编成可重定位目的文件hello.o,然后将其链接成ELF格式的可执行文件 hello.elf。通太过析 hello.o 文件的反汇编代码以及原始汇编文件 hello.s 的区别和相同点,可以清晰地理解汇编语言到呆板语言的转换过程。
(第4章1分)




第5章 链接

5.1 链接的概念与作用

链接的概念:
链接是将各种代码和数据片断网络并组合成为一个单一文件的过程,这个文件可以加载(复制)到内存并且执行。
链接的作用:
链接使分离编译成为大概,可以将大型的应用程序分为更小,更容易管理的模块,并独立的修改和编译这些模块。可以将公共函数聚合为单个文件
注:这儿的链接是指从 hello.o 到hello生成过程。
5.2 在Ubuntu下链接的命令

命令:ld hello.o -lc -o hello
https://img-blog.csdnimg.cn/direct/15140b159a4247db8f1d5f315065287c.png
图 5-1链接命令
5.3 可执行目的文件hello的格式

分析hello的ELF格式,用readelf等列出其各段的基本信息,包括各段的起始地点,巨细等信息。
命令:readelf -a hello > hello01.elf
5.3.1ELF头
hello的ELF头和hello.o的ELF头包罗的信息种类基本相同,均以一个16字节序列开始,该序列形貌了生成该文件的体系的字的巨细和字节顺序的,剩下的部分包罗帮助链接器语法分析和表明目的文件的信息。与hello.elf相比较,hello01.elf中的基本信息未发生改变,但范例发生改变,程序头巨细和节头数目增长,并且获得了入口地点。
https://img-blog.csdnimg.cn/direct/c82469ba557f468489266a7f6099596b.png
图 5-2 ELF头
5.3.2节头
形貌了各个节的巨细、偏移量和其他属性。链接器链接时,会将各个文件的相同段合并成一个大段,并且根据这个大段的巨细以及偏移量重新设置各个符号的地点。
https://img-blog.csdnimg.cn/direct/a02de80633dc452f8e4cfc5cbab497a9.png
图 5-3节头

5.3.3程序头
https://img-blog.csdnimg.cn/direct/afa9699d9d2c4bd2845951847323cd72.png
图 5-4程序头
程序包罗六个段。
1.PTDR: 指定程序头表在文件及程序内存映像中的位置和巨细。
2.INTERP: 指定要作为表明程序调用的以空字符末端的路径名的位置和巨细。对于动态可执行文件,必须设置此范例。
3.LOAD: 指定可装入段,通过p_filesz和p_memsz进行形貌。文件中的字节会映射到内存段的起始位置。
4.DYNAMIC: 指定动态链接信息。
5.GNU_RELRO: 指定在重定位竣事之后那些内存区域是需要设置只读。

5.3.4 hello.elf没有hello.elf的重定位节
https://img-blog.csdnimg.cn/direct/8c60916e06964b9ea1a596e25744d4ed.png
图 5-5 无重定位节
5.4 hello的假造地点空间

使用edb加载hello,检察本进程的假造地点空间各段信息,并与5.3对照分析说明。
如图5-6,ELF文件从概念上来说包括了5个部分:
1.ELF header,形貌体系布局和操作体系等基本信息,指出section header table和program header table在文件的位置
2.program header table,这个是从运行的角度来看ELF文件的,主要给出了各个segment的信息,在汇编和链接过程中没用
3.section header table,这个保存了所有的section的信息,这是从编译和链接的角度来看ELF文件的
4.sections,就是各个节区
5.segments,就是在运行时的各个段
https://img-blog.csdnimg.cn/direct/381213529ba0474fb560946c48d8c2c8.png
图 5-6 ELF文件布局
假造地点空间各段信息:
(1)程序起始地点0x04adc000;
https://img-blog.csdnimg.cn/direct/d30307e8b08e4c66ac113795aead0a23.png
图 5-7-1 edb检察内存单元
(2)同理,通过相应的地点,可以检察不同的内存单元
https://img-blog.csdnimg.cn/direct/4633a8dcdffa453e9b36eac23135122b.png
图 5-7-2 edb检察内存单元
5.5 链接的重定位过程分析

分析hello与hello.o的不同,说明链接的过程。联合hello.o的重定位项目,分析hello中对其怎么重定位的。
命令:objdump -d -r hello > hello01.asm
https://img-blog.csdnimg.cn/direct/1a37447a41134eb7911c532368a68aad.png
图 5-8 hello的反汇编指令
https://img-blog.csdnimg.cn/direct/d412cd0208ca4e5cb3035c4110494cb9.png
https://img-blog.csdnimg.cn/direct/b34fad3de6f64de09b80441785913cb9.png
图 5-9 hello的反汇编代码
(1)链接后函数数目增长
链接后,程序调用的外部函数被链接进入可执行文件,如链接后的反汇编文件hello01.asm中,多了.plt,.plt,puts@plt,printf@plt,getchar@plt,exit@plt,sleep@plt等函数。因为动态链接器将共享库hello.c用到的函数加入到了elf中。
(2)hello的反汇编结果比hello.o的多出来很多节,例如.init节和.plt节。
(3)关于重定位
hello.o中的待重定位条目在hello中被重定位,呆板指令的操作数经过运算被修改,使得程序可以直接访问相应的函数与数据。例如,程序中的puts(这个是printf被优化成puts的),在libc中,链接器首先会确定puts函数在libc中的地点,然后将这个地点写入到hello.o中对puts的调用指令中,然后更新符号表,使得符号puts在末了的可执行文件中指向libc中的实际地点,末了根据重定位表,修改hello.o中对puts的所有引用,使他们指向精确的内存地点。
(4)hello.o中main的地点从0开始,hello中main的地点不再是0,因为库函数的代码都链接到了程序中。
5.6 hello的执行流程

使用gdb/edb执行hello,说明从加载hello到_start,到call main,以及程序停止的所有过程(主要函数)。请列出其调用与跳转的各个子程序名或程序地点。
执行过程大致如图5-10所示
https://img-blog.csdnimg.cn/direct/46877075d94e4d1cbc14e4c3f51dd4b3.png
图 5-10 edb执行hello过程
名称 地点
ld-2.27.so! dl_start <0x00000000000e08e8>
ld-2.27.so! dl_init <0xf00000000000706e8>
ld-2.27.so!_dl_allocate_tls_init <0x00007f9fddc80770>
ld-2.27.so!_dl_allocate_tls <0x00007f9fddc809a0>
ld-2.27.so!_dl_deallocate_tls <0x00007f9fddc80a10>
ld-2.27.so!_dl_make_stack_executable <0x00007f9fddc81130>
ld-2.27.so!_dl_find_dso_for_object <0x00007f9fddc81480>
ld-2.27.so!_dl_exception_create <0x00007f9fddc84ca0>
ld-2.27.so!_dl_exception_create_format <0x00007f9fddc84da0>
ld-2.31.so!_dl_exception_free <0x00007f9fddc85250>
ld-2.27.so!__tunable_get_val <0x00007f9fddc865d0>
ld-2.27.so!__tls_get_addr <0x00007f9fddc86da0>
ld-2.27.so!__get_cpu_features <0x00007f9fddc86df0>
ld-2.27.so!malloc <0x00007f9fddc89490>
ld-2.27.so!calloc <0x00007f9fddc895b0>
ld-2.31.so!free <0x00007f9fddc895f0>
ld-2.27.so!realloc <0x00007f9fddc897e0>
ld-2.27.so!_dl_signal_exception <0x00007f9fddc89a70>
ld-2.27.so!_dl_signal_error <0x00007f9fddc89ac0>
ld-2.27.so!_dl_catch_exception <0x00007f9fddc89c40>
ld-2.27.so!_dl_catch_error <0x00007f9fddc89d30>
hello!_init <0x0000000000401000>
hello!puts@plt <0x0000000000401030>
hello!printf@plt <0x0000000000401040>
hello!getchar@plt <0x0000000000401050>
hello!atoi@plt <0x0000000000401060>
hello!exit@plt <0x0000000000401070>
hello!sleep@plt <0x0000000000401080>
hello!_start <0x00000000004010f0>
hello!_start <0x000000000x400550>
hello!_main <0x0000000000400582>
hello!puts@plt <0x00000000004004f0>
hello!exit@plt <0x0000000000400530>
5.7 Hello的动态链接分析

分析hello程序的动态链接项目,通过edb/gdb调试,分析在动态链接前后,这些项目的内容变化。要截图标识说明。
GOT表:
每一个外部定义的符号在全局偏移表中有相应的条目,GOT位于ELF的数据段中,叫做GOT段。其作用是把位置无关的地点计算重定位到一个绝对地点。程序首次调用某个库函数时,运行时毗连编辑器(rtld)找到相应的符号,并将它重定位到GOT之后每次调用这个函数都会将控制权直接转向那个位置,而不再调用rtld。
PLT表:过程毗连表(Procedure Linkage Table),一个PLT条目对应一个GOT条目。当main()函数开始时,会哀求plt中这个函数的对应GOT地点,如果第一次调用那么GOT会重定位到plt,并向栈中压入一个偏移,程序的执行回到_init()函数,rtld得以调用就可以定位printf的符号地点,第二次运行程序再次调用这个函数时程序跳入plt,对应的GOT入口点就是真实的函数入口地点。
动态毗连器并不会把动态库函数在编译的时间就包罗到ELF文件中,仅仅是在这个ELF被加载的时间,才会把那些动态函库数代码加载进来,之前体系只会在ELF文件中的GOT中保留一个调用地点。
通过readelf工具,在hello的节头表中可以发现GOT表,如图5-11所示
https://img-blog.csdnimg.cn/direct/2f4fc13f1e744411b2607844edd58616.png
图 5-11 got表
调用_dl_start之前为:
https://img-blog.csdnimg.cn/direct/bc7958db476446e681d7f03089dce0a1.png
图 5-12-1
调用_dl_start之后为:
https://img-blog.csdnimg.cn/direct/7bca5b0c7f1441178d4567d5961a9778.png
图 5-12-2
在之后的函数调用时,首先跳转到PLT执行.plt中逻辑,第一次访问跳转时GOT地点为下一条指令,将函数序号压栈,然后跳转到PLT,在PLT中将重定位表地点压栈,然后访问动态链接器,在动态链接器中使用函数序号和重定位表确定函数运行时地点,重写GOT,再将控制传递给目的函数。之后如果对同样函数调用,第一次访问跳转直接跳转到目的函数。
5.8 本章小结

本章详细讨论了链接的概念与作用、在Ubuntu下链接的命令,以及可执行目的文件hello的格式,详细分析可执行目的文件和可重定位目的文件的区别。表明了hello假造地点空间并分析了链接的重定位过程。通过hello的执行流程,深入探究了hello的动态链接,涉及ELF的布局,重定位的实现与动态毗连。
(第5章1分)




第6章 hello进程管理

6.1 进程的概念与作用

进程的概念:
进程是一个执行中程序的实例。体系中每个程序都运行在某个进程的上下文中。上下文是由程序精确运行所需的状态构成的。这个状态包括存放在内存中的程序的代码和数据,它的栈、通用目的寄存器的内容、程序计数器、环境变量以及打开文件形貌符的集合。
进程的作用:
通过进程,我们会得到一种假象,似乎我们的程序是当前唯一运行的程序,我们的程序独占处理器和内存,我们程序的代码和数据似乎是体系内存中唯一的对象。
6.2 简述壳Shell-bash的作用与处理流程

Shell是体系的用户界面,提供了用户与内核进行交互操作的一种接口。它吸收用户输入的命令并把它送入内核去执行。
功能:
实际上Shell是一个命令表明器,它表明由用户输入的命令并且把它们送到内核。不仅云云,Shell有自己的编程语言用于对命令的编辑,它允许用户编写由shell命令构成的程序。Shell编程语言具有普通编程语言的很多特点,比如它也有循环布局和分支控制布局等,用这种编程语言编写的Shell程序与其他应用程序具有同样的效果
处理流程:
shell首先查抄命令是否是内部命令,若不是再查抄是否是一个应用程序(这里的应用程序可以是Linux本身的实用程序,如ls和rm,也可以是购买的商业程序,如xv,或者是自由软件,如emacs)。然后shell在搜索路径里寻找这些应用程序(搜索路径就是一个能找到可执行程序的目次列表)。如果键入的命令不是一个内部命令并且在路径里没有找到这个可执行文件,将会表现一条错误信息。如果可以或许乐成找到命令,该内部命令或应用程序将被分解为体系调用并传给Linux内核。
6.3 Hello的fork进程创建过程

当shell运行hello时,父进程调用fork函数生成这个程序的子进程。这个子进程险些与父进程相同:子进程得到与父进程相同的假造地点空间的副本,包括代码,数据段,堆,共享库以及用户栈。不同的是子进程与父进程的PID不同。fork()函数创建新进程的过程:
(1)给新进程分配一个标识符;
(2)在内核中分配一个PCB,将其挂在PCB表上;
(3)复制它的父进程的环境(PCB中大部分的内容);
(4)为其分配资源(程序、数据、栈等);
(5)复制父进程地点空间里的内容(代码共享,数据写时拷贝);
(6)将进程置结果绪状态,并将其放入就绪队列,等候CPU调度。
6.4 Hello的execve过程

execve函数在新创建的子进程的上下文中加载并运行hello程序。execve函数加载并运行可执行目的文件filename,且带参数列表argv和环境变量列表envp。只有发生错误时execve才会返回到调用程序。所以,execve调用一次且从不返回。
加载并运行hello需要以下几个步调:
1.删除已存在的用户区域。删除当前进程假造地点的用户部分中已存在的区域布局。
2.映射私有区域。为新程序的代码、数据、bss和栈区域创建新的区域布局。所有这些新的区域都是私有的、写时复制的。代码和数据区被映射为hello文件中的.text和.data区。bss区域是哀求二进制零的,映射到匿名文件,其巨细包罗在hello中。栈和堆区域也是哀求二进制零的,初始长度为零。
3.映射共享区域。如果hello程序与共享对象链接,那么这些对象都是动态链接到这个程序的,然后再映射到用户假造地点空间中的共享区域内。
4.设置程序计数器。设置当前进程上下文中的程序计数器,使之指向代码区域的入口点。下一次调度这个进程时,它将从这个入口点开始执行。
6.5 Hello的进程执行

联合进程上下文信息、进程时间片,阐述进程调度的过程,用户态与核心态转换等等。
在运行hello程序时,进程为应用程序提供了以下抽象:(1)一个独立的逻辑控制流,给人一种错觉,仿佛进程独占地使用处理器;(2)一个私有的地点空间,使我们的程序看起来像是独占地使用内存。
操作体系提供的抽象包括:
逻辑控制流:
当我们使用调试器逐步执行程序时,会看到一系列的程序计数器(PC)值,这些值唯一地对应于程序的可执行文件中的指令或动态链接的共享对象中的指令。这个PC值的序列称为逻辑控制流,或逻辑流。当一个逻辑流与另一个流在时间上重叠执行时,这些流被称为并发流,并且它们是并发运行的。
上下文切换:
操作体系内核通过一种称为上下文切换的高级异常控制流机制来实现多任务处理。内核为每个进程维护一个上下文,上下文是内核重新启动被抢占的进程所需的状态。
时间片:
进程在每一时间段内执行其控制流的一部分,这个时间段称为时间片。因此多任务处理也称为时间分片。
用户模式和内核模式:
处理器通常通过控制寄存器中的模式位提供这种功能。当模式位设置时,进程运行在内核模式下,此时进程可以执行所有指令,并访问体系中的任何内存位置。当模式位未设置时,进程运行在用户模式下,此时进程不能执行特权指令,也不能直接访问内核区域的代码和数据。
上下文信息:
上下文是内核重新启动一个被抢占的进程所需的状态信息,包括通用寄存器、浮点寄存器、程序计数器、用户栈、状态寄存器、内核栈和各种内核数据布局的值。在hello程序执行过程中,当进程调用 execve 函数时,会为hello程序分配新的假造地点空间。程序开始在用户模式下运行,调用 printf 函数输出“Hello 2022111915 fjw 13009730974”。随后,程序调用 sleep 函数,进程进入内核模式,运行信号处理程序,之后返回用户模式。在执行过程中,CPU不停进行上下文切换,将执行过程划分为多个时间片,与其他进程交替使用CPU,从而实现进程调度。
6.6 hello的异常与信号处理
hello执行过程中会出现哪几类异常,会产生哪些信号,又怎么处理的。程序运行过程中可以按键盘,如不停乱按,包括回车,Ctrl-Z,Ctrl-C等,Ctrl-z后可以运行ps  jobs  pstree  fg  kill 等命令,请分别给出各命令及运行结截屏,说明异常与信号的处理。
hello执行过程中出现的异常种类大概会有:中断、陷阱、故障、停止等。
中断:中断是来自处理器外部的I/O装备的信号的结果。如在按下ctrl-z后,会触发一个中断异常。
陷阱:陷阱是有意的异常,是执行一条指令的结果。就像中断处理程序一样,陷阱处理程序将控制返回到下一条指令。陷阱最重要的用途是在用户程序和内核之间提供一个像过程一样的接口,叫做体系调用。
故障:故障由错误环境引起,它大概可以或许被故障处理程序修正。当故障发生时,处理器将控制转移给故障处理程序。如果处理程序可以或许修正这个错误环境,它就将控制返回到引起故障的指令,从而重新执行它。否则处理程序返回到内核中的abort例程并将其停止。
停止:停止是不可恢复的致命错误造成的结果,通常是一些硬件错误,比如DRAM或者SRAM位被损坏时发生的奇偶错误。停止处理程序从不将控制返回给应用程序。
(1)如图6-1,正常输入,循环打印10次后输入一个字符正常退出;
https://img-blog.csdnimg.cn/direct/14648792acc042609a85366785441c66.png
图 6-1
(2)如图6-2,运行过程中不停乱按键盘,包括回车对进程无影响,但是会将输入的内容存到缓冲区,作为接下来的命令行输入。
https://img-blog.csdnimg.cn/direct/0bef25c210f340f59a2bef02fe5f1a8d.png
图 6-2
(3)Ctrl+C,如图6-3,会使内核发送一个SIGINT信号,信号处理程序会接纳子进程https://img-blog.csdnimg.cn/direct/5dce8fa99e1648febc5a8fff74f2d6e5.png
图 6-3
(4)Ctrl+Z,如图6-4,Shell收到sigstp信号,shell表现屏幕提示信息并挂起hello进程。
https://img-blog.csdnimg.cn/direct/cdfb743044f74649b0b67eb563788266.png
图 6-4
(5)如图6-5,图6-6对hello进程的挂起可以由ps和jobs命令检察,可以发现hello进程是被挂起了,但是没有接纳。
https://img-blog.csdnimg.cn/direct/ede8b043310f4824842f1b18227375f1.png
图 6-5
https://img-blog.csdnimg.cn/direct/d96bcbe5ce4543ddb5aeff3e2eeb6ecf.png
图 6-6
(6)如图6-7,在shell中输入pstree命令,可以将所有进程以树状图表现:
https://img-blog.csdnimg.cn/direct/0359539c3efa4155ba1f3e2a64202e1e.png
https://img-blog.csdnimg.cn/direct/66a3a24012f7480b847d6884d53a9892.png
https://img-blog.csdnimg.cn/direct/60fac74d21fd440ba6ecfe02a8a74b83.png
图 6-7
(7)如图6-8,输入fg ,则命令将hello进程再次调到前台执行,可以发现shell首先打印hello的命令行命令,hello再从挂起处继续运行,打印剩下语句,然后正常竣事,并被进程管理器完成进程接纳
https://img-blog.csdnimg.cn/direct/4111ab6e38bd4b31be44763ebc777a23.png
图 6-8
(8)如图6-9,输入kill 可以杀掉指定进程
https://img-blog.csdnimg.cn/direct/1ff2cbeaebfb473e923f8ebb589eb081.png
图 6-9

6.7本章小结

本章阐述了进程的定义和作用,shell的作用和处理流程,执行hello时的fork和execve过程。分析了hello的进程执行和异常与信号处理过程。
(第6章1分)
第7章 hello的存储管理

7.1 hello的存储器地点空间

逻辑地点:呆板语言指令中,用来指定一个操作数或者是一条指令的地点,由CPU所生成,被内部和编程使用、并不唯一。例如程序中jump指令的地点。
线性地点:由假造地点到物理地点变换的中间层,是处理器可寻址的内存空间(称为线性地点空间)中的地点。程序代码会产生逻辑地点,或者说段中的偏移地点,加上相应段基址就成了一个线性地点。如果启用了分页机制,那么线性地点可以再经过变换产生物理地点。如果没有采用分页机制,那么线性地点就是物理地点。在程序中,这可以被看成是一种形貌,形貌hello程序应该在内存的哪些块上运行。
假造地点:由程序产生的由段选择符和段内偏移地点构成的地点。这2部分构成的地点并不能直接访问物理内存,而是要通太过段地点的变化处理后才会对应到相应的物理内存地点。即hello里的假造内存地点。
物理地点:程序运行时加载到内存地点寄存器中的地点,内存单元的硬件上的地点。物理地点用于内存芯片级的单元寻址,与处理器和CPU毗连的地点总线相对应,物理地点是明确的、终极用在总线上的编号,不必转换,不必分页,也没有特权级查抄。在hello程序中,物理地点表示程序运行时具体一条指令在内存地点上具体哪一块运行。
7.2 Intel逻辑地点到线性地点的变换-段式管理

1.基本原理:
在段式存储管理中,将程序的地点空间划分为若干个段(segment),如许每个进程有一个二维的地点空间。在段式存储管理体系中,为每个段分配一个连续的分区,而进程中的各个段可以不连续地存放在内存的不同分区中。程序加载时,操作体系为所有段分配其所需内存,这些段不必连续,物理内存的管理采用动态分区的管理方法。在为某个段分配物理内存时,可以采用首先适配法、下次适配法、最佳适配法等方法。在接纳某个段所占用的空间时,要注意将收回的空间与其相邻的空间合并。段式存储管理也需要硬件支持,实现逻辑地点到物理地点的映射。
程序通太过段划分为多个模块,如代码段、数据段、共享段:
(1)可以分别编写和编译
(2)可以针对不同范例的段采取不同的保护
(3)可以按段为单元来进行共享,包括通过动态链接进行代码共享
如许做的长处是:可以分别编写和编译源程序的一个文件,并且可以针对不同范例的段采取不同的保护,也可以按段为单元来进行共享。
总的来说,段式存储管理的长处是:没有内碎片,外碎片可以通过内存紧缩来消除;便于实现内存共享。缺点与页式存储管理的缺点相同,进程必须全部装入内存。

2.段式管理的数据布局:
为了实现段式管理,操作体系需要如下的数据布局来实现进程的地点空间到物理内存空间的映射,并跟踪物理内存的使用环境,以便在装入新的段的时间,合理地分配内存空间。
(1)进程段表:形貌构成进程地点空间的各段,可以是指向体系段表中表项的索引。每段有段基址(baseaddress),即段内地点。
在体系中为每个进程建立一张段映射表,如图7-1:
https://img-blog.csdnimg.cn/direct/d6f44391deb9436dab79178304cba6b0.png
图 7-1
(2)体系段表:体系所有占用段(已经分配的段)。
(3)空闲段表:内存中所有空闲段,可以联合到体系段表中。
段式管理的地点变换
https://img-blog.csdnimg.cn/direct/1d1b4e0b1f6e46c09a834390a1ba1395.png
图 7-2
在段式 管理体系中,整个进程的地点空间是二维的,即其逻辑地点由段号和段内地点两部分构成。为了完成进程逻辑地点到物理地点的映射,处理器会查找内存中的段表,由段号得到段的首地点,加上段内地点,得到实际的物理地点。这个过程也是由处理器的硬件直接完成的,操作体系只需在进程切换时,将进程段表的首地点装入处理器的特定寄存器当中。这个寄存器一样平常被称作段表地点寄存器。

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

1.基本原理
将程序的逻辑地点空间划分为固定巨细的页(page),而物理内存划分为同样巨细的页框(page frame)。程序加载时,可将任意一页放入内存中任意一个页框,这些页框不必连续,从而实现了离散分配。该方法需要CPU的硬件支持,来实现逻辑地点和物理地点之间的映射。在页式存储管理方式中地点布局由两部构成,前一部分是假造页号(VPN),后一部分为假造页偏移量(VPO):
https://img-blog.csdnimg.cn/direct/9e807426f9c24c46ab9abef9ff568cf5.png
图 7-3
页式管理方式的长处是:
(1)没有外碎片
(2)一个程序不必连续存放。
(3)便于改变程序占用空间的巨细(主要指随着程序运行,动态生成的数据增多,所要求的地点空间相应增长)。
缺点是:要求程序全部装入内存,没有足够的内存,程序就不能执行。
2.页式管理的数据布局
在页式体系中进程建立时,操作体系为进程中所有的页分配页框。当进程撤销时收回所有分配给它的页框。在程序的运行期间,如果允许进程动态地申请空间,操作体系还要为进程申请的空间分配物理页框。操作体系为了完成这些功能,必须记载体系内存中实际的页框使用环境。操作体系还要在进程切换时,精确地切换两个不同的进程地点空间到物理内存空间的映射。这就要求操作体系要记载每个进程页表的相干信息。为了完成上述的功能,—个页式体系中,一样平常要采用如下的数据布局。
页表:页表将假造内存映射到物理页。每次地点翻译硬件将一个假造地点转换为物理地点时,都会读取页表。页表是一个页表条目(PTE)的数组。假造地点空间的每个页在页表中一个固定偏移量处都有一个PTE。假设每个PTE是由一个有效位和一个n位地点字段构成的。有效位表明白该假造页当前是否被缓存在DRAM中。如果设置了有效位,那么地点字段就表示DRAM中相应的物理页的起始位置,这个物理页中缓存了该假造页。如果没有设置有效位,那么一个空隙点表示这个假造页还未被分配。否则,这个地点就指向该假造页在磁盘上的起始位置。
https://img-blog.csdnimg.cn/direct/fdba8e776ffd46c49eef9c3c05097175.png
图 7-4 页表
3.页式管理地点变换
MMU利用VPN来选择得当的PTE,将列表条目中PPN和假造地点中的VPO串联起来,就得到相应的物理地点。
https://img-blog.csdnimg.cn/direct/0e3a256f38064e29aae6e94dbda4c377.png
图 7-5
7.4 TLB与四级页表支持下的VA到PA的变换

假造地点被划分成4个VPN和1个VPO。每个VPNi都是一个到第i级页表的索引,此中1<=i<=4.第j级页表中的每个PTE,1<=j<=3,都指向第j+1级的某个页表的基址。第四级页表中的每个PTE包罗某个物理页面的PPN,或者一个磁盘块的地点。为了构造物理地点,在可以或许确定PPN之前,MMU必须访问4个PTE。将得到的PPN和假造地点中的VPO串联起来,就得到相应的物理地点。
https://img-blog.csdnimg.cn/direct/ade6abf405d34b35be16250b064a1a88.png
图 7-6
7.5 三级Cache支持下的物理内存访问

L1 d-cache的布局如图所示:通过6-11位的组索引找到对应的组,将组中每一行的tag与CT比较,若标志位匹配且有效位为1,说明命中,根据0-5位的块偏移取出数据,如果没有匹配乐成,则向下一级缓存中查找数据。取回数据后,如果有空闲块则放置在空闲块中,否则根据替换计谋选择牺牲块。
https://img-blog.csdnimg.cn/direct/f6323fce98894561a876718186184243.png
图 7-7 Cache分块
7.6 hello进程fork时的内存映射

当fork函数被当前进程调用时,内核为新进程创建各种数据布局,并分配给它一个唯一的pid。为了给这个新进程创建假造内存。它创建了当前进程的mm_struct、区域布局和页表的原样副本。它将两个进程中的每个页面都标志位只读,并将两个进程中的每个区域布局都标志为私有的写时复制。
当fork在新进程中返回时,新进程如今的假造内存刚好和调用fork时存在的假造内存相同。当这两个进程中的任一个后来进行写操作时,写时复制机制就会创建新页面。
7.7 hello进程execve时的内存映射

加载并运行hello需要以下几个步调:
1.删除已存在的用户区域。删除当前进程假造地点的用户部分中已存在的区域布局。
2.映射私有区域。为新程序的代码、数据、bss和栈区域创建新的区域布局。所有这些新的区域都是私有的、写时复制的。代码和数据区被映射为hello文件中的.text和.data区。bss区域是哀求二进制零的,映射到匿名文件,其巨细包罗在hello中。栈和堆区域也是哀求二进制零的,初始长度为零。
3.映射共享区域。如果hello程序与共享对象链接,那么这些对象都是动态链接到这个程序的,然后再映射到用户假造地点空间中的共享区域内。
4.设置程序计数器。设置当前进程上下文中的程序计数器,使之指向代码区域的入口点。下一次调度这个进程时,它将从这个入口点开始执行。
加载器怎样映射用户地点空间的区域:
https://img-blog.csdnimg.cn/direct/ed065044900049149ba785d685cb394d.png
图 7-8 地点空间分配
7.8 缺页故障与缺页中断处理

在假造内存的风俗说法中,DRAM缓存不命中称为缺页。例如:CPU引用了VP3中的一个字,VP3并未缓存在DRAM中。地点翻译硬件从内存中读取PTE3,从有效位推断出VP3未被缓存,并且触发一个缺页异常。缺页异常调用内核中的缺页异常处理程序,该程序会选择一个牺牲页,在此例中就是存放在PP3中的VP4。如果VP4已经被修改了,那么内核就会将它复制回磁盘。无论哪种环境,内核都会修改VP4的页表条目,反映出VP4不再缓存在主存中这一事实。缺页之前:
https://img-blog.csdnimg.cn/direct/b410ff098c704912bce530686f51384a.png
图 7-9
接下来,内核从磁盘复制VP3到内存中的PP3,更新PTE3,随后返回。当异常处理程序返回时,它会重新启动导致缺页的指令,该指令会把导致缺页的假造地点重发送到地点翻译硬件。但是如今VP3已经缓存在主存中了,那么也命中也能由地点翻译硬件正常处理了。缺页之后:
https://img-blog.csdnimg.cn/direct/38188903b6164c84a107fd3f1a35d3eb.png
图 7-10
7.9动态存储分配管理

动态内存分配器维护着一个进程的假造内存区域,称为堆。分配器将堆视为一组不同巨细的块的集合来维护。每个块就是一个连续的假造内存片,要么是已分配的,要么是空闲的。已分配的块显式地保留为供应用程序使用。空闲块可用来分配。空闲块保持空闲,直到它显式地被应用所分配。一个已分配的块保持已分配状态,直到它被释放,这种释放要么是应用程序显式执行的,要么是内存分配器自身隐式执行的。
(1)隐式空闲链表
https://img-blog.csdnimg.cn/direct/f22ad6a4eab3417784127ea151d9f343.png
图 7-11 隐式空闲链表
空闲块通过头部中的巨细字段隐含地毗连着。分配器可以通过遍历堆中所有的块,从而间接地遍历整个空闲块的集合。
1)放置计谋:首次适配、下一次适配、最佳适配。
首次适配从头开始搜索空闲链表,选择第一个合适的空闲块。下一次适配从上一次查询竣事的地方开始。最佳适配查抄每个空闲块,选择得当所需哀求巨细的最小空闲块。
2)合并计谋:立即合并、推迟合并。
立即合并就是在每次一个块被释放时,就合并所有的相邻块;推迟合并就是等到某个稍晚的时间再合并空闲块。
带界限标志的合并:
https://img-blog.csdnimg.cn/direct/48b3cd64dd284a958e2e2e2dd5f1c767.png
图 7-12 合并
在每个块的末端添加一个脚部,分配器就可以通过查抄它的脚部,判断前面一个块的起始位置和状态,从而使得对前面块的合并可以或许在常数时间之内进行。
(2)显式空闲链表
https://img-blog.csdnimg.cn/direct/707c3abfa9a74a1396986fa7b6ecbd87.png
图 7-13 显式空闲链表
每个空闲块中,都包罗一个pred(前驱)和succ(后继)指针。使用双向链表使首次适配的时间淘汰到空闲块数目的线性时间。
空闲链表中块的排序计谋:一种是用后进先出的顺序维护链表,将新释放的块放置在链表的开始处,另一种方法是按照地点顺序来维护链表,链表中每个块的地点都小于它后继的地点。
分离存储:维护多个空闲链表,每个链表中的块有大致相等的巨细。将所有大概的块巨细分成一些等价类,也叫做巨细类。
分离存储的方法:简单分离存储和分离适配。
Printf会调用malloc,请简述动态内存管理的基本方法与计谋。
7.10本章小结

本章主要介绍了hello的存储器地点空间、intel的段式管理、hello的页式管理,以intel Core i7在指定环境下介绍了假造地点VA到物理地点PA的转换、物理内存访问,分析了hello进程fork时的内存映射、hello进程、execve时的内存映射、缺页故障与缺页中断处理。同时简单阐述了堆的布局以及malloc和free时对堆的管理,以及利用gdb调试的方法进入printf函数内部检察printf对堆的操作。
(第7章 2分)




第8章 hello的IO管理

8.1 Linux的IO装备管理方法

(以下格式自行编排,编辑时删除)
装备的模子化:文件
装备管理:unix io接口
8.2 简述Unix IO接口及其函数

(以下格式自行编排,编辑时删除)
8.3 printf的实现分析

(以下格式自行编排,编辑时删除)
https://www.cnblogs.com/pianist/p/3315801.html
从vsprintf生成表现信息,到write体系函数,到陷阱-体系调用 int 0x80或syscall等.
字符表现驱动子程序:从ASCII到字模库到表现vram(存储每一个点的RGB颜色信息)。
表现芯片按照刷新频率逐行读取vram,并通过信号线向液晶表现器传输每一个点(RGB分量)。
8.4 getchar的实现分析

(以下格式自行编排,编辑时删除)
异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到体系的键盘缓冲区。
getchar等调用read体系函数,通过体系调用读取按键ascii码,直到接受到回车键才返回。
8.5本章小结

(以下格式自行编排,编辑时删除)
(第8章1分)


结论

用计算机体系的语言,逐条总结hello所经历的过程。
你对计算机体系的计划与实现的深切感悟,你的创新理念,如新的计划与实现方法。
Hello程序在计算机中从出生到殒命整个过程:
1.编程:编写hello程序的代码;
2.预处理:生成hello.i文件;
3.编译:将预处理hello.i文件编译生成.s文件;
4.汇编:将汇编语言转换成呆板指令并生成重定位信息,结果为可重定位.o文件;
5.链接:与库链接,生成可执行文件hello;
6.创建进程:使用shell输入命令运行hello程序,并通过fork函数为hello创建进程;
7.加载程序:使用加载器,调用execve函数删除原来的进程内容,加载hello程序的代码和数据等内容到内存中;
8.执行指令:CPU为其分配时间片,在一个时间片中,hello享有CPU资源,顺序执行自己的控制逻辑流;
9.异常(信号):程序执行时,如果从键盘输入Ctrl-C等命令,会给进程发送一个信号,然后转到信号处理函数处理信号;
10.竣事:程序执行完后,父进程接纳子进程,内核删除为这个进程创建的所有数据布局。

(结论0分,缺失 -1分,根据内容酌情加分)
附件


列出所有的中间产物的文件名,并予以说明起作用。
hello.i       预处理后得到的文本文件
hello.s       编译后得到的汇编语言文件
hello.o       汇编后得到的可重定位目的文件
hello.asm   可重定位文件hello.o的反汇编文件
hello01.asm  可执行文件hello的反汇编文件
hello.elf   hello.o的elf文件
hello01.elf   可执行文件hello的elf文件
(附件0分,缺失 -1分)














                         

参考文献

为完本钱次大作业你翻阅的册本与网站等
 林来兴. 空间控制技能. 北京:中国宇航出版社,1992:25-42.
 辛希孟. 信息技能与信息服务国际研讨会论文集:A集. 北京:中国科学出版社,1999.
  赵耀东. 新时代的工业工程师. 台北:天下文化出版社,1998 . http://www.ie.nthu.edu.tw/info/ie.newie.htm(Big5).
 谌颖. 空间交会控制理论与方法研究. 哈尔滨:哈尔滨工业大学,1992:8-13.
  KANAMORI H. Shaking Without Quaking. Science,1998,279(5359):2063-2064.
  CHRISTINE M. Plant Physiology: Plant Biology in the Genome Era. Science,1998,281:331-332. http://www.sciencemag.org/cgi/ collection/anatmorp.
 深入理解计算机体系第三版.
  https://blog.csdn.net/fndfnd/article/details/85381044.
(参考文献0分,缺失 -1分)

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 程序人生-Hello’s P2P From Program to Process