计算机系统期末复习

计算机系统期末复习

浮点数部分

查看笔记,其中重点是①浮点数值的分类(规格化…)②如何从小数转换成浮点数 ③最小不能精确表示的整数

硬布线实现VSCPU(非常简单CPU)

CPU设计规范

设计CPU首先要确定CPU的用途,确定它要执行的任务之后,我们就要设计一个能处理这些任务的指令集结构,并画出其CPU设计状态图。总的来说,CPU执行如下操作序列:
取指令周期:从存储器取出一个指令,然后转到译码周期。
译码周期:对指令进行译码,即确定取到的是哪一种指令,然后转移到这种指令对应的执行周期。
执行周期:执行该指令,然后转移到取值周期去取下一条指令。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JmIa179F-1679661941406)(https://tva3.sinaimg.cn/large/a081fc05gy1h37yveys9vj20id0ga74w.jpg)]

设计指令集

设计的指令集如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ohrWwASc-1679661941407)(https://tva3.sinaimg.cn/large/a081fc05gy1h37ywciybej20ne05laap.jpg)]
需要的寄存器如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d9mFREEf-1679661941407)(https://tvax2.sinaimg.cn/large/a081fc05gy1h37yx3xonyj20lb049js8.jpg)]

取值,译码,执行

取指周期
状态1:把当前要执行的指令的地址PC放到地址寄存器AR中。
状态2:从存储器M中读取指令地址中的值到数据寄存器DR中,同时PC+1,此时PC中是下一条指令的地址(在取值周期PC+1更好实现)。
状态3:将数据寄存器高两位传送到指令寄存器中,同时将数据寄存器低六位拷贝到地址寄存器中,减少这些指令在执行周期的状态。
FETCH1:AR <- PC
FETCH2:DR <- M, PC <- PC+1
FETCH3:IR <- DR[7…6], AR <- DR[5…0]

译码周期:略

执行周期:
设计出每个执行周期的状态图(即每个执行的指令可以拆分成什么步骤来完成),然后再设计整个CPU的状态图。
ADD指令: ADD1:DR<-M; ADD2:AC<-AC+DR.
AND指令:AND1:DR<-M; AND2:AC<-AC∩DR.
JMP指令:PC<-DR[5…0]
INC指令:AC<-AC+1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ILxDNNug-1679661941407)(https://tvax4.sinaimg.cn/large/a081fc05gy1h37z5eczjcj20he0cvq3k.jpg)]

创建数据通路(RTL语言描述)

不同的指令会产生不同的控制信号,比如取值周期:
状态1:PCBUS=1,ARLOAD=1
状态2:READ=1,MEMBUS=1,DRLOAD=1,PCINC=1
状态3:DRBUS=1,IRLOAD=1,ARLOAD=1

最后总的RTL视图如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KQf2Z751-1679661941408)(https://tvax4.sinaimg.cn/large/a081fc05gy1h37z6mdggoj20hg0jmgmv.jpg)]

设计ALU

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dLYXCamA-1679661941408)(https://tvax1.sinaimg.cn/large/a081fc05gy1h37za9aj0oj20b509nq37.jpg)]

硬连线控制设计控制单元

虽然我们只有4个指令,但是有些指令不是只有一个状态,因此我们翻译一个指令,其实输出的不只一个操作。对于VSCPU,总共有9个状态,需要一个4位计数器和一个4-16位的译码器,译码器的输出位有7个用不到。

首先,假使我们用最原始的映射,即10IR[1…0],则得到如图所示的映射图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qnKUkPPJ-1679661941409)(https://tvax1.sinaimg.cn/large/a081fc05gy1h37zj27806j20su06w3z7.jpg)]
不难发现这种映射方法存在一个问题,ADD1后面跟着的不是ADD2了,而是AND1。ADD2的指派计数值就不确定了,并且我们ADD1后面就要执行ADD2了,如何从ADD1去访问ADD2呢?因此这种映射存在缺陷,我们需要改进。

我们可以观察到VSCPU中没有一个指令拥有两个状态以上,那么我们可以映射成1IR[1…0]0。这样我们可以指派ADD1为8(1000),则ADD2为9(1001),ADD1后面跟着就是ADD2,在内存中是连续储存,直接PC+1读取就行,这样指令执行起来就连贯了。

当我们完成译码器输出到每个状态之间的指派关系,我们就能使用这些信号来为计数器的控制单元以及CPU的其他部分产生控制信号。对于计数器,我们必须产生INC,CLR,LD信号。当控制单元遍历顺序状态,从FETCH1,FETCH2,ADD1到AND1时,INC信号有效。CLR 则用来从每一个执行周期的末尾返回到取指周期,这可能发生在ADD2,AND2,JMP1和INC1状态。最后,如上所述,LD信号在每个取指令周期的末尾FETCH3状态中发出。注意CPU状态图中的每一个状态只会产生这三种信号中的一种。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OVXf442d-1679661941409)(https://tva3.sinaimg.cn/large/a081fc05gy1h37zqu97igj20fc0dsjrw.jpg)]

根据之前设计CPU的经验,什么状态会对控制信号产生影响的,用或门或起来就行。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I1kUW5dZ-1679661941409)(https://tva4.sinaimg.cn/large/a081fc05gy1h37zyudqebj20i50bvwf6.jpg)]

链接

链接 (linking) 是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(或被拷贝)到存储器并执行。在现代系统中,链接是由叫做链接器 (linker) 的程序自动执行的。

静态链接和动态链接

链接被分为静态和动态,静态链接和动态链接两者最大的区别就在于链接的时机不一样,静态链接是在形成可执行程序前,而动态链接的进行则是在程序执行时。

之所以会产生动态链接,是因为静态链接存在两大缺点:
①浪费空间。举个例子,比如每个C程序几乎都会使用标准IO函数,像printf和scanf。在运行时,这些函数的代码会被复制到每个运行进程的文本段中,但这些函数其实都是重复的,不需要全部进程都复制一次。当有上百成千个进程运行时,这会造成极大的内存空间浪费。
②更新困难。静态库需要定期维护更新,每当静态库的代码产生了修改,那么运行程序时需要重新编译链接生成可执行文件,这是一个相当烦人的过程。

因此动态链接和共享库应运而生。共享库是一个目标模块,在运行时,可以加载到任意的存储器地址,并和一个在存储器中的程序链接起来。这个过程称为动态链接 (dynamic linking), 是由一个叫做动态链接器 (dynamic linker) 的程序来执行的。但动态链接也不是没有缺点,由于把链接推迟到了程序运行时,所以每次执行程序都需要进行链接,相较于静态链接生成的程序,其执行速度会慢一些。

目标文件

我们回到静态链接,通过其链接过程来讲述一系列概念。静态链接器以一组可重定位目标文件和命令行参数作为输入,生成一个完全链接的可以加载和运行的可执行目标文件作为输出。
为了构造可执行文件,链接器必须完成两个主要任务:
符号解析 (symbol resolution) 。目标文件定义和引用符号。符号解析的目的是将每个符号引用刚好和一个符号定义联系起来。
重定位 (relocation) 。编译器和汇编器生成从地址开始的代码和数据节。链接器通过把每个符号定义与一个存储器位置联系起来,然后修改所有对这些符号的引用,使得它们指向这个存储器位置,从而重定位这些节。

首先来看目标文件是什么,目标文件一般分三种:
可重定位目标文件。包含二进制代码和数据,其形式可以在编译时与其他可重定位目标文件合并起来,创建一个可执行目标文件。
可执行目标文件。包含二进制代码和数据,其形式可以被直接拷贝到存储器并执行。
共享目标文件。一种特殊类型的可重定位目标文件,可以在加载或者运行时被动态地加载到存储器并链接。

其中ELF可重定位目标文件的格式如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-syKQs3io-1679661941410)(https://tvax2.sinaimg.cn/large/a081fc05gy1h381r2df7gj209w0bqgm4.jpg)]
ELF头:ELF头(ELF header)以一个16字节的序列开始,这个序列描述了生成该文件的系统的字的大小和字节顺序。ELF头剩下的部分包含帮助链接器语法分析和解释目标文件的信息。
节头部表:不同节的位置和大小是由节头部表描述的,其中目标文件中每个节都有一个固定大小的条目(entry)。
夹在ELF头和节头部表之间的都是节,其中重点关注text节,data节,bss节即可。
.text: 已编译程序的机器代码。
.rodata: 只读数据,比如 printf 语句中的格式串
和开关语句的跳转表(参见练习题7.14)
.data: 已初始化的全局变量。局部变量在运行时保存在栈中,既不出现在.data节中,也不出现在.bss节中。
.bss: 未初始化的全局变量。在目标文件中这个节不占据实际的空间,它仅仅是一个占位符。目标文件格式区分初始化和未初始化变量是为了空间效率:在目标文件中,未初始化变量不需要占据任何实际的磁盘空间。
.symtab: 一个符号表,它存放在程序中定义和引用的函数和全局变量的信息。一些程序员错误地认为必须通-g 选项来编译程序才能得到符号表信息。实际上,每个可重定位目标文件在 symtab 中都有一张符号表。然而,和编译器中的符号表不同, .symtab 符号表不包含局部变量的条目。
.rel.text: 一个.text 节中位置的列表,当链接器把这个目标文件和其他文件结合时,需要修改这些位置。一般而言,任何调用外部函数或者引用全局变量的指令都需要修改。另一方面,调用本地函数的指令则不需要修改。注意,可执行目标文件中并不需要重定位信息。因此通常省略,除非用户显式地指示链接器包含这些信息。
.rel.data: 被模块引用或定义的任何全局变量的重定位信息。一般而言,任何已初始化的全局变量,如果它的初始值是一个全局变量地址或者外部定义函数的地址,都需要被修改。
.debug: 一个调试符号表,其条目是程序中定义的局部变量和类型定义,程序中定义和引用的全局变量,以及原始的 源文件。只有以 选项调用编译驱动程序时才会得到这张表。
.line: 原始C源程序中的行号和 .text 节中机器指令之间的映射。只有以 -g 选项调用编译驱动程序时才会得到这张表。
.strtab: 一个字符串表,其内容包括 .symtab .debug 节中的符号表,以及节头部中的节名字。字符串表就是以 null 结尾的字符串序列。

符号

符号有三种:
全局符号:由模块m定义并且能被其他模块引用的符号(非静态全局变量和非静态C函数)。
外部符号:有其他模块定义并能被模块m引用的全局符号。
本地符号:由模块m定义和引用的本地符号(带静态属性的C函数和变量)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UPYKI9Aa-1679661941410)(https://tvax3.sinaimg.cn/large/a081fc05gy1h382088fojj20w80fiabk.jpg)]

如何判断符号所在节,可以根据其性质决定,列举如下情况:
①全局符号并且是函数,会被分配到.text节。
②全局符号并且是变量,如果初始化了的,会被分配.data节;如果未初始化的,会被分配到.bss节。
③外部符号并且是函数,在符号表中Ndx处显示为UNDEF,代表未定义的符号,也就是在本目标模块中引用,但是却在其他地方定义的符号。如果深究最后分配到哪个节,个人认为是.text节。
④外部符号并且是变量,同样是UNDEF,最后应该在.data节。
⑤对于本地符号,在Ndx一律显示COMMON,表示还未被分配位置的未初始化的数据目标,大概率是.bss节。

不同模块但有重名的符号,合并时链接器必须进行处理,所以诞生了强弱符号的概念并有一下规则:
强符号——函数和已初始化的全局变量;弱符号——未初始化的全局变量。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pcuDcuMb-1679661941410)(https://tva2.sinaimg.cn/large/a081fc05gy1h382ems1czj20yy0cy0ui.jpg)]

注意这么一个问题:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zkflCpE9-1679661941411)(https://tva4.sinaimg.cn/large/a081fc05gy1h382p47yqzj211s0idjtu.jpg)]
产生这个问题的原因在于两边模块都有重名的符号d,由于int d是强符号,起初d为100。当调用p1后,d=1.0将用1.0的双精度浮点表示覆盖存储器中d和x的位置。而1.0用浮点数表示为:0 01111111111 0…0=0x3ff0 0000 0000 0000
又由于linux中采用小端法存储,因此d=0,x=3ff0 0000=1072693248。

重定位

重定位由两步组成:
重定位节和符号定义。在这一步中,链接器将所有相同类型的节合并为同一类型的新的聚合节,然后链接器将运行时存储器地址赋给新的聚合节,赋给输入模块定义的每个节,以及赋给输入模块定义的每个符号。
重定位节中的符号引用。在这一步中,链接器修改代码节和数据节中对每个符号的引用,使得它们指向正确的运行时地址。

最基本的两种重定位类型为:
R_386_PC32:重定位一个使用32位PC相对地址的引用。即有效地址 = PC + 重定位值,PC的内容是下条指令的指令地址。一般来说,被调用的函数都是相对引用。
R_386_32:重定位一个使用32位绝对地址的引用。即有效地址 = 重定位值。一般来说,除了被调用的函数外其余的都是绝对引用。

重定位PC相对引用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EJ4GUGKb-1679661941411)(https://tvax4.sinaimg.cn/large/a081fc05gy1h38347zaq1j20hl01mweg.jpg)]
从这个列表中,我们看到 call 指令开始于节偏移 0x6 处,由1个字节的操作码 0xe8 和随后的 32 位引用 0xfffffffc (十进制 -4) 组成,它是以小端法字节顺序存储的。
由此可知,重定位条目r由三个字段组成:
r.offset = 0x7 (算上一个字节的操作码e8后的偏移量)
r.symbol = swap
r.type = R_386_PC32

链接器已经为每个节(用 ADDR (s) 表示)和每个符号都选择了运行时地址(用 ADDR(r.symbol) 表示),这些字段告诉链接器修改开始于偏移量 0x7 处的32位PC相对引用,使得在运行时它指向swap程序。现在,假设链接器已经确定:
ADDR(s)= ADDR (.text) = 0x80483b4
ADDR(r.symbol)= ADDR(swap) = 0x80483c8 (重定位后)

链接器首先计算出refaddr(引用的运行时地址)
refaddr = ADDR(s) + r. offset = 0x80483b4 + 0x7 = 0x80483bb

然后,它将引用从当前值 (-4) 修改为 0x9, 使得它在运行时指向 swap 程序
*refptr = (unsigned) (ADDR(r.symbol) + *refptr - refaddr) = (unsigned) (0x80483c8 + (-4) - 0x80483bb) = (unsigned) (0x9)

修改完后,在得到的可执行目标文件中, call 指令有如下的重定位的形式:
80483ba: e8 09 00 00 00 call 80483c8 swap();

在运行时,call指令将存放在地址0x80483ba处。当CPU执行call指令时,PC的值为0x80483bf, 即紧随在call指令之后的指令的地址。为了执行这条指令,CPU执行以下的步骤:
push PC onto stack
PC<- PC+ 0x9 = 0x80483bf + 0x9 = 0x80483c8
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zZZYQDgC-1679661941411)(https://tvax1.sinaimg.cn/large/a081fc05gy1h38q2zuka6j20l90hadi3.jpg)]

重定位绝对引用
因为 bufp0 是一个已初始化的数据目标,那么它将被存放在可重定位目标模块swap.a的.data节中。因为它被初始化为一个全局数组的地址,所以它需要被重定位。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eO3kpP5N-1679661941412)(https://tva2.sinaimg.cn/large/a081fc05gy1h38q6vy59cj20ij02zweh.jpg)]

我们看到.data节包含一个32位引用,bufp0指针的值为0x0。重定位条目告诉链接器这是一个32位绝对引用,开始于偏移0处,必须重定位使得它指向符号buf。现在,假设链接器已经确定:
ADDR(r.symbol) = ADDR(buf) = 0x8049454

然后修改引用:
*refptr = (unsigned) (ADDR(r.symbol) + *refptr)
= (unsigned) (0x8049454 + 0)
= (unsigned) (0x8049454)

则最后有:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IARAOz0y-1679661941412)(https://tva4.sinaimg.cn/large/a081fc05gy1h38qbzbxymj20n405l3yw.jpg)]

加载可执行目标文件和动态链接

详情见小班讨论课7选题二

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值