深入理解计算机系统答案
【篇一:深入理解计算机系统笔记】
对于一个无符号数字 x, 截断它到 k 位的结果就相当于计算 x mod 2Ak.
在大多数的机器上 , 整数乘法指令相当地慢 , 需要 12 或者更多的始 终周期 ,然而其他整数运算-例如加法、减法、位移运算和移位-只 需要 1 个时钟周期 .因此 ,编译器使用的一项重要的优化就是试着使用 移位和加法运算的组合来代替乘以常数因子的乘法 .
在大多数的机器上 , 整数除法要比整数乘法更慢-需要30 或者更
多的始终周期 .除以 2 的幂也可以用移位运算来实现 ,只不过我们用的 是右移 ,而不是左移 .对于无符号和二进制补码数 ,分别使用逻辑移位和 算术移位来达到目的 .
1.注意系统的分类:主流的ia32(也就是x86),以及x86-64(也就是 x64) ,还有种 intel 的与原 32 位系统不兼容的 ia64。
2 .编译系统由预处理器,编译器,汇编器和链接器组成。
单指令多数据并行称为 simd 并行,其扩展为 sse 指令集。
x64上long为8字节,指针也为 8字节。
无符号数右移必须采用逻辑右移,而有符号数一般采用算术右移。
有符号数遇见无符号数会默认强转为无符号数。
short 转为 unsigned 时,是先扩展大小再符号转换。
补码非的计算:从左到右将第一个为 1 的位前的所有位取反。
负数的补码移位向下舍入。
1 0.正浮点数能使用整数排序函数来进行排序。
1 1 .浮点加法和乘法不具备结合性,浮点乘法在加法上不具备分配性。
1 2 .预处理器扩展源代码,然后编译器生成源代码的文本汇编代码, 汇编器转成二进制汇编码,链接器生成 exe 或 dll 或 lib 。
寄存器可以保存地址也可以保存值。注意汇编中的加括号表示为 取该地址指向的值,如(%eax)指%eax中保存的地址指向的值。
传送指令的两个操作符不能都指向存储器。
栈指针%esp保存着栈顶元素的值,%eax保存函数返回值。
栈从高地址往低地址分配,堆从低地址往高地址分配。
注意:lea,假设为 leal 7(%edx, %eax, 4),则当 %edx 中保存 的是地址时, lea 为取有效地址,而当 %edx 中保存的是值时, lea 为算术运算,即 7 + %edx + %eax * 4 。这儿的 %eax 总保存值。说 白了,其实 lea 一直是在做计算,只是 %edx 影响了直观表达而已。
注意:处理有无符号值的操作是通过不同的汇编指令来区分的。
大多数汇编器根据一个循环的 do-while 形式来产生循环代码, 逆向工程会用到。
指令无视操作数的长度。
因为有个条件传送的优化策略,所以 (xp ? *xp : 0) 这条语句其实 两个选择分支都会执行。
22.32 位系统中,大多数栈中信息的访问其位置都是基于帧指针的。 而 64 位系统中,栈的存储信息数已被弱化,所以无帧指针了。
访问某个局部变量的前提是该局部变量至少有个可引用的地址, 所以局部变量被保存在了栈中。
为了防止从效率低的存储器读写值时,可能因数据未对齐而造成 多次读写从而导致低性能, ia32 要求数据一定要对齐。编译器在编 译时会强制对齐。
汇编指令 leave 等于俩 pop ,效果一样,选择随意。 pop 和 push 在栈上分配空间的方式是直接栈指针减去或加上偏移量。
指针之差等于 相差字节数 / 所指类型大小字节数。
寄存器不够用时会出现寄存器溢出,这时就必须有值被保存在栈 上了,一般是将只读变量放入栈。
gcc 会对局部 char 类型的缓冲区插入金丝雀保护代码。
在 c 中 内联汇编代码只能针对某一类机器。
sse2 引入浮点数面向寄存器的指令集,而不用基于栈的方法。
x64 能让汇编代码比 x32 少很多,但是实际性能提升不会很大。 但是从改进上来说性能应该提升很大很大啊,为什么。。。难道是 x32 已经被优化的变态了???
注意 rep 有时当空操作使。
x64 中,栈空间向下 128 字节以内的区域仍可以被函数访问,该 区域被 abi 称为红色地带。
浮点相关:把存储模型,指令和传递规则组合称为浮点体系结构。
逻辑门只是简单的响应输入的变化而已。
hcl 中, = 只是表示用一个名字来称谓一个表达式。其类switch
的表达中的 ”1:等“同于 switch 中的 default case 。
寄存器文件上的读或写端口都分别成对,一个传 id ,一个传内容
访存阶段读写存储器,写回阶段将结果写到寄存器文件。
寄存器文件和数据存储器等都是当前时钟随意读,下一时钟统一 写入更新。即时钟控制状态元素的更新。
流水线即保持各单元在时钟周期内忙碌不已,一套流水线硬件供 多个流水线使用。
加载互锁