3.58
long decode2(long x, long y, long z){
//x in %rdi, y in %rsi, z in %rdx
y -= z;
x *= y;
long ret = y;
ret <<= 63;
ret >>= 63;
ret ^= x;
return ret;
}
3.59
3.60
long loop(long x, int n){
//x in %rdi, n in %esi
long result =0;
long mask;
for (mask = 1; mask !=0; mask = mask << n){
result |= (x & mask);
}
return result;
}
3.61
long cread_alt(long *xp)
{
long t=0;
long *p = xp ? xp : &t;
return *p;
}
3.62
typedef enum
{
MODE_A,
MODE_B,
MODE_C,
MODE_D,
MODE_E
} mode_t;
long switch3(long *p1, long *p2, mode_t action)
//p1 in %rdi, p2 in %rsi, action in %edx
{
long result = 0;
switch (action)
{
case MODE_A: //0
result = *p2;
*p2 = *p1;
break;
case MODE_B: //1
result = *p1;
*p1 = *p2;
break;
case MODE_C: //2
*p1 = 59;
result = *p2;
break;
case MODE_D: //3
*p1 = *p2;
result = 27;
break;
case MODE_E: //4
result = 27;
break;
default:
result = 12;
}
return result;
}
3.63
long switch_prob(long x, long n)
//x in %rdi, n in %rsi
{
long result = x;
switch (n){
/*Fill in code here */
case 60:
case 62:
result = x * 8;
break;
case 63:
result = x >> 3;
break;
case 64:
result = (result << 4) - x;
x = result;
case 65:
x *= x;
default:
result = x + 75;
}
return result;
}
3.64
long A[R][S][T];
则&A[i][j][k] = A + i * (S * T) + j * T + k
k + i * 65 + 13 * j
S * T=65, T=13
S = 5
SIZEOF(A)=3640
3640/5/13/8=7
故R=7
3.65
%rdx -> A[i][j]
%rax -> A[j][i]
8 * M = 120 => M = 15
3.66
NR(n) = 3n
NC(n) = 4n+1
3.67
A. 调用process前栈帧
B. eval调用process时通过%rdi传递了返回值结构体的起始地址,在本例中即为rsp+64,在process过程中通过运算将返回值的结构体放在%rdi所指向的位置从而完成结构体的返回。
C. process过程通过rsp寻址结构体参数s中的元素,并没有显式的参数传递。在eval过程中,结构体s位于eval的栈帧中rsp+0的位置,由于在call process指令执行时会将返回地址压栈(rsp的值减去了8字节),因此到了过程process中结构体参数s位于rsp+8的位置上。
D. process过程通过rdi寻址返回值结构体r。rdi寄存器中存放了返回值结构体r的起始地址,通过rdi寄存器加上偏移即可寻址返回值结构体的各个元素。
E. 调用process后的栈帧:
调用process后回到eval中,process的返回值结构体r被放在了rsp+64开始的内存处,因此只需要在这个地址的基础上加上偏移就可以访问到返回的结构体r的各个元素。
F. 结构体无论是作为函数参数还是作为返回值,都是通过内存传参,而不是通过寄存器。作为函数参数时,在子过程中通过rsp+偏移访问结构体参数的各个元素,作为返回值时,在调用子过程时通过rdi寄存器将返回值结构体在主过程中的存放的起始地址传给子过程。
3.68
A=9
B=5
分析可知:
A * B的可能值:45 46
B的可能值:5 6 7 8
只有可能A * B = 45, B = 5
3.69
注意0x120=(288)10进制
CNT=7
typedef struct
{
long idx;
long x[4];
}
3.70
A.
e1.p: 0
e1.y: 8
e2.x: 0
e2.next: 8
B. 16
C. up->e2.x = * ((up->e2.next)->e1.p) - (up->e2.next)->e1.y
3.71
void good_echo()
{
const int SIZE = 5;
char str[SIZE];
while (1)
{
fgets(str, SIZE, stdin);
printf("%s", str);
if (str[strlen(str) - 1] == '\n')
{
break;
}
}
}
3.72
计算机栈顶指针会向16字节对齐。
A. andq $-16, X这条指令相当于将低4位置零,也就是使得rax中保存的8n+30对16取整。所以s2-s1为8n+30对16取整的结果。
B. p的值为rsp+15对16取整的结果,确保了p数组的起始地址为16的整数倍。
C. 8n + 30对16取整有两种可能:一种是8n本身就是16的整数倍即n = 2k,此时取整后为8n+16; 另一种是8n = 16k + 8即n = 2k + 1,此时取整后为8n + 24。由System V AMD64 ABI标准可知,s1的地址为16的整数倍(即结尾为0000),所以s2的地址也肯定是16的整数倍(结尾为0000)。又因p是由s2减15对16取整得到的结果,所以p和s2之间肯定相差2字节,即e2 = 2 bytes. 所以e1最大为(n为奇数) :8n + 24 - 16 - 8n = 8 bit, 最小为(n为偶数):8n + 16 -16 - 8n = 0.(这个题我估计没有考虑到ABI标准对于栈帧对齐的问题,s1的地址本来就应该是16的整数倍)
D. 由A B C可知,这种方法保证了s2 和 p的起始地址为16的整数倍,而且保证了e1最小为8n,能够存储p数组。