《深入理解计算机系统》 练习题3.49详解
3.49
解释5-7行
第5行汇编得到8n+22。
第6行8n+22与立即数-16进行与运算。按照最高位为符号位来说,-16的二进制为1 0000
,因为符号拓展值不变,所以-16的8字节表示为.... 1111 0000
,省略号全为1。所以第6行是要将8n+22与.... 1111 0000
进行与运算,这会导致8n+22的低4位如果谁有1都会被舍弃掉,原文描述为:“把它向下舍入到最接近的16的倍数”,因为是舍弃低4位所以是“向下舍入”。按照本人描述为:舍弃掉权值为8,4,2,1的二进制位,只留下权值大于等于8的二进制位。
所以,与$-16
进行与运算后,结果将会是16的倍数。倍数可能是0,1…
当n为偶数时,将8n+22拆分为8n和22。既然n为偶数,则8n为16的倍数,那么8n and $-16 = 8n
。22 and $-16 = 16
。将两个结果加起来就是8n + 16
.
当n为奇数时,将8n+22拆分为8(n-1)和30。既然n-1为偶数,则8(n-1)为16的倍数,那么8(n-1) and $-16 = 8(n-1)
。30 and $-16 = 16
。将两个结果加起来就是8n + 8
.
还有就是这个22,其实可以替换为16-23中一个数都可以,把这个数称为m,那么要求m或者m+8在和与$-16
进行与运算后,结果必须为16,从这个要求就可以得出这个范围。
举一反三地,一个数与$-32
进行与运算后,结果是32的倍数,道理和上面一样。一个数与$-1
进行与运算后,结果是1的倍数,因为二进制位上全是1,即它本身。
从结果来看,除了数组需要的8n空间外,还可能多分配8或16字节的空间另作他用。另外不管是奇数偶数,两种情况结果都将是16的倍数。
解释8-10行
在此之前,先回想一下补码除以2的幂里面,将产生数值,当x为负数时,我们通过加一个偏置值bias,使得将产生数值,bias为。
同样地,在第8行,将%rsp加上7即,假设%rsp栈指针为x,在第9行右移3位,这里将产生即。第10行乘以8,相当于左移3位。
可以想象,当%rsp刚好是8的倍数时,执行完8-10行,不变,因为向上取整时为本身。当%rsp不是8的倍数时,执行完8-10行,为%rsp+8,因为向上取整时加1了。
换个角度,7的二进制为111
,当%rsp的低三位是000
时,加上111
不会使得第4位加1;当%rsp的低三位不是000
而是其他情况时,加上111
肯定使得第4位加1。然后第9,10行的操作是先右移3位,再左移3位,这就相当于把低3位的二进制值清0。
总结一下:要么%rsp不变,要么%rsp向上舍入到最接近8的倍数。
确定结果值
在第7行汇编分配栈空间时,是将和和数组的空间一起考虑的了。
当第10行汇编执行,才会确定了和的大小。因为只有这个时候才知道了数组空间的开始地址和结束地址。
注意这个图里面,和不一定都是8个字节哦。
当为刚好为8的倍数时,和就没什么用了,起码不需要它俩来8K对齐了,因为本来就是8K对齐的。
当为其他情况时(其他情况中,如果让数组空间直接从开始分配都会造成8K不对齐),和就可以用来保证数组每个元素8K对齐。
分析答案前,可以理解这么一个事实,当一个数组空间本身不8K对齐时(前提数组元素需要8字节存储),那么前后移动1-7字节便一定可以8K对齐。
在第一行答案中,可见和都不是8K对齐的,本来p数组理应从这个地址开始分配,但这里必须从上面舍入到8的倍数,这样就保证了数组p的8K对齐。相当于数组p往地址增加方向移动了7个字节。
解释15-18行
其实这里有点不大理解,因为15和16行看起来有点多此一举,如果是因为局部变量i
需要存储在栈中,那么有15行就够了呀,16行汇编执行后并不会让寄存器%rax
改变(所以说它没有用)。
其他
这个题是考虑了这么一种情况,调用此函数时的栈指针就已经不是8K对齐的了。