当前位置:文档之家› 深入理解计算机系统答案

深入理解计算机系统答案

深入理解计算机系统答案

【篇一:深入理解计算机系统笔记】

(1) 对于一个无符号数字x,截断它到k位的结果就相当于计算x mod 2^k.

(2) 在大多数的机器上,整数乘法指令相当地慢,需要12或者更多的始终周期,然而其他整数运算-例如加法、减法、位移运算和移位-只

需要1个时钟周期.因此,编译器使用的一项重要的优化就是试着使用

移位和加法运算的组合来代替乘以常数因子的乘法.

(3) 在大多数的机器上,整数除法要比整数乘法更慢-需要30或者更

多的始终周期.除以2的幂也可以用移位运算来实现,只不过我们用的

是右移,而不是左移.对于无符号和二进制补码数,分别使用逻辑移位和算术移位来达到目的.

1.注意系统的分类:主流的ia32(也就是x86),以及x86-64(也就是

x64),还有种intel的与原32位系统不兼容的ia64。

2.编译系统由预处理器,编译器,汇编器和链接器组成。

3.单指令多数据并行称为simd并行,其扩展为sse指令集。

4.x64上long为8字节,指针也为8字节。

5.无符号数右移必须采用逻辑右移,而有符号数一般采用算术右移。

6.有符号数遇见无符号数会默认强转为无符号数。

7.short转为unsigned时,是先扩展大小再符号转换。

8.补码非的计算:从左到右将第一个为1的位前的所有位取反。

9.负数的补码移位向下舍入。

10.正浮点数能使用整数排序函数来进行排序。

11.浮点加法和乘法不具备结合性,浮点乘法在加法上不具备分配性。

12.预处理器扩展源代码,然后编译器生成源代码的文本汇编代码,

汇编器转成二进制汇编码,链接器生成exe或dll或lib。

13.寄存器可以保存地址也可以保存值。注意汇编中的加括号表示为

取该地址指向的值,如(%eax)指%eax中保存的地址指向的值。

14.传送指令的两个操作符不能都指向存储器。

15.栈指针%esp保存着栈顶元素的值,%eax保存函数返回值。

16.栈从高地址往低地址分配,堆从低地址往高地址分配。

17.注意:lea,假设为leal 7(%edx, %eax, 4),则当%edx中保存

的是地址时,lea为取有效地址,而当%edx中保存的是值时,lea

为算术运算,即7 + %edx + %eax * 4。这儿的%eax总保存值。说

白了,其实lea一直是在做计算,只是%edx影响了直观表达而已。

18.注意:处理有无符号值的操作是通过不同的汇编指令来区分的。

19.大多数汇编器根据一个循环的do-while形式来产生循环代码,

逆向工程会用到。

20.指令无视操作数的长度。

21.因为有个条件传送的优化策略,所以(xp ? *xp : 0)这条语句其实

两个选择分支都会执行。

22.32位系统中,大多数栈中信息的访问其位置都是基于帧指针的。而64位系统中,栈的存储信息数已被弱化,所以无帧指针了。

23.访问某个局部变量的前提是该局部变量至少有个可引用的地址,

所以局部变量被保存在了栈中。

24.为了防止从效率低的存储器读写值时,可能因数据未对齐而造成

多次读写从而导致低性能,ia32要求数据一定要对齐。编译器在编

译时会强制对齐。

25.汇编指令leave等于俩pop,效果一样,选择随意。pop和

push在栈上分配空间的方式是直接栈指针减去或加上偏移量。

26.指针之差等于相差字节数 / 所指类型大小字节数。

27.寄存器不够用时会出现寄存器溢出,这时就必须有值被保存在栈

上了,一般是将只读变量放入栈。

28.gcc会对局部char类型的缓冲区插入金丝雀保护代码。

29.在c中

内联汇编代码只能针对某一类机器。

30.sse2引入浮点数面向寄存器的指令集,而不用基于栈的方法。

31.x64能让汇编代码比x32少很多,但是实际性能提升不会很大。

但是从改进上来说性能应该提升很大很大啊,为什么。。。难道是

x32已经被优化的变态了???

32.注意rep有时当空操作使。

33.x64中,栈空间向下128字节以内的区域仍可以被函数访问,该

区域被abi称为红色地带。

34.浮点相关:把存储模型,指令和传递规则组合称为浮点体系结构。

35.逻辑门只是简单的响应输入的变化而已。

36.hcl中,=只是表示用一个名字来称谓一个表达式。其类switch

的表达中的”1:“等同于switch中的default case。

37.寄存器文件上的读或写端口都分别成对,一个传id,一个传内容。

38.访存阶段读写存储器,写回阶段将结果写到寄存器文件。

39.寄存器文件和数据存储器等都是当前时钟随意读,下一时钟统一

写入更新。即时钟控制状态元素的更新。

40.流水线即保持各单元在时钟周期内忙碌不已,一套流水线硬件供

多个流水线使用。

41.加载互锁和数据转发技术结合起来足以处理可能类型的数据冒险。

42.当流水线化的系统中出现多条指令引起的异常时,最深的指令被

处理的优先级最高。

43.每个时钟周期执行多个操作称为超标量,而超线程是指一个核同

时运行俩线程。

44.处理器功能单元的性能表示中,延迟指按照严格顺序执行完成合

并运算所需要的最小周期数,而吞吐量指理论上最快完成一个操作

所需周期数。

45.使用sse可以降低吞吐量界限。

46.书写适合条件传送实现的”功能式“代码。

47.每个加载/存储单元每个时钟周期只能启动一条加载/存储操作。

48.性能提高技术:①.采用合适的算法和数据结构。②.消除连续的

函数循环调用,在可能时尽量将计算移到循环外;消除不必要的存

储器引用,引入临时变量来保存中间结果;保持内层循环在存储器

层面的局部性。③展开循环;通过多个累计变量和重新结合等技术,提高指令级并行;用功能的风格重写条件操作,使得编译采用条件

数据传送。

49.内存是硬盘的缓存。

50.core i7上所有的sram高速缓存存储器都在cpu芯片上。

51.对于性能来说,存储器访问总数和不命中率相比,不命中率影响

要更大。估计是因为存储器的写回缓存机制。

52.存储器性能注意:将注意力集中在内循环上,大部分计算和存储

器访问都发生在这里;通过按照数据对象存储在存储器中的顺序,

以步长为1来读数据,从而使得空间局部性最大;一旦从存储器中

读入了一个数据对象,就尽可能多的使用它,从而使得时间局部性

最大。

53.对于静态库的链接,只会链接程序中用到的该库(.lib)中的模块(.obj)。这其实也解释为什么分别链接静态库版本和动态库版本的两

程序大小相差不是那么悬殊。

54.当前指令处理完后,处理器才能去发现中断是否发生。

55.linux系统调用的参数都是通过通用寄存器而不是栈传递的。

56.c++的try-catch是c种setjmp和longjmp的更加结构化的版本。

57.dram作为磁盘的缓存,不命中开销巨大。

58.磁盘上的交换文件同时又作为dram保存数据的缓存。

59.延迟私有对象中的拷贝最充分的利用了稀有的物理存储器,这是通过写时拷贝实现的。

60.一个系统中被所有进程分配的虚拟存储器的全部数量是受磁盘上交换空间的数量限制的。

61.造成堆利用率很低的主要原因是内存碎片的存在。

62.有时为了极个别的几个特殊情况而要去每次调用时都检查,还不如通过某些方式直接把特殊情况一般化,能用通用的方式去处理。

63.内存引用导致的崩溃要注意:引用坏指针/野指针,以及读未初始化的存储器。

64.unix信号是不排队的,若为考虑处理,则会直接丢弃。

65.函数内部的static变量也是线程间共享的。

66.注意并行和并发的区别,并行程序是一个运行在多个处理器上的并发程序。

67.线程数多过核数对效率反而会有影响,但影响不大。

68.注意:rand和ctime,localtime等函数时线程不安全的,慎用啊慎用!可用其可重入版本。

69.互斥锁记得相同顺序加锁解锁。

70.包装错误处理函数,是一个非常不错的做法。

//============================================

2010.07.08

深入理解计算机系统

(1) 反汇编器一些特性说明:

1) ia32指令长度从1~15个字节不等.指令编码被设计成使常用的指令以及操作较少的指令所需的字节数少,二那些不太常用或操作数较多的指令所需字节数较多.

2) 指令格式是按照这样一种方式设计的,从某个给定位置开始,可以将字节唯一地解码成机器指令.例如,只有指令pushl %ebp是以字节值55开头的.

3) 反汇编器只是根据目标文件中的字节序列来确定汇编代码的.它不需要访问程序的源代码或汇编代码.

4) 反汇编器使用的指令命名规则与gas(gnu asembler)使用的有些细微的差别.

5) 与code.s中的汇编代码相比,我们发现结尾多了一条nop指令.这条指令根本不会被执行(它在过程返回指令之后),即使执行了也不会有任何影响(所以称之为nop,是no operation的简写,同城读作no op).编译器插入这样的指令是为了填充存储该过程的空间.

(2) ia32加了一条限制,传送指令的两个操作数不能都指向存储器位置.将一个值从一个存储器位置拷到另一个存储器位置需要两条指令-第一条指令将源值加载到寄存器值写入目的位置.

(4) 根据惯例,所有返回真书或指针值的函数都是通过将结果放在寄

存器%eax中来达到目的的.

(5) 加载有效地址(load effective address)指令leal实际上是movl 指令的变形.它的指令形式是从存储器读取数据到寄存器,但实际上它根本就没有引用存储器.它的第一个操作数看上去是一个存储器引用,但该指令并不是从指定的位置读入数据,而是将有效地址写入到目的操作数(如寄存器).

(6) 一元操作,只有一个操作数,既作源,也作目的.这个操作数可以是一个寄存器,也可以是一个存储器位置.比如说incl(%esp)会是栈顶元素加1.这种语法让人想起c中的加1运算符(++)和减1(--).

(7) 二元操作,第二个操作数既是源又是目的.这种语法让人想起c中向+=这样的赋值运算符.不过要注意,源操作数是第一个,目的操作数

是第二个,这是不可交换操作特有的.例如,指令subl %eax, %edx使寄存器%edx的值减去%eax中的值.第一个操作数可以是立即数、寄存器或存储器位置.第二个操作数可以是寄存器或是存储器位置.不过同 movl指令一样,两个操作数不能同时都是存储器位置.

(8) divi指令执行无符号除法,通常会事先将寄存器%edx设置为0.

//============================================

2010.07.09

深入理解计算机系统

(1) 汇编语言中,直接跳转时给出一个标号作为跳转目标地;间接跳转的写法是*后面跟一个操作数指示符.如

jmp *%eax 表示用寄存器%eax中的值作为跳转目标;

jmp *(%eax) 表示已%eax中的值作为读地址,从存储器中读出跳转目标;

(2) call指令有一个目标,指明被调用过程起始的指令地址. 同跳转一样,调用可以是直接的,也可以是间接的.在汇编代码中,直接调用的目

标是一个标号,而间接调用的目标是*后面跟一

【篇二:《深入理解计算机系统》-读后感】

ass=txt>本书的最大优点是为程序员描述计算机系统的实现细节,

帮助其在大脑中构造一个层次型的计算机系统,从最底层的数据在

内存中的表示到流水线指令的构成,到虚拟存储器,到编译系统,

到动态加载库,到最后的用户态应用。通过掌握程序是如何映射到

系统上,以及程序是如何执行的,读者能够更好地理解程序的行为

为什么是这样的,以及效率低下是如何造成的。

写下之下的这些文字是为了帮助自己更好的复习全书的内容,尤其

是自己以前掌握不深刻的部分

书的第一部分是全书的精华,主要讲程序与硬件,第四章除外,我

没有看

第二章,重点是数的表示方法

移位运算算术右移和逻辑右移的区别

字节顺序大端和小端

数的格式转换先改变大小,再改变有无符号,无符号有符号隐式转换带来的灾难整数的运算主要是各种溢出问题

浮点数乘法不具备可结合性,转换为整数时可溢出

第三章,重点是汇编程序,个人认为收获最大的一章

各种指令,mov,leal,移位,运算,控制,条件传送指令*,

各种逆向工程,结合习题很有意思

函数调用时帧栈结构

联合、结构数据分布和对齐的问题

内存越界和缓冲区溢出

64位(没有太仔细看,寄存器多了大了,函数调用有很多不同,很

多函数不需要栈帧,参数通过寄存器传送)

第五章,程序优化,全章由一个例子贯穿始末,量化了不同方法带

来的性能改进

编译器优化的局限性,限制这种能力的原因有:存储器别名的情况,函数调用(静态变量,可重入)

循环优化,不变的变量只算一次

减少函数调用(性能和可读性的折衷)

不必要的内存引用(尽量用临时变量在寄存器中,避免不必要的内存读写)

从处理器的角度考虑(流水、预测分支、关键路径),循环展开,考虑流水(充分利用处理器

的多个加法器等,超标量)

程序剖析的工具 gprof

第六章,存储器层次结构

各种缓存,高速缓存l1l2是内存的缓存,内存是硬盘的缓存,各种缓存的管理机制(这里只讲了高速缓存的,后面会将内存管理)

程序的局部性,时间和空间的

第二部分,主要将程序在系统的中的运行,这一部分和前一部分差距较大,原因是这一部分我比较熟?

第七章,链接

可以参见《程序员的自我修养》这本书,主要是目标文件格式阿,符号解析阿,重定位阿的,内容比较简略

静态库的链接顺序,经常会出错的一个问题

一些工具的使用,readelf,objdump,ldd

感觉从这一章开始,翻译就很不给力了

第八章,名字很奇特,叫异常控制流,讲了各个层面的异常,其实我觉得这一章还不如叫进程

四类异常:中断(io设备),陷阱(trap,咋这么翻译呢,系统陷入多好听,主要是系统调用),故障(缺页),终止

信号,读后感《《深入理解计算机系统》-读后感》。signal

非本地跳转,软异常?setjmp,longjmp,据说是try\catch实现的基础

一些工具(pmap,strace,ps,top)

第九章,虚拟存储器,重点应该是内存管理,地址翻译的机制,我讨厌有些地方该叫内存却叫做存储器

内存管理,主要做了两件事,从虚拟地址到物理地址的翻译,提供了内存读写的保护(只读的内存不能写,只读写的不能运行)

动态内存的分配,给出了几种分配器的数据结构,这一部分没有仔细看

垃圾回收

各种内存的错误,总结的很好,基本我都犯过

回头再看第一章,人家总结的真好,整个一个计算机系统就是一个

大抽象,把各种硬件系统抽象为一些简单的概念,这些概念让我们

这些程序员能够轻松的处理程序而不用再管硬件了,

伟大啊

三个基本抽象:

文件--负责抽象io设备

虚拟存储器--负责抽象io设备、内存进程--负责抽象io设备、内存、处理器

整本书就是负责介绍怎么抽象的

【篇三:深入理解计算机系统配套练习卷】

1.1.0 字母a的ascii码为97,那么love中各字母ascii码之和是()

a、99

b、520

c、438

d、360

1.2.0_1 在编译过程中,hell.c经过汇编阶段后生成文件为()

a、hell.i

b、hell.s

c、hell.o

d、hell.exe

1.2.0_2 在编译过程中,hell.c经过()阶段生成hell.s。

a、预处理

b、编译

c、汇编

d、链接

1.4.1 下面哪一项不是i/o设备

a、鼠标

b、显示器

c、键盘

d、《深入理解计算机系统》

1.4.2 数据可以不通过处理器直接从磁盘到达主存吗?dma又是什么?

a、可以;直接存储器存取

b、可以;动态存储器存取

c、不可以;直接存储器存取

d、不可以;动态存储器存取

chapter 2

2.1.1_1 二进制串11010110对应的十六进制数是()

a、0xx0

b、0xd6

c、0xc6

d、0xd5

2.1.1_2 十六进制数0x77对应的十进制数为()

a、77

b、117

c、109

d、119

2.1.3 对于32位机器,char * 的字节数为()

a、1

b、2

c、4

d、8

2.1.4_1 使用小端法的机器,数字0x123678的高位字节是()

a、0x12

b、0x21

c、0x78

d、0x87

2.1.4_2 从使用小端法的机器读入数字0x1234,存入使用大端法的机器,这时高位字节是()

a、0x12

b、0x21

c、0x34

d、0x43

2.1.8 char a=0xdb, 则 ~a 的值为()

a、0xdb

b、0xbd

c、0x24

d、0x42

2.1.8 int a=1, b=2, 经运算 a^=b^=a^=b 后结果为()

a、a=3, b=2

b、a=1, b=2

c、a=2, b=1

d、不知道

2.1.10 int a = 3, 则 a3 的结果为()

a、3

b、24

c、12

d、48

2.2.1 unsigned char 的最小值为()

a、128

b、255

c、-127

d、0

2.2.3 对长度为4位的整数数据,-5对应的补码编码为()

a、1011

b、1101

c、0101

d、1010

2.3.2 对长度为4的整数数据,x=[1010], y=[1100],x+y补码加法的结果为()

a、1010

b、0110

c、1100

d、10110

chapter 3

3.2.2 命令 unix gcc -o1 -c code.c 所生成文件相当于经编译过程中()阶段后的结果。

a、预处理

b、编译

c、汇编

d、链接

3.3 movl传送的是()字节整数。

a、8

b、4

c、2

d、1

3.4 最初的8086中,寄存器的特殊用途可从名字反映出来。累加器应为()

a、%ax

b、%cx

c、%dx

d、%bx

3.4.1 比例变址寻址 0x12(%edx, %edx, 4) 表示的操作数值为()

a、r[ %edx ]

b、m[ 0x12 + r[ %eax ] * 5 ]

c、r[ 0x12 + m[ %edx ] * 5 ]

d、m[ 0x12 + r[ %edx ] * 5 ]

3.4.2 %eax存的值为0x123, %esp存的值为0x108, pushl %eax 指令后%esp的值为()

a、0x123

b、0x108

c、0x104

d、0x112

相关主题
文本预览
相关文档 最新文档