3.58
1 2 3
| y-=z; x*=y; return ((y<<63)>>63)^x
|
3.59
p=xy=(xhyl+yhxl)264+xlyl
记 xlyl=qh264+ql,则 p=(xhyl+yhxl+qh)264+ql
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
B
R=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
B
64(%rsp)
C
s 在栈内,所以通过 %rsp 加上偏移量来访问。
D
同上
E
F
结构存储在栈上,传递和访问时都通过指针来进行寻址。
3.68
由第 2 行确定 B 的取值区间为 (4,8],由第 3 行确定 A 的取值区间为 (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 3 add (%rsi),%ecx 4 lea (%rdi,%rdi,4),%rax 5 lea (%rsi,%rax,8),%rax 6 mov 0x8(%rax),%rdx 7 movslq %ecx,%rcx 8 mov %rcx,0x10(%rax,%rdx,8) 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。