划时代的意义 Hello P2P

程序人生-Hello’s P2P

第1章 概述

1.1 Hello简介

P2P

程序完成后(代码完成),依此需要完成预处理,编译,汇编,链接操作,生成可执行程序hello,在命令行中fork子进程,由程序变为进程。

020

shell为其execve加载,映射虚拟内存,进入程序入口后程序开始载入物理内存,启动代码设置栈,并将控制传递给程序的主函数执行代码,CPU为运行的hello分配时间片执行逻辑控制流。当程序运行结束后,shell父进程负责回收hello进程,内核删除相关数据结构。

1.2 环境与工具

1.2.1 硬件环境

处理器 Intel i7-7500 CPU 2.70GHz,内存 8.00GB,硬盘空间:SSD 128GB 硬盘 1T。

1.2.2 软件环境

Windows10 64位操作系统,基于x64处理器; VMware Workstation Pro; ubuntu-16.04.31.2.3

1.2.3 开发工具

GDB, EDB, codeblocks, objdump, readelf。

1.3 中间结果

文件名文件作用
hello.ihello.c预处理后保存的文件
hello.s将hello.i翻译成汇编语言保存文件
hello.o将hello.s中汇编翻译成机器语言指令的保存文件
hello链接成功的结果hello
data1保存objdump –d –r hello的文件
data2保存objdump –d hello.o的文件

1.4 本章小结

简述了hello.c文件处理过程大致流程、使用工具和中间文件,确定接下来各章的主体和联系。
2—5章完成P2P,6—8章完成020。

第2章 预处理

2.1 预处理的概念与作用

2.1.1 概念

在编译之前对文件进行的处理。

2.1.2 作用

1)将所有的#define删除,并展开所有的宏定义;
2)处理所有的预编译指令,例如:#if,#elif,#else,#endif;
3)处理#include预编译指令,将被包含的文件插入到预编译指令的位置;
4)添加行号信息文件名信息,便于调试;
5)删除所有的注释:// /**/;
6)保留所有的#pragma编译指令。

2.2 在Ubuntu下预处理的命令

2.2.1 命令

gcc –E –o hello.i hello.c

2.2.2 结果

在这里插入图片描述

2.3 Hello的预处理结果解析

2.3.1

hello.c里开头有#include,所以在hello.i文件中依次将stdio.h, unistd.h, stdlib.h展开
在这里插入图片描述

2.3.2

添加行号信息文件名信息。

2.3.3

删去所有的注释。
在这里插入图片描述

2.3.4

main函数在hello.i文件最后一段。
在这里插入图片描述

2.4 本章小结

预处理的作用1、3、4、5可以在hello.i中体现,前后结合更容易理解处理方式。
理解预处理的操作和作用,完成了生成可执行目标文件的第一步。

第3章 编译

3.1 编译的概念与作用

3.1.1 概念

完成词法分析、语法分析、语义分析等,在检查无错误后后,把代码翻译成汇编语言。

3.1.2 作用

将文本文件hello.i翻译成文本文件hello.s,包含一个汇编语言程序。

3.2 在Ubuntu下编译的命令

3.2.1 命令

gcc –S –o hello.s hello.i

3.2.2 结果

在这里插入图片描述

3.3 Hello的编译结果解析

指令含义
.file声明源文件
.globl声明一个全局变量
.alogn声明对指令或者数据的存放地址进行对齐的方式
.type指定是函数类型或是对象类型
.size声明数据大小
.long声明一个long类型
.rodata .sectionrodata节
.string声明一个 string类型
.text代码段
3.3.1数据
1.常量
字符串

1.根据中文编码UTF-8 和hello.c文件,\345\255……代表–学号 姓名
整体字符串 “Usage: Hello 学号 姓名!\n” 是第一个printf函数所传参数。
2.字符串 “Hello %s %s\n” 是第二个printf函数参数。
在这里插入图片描述

2.变量
1)全局整形变量

根据.globl指令可知声明sleepsecs为全局变量。
在这里插入图片描述

2)局部整形变量

int i;
可以看出-4(%rbp)存储的是循环结束条件i。
在这里插入图片描述

3)数组

根据hello.c文件利用char *argv[]数组。

3.3.2 赋值
1. =
1)sleepsecs = 2.5

使用.align声明对齐方式为4,.type确定为对象类型,.size声明大小4字节,.long声明为整型,并赋值为2。hello.c文件中int sleepsecs=2.5; 有所不同,应为编译时优化,默认转为int赋值。
在这里插入图片描述

2)i = 0

利用movl指令将i赋值为0。
在这里插入图片描述

3.3.3类型转换
隐形转换

int sleepsecs = 2.5。编译时直接初始赋值为2,这时编译时优化,默认转为int赋值。

3.3.4算术操作
++

i++,直接采取addl指令加1。
在这里插入图片描述

3.3.5关系操作
1. <

i<10,利用cmpl和jle指令与立即数9比较是否小于相等。
在这里插入图片描述

2. !=

argc != 3,利用cmpl和je指令与立即数3比较是否相等。
在这里插入图片描述

3.3.6 数组/指针/结构操作
1.A[i]

argv[0],argv1,argv类型为char*其中每个数据占有8个字节,并且.L4是循环内部,所以可以看出第一行在-32(%rbp)获取了argv初始地址,由%rax保存,之后分别在第三行获得 argv[0],第6行获取argv1。
在这里插入图片描述

3.3.7控制转移
1.if

根据3.3.5节可知,if语句采用cmpl和je指令判断是否进入if内。

2.for

根据3.3.2, 3.3.4, 3.3.5可知,for循环利用movl->i = 0,cmpl-> i<10 addl->i++
完成for语句。

3.3.8函数操作
1.参数传递

在X86-64系统包含16个存储64位值的通用目的寄存器,其中有6个保存参数寄存器,如果参数过多可以采用用栈指针保存地址。
1)%esi保存字符串.LC0(3.3.1已提),为下面的puts函数调用传参。
在这里插入图片描述
2)%edi保存字符串.LC1(3.3.1已提),为下面的printf函数传参。
在这里插入图片描述
3)%edi保存%eax,为下面的sleep函数传参。
在这里插入图片描述
4)%edi保存立即数1,为下面的exit函数传参。
在这里插入图片描述

2.函数调用
1)puts

本次调用是由printf(“Usage: Hello 学号 姓名!\n”);编译,打印第一个printf函数的参数。
在这里插入图片描述

2)printf

本次调用是由printf(“Hello %s %s\n”,argv[1],argv[2]);编译,打印第二个printf函数的参数。
在这里插入图片描述

3)sleep

暂时挂起。
在这里插入图片描述

4)exit

利用传参%edi,保证退出为1->exit(1)。
在这里插入图片描述

5)getchar

获取输入。
在这里插入图片描述

3.函数返回
return 0

main函数最后设返回值为0,利用movl指令将0赋给返回值寄存器%eax。
在这里插入图片描述

3.4 本章小结

汇编器处理C语言时(无错误),需要完成词法分析、语法分析、语义分析,并且根据优化程度将其翻译成相应的汇编语言。
优化程度高,与原程序结构差异度高。
完成了编译步骤,阐述了C语言的数据(常量,变量,全局,局部,宏)和操作(赋值,类型转换,算术操作,关系操作,函数调用等)翻译成汇编的具体完成方式。

第4章 汇编

4.1 汇编的概念与作用

4.1.1 概念

汇编器(as)将hello.s翻译成机器语言指令,把这些指令打包成可重定义目标程序的格式,并将结果保存在目标文件hello.o中。

4.1.2 作用

将汇编指令转换成一条条机器可以直接读取分析的机器指令。

4.2 在Ubuntu下汇编的命令

4.2.1 命令

gcc –c hello.s –o hello.o

4.2.2 结果

在这里插入图片描述

4.3 可重定位目标elf格式

4.3.1 Elf头

ELF头以一个16字节的序列Magic开始,它描述了生成该文件的系统的字的大小和字节顺序,ELF头剩下的部分包含帮助链接器语法分析和解释目标文件的信息,其中包括ELF头的大小、目标文件的类型、机器类型、字节头部表的文件偏移,以及节头部表中条目的大小和数量等信息
在这里插入图片描述

4.3.2 节头部表

描述不同节的位置和大小
在这里插入图片描述

4.3.3 重定位节

在这里插入图片描述

4.4 Hello.o的结果解析

在这里插入图片描述
根据上述比较,意思相同,但结构和指令有所改变。

hello.shello.o反汇编
跳转指令以块名(.L1)为操作量跳转指令以地址为操作量
在控制转移中结束跳转其他块控制转移结束后跳转到该流程下方
立即数为十进制立即数等为十六进制

4.5 本章小结

本章完成了汇编过程,并利用readelf查看可重定位目标elf格式,之后比较了
反汇编与编译,了解到它们存在差异。

第5章 链接

5.1 链接的概念与作用

5.1.1 概念

将可重定位目标程序链接为可执行目标程序的过程。

5.1.2 作用

可重定位目标程序不能直接执行,需要链接过后形成可真正可以执行的可执行目标程序才能让计算机执行hello。

5.2 在Ubuntu下链接的命令

5.2.1命令

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.2.2 结果

在这里插入图片描述

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

在这里插入图片描述

5.4 hello的虚拟地址空间

edb加载hello

在这里插入图片描述

打开Symbols

在这里插入图片描述
通过上述两图可以查出对应虚拟地址

在这里插入图片描述
查看Data Dump可以发现虚拟地址自0x400000开始,0x400fff结束,开始与结束间隔与5.3中地址声明大小相同,之后存放的是.dynamic~.shstrtab节。

5.5 链接的重定位过程分析

在这里插入图片描述

5.5.1 差别:

左图称为data1(是可执行目标程序hello反汇编的文件中的重定位条目)
右图称data2(为hello.o反汇编)

data1data2
采取虚拟内存地址采取相对地址
节.init .plt .plt .got .text .fini节.text
调用外部链接函数puts,printf,getchar,sleep等没有调用外部函数
5.5.2 重定位过程
1)将多个单独的代码节和数据节合并为单个节。

将相同的节:hello.o的.text节和系统.text节合并
在这里插入图片描述
在这里插入图片描述

2)对定义符号重定位(确定地址)

在这里插入图片描述
函数确定首地址后,之后调用其他函数可以确定其地址,直接采用
call 地址+函数名。

3)对引用符号重定位(确定地址)

修改.text节和.data节中对每个符号的引用(地址)
需要用到在.rel_data和.rel_text节中保存的重定位信息。

5.6 hello的执行流程

在这里插入图片描述
在这里插入图片描述

5.7 Hello的动态链接分析

在这里插入图片描述
动态链接比静态链接要慢1%~5%,原因如下:
○1.动态链接下对于全局和静态数据的访问都要进行复杂的GOT(全局偏移表)定位,然后间接寻址;对于模块间的调用也要先定位GOT,然后再进行跳转。
○2动态链接的链接工作是在运行时完成,即程序开始运行时,动态链接器都要进行一次链接工作,而链接工作需要复杂的重定位等工作,减慢了启动速度。
而hello为解决第二个问题,采取延迟绑定,即函数第一次被用到时才进行绑定。
从而发生以上变化。动态链接器使用过程链接表PLT+全局偏移量表GOT实现函数的动态链接,GOT中存放函数目标地址,PLT使用GOT中地址跳转到目标函数。
dl_init@plt:
jmp *(dl_init@GOT)
push n
push moduleID
jump _dl_runtime_resolve
在dl_init@plt第一指令指向GOT表中函数dl_init地址。
在未遇到dl_init函数前,GOT表无该函数的地址信息,将后续指令地址填充到GOT中dl_init函数,这时jmp指令会直接跳转继续执行后续的push n等指令,这时不需遍历寻址目标符号。之后调用_dl_runtime_resolve函数完成具体的符号解析和重定位工作,将外部模块中dl_init函数真正地址填入GOT对应的dl_init@GOT。

5.8 本章小结

由链接的概念和作用入手,查看hello的ELF格式并分析hello的虚拟地址空间、重定位过程(与上一章比较来突出作用)、执行流程、动态链接过程。学号了edb的一些基本操作。

第6章 hello进程管理

6.1 进程的概念与作用

6.1.1概念:

一个执行中程序的实例,即程序的一次运行过程。

6.1.2 作用

每个进程拥有独立的逻辑控制流和一个私有的虚拟地址空间。这提高CPU的执行效率,减少因为程序等待带来的CPU空转以及其它计算机软硬件资源浪费。

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

作用

shell 是一个交互型的应用级程序,它代表用户运行其他程序。

处理流程
  1. 从文件或用户终端读取命令。
  2. 根据特定格式切割字符串获取单词和运算符。
  3. 将标记解析为简单的复合命令。
  4. 根据命令对应情况处理。

6.3 Hello的fork进程创建过程

在终端输入./hello 1170300622 梁猛,壳开始处理,读取命令,将读取的字符串切割,hello是特殊的(非内置的shell命令),无法直接解释,程序认为./hello的语义为执行当前目录下的可执行目标文件hello,调用fork函数创建一个新的运行的子进程(子进程与父进程虚拟地址空间相同,但相互独立,并且子进程与父进程PID不同)。
在这里插入图片描述

6.4 Hello的execve过程

首先加载并运行可执行目标文件hello(找不到hello返回),并且带参数列表argv和环境变量列表envp,创建内存映像,覆盖当前进程的代码、数据、栈但没有创建新进程拥有相同的PID。加载之后调用启动代码,设置栈并将控制传递给新程序的主函数。
当main执行时,用户栈结构如下。
在这里插入图片描述

6.5 Hello的进程执行

1.sleep

操作系统内核使用上下文切换来实现多任务。如果在调用sleep前hello没有被抢占,就顺序执行,否则进行上下文切换,首先保存当前进程的上下文,然后恢复之前sleep被抢占时保存的上下文并将控制传递给sleep进程。
如下图,hello进程在一开始处于用户模式,调用sleep后进入内核模式,此时处于sleep暂时挂起,将控制传递给其他进程,然后在sleep结束后返回,继续运行。
在这里插入图片描述

2.getchar

调用getchar读取命令行上输入字符,hello之前运行在用户模式,执行getcahr进入内核模式,读取键盘输入缓存区。结束后返回上下文切换,继续进行hello进程。
在这里插入图片描述

6.6 hello的异常与信号处理

6.6.1 运行操作
1. 不停乱按

用户键盘输入的字符被读进stdin缓冲区中。
在这里插入图片描述

2. Ctrl+z

内核向进程发出挂起命令SIGSTP,可以看出进程暂停。
在这里插入图片描述

3. Crtl+c

内核向进程发出终止命令SIGINT,可以看出进程终止。
在这里插入图片描述

6.6.2 异常总结:

1.终止:SIGINT 来自键盘的中断
2.终止:SIGKILL 杀死程序
3.中断:SIGSTP 挂起程序

6.7本章小结

本章介绍了进程的概念和作用,描述了shell如何在用户和系统内核之间建起一个交互的桥梁。讲述了shell的基本操作以及各种内核信号和命令,还总结了shell是如何fork新建子进程、execve如何执行进程、hello进程如何在内核和前端中反复跳跃运行的。

第7章 hello的存储管理

7.1 hello的存储器地址空间

物理地址:程序运行时加载到内存地址寄存器中的地址,内存单元的真正地址。在hello程序中表示了这个程序运行时的一条确切的指令在内存地址上的具体哪一块进行执行。
虚拟地址:程序使用的地址,CPU通过生成一个虚拟地址来访问主存,这个虚拟地址被送到内存之前通过硬件与操作系统被转换成适当的物理地址
逻辑地址:由程序产生的与段相关的偏移地址部分,在有地址变换功能的计算机中,访存指令给出的地址叫逻辑地址,也叫相对地址。逻辑地址由段基值和偏移量组成。
线性地址:逻辑地址经过段变换后的地址,即虚拟地址

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

在实地址模式下,处理器使用20位的地址总线,可以访问1MB(0~FFFFF)内存。而8086的模式,只有16位的地址线,不能直接表示20位的地址,采用内存分段的解决方法。
一个逻辑地址由两部份组成,段标识符和段内偏移量。
段标识符是由一个16位长的字段组成,称为段选择符。其中前13位是一个索引号。后面3位包含一些硬件细节。
索引号指出选择描述符表中的哪个条目。
TI位表示段描述符的位置,TI=0段描述符在GDT中,TI=1段描述符在LDT中。
RPL表示程序的当前优先级
在这里插入图片描述
由以上找出在目标描述符条目的基地址,然后加上段内偏移量,构成线性地址。

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

CPU的页式内存管理单元,负责把一个线性地址,转换为物理地址。
首先线性地址可以划分为两部分:虚拟页号(VPN),虚拟页偏移量(VPO)
根据页表基址寄存器确定页目录指向当前页表,MMU(内存管理单元)利用VPN选择适当的PTE(有效位需为1,有可能发生不命中),然后将页表的物理页号和VPO串联得到对应的物理地址。
在这里插入图片描述
在这里插入图片描述

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

一级页表: 每个PTE指向一个二级页表,根据7.3类比(cr3指向一级页表基址),判断一级页表是否命中(找到物理地址),不命中由该PTE确定二级页表基址,然后继续判断是否命中。三四级页表同。
在这里插入图片描述
在这里插入图片描述

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

L1是32KB,8路相联,64字节/块,47位地址范围
确定B=64,S=64,s=6,E=8,e=3,C=64646=32768
块偏移:6bits,组索引:6bits,标记:35bits
当CPU提出访存请求后给出物理地址,然后高速缓存根据CI找到缓存组,在缓存组中根据CT与缓存行中的标记位进行匹配,如果匹配成功并且有效位为1,为命中,则按照块偏移对数据块中的数据进行访问,否则为不命中,向下一级缓存中寻找数据,如果找到,则按照放置策略和替换策略替换该级缓存中的缓存块,否则继续向下一级缓存或主存中寻找数据。
在这里插入图片描述

7.6 hello进程fork时的内存映射

1.为新进程创建虚拟内存

1)创建当前进程的的mm_struct, vm_area_struct和页表的原样副本。
2)两个进程中的每个页面都标记为只读。
3)两个进程中的每个区域结构(vm_area_struct)都标记为私有的写时复制。

2.在新进程中返回时,新进程拥有与调用fork进程相同的虚拟内存。
3.随后的写操作通过写时复制机制创建新页面。

7.7 hello进程execve时的内存映射

1.删除已存在的用户区域
2.创建新的区域结构

1)映射私有区域
代码和初始化数据映射到.text和.data区(目标文件提供)。
2)映射共享区域
Hello与标准C库lib.c等链接,这些对象动态链接到这个程序,然后再映射到用户虚拟地址空间中的共享区域。.bss和栈映射到匿名文件。
在这里插入图片描述

3.设置PC,指向代码区域的入口点

Linux根据需要换入代码和数据页面。

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

1.缺页

DRAM缓存不命中,即一个虚拟地址对应的物理页不在内存,在磁盘中。

2.缺页中断处理

触发缺页故障,调用内核中的缺页异常处理程序,选择一个牺牲页,从磁盘中复制物理页到内存,然后更新PTE,随后返回。之后重新启动导致缺页的指令,此时命中。

7.9动态存储分配管理

在程序运行时程序员使用动态内存分配器 (比如malloc) 获得虚拟内存。
动态内存分配器维护着进程的一个虚拟内存区域,称为堆。
分配器将堆视为一组不同大小的块的集合来维护,每个块是连续的虚拟内存片,要么是已分配的,要么是空闲的。
在这里插入图片描述
分配器风格
显式分配器
要求应用显式地释放任何已分配的块。
例如,C语言中的malloc和free。
显式空闲链表:在空闲块中使用指针。
在这里插入图片描述
隐式分配器
应用检测到已分配块不再被程序所使用,就释放这个块。
隐式空闲链表:空闲块通过头部中的大小字段隐含地连接着的。分配器可以通过遍历堆中的所有的块,从而间接地遍历整个空闲块的集合。
在这里插入图片描述

7.10本章小结

介绍了存储器地址空间、段式管理、页式管理,VA到PA的变换、物理内存访问,并且根据本章知识解释第6章的fork,execve实现原理。然后讲解内存分配器的种类及其特点。

第8章 hello的IO管理

8.1 Linux的IO设备管理方法

一个 Linux 文件就是一个 m 字节的序列:B0,B1…Bk… Bm-1。
所有的I/O设备的模型化(包括内核):文件
所有的输入输出:相应文件的读和写执行
设备管理:unix io接口

8.2 简述Unix IO接口及其函数

1.Unix IO接口

1)打开文件
应用程序通过要求内核打开相应的文件,来宣告它想要访问的一个I/O设 备。
2)基本准备
每个进程开始都要打开三个文件:标准输入、标准输出和标准错误。
3)改变当前的文件位置
内核保持文件位置k,初始为0,这个文件位置是从文件开头起始的字 节偏移量。
4)读写文件
一个读操作就是从文件复制n(大于0)个字节到内存,从当前文件位置k开始,然后将k增加到k+n。
5) 关闭文件
当应用完成了对文件的访问之后,就通知内核关闭这个文件。

2.函数

1)int open(char* filename, int flags, mode_t mode)
将filename转换为一个文件描述符,并且返回描述符数字。返回的描述符总是在进程中当前没有打开的最新描述符。flags参数指明了进程访问文件方式,mode参数指定了新文件的访问权限位。
返回:若成功则为新文件描述符,如出错为-1。
2)int close(int fd)
关闭一个已关闭的描述符会出错。
返回:若成功为0,否则为-1。
3)ssize_t read(int fd, void *buf, size_t n)
从描述符为fd的当前文件位置复制到最多n个字节到内存位置buf。
返回:若成功则为读的字节数,若EOF则为0,出错为-1
4) ssize_t write(int fd, const void *buf, size_t n)
从内存位置buf复制至多n个字节到描述符fd的当前文件位置。
返回:若成功则为写的字节数,出错为-1。

8.3 printf的实现分析

https://www.cnblogs.com/pianist/p/3315801.html

int printf(const char *fmt, ...) 
{ 
int i; 
char buf[256]; 
    
     va_list arg = (va_list)((char*)(&fmt) + 4); 
     i = vsprintf(buf, fmt, arg); 
     write(buf, i);

     return i; 
 }

首先va_list为char*,所以arg数据类型为char 。而(char)(&fmt) + 4) 表示的是…中的第一个参数。这样就可以利用arg来表示后面的参数

vsprintf(char *buf, const char *fmt, va_list args) 
{ 
    char* p; 
    char tmp[256]; 
    va_list p_next_arg = args; 
   
    for (p=buf;*fmt;fmt++) { 
    if (*fmt != '%') { 
    *p++ = *fmt; 
    continue; 
    } 
   
    fmt++; 
   
    switch (*fmt) { 
    case 'x': 
    itoa(tmp, *((int*)p_next_arg)); 
    strcpy(p, tmp); 
    p_next_arg += 4; 
    p += strlen(tmp); 
    break; 
    case 's': 
    break; 
    default: 
    break; 
    } 
    } 
   
    return (p - buf); 
} 

然后调用vsprintf函数,接受确定输出格式的格式字符串fmt。用格式字符串对个数变化的参数进行格式化,产生格式化输出,返回格式化数组(最终输出)的长度。
调用write函数,根据printf函数作用,write函数是完成输出,将buf中的i个元素写到终端。
字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。

8.4 getchar的实现分析

int getchar(void)
{
    static char buf[BUFSIZ];
    static char* bb=buf;
    static int n=0;
    if(n==0)
    {
        n=read(0,buf,BUFSIZ);
        bb=buf;
    }
    return(--n>=0)?(unsigned char)*bb++:EOF;
}

用户(摁下键盘)输入一个字符后,I/O设备收到按键扫描码,并发送键盘中断命令,内核采取中断,然后将按键扫描码转成ascii码,存放在系统键盘缓冲区中。
之后getchar调用read函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。如果用户在按回车之前输入了不止一个字符,其他字符会保留在键盘缓存区中,等待后续getchar调用读取。

8.5本章小结

说明了I/O管理中Unix接口和基本函数,之后分析printf(依赖write函数)、getchar(依赖read函数)函数的实现步骤。

结论

人类编写程序

首先在一个文本中敲写完成程序(program)的编写。

程序适应机器

P2P
  1. 预处理完成对文件进行的初步处理
  2. 编译把代码翻译成汇编语言
  3. 汇编将汇编语言翻译成机器语言指令
  4. 链接将可重定位目标程序链接为可执行目标程序。
020

shell为它fork进程,execve程序,mmap为其分配独有的虚拟内存,CPU分配工作时间,让它利用所有的资源完成任务,在面对异常时有对应“人员”(异常指令)处理。

机器回应人类

利用I\O设备根据用户输入完成程序运行,并输出最终结果。

附件

文件名文件作用
hello.ihello.c预处理后保存的文件
hello.s将hello.i翻译成汇编语言保存文件
hello.o将hello.s中汇编翻译成机器语言指令的保存文件
hello链接成功的结果hello
data1保存objdump –d –r hello的文件
data2保存objdump –d 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.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CSDN IT狂飙上传的代码均可运行,功能ok的情况下才上传的,直接替换数据即可使用,小白也能轻松上手 【资源说明】 基于MATLAB实现的有限差分法实验报告用MATLAB中的有限差分法计算槽内电位;对比解析法和数值法的异同点;选取一点,绘制收敛曲线;总的三维电位图+使用说明文档 1、代码压缩包内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2020b;若运行有误,根据提示GPT修改;若不会,私信博主(问题描述要详细); 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可后台私信博主; 4.1 期刊或参考文献复现 4.2 Matlab程序定制 4.3 科研合作 功率谱估计: 故障诊断分析: 雷达通信:雷达LFM、MIMO、成像、定位、干扰、检测、信号分析、脉冲压缩 滤波估计:SOC估计 目标定位:WSN定位、滤波跟踪、目标定位 生物电信号:肌电信号EMG、脑电信号EEG、心电信号ECG 通信系统:DOA估计、编码译码、变分模态分解、管道泄漏、滤波器、数字信号处理+传输+分析+去噪、数字信号调制、误码率、信号估计、DTMF、信号检测识别融合、LEACH协议、信号检测、水声通信 5、欢迎下载,沟通交流,互相学习,共同进步!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值