CSAPP hw3

3.58

1
2
3
y-=z;
x*=y;
return ((y<<63)>>63)^x

3.59

p=xy=(xhyl+yhxl)264+xlyl\begin{aligned} p &=xy\\ &=(x_hy_l+y_hx_l)2^{64}+x_ly_l \end{aligned}

xlyl=qh264+qlx_ly_l=q_h2^{64}+q_l,则 p=(xhyl+yhxl+qh)264+qlp=(x_hy_l+y_hx_l+q_h)2^{64}+q_l

1
2
3
4
5
6
7
8
9
10
11
# 将y存入%rax
# 将y进行符号扩展
# 将x存入%rcx
# 取x的符号位
# 计算 y_h*x_l
# 计算 x_h*y_l
# 计算 x_h+y_l
# 计算 x_l*y_l
# 计算 x_h*y_l+y_h*x_l+q_h
# p_l放入低8字节
# p_h放入高8字节

3.60

A

x: %rdi, n: %esi, result: %rax, mask: %rdx

B

result: 0, mask: 1

C

mask!=0

D

mask=mask<<n

E

result|=mask&x

F

0

1

!=0

mask<<n

mask&x

3.61

1
2
3
4
5
6
long cread_alt(long *xp)
{
long x=0;
xp=xp?xp:&x;
return *xp;
}

3.62

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
case MODE_A:
result=*p2;
*p2=*p1;
break;
case MODE_B:
result=*p1+*p2;
*p1=result;
break;
case MODE_C:
*p1=59;
result=*p2;
break;
case MODE_D:
*p1=*p2;
result=27;
break;
case MODE_E:
result=27;
break;
default:
result=12;
break;

3.63

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
case 60:
case 62:
result=8*x;
break;
case 63:
result=x>>3;
break;
case 64:
result=15*x;
x=result;
case 65:
x=x*x;
default:
result=x+75;
break;

3.64

A

&A[i][j][k]=xA+(i×S×T+j×T+k)×8\&A[i][j][k]=x_A+(i\times S\times T+j\times T+k)\times8

B

R=7,S=5,T=13R=7,S=5,T=13

3.65

A

%rdx

B

%rax

C

15

3.66

NR(n) 3*n, NC(n) 4*n+1

3.67

本题的一个注意点是:当调用 process 时栈指针会 -8,用于存放返回地址。

A

图1

B

64(%rsp)

C

s 在栈内,所以通过 %rsp 加上偏移量来访问。

D

同上

E

图2

F

结构存储在栈上,传递和访问时都通过指针来进行寻址。

3.68

由第 2 行确定 B 的取值区间为 (4,8](4,8],由第 3 行确定 A 的取值区间为 (6,10](6,10]。又由第 4 行确定 A*B 为 45 或 46。

综上所述,唯一确定 A=9,B=5。

3.69

这个题目有一定的难度。

1
2
3
4
5
6
7
8
9
1 test:
2 mov 0x120(%rsi),%ecx # 取出 bp->last
3 add (%rsi),%ecx # 计算 n 并存入 %rcx
4 lea (%rdi,%rdi,4),%rax # 将 5i 存入 %rax
5 lea (%rsi,%rax,8),%rax # 将 bp+40i 存入 %rax
6 mov 0x8(%rax),%rdx # 从内存中 bp+40i+8 的位置取数,存入 %rdx
7 movslq %ecx,%rcx # 将 n 符号扩展
8 mov %rcx,0x10(%rax,%rdx,8) # 将 n 写入内存中 bp+40i+8*idx+16 的位置
9 retq

第 2 行说明 bp->first 和 bp->a[CNT] 一共占了288 个字节。

第 5 行说明一个 a_struct 占 40 个字节。结合前面的 288 可以推断出:a_struct 内最大类型占 8 个字节,因此 first 为了对齐也占了 8 个字节,CNT=7。8+40*7=288,吻合。

第 6 行取的数必然是 idx,由寄存器可以看出类型为 long。而 bp+40i+8 正好是 ap 的起始地址。所以 a_struct 内 idx 在前,x 在后。

第 8 行中,16 拆分为 8+8。其中 bp+40i+8 为 ap 的值,另一个 8 是 idx 的大小。也就是说,bp+40i+16 为ap->x 的起始地址,而 8*idx 为数组的索引。结合对 n 做了扩展,可以推断数组 x 元素类型是 long。a_struct 占 40个字节,所以 x 的大小为4。8+8*4=40,吻合。

画了张图便于理解。

A

CNT=7

B

1
2
3
4
typedef struct{
long idx;
long x[4];
}a_struct;

3.70

A

e1.p: 0, e1.y: 8, e2.x: 0,e2.next: 8

B

16

C

e2.x

up->e2.next->e1.p

up->e2.next->e1.y

3.71

1
2
3
4
5
6
7
8
9
10
11
12
#define BUF_SIZE 2
void good_echo()
{
char buf[BUF_SIZE];
while(1)
{
char *p=fgets(buf,BUF_SIZE,stdin);
if(p==NULL) break;
printf("%s",p);
}
return;
}

3.72

A

s2=s1-(8n+30)&-16

B

p=(s2+15)&-16

C

当 n 为奇数时,s1-s2=8n+24,n 为偶数时,s1-s2=8n+16。这里的 16 和 24 就是 e1+e2 的值。

若想要 e1 最大,则 n 为奇数,且 s2%16=0。此时 e2=0,e1 取得最大值 24。

若想要 e1 最小,则 n 为偶数,且 s2%16=1。此时 e2=15,e1 取得最小值1。

D

s2 起始地址是 16 的倍数,p 的地址对齐 16。

3.73

参考了网上的,代码不是很难,主要是如何在 c 程序中插入一段汇编代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <stdio.h>
#include <assert.h>

typedef enum {NEG, ZERO, POS, OTHER} range_t;

range_t find_range(float x) {
__asm__(
"vxorps %xmm1, %xmm1, %xmm1\n\t"
"vucomiss %xmm1, %xmm0\n\t"
"jp .P\n\t"
"ja .A\n\t"
"jb .B\n\t"
"je .E\n\t"
".A:\n\t"
"movl $2, %eax\n\t"
"jmp .Done\n\t"
".B:\n\t"
"movl $0, %eax\n\t"
"jmp .Done\n\t"
".E:\n\t"
"movl $1, %eax\n\t"
"jmp .Done\n\t"
".P:\n\t"
"movl $3, %eax\n\t"
".Done:\n\t"
);
}

int main(int argc, char* argv[]) {
range_t n = NEG, z = ZERO, p = POS, o = OTHER;
assert(o == find_range(0.0/0.0));
assert(n == find_range(-2.3));
assert(z == find_range(0.0));
assert(p == find_range(3.33));
return 0;
}

3.74

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
#include <assert.h>

typedef enum {NEG, ZERO, POS, OTHER} range_t;

range_t find_range(float x) {
__asm__(
"vxorps %xmm1, %xmm1, %xmm1\n\t"
"movq $1, %rax\n\t"
"movq $2, %r8\n\t"
"movq $0, %r9\n\t"
"movq $3, %r10\n\t"
"vucomiss %xmm1, %xmm0\n\t"
"cmovaq %r8, %rax\n\t"
"cmovbq %r9, %rax\n\t"
"cmovpq %r10, %rax\n\t"
);
}

int main(int argc, char* argv[]) {
range_t n = NEG, z = ZERO, p = POS, o = OTHER;
assert(o == find_range(0.0/0.0));
assert(n == find_range(-2.3));
assert(z == find_range(0.0));
assert(p == find_range(3.33));
return 0;
}

3.75

A

第一个参数实部 %xmm0,虚部 %xmm1。第二个参数实部 %xmm2,虚部 %xmm3。依此类推。

B

实部 %xmm0,虚部 %xmm1。


CSAPP hw3
https://je3ter.github.io/2024/02/17/CSAPP/CSAPP hw3/
作者
Je3ter
发布于
2024年2月17日
许可协议