《深入理解计算机系统》 练习题3.49详解

3.49

《深入理解计算机系统》 练习题3.49详解_第1张图片
《深入理解计算机系统》 练习题3.49详解_第2张图片

解释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 = 8n22 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 > > k x >>k x>>k将产生数值 ⌊ x / 2 k ⌋ \lfloor {x/2^k} \rfloor x/2k,当x为负数时,我们通过加一个偏置值bias,使得 ( x + b i a s ) > > k (x+bias) >>k (x+bias)>>k将产生数值 ⌈ x / 2 k ⌉ \lceil {x/2^k} \rceil x/2k,bias为 2 k − 1 2^k-1 2k1

同样地,在第8行,将%rsp加上7即 2 3 − 1 2^3-1 231,假设%rsp栈指针为x,在第9行右移3位,这里将产生 ⌈ x / 2 3 ⌉ \lceil {x/2^3} \rceil x/23 ⌈ x / 8 ⌉ \lceil {x/8} \rceil x/8。第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行汇编分配栈空间时,是将 e 1 e_1 e1 e 2 e_2 e2和数组的空间一起考虑的了。
当第10行汇编执行,才会确定了 e 1 e_1 e1 e 2 e_2 e2的大小。因为只有这个时候才知道了数组空间的开始地址和结束地址。
注意这个图里面, e 1 e_1 e1 e 2 e_2 e2不一定都是8个字节哦。

s 1 s_1 s1为刚好为8的倍数时, e 1 e_1 e1 e 2 e_2 e2就没什么用了,起码不需要它俩来8K对齐了,因为本来就是8K对齐的。
s 1 s_1 s1为其他情况时(其他情况中,如果让数组空间直接从 s 2 s_2 s2开始分配都会造成8K不对齐), e 1 e_1 e1 e 2 e_2 e2就可以用来保证数组每个元素8K对齐。
《深入理解计算机系统》 练习题3.49详解_第3张图片
《深入理解计算机系统》 练习题3.49详解_第4张图片
分析答案前,可以理解这么一个事实,当一个数组空间本身不8K对齐时(前提数组元素需要8字节存储),那么前后移动1-7字节便一定可以8K对齐

在第一行答案中,可见 s 1 s_1 s1 s 2 s_2 s2都不是8K对齐的,本来p数组理应从 s 2 s_2 s2这个地址开始分配,但这里必须从 s 2 s_2 s2上面舍入到8的倍数,这样就保证了数组p的8K对齐。相当于数组p往地址增加方向移动了7个字节。

解释15-18行

其实这里有点不大理解,因为15和16行看起来有点多此一举,如果是因为局部变量i需要存储在栈中,那么有15行就够了呀,16行汇编执行后并不会让寄存器%rax改变(所以说它没有用)。

其他

这个题是考虑了这么一种情况,调用此函数时的栈指针就已经不是8K对齐的了。

你可能感兴趣的:(CSAPP.3e)