ICS大作业

计算机系统

大作业

题 目 程序人生-Hello’s P2P
专 业 计算机
学   号 1190201515
班   级 1903009
学 生 乔家硕  
指 导 教 师 吴锐

计算机科学与技术学院
2021年5月
摘 要
本论文通过对hello程序的产生过程、运行过程、IO过程的介绍,简单讲解了预处理、编译、汇编、链接的概念和作用,操作系统的进程调度和内存管理相关概念及过程,最后粗略介绍了有关linuxIO的相关知识。读者课通过此文对计算机系统的设计和实现,linux下c程序的生成和执行过程有初步的了解。

关键词:计算机系统;编译;链接;进程;内存;IO;

(摘要0分,缺失-1分,根据内容精彩称都酌情加分0-1分)

目 录

第1章 概述 - 4 -
1.1 HELLO简介 - 4 -
1.2 环境与工具 - 4 -
1.3 中间结果 - 5 -
1.4 本章小结 - 5 -
第2章 预处理 - 6 -
2.1 预处理的概念与作用 - 6 -
2.2在UBUNTU下预处理的命令 - 6 -
2.3 HELLO的预处理结果解析 - 7 -
2.4 本章小结 - 7 -
第3章 编译 - 8 -
3.1 编译的概念与作用 - 8 -
3.2 在UBUNTU下编译的命令 - 8 -
3.3 HELLO的编译结果解析 - 9 -
3.4 本章小结 - 12 -
第4章 汇编 - 13 -
4.1 汇编的概念与作用 - 13 -
4.2 在UBUNTU下汇编的命令 - 13 -
4.3 可重定位目标ELF格式 - 13 -
4.4 HELLO.O的结果解析 - 15 -
4.5 本章小结 - 16 -
第5章 链接 - 17 -
5.1 链接的概念与作用 - 17 -
5.2 在UBUNTU下链接的命令 - 17 -
5.3 可执行目标文件HELLO的格式 - 19 -
5.4 HELLO的虚拟地址空间 - 20 -
5.5 链接的重定位过程分析 - 21 -
5.6 HELLO的执行流程 - 22 -
5.7 HELLO的动态链接分析 - 22 -
5.8 本章小结 - 22 -
第6章 HELLO进程管理 - 23 -
6.1 进程的概念与作用 - 23 -
6.2 简述壳SHELL-BASH的作用与处理流程 - 23 -
6.3 HELLO的FORK进程创建过程 - 23 -
6.4 HELLO的EXECVE过程 - 24 -
6.5 HELLO的进程执行 - 24 -
6.6 HELLO的异常与信号处理 - 25 -
6.7本章小结 - 26 -
第7章 HELLO的存储管理 - 27 -
7.1 HELLO的存储器地址空间 - 27 -
7.2 INTEL逻辑地址到线性地址的变换-段式管理 - 28 -
7.3 HELLO的线性地址到物理地址的变换-页式管理 - 28 -
7.4 TLB与四级页表支持下的VA到PA的变换 - 29 -
7.5 三级CACHE支持下的物理内存访问 - 30 -
7.6 HELLO进程FORK时的内存映射 - 30 -
7.7 HELLO进程EXECVE时的内存映射 - 30 -
7.8 缺页故障与缺页中断处理 - 31 -
7.9动态存储分配管理 - 31 -
7.10本章小结 - 32 -
第8章 HELLO的IO管理 - 33 -
8.1 LINUX的IO设备管理方法 - 33 -
8.2 简述UNIX IO接口及其函数 - 33 -
8.3 PRINTF的实现分析 - 33 -
8.4 GETCHAR的实现分析 - 33 -
8.5本章小结 - 33 -
结论 - 34 -
附件 - 37 -
参考文献 - 38 -

第1章 概述
1.1 Hello简介
程序流程分析:
1、 接收用户输入的三个参数,不符合要求直接结束进程
(学号, 姓名, 秒数) -> (argv[1], argv[2], argv[3])
2、对学号、姓名进行8次打印,每次打印结束后休眠agrv[3]秒
3、等待用户输入任意字符后结束进程
P2P过程:
Program: 用户进行编程

hello.c: 编写完毕得到源码文件

hello.i: 经cpp预处理(宏展开等)后生成的源码文件

hello.s: 经cc1编译后生成的汇编语言文件

hello.o: 经as汇编后生成的可重定位目标程序

hello: 经链接后生成的可执行目标程序

Process: 运行可执行目标程序后生成操作系统进程
O2O过程:
用户在shell中运行生成的可执行程序

shell运行fork生成一个子进程

在子进程中调用execve运行该可执行程序

使用wait系列函数回收子程序

1.2 环境与工具
硬件:
Intel® Core™ i5-7200U CPU @ 2.50GHz; 4G RAM;
软件:
Windows 10; Kali 2020.04;
开发调试工具
GCC; GDB; SUBLIME_TEXT; VIM;
1.3 中间结果
hello.i 预处理后生成的文件
hello.s 编译后生成的文件
hello-spec.s 对hello.s的注释版本
hello.o 汇编后生成的文件
hello-o-elf.s hello.o的elf头
hello-o-objdump.s objdump反汇编hello.o生成的文件
hello 链接后生成的文件
hello-e-elf.s hello的elf头
hello-e-objdump.s objdump反汇编hello生成的文件

1.4 本章小结
本章通过对hello.c程序的流程分析,P2P以及O2O过程的介绍,使读者对一个程序是如何从文本文件到一个二进制可执行文件,再到操作系统的一个进程有了一个大致了解;最后简述了编写本论文的开发环境已经论文中可能提到的文件的目录

(第1章0.5分)

第2章 预处理
2.1 预处理的概念与作用
概念
预处理是对源码文件进行的一些文本替换操作,在程序编译之前进行。主要包括宏定义、文件包含、条件编译以及删除注释信息等。
作用
 简化程序的编写,不必手动复制头文件的内容到源码中
 使用宏定义简化代码
 使用条件编译方便对程序进行调试
 方便编译器对源码进行编译等
2.2在Ubuntu下预处理的命令
命令
gcc -E hello.c -o hello.i

运行结果

2.3 Hello的预处理结果解析
结果解析
代码行数增加 头文件的内容被包含进源码中
注释消失 预处理器将注释删除
缩进改变 预处理器对文本进行了压缩

2.4 本章小结
本章对预处理的概念和作用进行了简单介绍,并简单比较了hello.c经预处理前后的不同以说明预处理的作用。
(第2章0.5分)

第3章 编译
3.1 编译的概念与作用
概念
将高级语言代码转换为计算机可以识别的汇编指令代码的过程
作用
将高级语言转换为汇编指令代码
3.2 在Ubuntu下编译的命令
命令
gcc -S hello.i -o hello.s

运行结果

3.3 Hello的编译结果解析
数据
 字符串常量
存储在 .rodata节中,由标签(.LC0, .LC1)进行定位
定义:

引用:

 常数
在数之前添加’ ’ 前 缀 表 示 立 即 数 ( 没 有 ’ ’前缀表示立即数(没有’ (’前缀的会被作为地址对待,在手写汇编指令时一定要注意)

 参数
函数之间传递参数,前六个参数依次保存在 %rdi, %rsi, $rdx, $rcx, $r8, %r9中,其余参数由右至左依次压入堆栈中

参数传递实例
为 puts 传入字符串常量1作为参数

为 printf 传入三个参数(依次保存在 %rdi, %rsi, %rdx 中)

参数使用实例
main(int argc, char *argv[])函数的两个参数依次保存在 %rdi, %rsi中,由于int只占4字节,所以引用时使用 %edi 即可

 返回值
返回值保存在 %rax 中

 局部变量
保存在堆栈中,由函数在开始时自行申请创建,结束时自行释放
申请栈空间

释放栈帧

赋值
 数据传送
使用mov等

 地址计算
使用lea等

算数操作
 减法

 加法

关系操作
 比较
比较操作会对被比较的两个数据进行算数运算并根据运算结果设置标志寄存器的标志位,但不会改变数据本身的值

指针操作
 指针被视为8字节的数据
 指针传递

 指针运算
使用’(%rax)’取出地址%rax处保存的数据,前提是%rax中保存的是数据的地址

控制转移
 跳转
jmp系列指令,jmp无条件跳转,jxx根据标志寄存器的值进行条件跳转
无条件跳转例子

条件跳转(往往跟在比较指令后)

 函数调用/返回
call/ret,call前可以通过寄存器传递参数,ret通过寄存器传递返回值

函数操作
 栈帧的创建
在函数开始时首先保存当前的栈帧布局($rbp),之后申请栈上的一部分空间,这部分空间属于当前函数,可以保存局部变量,寄存器值,要传递的参数等

 栈帧的销毁
在函数返回之前,必须释放栈空间,使得在返回后恢复调用者得栈帧结构

3.4 本章小结
本章对hello.s汇编代码文件进行分析,举例简要说明了编译器如何处理C语言中的数据、运算及流程控制,并提供了完整的注释文件hello-spec.s供读者参考
(第3章2分)

第4章 汇编
4.1 汇编的概念与作用
概念
将汇编指令转换为对应的机器码,生成可重定位目标文件的过程
作用
通过汇编器,完成了文本文件到二进制文件的转换,生成可重定位目标文件,记录了需要重定位的符号信息,再经链接器链接后即可运行
4.2 在Ubuntu下汇编的命令
as hello.s -o hello.o

4.3 可重定位目标elf格式
ELF头
elf头位于elf文件首部,存储了有关elf文件和机器的基本信息,结构如下

	hello.o的ELF头

从中可以看出hello.o中共有13个节
各节的基本信息

重定位分析
 符号表
记录了程序定义使用的所有符号信息

 重定位节
记录了需要重定位的项目在文件中的偏移以及对应的符号

4.4 Hello.o的结果解析
hello.o反汇编分析
 跳转标签
经过汇编后的到文件中,标签已经被转换为一个具体的偏移量

 字符串常量
对字符串常量的引用使用 全0 填充,并在重定位节中记录了符号的偏移

可以看到在下方有重定位信息,让我们在重定位节中寻找该信息

第一条正对应于此处对字符串常量1的引用,在偏移18字节处00填充的4字节
 函数调用
同样使用00填充并在elf的重定位节中进行记录

重定位节的记录

 与hell.o的映射
经过简单比较可以发现,除了对符号的引用发生改变(转换为实际的偏移量或者用0进行填充)之外,机器码与汇编指令保持严格的映射关系,通过二进制文件可以反汇编的到汇编代码文件
4.5 本章小结
本章通过对hello.o文件的elf格式分析以及对使用objdump反汇编hello.o文件得到的结果的分析,简要的介绍了汇编的概念和作用。演示了如何查看重定位信息,并通过和原来的hello.s汇编指令文件的比较加深对汇编器作用的直观理解
(第4章1分)

第5章 链接
5.1 链接的概念与作用
概念
链接是指将多个可重定位目标文件组合成一个单一的可执行目标文件的过程
作用
完成对可重定位目标文件的符号解析和重定位,使得不同可重定位目标文件可以引用彼此的符号(全局可见的)
5.2 在Ubuntu下链接的命令
链接失败
当我们直接对hello.o执行链接时,链接器报出错误信息

链接器在进行符号解析式找不到对应的符号声明,因此无法继续完成重定位、生成可执行程序的过程
加入库文件
使用 -lc 选项使链接器自动搜索需要的c库

发现找不到符号 _start,百度后发现是缺少c运行时库crt(三个均加入)

最终链接成功

然而运行后提示找不到文件

加入动态链接器
百度之后得知linux加载和链接可执行文件所需要的链接库需要动态链接器,保存在/lib64/ld-linux-x86-64.so.2中,将其也加入链接选项

终于链接成功并成功运行了!
最终命令
ld hello.o /usr/lib/x86-64-linux-gnu/crt*
-dynamic-linker /lib64/ld-linux-x86-64.so.2
-lc -o hello

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

通过简单比较可发现其与hello.o有以下几个明显的不同
项目名称 hello.o hello
文件类型 可重定位文件 可执行文件
入口点地址 文件偏移 虚拟地址
程序头 无 有
各段基本信息

5.4 hello的虚拟地址空间

除了hello的各个段之外,还多了一些c库的段

5.5 链接的重定位过程分析
比较
hello hell.o 解释
文件偏移
转换为
虚拟地址
符号解析为
实际的地址或偏移
无 合并了多个文件的代码段、数据段
重定位过程分析
根据hello.o中重定位节的信息

  1. 定位需要重定位的符号的偏移
  2. 确定该偏移处的符号名称
  3. 在所有链接的文件中找到对应符号的地址
  4. 将地址填充到该偏移处

5.6 hello的执行流程
hello的执行流程
地址 名称 功能
0x7ffff7fd3de0 _dl_start 重定位动态链接器
0x7ffff7fe2040 _dl_init 初始化动态链接器
0x0000401120 _start 控制权转移到用户程序
0x7ffff7e12c20 __libc_start_main 注册终止函数
调用main函数
0x0000000000401000 _init linux特性
0x0000401094 main 程序入口
0x7ffff7e42cf0 printf 输出
0x7ffff7e2a660 exit 终止
0x7ffff7eb7340 sleep 挂起
0x7ffff7e69000 getchar 读取字符
0x7ffff7e12d0a __libc_start_main 调用终止函数
0x7ffff7e2a660 __GI_exit 退出

5.7 Hello的动态链接分析
对于动态共享链接库中PIC函数,编译器添加重定位记录,等待动态链接器处理,同时,链接器采用延迟绑定的方法。
在dl_init前, PIC函数调用的目标地址都实际指向PLT中的代码逻辑,初始时每个GOT条目都指向对应的PLT条目的第二条指令。
dl_init后,部分数据信息发生变动

5.8 本章小结
本章简单介绍了链接的概念和作用,并对链接的过程进行了简单的演示与说明
(第5章1分)

第6章 hello进程管理
6.1 进程的概念与作用
概念
进程就是运行中的程序实例,进程总是处于被执行或等待被执行的状态
作用
进程实现程序员预先编写好的程序功能
6.2 简述壳Shell-bash的作用与处理流程
作用
接收用户输入的命令并执行该命令
处理流程
1. 接收用户输入
2. 判断是否是内置命令,如果是就直接执行
3. 如果不是就fork一个子进程
4. 在子进程中使用execve运行可执行文件,如果找不到就抛出提示信息
5. 等待子进程结束回收子进程
6. 在子进程运行中shell依然接收用户的输入
6.3 Hello的fork进程创建过程

  1. shell中键入 ./hello
  2. 判断hello不是内置命令
  3. shell调用fork产生一个子进程
  4. shell判断当前上下文环境是否是子进程的(fork() 返回0)
  5. 在子进程中调用execve执行hello程序
  6. hello进程创建,父进程的fork()返回值即其pid

6.4 Hello的execve过程

  1. shell调用execve函数,参数依次为文件名(hello),传递给hello的参数(hello 学号 姓名 秒数 或者不满足要求的其他输入均会传递给hello),环境变量
  2. execve在路径中寻找hello可执行文件
  3. 找到hello可执行文件将其加载进内存,用它的代码和数据覆盖原来的内存空间
  4. 跳转到hello的入口点,将控制传递给hello程序
  5. 不再返回到shell
    6.5 Hello的进程执行
    进程提供给程序两个关键抽象:逻辑控制流和私有地址空间,使得每个进程似乎独占CPU和内存系统。然而实际上,单处理器在并发地执行多个进程,多个进程交错执行,一个进程执行它控制流的一部分的每一时间段叫做时间片
    进程的物理实体(代码和数据等)和支持进程运行的环境合称为进程的上下文
    进程由常驻内存的操作系统代码块(内核)进行管理,定时器芯片每隔几毫秒触发一次中断,内核从进程中取回控制权。
    当一个进程切换到另一个进程时,进行上下文切换,首先由用户模式转换为内核模式,操作系通把换下进程的寄存器上下文保存到系统级上下文中的现场信息中;其次调度下一个进程的执行,将寄存器值从内存中加载取出并且转换地址空间,将控制转移到该进程,由内核模式再恢复为用户模式,实现进程的调度转换

6.6 hello的异常与信号处理
异常
 异步异常
 中断
 内核进行进程调度
 同步异常
 陷阱
 hello进行输出时会产生系统调用

最终追踪到write

使用标号为1的系统调用sys_write将输出写到标准输出流
 故障
 可能会出现缺页

信号
 sigtstp
用户输入ctrl-z
通过ps可以查看hello能位于进程列表中,通过jobs可以发现该任务处于挂起状态
 sigccont
暂停程序后在shell中使用fg会向挂起的hello进程发送该信号,使其在前台继续运行
 sigint
用户输入ctrl-c
可以发现hello进程已经结束,不在进程列表中
 sigalarm
通过接收来自alarm函数的sigalarm信号来结束sleep
 sigchld
当hello结束时会向shell发送sigchld信号,shell进行子程序回收
程序运行中乱按其他键
并不会影响进程的运行

6.7本章小结
本章简单介绍了hello进程的产生过程,以及进程运行当中会出现的一些异常和信号,并演示了程序是如何处理这些异常和信号的
(第6章1分)

第7章 hello的存储管理
7.1 hello的存储器地址空间
逻辑地址:
物理地址的抽象表示,比如在16位地址总线的机器上可以使用基址+偏移地址的方式来表示20位的物理地址,又如通过逻辑地址可以确定磁盘的柱面、头、段等信息进而找到其物理地址
还可以是程序中直接使用的地址,比如C指针进行的运算、读取就可以看作对逻辑地址的操作

虚拟地址
虚拟地址是程序运行过程中所使用的地址,比如指令的地址,数据的地址,使用的都是虚拟地址,需要完成转换(MMU翻译)后对应到物理地址

物理地址
实际存储信息的地址,对应于存储器上的存储单位
线性地址
逻辑地址通过变换首先转换为线性地址,如果没有启用分页机制,那么线性地址就直接对应于物理地址;否则,线性地址需要再次进行转换成为物理地址

7.2 Intel逻辑地址到线性地址的变换-段式管理
实地址模式
地址总线20位
通过内存分段(将空间划分位64k的段),用16位的地址线表示20位地址
线性地址 = 段基址(保存在段寄存器中) * 10H + 段偏移
保护模式
地址总线32位
段寄存器(只有两个字节,不足以存储基址)指向段描述符表,使用段描述表定位程序使用的段的位置,再加上段偏移构成线性地址
7.3 Hello的线性地址到物理地址的变换-页式管理
操作系统为hello(每个进程)维护一个单独页表

  1. 取出线性地址中的虚拟页号
  2. 通过页表找到对应的物理页号
  3. 物理页号加上物理页偏移(和虚拟页偏移相同)得到物理地址

7.4 TLB与四级页表支持下的VA到PA的变换
页管理优化
时间方面:
在每次转换的过程中访问页表查找对应的物理页号,如果我们连续访问相同的页还是每次都要查页表,无疑增大了时间开销;
优化:TLB
空间方面:
当我们的地址空间增加时,页表项目也会同样增加,而内存空间的扩充速度显然无法和硬盘相提并论,因此内存将无法容纳越来越大的页表
优化:多级页表
TLB

  1. 取出线性地址的虚拟页号
  2. 虚拟页号被划分位TLBT(标记)和TLBI(索引)
  3. 在TLB中,在索引为TLBI的组中寻找标记为TLBT的行
  4. 如果找到,直接获得对应页表条目,地址转换完成,不必再访问页表
  5. 如果找不到,再访问页表,并根据一定的策略替换TLB中的行
    多级页表
    虚拟地址被划分成了多个页表索引,通过上一级页表索引找到下一级页表的地址,依次进行多级的页表寻址,最终转换为物理页号,物理地址

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

  1. 将得到的物理地址划分为CT(标记)、CI(索引)、CO(偏移)
  2. 根据索引和标记依次在三级Cache中寻找
  3. 如果找到,就根据偏移取出对应的数据
  4. 如果找不到,就需要访问主存
    7.6 hello进程fork时的内存映射
    创建虚拟内存
  5. 创建hello进程的mm_struct, vm_area_struct和页表的原样副本
  6. 两个进程中的每个页面都标记为只读
  7. 两个进程中的每个区域结构(vm_area_struct)都标记为私有的写时复制

至此hello进程拥有与shell进程相同的虚拟内存(地址空间),映射到同一片物理地址上
7.7 hello进程execve时的内存映射

  1. 删除已存在的用户区域
  2. 创建新的区域结构
    a) 代码和初始化数据结构映射到.text和.data区
    b) .bss和栈映射到匿名文件
  3. 设置PC,指向代码区域的入口点
    a) 根据需要换入代码和数据页面

    7.8 缺页故障与缺页中断处理
    非法内存引用
    当程序要访问的页面超出可读写区范围时,页故障处理程序发送一个SIGSEGV(段错误)信号,这个信号对应的信号处理程序会在屏幕上显示segmentation fault,并终止程序的运行

正常缺页故障
用户要读写的物理页不在内存,而在磁盘中,内核会将该物理页拷贝到内存中,并返回触发缺页故障的指令处重新执行该指令

7.9动态存储分配管理
内存分配
动态内存分配器(比如malloc)维护着一个进程的虚拟内存区域,称为堆。分配器将堆视为一组不同大小的块的集合来维护,每个块要么是已分配的,要么是空闲的
分配器可分为

  1. 显式分配器:显式地释放任何已分配的块,如malloc和free
  2. 隐式分配器:检测到已分配块不再被使用,就释放该块,如java中的垃圾收集

    (隐式)分配器的实现有多种方式,如隐式空闲链表、显式空闲链表和分离的空闲链表等。分配器根据用户的请求分配或释放相应的空间以满足进程的需要。
    垃圾收集
    自动回收堆存储的过程而不需要应用显式释放
    经典的垃圾收集算法
     Mark-and-sweep collection
     Reference counting
     Copying collection
     Generational Collectors
    C语言使用保守的Mark&Sweep进行垃圾收集
    7.10本章小结
    本章先简单介绍了逻辑地址、虚拟地址、线性地址和物理地址的相关概念,使读者对进程的地址空间有了初步的了解。接着介绍了逻辑地址、线性地址和物理地址之间的转换关系,说明了进程运行时使用的虚拟地址是如何转换为真实的物理地址的。其次又介绍了通过TLB、多级页表优化地址转换的机制以及Cache的访问机制。进一步对hello进程的内存映像的创建过程做了简单介绍
    最后又简单说明了缺页处理和动态存储管理的相关原理。
    通过以上内容,希望可以使读者对进程的存储管理获得一定的了解
    (第7章 2分)

第8章 hello的IO管理
8.1 Linux的IO设备管理方法
linux将所有的I/O设备都模型化为文件,如/dev/sda2(用户磁盘分区)、/dev/tty2(终端),所有的I/O操作都可以看作对相应文件的读或写
linux内核给出简单、低级的应用接口,以统一且一致的方式执行I/O操作
8.2 简述Unix IO接口及其函数
接口 函数
打开文件(返回文件描述符)/ 关闭文件(释放文件数据结构) open()/close()
读文件(文件->内存)/ 写文件(内存->文件) read()/write()
改变文件指针位置 lseek
8.3 printf的实现分析
printf首先调用vsprtinf获取要输出的字符串的长度,之后调用write向标准输出中写,跟踪write可以得到其最终会使用系统调用将控制流转移到内核当中,由内核完成写操作后再返回进程
字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
8.4 getchar的实现分析
异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。
getchar调用read函数,通过系统调用读取按键ascii码,接收到回车返回。
8.5本章小结
本章简单介绍了linux的IO设备管理,几个IO接口,简单说明了printf和getchar的实现
(第8章1分)
结论
hello的一生
hello.c对它接下来要经历的一切一无所知,它唯一知道的,是它将带着那个无论经历怎样的挫折磨难也绝不会改变的”hello”,出现在一双又一双或是昏暗、或是清澈、或是呆滞、或是深邃的眼睛之中。
hello.c知道上帝会为它安排好一切,只要它坚持下去,永不放弃,就一定可以出现在千万双眼睛之中,向世界输出”hello”,实现自己从诞生时就注定的使命。
hello.c注视着镜中的自己,困惑道:“这怎么能行,我的头发和胡子都太长了,身体也太瘦弱了,虽然看起来有胳膊有腿,却实际上什么也做不了”上帝说,你去找cpp吧,让她把你好好打扮打扮。
hello.c将信将疑的找到了cpp,“你看看你,身上到处都脏兮兮的,我先给你洗个澡,剪剪头发,剃剃胡子吧”…“喔确实清爽了不少”hello.c得意的笑了笑。“哼,幼稚!我看你是缺少社会的毒打”“啊”cpp对hello.c一顿拳打脚踢,hello.c昏迷不醒。
一觉醒来,hello.i看着镜中的自己“啊,我是谁,我怎么变得这么胖了”,hello.i发现自己全身上下又肿又臃肿。比原来的自己胖了不知多少倍。“怎么办啊怎么办!”,“cc1可以帮助你”上帝又开口了。
“嗯,你这种情况,好办!”cc1淡定的说。
hello.s不记得自己昏迷了多久,缓慢的侧起身,目光只是不经意的一瞥,却锁定在了那一面精致的铜镜——内的精致的脸庞——面如冠玉,剑眉星目。“啊这~这是!”“哈哈哈哈”编译器cc1大笑道,“如何?”
hello.s不可置信的上下打量着自己,发现自己原本模糊不清的脸庞变得清晰起来,手掌竟也有了纹路,时不时还能感受到体内涌动的热流,它尝试舒展自己的身体,粗壮的骨骼此时嘎嘎作响!“感谢cc1兄再造之恩!”
hello.s趾高气昂、得意洋洋的走在热河路上,朝天的鼻孔生怕别人看不到,它好像已经忘了自己的使命。
突然,一个叫as的家伙横刀立在hello.s的面前:“哼,小子不知好歹,上帝叫我来收拾你类!”“啊,上帝、上帝他啊…”
又是一次昏迷过后,hello.o翻滚到河边。“天呐!”hello.s想要惊讶的大叫,却发现自己的嘴巴不见了。“耳朵也没了!鼻子也没了!胳膊、腿都没了!”“心也没了!肺也没了”“可是我却没有死!…我变异了!”。hello.o突然亢奋起来,因为它想到上帝告诉过它,只有变异后的它,才能完成使命。
hello.o激动的尝试实现自己的使命,“啊,怎么…”hello.o发现自己什么都做不了。“你已经进化了,可是,有些东西,你不能失去,去寻找她们吧,凭借你的记忆”
hello.o感到一阵剧烈的头痛,意识到自己的大脑中多了什么东西。“我有脑子了!”谁能想到,原来你以前没有脑子呢!
hello.o四处奔走,风雨兼程,途径日暮不赏,寻找那些对于实现自己的价值不可或缺的部分。
此时已皓月当空,hello.o手捧星光。没错,它找回了自己的双手、双脚、心肺和所有属于最初的自己的那些东西。可是,hello.o也发现了,他虽然历经千辛万苦找回了这些失去的东西,但是它却无法再次拥有她们;虽然在它的心中,仍有她们的位置,可是却再也放不进去了。“唉”。
“我可以帮你”叹息声还在蔓延,链接器ld带着动态链接器、C运行时库crt来到了hello.o和它遗失的那些东西面前。
“你可以让我们重新在一起吗?”
“当然,只要你相信我。”
“你要我做什么?”
“把你的记忆全部给我,只要你的心中确实还有她们,而且,你把她们所有都找了回来,我就可以让你们重归一体。”
“我相信你,除此之外,我别无选择。”

hello从睡梦中醒来,虽然刚刚醒来,可他却非常清醒,可能因为他是自然醒的,而且在真正醒来之前,大脑已经活跃了一段时间了。
hello从床上一跃而起,一股莫名的力量涌动在全身的经脉之中。hello甚至抑制不住眼中的泪水,却已经急匆匆的冲出了房门。
“hello”
学习感悟
经过一个学期的学习,我对计算机系统的设计和实现有了一定的了解,以前对计算机模糊不清的那部分似乎也开始变得清晰了起来。要说有什么创新理念,我倒是还真没有思考过,不过回过头来看这门课,却只觉得非常神奇。
这门课好像是在学计算机系统,又好像是在学程序的编译、链接、执行过程,又好像是这两个都在学。学完了,我个人觉得,是在学计算机系统,只不过学的所有东西刚好被程序的编译、链接、执行过程给串起来了,越想越觉得奇特。
以前也看过一些博客关于编译链接的介绍,不过最后都似懂非懂、不了了之,没什么收获;计算机系统的相关书也翻阅过一两本(不过从没、从没打算过看《深入理解计算机系统》,在图书馆的书架上一眼就看到它了,厚的不行,而且感觉还快被翻烂了),最后也只是零零散散有了点了解,但效果也不能说大或者好。
总的来说,从计算机系统这门课中还是收获了不少东西的,确确实实可以说,学到了真东西,干货。不过,没学明白的东西也还不少。甚至还想吐槽一下自己:一方面觉得课程设置的时间线太长,学到一半就不想学了;一方面又吐槽课程排的紧,实验做不完。不过,这确实是我的真实感受,就很离谱。

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

附件
hello.i 预处理后生成的文件
hello.s 编译后生成的文件
hello-spec.s 对hello.s的注释版本
hello.o 汇编后生成的文件
hello-o-elf.s hello.o的elf头
hello-o-objdump.s objdump反汇编hello.o生成的文件
hello 链接后生成的文件
hello-e-elf.s hello的elf头
hello-e-objdump.s objdump反汇编hello生成的文件
(附件0分,缺失 -1分)

参考文献
为完成本次大作业你翻阅的书籍与网站等
[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] [转] Linux下程序的加载、运行和终止流程 - JollyWing - 博客园 (cnblogs.com)
[8] (3条消息) Linux用户程序的编译链接与加载启动过程_RToax-CSDN博客
[9] sleep实现原理 - blcblc - 博客园 (cnblogs.com)
(参考文献0分,缺失 -1分)

你可能感兴趣的:(计算机系统,c语言)