CSAPP Homework 20251119
CSAPP Homework 20251119
3.58
1 | long decode2(long x, long y, long z) { |
3.59
$x=2^{64}\times x_h+x_l,y=2^{64}\times y_h+y_l$.
乘积为 $P=xy=2^{128}x_h y_h+2^{64}(x_h y_l+y_h x_l)+x_l y_l$.
由于 __int128 类型只能存储 128 位,所以 $2^{128}x_h y_h$ 溢出不考虑。
故 $P=2^{64}(x_h y_l+y_h x_l)+x_l y_l$.
1 | store_prod: |
3.60
1 | loop: |
A: x: %rdi, n: %esi, result: %rax, mask: %rdx.
B: result = 0, mask = 0.
C: mask != 0.
D: mask <<= n.
E: result |= (x & mask).
F:
1 | long loop(int x, int n) { |
3.61
1 | long cread(long* xp) { |
3.62
1 | long switch3(long *p1, long *p2, mode_t action) |
3.63
1 | long switch_prob(long x, long n) { |
3.65
**A:**循环中地址应该增加 8,指令 addq $8, %rdx 显示寄存器 %rdx 每次增加 8,故答案为:%rdx
**B:**一行的字节大小为 $M \times 8$,指令 addq $120, %rax 显示寄存器 %rax 每次增加 120,故答案为:%rax
C:$M = 120 / 8 = 15$。
3.66
NR(n): 寄存器 %rdi 保存循环的终止界限。指令 leaq (%rdi,%rdi,2), %rax 计算出 $n + 2n = 3n$,随后指令 movq %rax, %rdi 将其存入 %rdi。循环条件 cmpq %rdi, %rdx 表明循环执行次数为 %rdi 的值,故 NR(n) 为: 3n
NC(n): 寄存器 %r8 保存数组行与行之间的字节步长。指令 leaq 1(,%rdi,4), %r8 计算出 $4n + 1$,指令 salq $3, %r8 将其左移 3 位(乘以 8),得到 $(4n + 1) \times 8$。由于在列中移动时,地址增量等于一行的总字节数 $NC(n) \times 8$,故 NC(n) 为: 4n + 1
3.67
A: eval 在栈上分配 104 字节。结构体 s 位于栈顶,偏移量为 0~23。结构体 r(返回值)的存储空间分配在偏移量 64~87 处。变量 z 位于偏移量 24 处。
B: eval 传递了一个指针(地址)给 process,该地址存储在 %rdi 中,指向 eval 栈帧中偏移量为 64 的位置,用于存放返回的结构体 r。
C: process 通过相对于栈指针 %rsp 的偏移量来访问 s 的元素。由于 call 指令压入了返回地址,偏移量比 eval 中增加了 8。即 s.a[0] 在 8(%rsp),s.a[1] 在 16(%rsp),s.p 在 24(%rsp)。
D: process 使用传入的 %rdi 作为基址来写入结果。r.u[0] 存入 (%rdi),r.u[1] 存入 8(%rdi),r.q 存入 16(%rdi)。
E: 返回后,eval 通过栈帧偏移量访问 r。r.u[0] 位于 64(%rsp),r.u[1] 位于 72(%rsp),r.q 位于 80(%rsp)。
F: 当结构体作为参数传递且过大无法放入寄存器时,它们通过栈传递。当函数返回结构体时,调用者分配空间并将其地址作为第一个参数(隐藏参数)传递给被调用者。
3.70
A:
e1.p: 0
e1.y: 8
e2.x: 0
e2.next: 8
B: 16
C:
1 | void proc (union ele *up) { |