2020-11-15

CSAPP: ICS 期中复习

Chapter2

字节:最小的可寻址的内存单位。

char是[signed] char,short<->unsigned short,int <-> unsigned,long<->unsigned long,

int32_t<->uint32_t,int64_t <-> uint64_t(ISO C99)

unsigned long/ unsigned long int/ long unsigned/ long unsigned int 都是一个意思。

大多数Intel兼容机都只用小端模式,IBM和Oracle(收购Sun Microsystems开始)大多数极其按大端模式。

双端法:ARM选定了操作系统,字节顺序固定。(Android、IOS小端)

同一段代码,指令编码在不同机器上是不一样的。不同的机器类型使用不同的且不兼容的指令和编码方式。二进制代码是不兼容的,很少能在不同的机器和操作系统组合之间移植。

移位运算从左至右可以结合。x<<j<<k <==> (x<<j)<<k.

逻辑右移:补零,算术右移:带符号。

移动k位,k大于本身数据的位数,则移动k mod w位。(C语言标准,许多机器上)

移位运算的操作符优先级:比加减法低,于是1<<2+3<<4 <==> 1<<(2+3)<<4

k2的k次幂
664
7128
8256
9512
101024
112048
124096
1532768
1665536
312,147,483,648
324,294,967,295

B2U_w :0~2w-1

B2T_w:-2w-1~2w-1-1

-1和UMax位表示相同。

<limits.h>定义了一组常量INT_MAX/INT_MIN/UINT_MAX

<stdint.h>定义了int32_t/uint32_t,这些数据类型打印需要使用宏,PRIu64/PRIU32,在不同字长的程序里面会展开为d/l/u等等。

反码(Ones’ Complement):B2O——最高有效位的权是-(2-w-1-1)。

原码(Sign-Magnitude):B2S——最高有效位是符号位。

对于反码,-x表示为x的反码取反,也就是说-x = [11111…1]-x,ones有很多1.

对于补码,-x表示为~x+1。也就是取反后+1,x=[1000…0000]-x=2w-x,two’s,只有一个2.

补码转换为无符号数,在负数的部分加上2w。无符号数转化为补码:超过TMax的部分减掉2w

声明常量时,大多数认为是有符号的,要创建无符号常量需要加上后缀uorU。

因式类型转换:

//case1:assignment
int tx,ty;
unsigned ux,uy;
tx = ux; //cast to signed
uy = ty; //cast to unsigned
//attention: cast to the type being assigned

//case2:printf
int x = -1;
unsigned u = 2147483648; /* 2 to the 31st */
printf("x = %u = %d\n",x, x); // x = 4294967295 = -1 (UMax,-1)
printf("u = %u = %d\n",u, u); // u = 2147483648 = -2147483648 (TMax+1,TMin)

//case3:operation (对标准的算术运算没有差别,对>,<有差别,整型升级)
0 == 0u; //cast to unsigned

C语言中TMin的写法:

#define INT_MAX 2147483647
#define INT_MIN (-INT_MAX - 1)

符号扩展:保持原有数值大小不变。

小的有符号数转换为大的无符号数,先改变大小(符号扩展)再从有符号到无符号转换。例如:

short sx = -12345;
unsigned uy = sx; // (unsigned)(int)sx = ff ff cf c7 = 4294954951

截断补码:把位表示超出范围的部分扔掉,再把低位表示转化为低位补码。

检测无符号加法的溢出:溢出等价于x+y<x。

无符号数求反:-x = 2w-x。

补码加法:正溢出、负溢出、正常

TMin的补码非等于自己:-TMin = TMin。

无符号乘法和补码乘法具有位级等价性。

整数除法总是舍入到0。

除以2的幂的补码除法,用移位会向下舍入。

除以2的幂的补码,偏置可以使之向上舍入。

因此计算除以2的幂的表达式:x/2^k = x<0? (x+(1<<k)-1:x)>>k

IEEE标准754——1985年。

小数的二进制表示法只能表示那些能够写成x2y线性组合的数。其他只能近似表示,比如1/5。

精度:小数位数;范围:表示大小

浮点标准:V = (-1)s x M x 2E

范围:尾数(M),二进制小数,范围为1到2-epi或者是0到1-epi(全0表示和全1表示)。

float 1,8,23,double 1,11,52

规格化:exp不全为0且不全为1,E=e-Bias,Bias = 2k-1-1,指数的取值范围为 1-(2k-1-1) = 2-2k-1 到 2k-2-(2k-1-1) = 2k-1-1。单精度为-126到127,双精度是-1022到+1023。

非规格化:exp全0,阶码E=1-Bias,尾数M不包含隐含的1.可以表示+0和-0。还可以表示非常接近0的数(逐渐溢出)。

特殊值:exp全1.M全0为无穷,M不为0为NaN。

注意:如果将位表达式解释为无符号整数,只看正数,最小的非规格化数到最大的非规格化数,到最小的规格化数到最大的规格化数,到无穷大,位表示按照无符号解释是依次递增的。——IEEE设计为了浮点数可以使用整数的排序函数。

整数转浮点数:将二进制小数点左移到最高位后面(创建规格化表示),丢掉最高位的1,在末尾补够0(构造小数字段),再构造阶码字段(指数+bias),再加上符号位。

一个具有n为小数的浮点格式(假设阶码无限大),则不能准确描述的最小正整数=2n+1+1,因为准确表示它需要n+1位小数。

舍入:向偶数舍入——当在两个可能值的正中间时,倾向于使最低有效为为0.

1/-0 = -infty,1/+0 = +infty

浮点数运算:Round(x + y)因此不能结合——3.14+(1e10-1e10)

浮点乘法同样:Round(x*y),(1e20 * 1e20) * 1e-20,没有分配性。

注意NaN的一切逻辑运算都是非,除了NaN != xx(包括NaN)。

单调性:对于a,b,c都不等于NaN,浮点乘法满足单调性。

FromtoOverflowRounding
intfloatnoYes
intdoublenoNo
floatintyesyes(向0舍入)
doubleintyes(整数不确定)Yes(向0舍入)
floatdoublenono
doublefloatyesyes

Chapter 3

hello.c(文本) hello.i(文本) hello.s(文本) hello.o(二进制) hello(二进制) printf.o 预处理器(cpp) 编译器(cc1) 汇编器(as) 链接器(ld) 链接器(ld) hello.c(文本) hello.i(文本) hello.s(文本) hello.o(二进制) hello(二进制) printf.o

用gcc编译.c文件:gcc -Og(优化等级) -o p(最终生成的文件名) p1.c

用gcc生成.s文件:gcc -Og -S mstore.c

用gcc编译并汇编成.o文件:gcc -Og -c mstore.c(二进制字节序列)

反汇编器:OBJDUMP—— objdump -d mstore.o

程序内存包含:程序的可执行机器代码,操作系统需要的一些信息,用来管理过程调用和返回的运行时栈,用户分配的内存块(malloc)。

x86-64的64位虚拟地址的高16位必须设置为0.(地址实际上用的是248或64TB范围内的一个字节)。

计算机系统的两种抽象:1.指令集体系结构ISA;2.虚拟内存地址。

X86-64的指令长度从1到15个字节不等。常用的指令字节数少,不常用的多。

设计指令格式的方式是,从某个给定的位置开始,可以将字节唯一地解码成机器指令。例如只有pushq %rbx是由字节值53开头的。

我们表述的是ATT格式的汇编代码,与Intel格式的汇编代码有一些区别,比如寄存器名称前没有%,push后面没有q等等。

汇编代码使用同样的后缀‘l’来表示double和int,但是不产生歧义是因为浮点数使用一组完全不同的指令和寄存器。

功能四字双字字节
返回值%rax%eax%ax%al
栈指针%rsp%esp%sp%spl
被调用者保存%rbp%ebp%bp%bpl
被调用者保存%rbx%ebx%bx%bl
被调用者保存%r12%r12d%r13w%r12b
被调用者保存%r13%r13d%r13w%r13b
被调用者保存%r14%r14d%r14w%r14b
被调用者保存%r15%r15d%r15w%r15b
参数1%rdi%edi%di%dil
参数2%rsi%esi%si%sil
参数3%rdx%edx%dx%dl
参数4%rcx%ecx%cx%cl
参数5%r8%r8d%r8w%r8b
参数6%r9%r9d%r9w%r9b
调用者保存%r10%r10d%r10w%r10b
调用者保存%r11%r11d%r11w%r11b

指令以寄存器为目标时有两条规则:生成1字节和2字节数字的指令会保持剩下字节不变;生成四字节的数字会把高位4个字节置为0.

movabsq I,R,表示传送绝对的四字(64位立即数)I到寄存器R(只能以寄存器作为目的)。常规的movq指令只能以表示为32位补码数字的立即数作为源操作数。然后把这个值符号扩展得到64位值。

x86-64的限制:传送指令的两个操作数不能都指向内存。

将较小的源值放到较大的目的时使用movz、movs两种指令(3种源,目的只能是R),一个是零扩展,一个是符号扩展。

cltq指令专门用于将%eax符号扩展为%rax。没有操作数。效果与movslq %eax,%rax相同

注意没有指令movzlq。(用movl实现即可)

寻址模式:比例因此必须是1,2,4或者8!(立即数M可以任意没事)

寻址模式:不能使用%eax这些不满64字节的寄存器!因为地址为64位!

pushq:先将栈指针减8,再把数据写入栈指针所在位置。所有数据类型都行。

popq操作数不能是立即数,其他都可以。

INC、DEC、NEG、NOT分别是加1,减1,取负,取补。

INC的操作数可以是内存或者寄存器。

INC和DEC会设置溢出和零标志,但不会改变进位标志!

移位操作的进位标志会设置为最后一个被移出的位,而溢出标志设为0.

LEAQ操作的目的不能是内存,只能是寄存器。

注意:移位操作SAL等等的操作数可以是立即数,也可以放在单字节寄存器%cl中,移位量是由%cl的低m位决定的,高位会被忽略。salb最多会移动7位,salw最多会移动15位,sall最多移动31位,salq最多移动63位。

SAL和SHL的效果是一样的。

intel引入16字节的数称为八字。

指令效果描述
imulq S
mulq S
R[%rdx]: R[%rax]<-S X R[%rax]
R[%rdx]: R[%rax]<-S X R[%rax]
有符号全乘法
无符号全乘法
cltoR[%rdx]: R[%rax]<- 符号扩展(R[%rax])转换为八字
Idivq SR[%rdx]: R[%rdx]<-R[%rax] mod S
R[%rdx]: R[%rax]<-R[%rax] / S
有符号除法
Divq SR[%rdx]<- R[%rdx]: R[%rax] mod S
R[%rdx]<= R[%rdx]: R[%rax] / S
无符号除法

乘法必须把第一个参数放在%rax中,乘积高64位存放在%rdx,低64位存放在%rax。

Divq前需要cqto。

算术操作:leaq、inc、dec、neg、not、add、sub、imul、xor、or、and、sal、shl、sar、shr。其中只有leaq不设置条件码。

除了算术操作设置条件码,CMP和TEST也会设置条件码。

条件码通常不会被直接读取,但是可以有三种方法间接获取:(1)SET指令;(2)条件跳转;(3)条件传送。

SET指令可以把条件(逻辑值)赋给目的操作数。

注意指令具有同义名。(比如setg和setnle)

jmp可以直接和间接跳转——跳转目标可以是label,*(操作数)。比如jmp .L1, jmp *%rax, jmp *(%rax)。

条件跳转只能是直接跳转!!

跳转指令有几种不同的编码,但是最常用的是PC相对的(偏移量编码为1,2,4个字节)。也可以给出绝对地址,用4个字节直接指定目标。

条件传送指令源操作数为寄存器或内存,目的一定是寄存器。**不支持单字节的条件传送!!**条件传送不指定操作数长度,因为汇编器可以从目标寄存器推断(无条件传送不行,因为目的可能是内存)

基于条件传送的代码会对两个expr都求值,但是如果计算量都很大,可能性能也会下降。

jump to middle -Og; guarded-do -O1

跳转表的优点:执行开关语句的时间与开关情况的数量无关。GCC根据开关情况的数量开关情况值的稀疏程度来翻译开关语句。

call指令和jmp指令的目的没什么区别。

对抗缓冲区溢出攻击的方法:栈随机化(空操作雪橇)、栈破坏检测(金丝雀)、限制可执行代码区域。

变长栈帧(alloca)使用%rbp作为帧指针(基指针,base pointer)。使用帧指针时,先将%rbp保存(callee saved)。

Chapter4

指令集体系结构:一个处理器支持的指令指令的字节级编码。

程序员可见状态:15个程序寄存器(没有%r15)+3个条件码(没有CF)+ PC + 内存 + 状态码Stat

虚拟地址:字节数组 v.s. 物理地址:硬件和操作系统软件联合起来将虚拟地址翻译,指明数据实际存在内存中哪个地方

Y86地址计算不支持第二变址寄存器和任何寄存器值的伸缩。形如3(%rax)

注意指令中有常数字会变成8个字节然后再按小端法反序。

CISC早期RISC
指令数量很多。指令数量少得多,通常少于100个
有些指令延迟很长。没有较长延迟的指令(早期RISC甚至没有整数乘法)
编码可变长度1到15字节编码固定长度(4个字节)
指定操作数方式很多样,比如内存操作数指示符简单寻址方式。通常只有基址和偏移量寻址
可以对内存和寄存器操作数进行算术和逻辑运算只能对寄存器操作数进行算术和逻辑运算,允许使用内存已用的只有load/store
机器及程序实现细节不可见。ISA提供抽象对机器级程序来说实现细节是可见的。
有条件码。并设置了一些特殊的标志位没有条件吗。条件检测要用明确的测试指令
栈密集的过程链接。栈被用来存取过程参数和返回地址寄存器密集的过程连接。寄存器被用来存取过程参数和返回地址。通常由更多寄存器(最多的有32个)

RISC处理器产品(Sun Microsystem),IBM,Motorola(PowerPC)。ARM提出了自己的体系结构(Acorn RISC Machine),广泛应用在嵌入式系统中。

伪指令:.pos 0告诉汇编器应该从地址0处开始产生代码。(所有Y86-64程序的起点)。

Y86的汇编器:YAS

指令集模拟器:YIS(模拟机器代码程序的执行)

pushq %rsp压入%rsp的原始值再讲%rsp-8,popq将栈指针的值修改为内存读出来的值(先写入valE,后写入valM)。

逻辑门总是活动的,一旦一个门的输入变化了,在很短时间内输出就会变化。

HCL中所有字级信号都声明为int,不指定字的大小。

不要求选择表达式互斥,前面的没选中自动执行后面的。

向寄存器文件写入字是由时钟信号控制的。每次时钟上升时,valW上的值会被写入输入dstW上的寄存器ID指示的程序寄存器。当dstW设为0xF时,不会写任何程序寄存器。写端口可以每个时钟周期更新两个寄存器。

SEQ的实现包括组合逻辑和两种存储器设备:时钟寄存器(PC和Cnd)、随机访问存储器(RF、DataM、InsM)

由于只从指令内存读取数据,可以看做组合逻辑。(不需要时序)

PC/CND、DataM、RF通过一个时钟信号控制,除法将新值装载到寄存器以及将值写回随机访问存储器。

Icode,ifun要么等于从内存读出的值,或者当指令地址不合法时使其对应于nop。

寄存器文件支持同时进行两个读和两个写,每个端口有一个地址连接和一个数据连接。

根据icode以及rA、rB、Cnd,控制逻辑块srcA会选择相应的寄存器。

SEQ的控制逻辑单元:

更新PC:new_pc

访存:Stat/mem_read/mem_write/mem_addr/mem_data

执行:set_cc/aluA/aluB/alu_fun

译码写回:dstE/dstM/srcA/srcB

取指:instr_valid/need_valC/need_regids/icode/ifun

Chapter 6

SRAM可以onchip也可以offchip,作为高速缓存存储器(不超过几兆,6晶体管电路每单元,密集度低,贵,功耗更大,干扰不敏感)

DRAM用来作为主存以及图形系统的帧缓冲区(几百或几千兆,每个位存储为对电容的充电)

传统的DRAM:d个超单元,每个超单元由w个DRAM单元组成,每个超单元被组织成r行c列的长方形阵列。信息通过成为引脚的外部连接器流入和流出芯片,每个引脚携带一个1位的信号。每个DRAM芯片被连接到某个称为内存控制器的电路,这个电路可以一次传送w位到每个DRAM芯片或一次从每个DRAM芯片传出w位。为了读出超单元(i,j)的内容,内存控制器将行地址i发送到DRAM,然后是列地址j。行地址i称为CAS(Column Access Strobe)请求。RAS和CAS请求共享相同的DRAM地址引脚。

内存模块:DRAM芯片封装在内存模块中,它插到主板的扩展槽上。

增强的DRAM:

  • 快页模式(FPM DRAM,fast page mode DRAM),允许行缓冲区(有点像cache hit)

  • 扩展数据输出(EDO DRAM, extended Data Out DRAM),FPM DRAM的增强型是,允许各个CAS信号在时间上靠的更紧密。

  • 同步DRAM(Synchronous DRAM, SDRAM),同步,更快!

  • 双倍数据速率同步DRAM(DDR SDRAM),比SDRAM速度翻倍!

  • 视频RAM(Video RAM, VRAM)用在图形系统的帧缓冲区中。思想和FPM DRAM类似。

非易失性存储器:ROM以它们能够被重编程(写)的次数和对它们进行重编程所用的机制来区分

  • 可编程ROM(PROM)只能被编程一次。
  • 可擦写可编程ROM(EPROM)紫外光
  • 电子可擦除PROM(EEPROM)105
  • 闪存,基于EEPROM(基于闪存:固态硬盘SSD)

**固件:**存储在ROM设备中的程序,通电后运行

访问主存:数据流通过总线(CPU<->系统总线<->IO桥<->内存总线<->主存)在处理器和DRAM主存之间来来回回。

磁盘存储:数量级可以达到几百到几千千兆字节,基于RAM的存储器只能有几百或几千兆字节。不过读信息的时间为毫秒级。

多区记录技术:柱面的集合被分割成不相交的子集,称为记录区,每个区包含一组连续的柱面。一个区中的每个柱面的每条磁道都有相同数量的扇区。

制造商以千兆字节(GB)或兆兆字节(TB)为单位表达磁盘容量,1GB=109字节,1TB=1012字节。

K,M,G,T这样的前缀含义依赖于上下文:DRAM和SRAM容量相关的计量单位,K=210,M=220,G=230,而T=240,而对于像磁盘和网络这样的IO设备相关的计量单位就不是这样。速率和吞吐量也是后者。

平均旋转时间是最大旋转延迟的一半。

连接IO设备:通过IO总线(比如Intel的PCI总线)连接到CPU和主存。系统总线和内存总线是CPU相关的,但IO总线不是。IO总线比它们蛮。

主机总线适配器将一个或多个磁盘连接到IO总线,两个最常用的磁盘接口是SCSI和SATA,SCSI更快,更贵,可以支持多个磁盘驱动器。

访问磁盘:CPU使用内存映射技术来向IO设备发射命令。在使用内存映射IO的系统中,地址空间中有一块地址是为与IO设备通信保留的。每个这样的地址成为一个IO端口。当一个设备连接到总线时,它被映射到一个或多个端口。比如说假设磁盘控制器映射到端口0xa0,CPU可能通过执行三个对地址0xa0的存储指令,发起磁盘读。磁盘控制器收到来自CPU的指令后将逻辑块号翻译成一个扇区地址,然后将内容直接传送到主存,不需要CPU的干涉。(直接内存访问DMA传送,direct Memory Access)DMA传送完成后,磁盘控制器通过给CPU发送一个中断信号来通知CPU。

SSD封装插到IO总线上标准硬盘插槽(USB或SATA),一个SSD封装由一个或多个闪存芯片和闪存翻译层。闪存芯片替代机械驱动器,闪存翻译层是一个固件/硬件设备,扮演磁盘控制器的角色,将对逻辑块的请求翻译成对地层物理设备的访问。

**读SSD比写SSD要快!**随机读和写的性能差别是由底层闪存基本属性决定的。一个山村由B个块的序列组成,每个块由P页组成,通常页的大小时512字节到4kb,块由32-128页组成,块大小为16kb到512kb。只有在一页所属的块被擦除之后,才能写这一页(通常是指该块中所有位都被设置为1)。不过一旦一个块被擦除后,块中每个页都可以不需要进行擦除就可以写一次。随机写很慢的原因:(1)擦除块需要较长的时间,比访问页高一个数量级;(2)如果写操作试图修改一个包含已有数据的页,那么这个块中所有带有用数据的页都必须被复制到一个新(被擦除过的)块。

存储技术趋势:SRAM级数的成本和心梗以相同的速度改善;DRAM和磁盘变化趋势更大,DRAM每兆字节成本下降了44000倍,DRAM的访问时间只下降了大约10倍。磁盘的成本跌了6个数量级,但访问时间提高得很慢。(事实:增加密度比降低访问时间容易得很多)

DRAM和磁盘的性能滞后于CPU的性能。SRAM滞后于CPU,但性能还是保持增长,DRAM和磁盘性能与CPU性能差距加大。现代计算机频繁地使用基于SRAM的高速缓存,试图弥补处理器-内存之间的差距。

寄存器->L1高速缓存->L2高速缓存->L3高速缓存->主存(DRAM)->本地二级存储(本地磁盘)->远程二级存储(分布式文件系统、Web服务器)

Corei7高速缓存的基本特性:

高速缓存类型访问时间(周期)高速缓存大小(C)相联度(E)块大小(B)组数(S)
L1 i-cache432KB864B64
L1 d-cache432KB864B64
L2统一的高速缓存10256KB864B512
L3统一的高速缓存40-758MB1664B8192

影响:

  • 较大的高速缓存可能提高命中率,可能增加名和总时间。
  • 较大的块能利用空间局部性,不过对于给定的高速缓存大小,块越大意味着高速缓存行数越少,会损害时间局部性比空间局部性更好的程序命中率。较大的块对不命中处罚也有负面影响,因为块越大传送时间越长。
  • 较高的相联度降低了抖动的可能性,不过成本会增加,速度降低,标记位更多,需要LRU状态位和额外的控制逻辑。还会增加不命中处罚(牺牲行的选择复杂性增加)
  • 直写高速缓存比较容易实现,能使用独立于高速缓存的的写缓冲区。
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一个 SQL 语句,用于向借阅表中插入数据。该表包含以下字段:借阅编号、读者编号、书籍编号、借阅日期、归还日期、借阅状态。每条数据表示一次借阅记录。其中借阅编号、读者编号、书籍编号、借阅日期和借阅状态是必填项,归还日期为可选项,如果借阅状态为“已还”则必须填写归还日期。 具体插入的数据如下: - 借阅编号:100001,读者编号:123413,书籍编号:0001,借阅日期:2020-11-05,归还日期:NULL,借阅状态:借阅 - 借阅编号:100002,读者编号:223411,书籍编号:0002,借阅日期:2020-9-28,归还日期:2020-10-13,借阅状态:已还 - 借阅编号:100003,读者编号:321123,书籍编号:1001,借阅日期:2020-7-01,归还日期:NULL,借阅状态:过期 - 借阅编号:100004,读者编号:321124,书籍编号:2001,借阅日期:2020-10-09,归还日期:2020-10-14,借阅状态:已还 - 借阅编号:100005,读者编号:321124,书籍编号:0001,借阅日期:2020-10-15,归还日期:NULL,借阅状态:借阅 - 借阅编号:100006,读者编号:223411,书籍编号:2001,借阅日期:2020-10-16,归还日期:NULL,借阅状态:借阅 - 借阅编号:100007,读者编号:411111,书籍编号:1002,借阅日期:2020-9-01,归还日期:2020-9-24,借阅状态:已还 - 借阅编号:100008,读者编号:411111,书籍编号:0001,借阅日期:2020-9-25,归还日期:NULL,借阅状态:借阅 - 借阅编号:100009,读者编号:411111,书籍编号:1001,借阅日期:2020-10-08,归还日期:NULL,借阅状态:借阅
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值