深入理解计算机系统(第三版)第3章 家庭作业

3.58

long decode2(long x, long y, long z)
{
    long result;

    y = y - z;
    x = x * y;
    result = (y << 63) >> 63;
    result = result ^ x;

    return result;
}

3.59

用x1, y1来分别表示x和y的低位,用x2, y2来分别表示x和y的高位,用N表示2^64,因此有:

p = x * y
  = (x2 * N + x1) * (y2 * N + y1)
  = (x2 * y2 * N * N) + N * (x2 * y1 + x1 * y2) + (x1 * y1)

在这里面x2*y2*N*N超过了128位,而且没有超出128位的部分每位都是0,因此可以直接去掉,
于是公式就变成了p=N*(x2*y1+x1*y2)+(x1*y1),值得注意的是,(x1*y1)可能会超出64位,
(x1*y1)超出64位的部分为z2,没有超出的部分为z1,则公式可变为p=N*(x2*y1+x1*y2)+z1;
所以,要把(x2*y1+x1*y2)放到最终结果的高位(%rdi)(x1*y1)(z1)放到低位8(%rdi)

[注]:%rdx和%rax共同代表一个128位数,是指可以用公式%rdx * 2^64 + %rax来表示这个数,
而并不是把%rax和%rdx的二进制串连起来表示。
store_prod:
    movq   %rdx, %rax       # %rax = y1
    cqto                    # 有符号扩展高位,%rdx和%rax分别表示高位和低位, %rdx = y2
    movq   %rsi, %rcx       # %rcx = x1
    sarq   $63, %rcx        # 将%rcx右移63位,跟%rdx的含义一样,要么是-1,要么是0。 %rcx = x2
    imulq  %rax, %rcx       # %rcx = x2 * y1
    imulq  %rsi, %rdx       # %rdx = y2 * x1
    addq   %rdx, %rcx       # %rcx = x2 * y1 + y2 * x1
    mulq   %rsi             # 无符号计算x1 * y1,并将128位结果的高位放到%rdx,低位放到%rax,所以%rdx = z2, %rax = z1
    addq   %rcx, %rdx       # %rdx = z2 + x2 * y1 + y2 * x1 
    movq   %rax, (%rdi)     # 将%rax的值放到低位
    movq   %rdx, 8(%rdi)    # 将%rdx的值放到高位
    ret

3.60

A:  %rdi-->x
    %esi-->n
    %rdx-->mask
    %rax-->result
    
B:  result = 0
    mask = 1

C:  mask != 0

D:  mask <<= (n & 0xFF)

E:  result |= (x & mask)

F:
long loop(long x, int n)
{
    long result = 0;
    long mask;
    
    for (mask = 1; mask != 0; mask = mask << (n & 0xFF))
    {
        result |= (x & mask);
    }
    
    return result;
}

3.61

cread_alt(long *xp)
{
    long rval = *xp;
    long eval = 0;
    long ntest = (xp = 0);
    if (ntest) rval = eval;
    return rval;
}

3.62

long switch3(long *p1, long *p2, mode_t action)
{
    long result = 0;
    switch(action){
    case MODE_A:    result = *p2;
                    action = *p1;
                    *p2 = action;
                    break;
                    
    case MODE_B:    result = *p1 + *p2;
                    *p1 = result;
                    break;
                    
    case MODE_C:    *p1 = 59;
                    result = *p2;
                    break;
                    
    case MODE_D:    result = *p2;
                    *p1 = result;
                    
    case MODE_E:    result = 27;
    
    default:        result = 12;
    }
    return result;
}

3.63

long switch_prob(long x, long n)
{
    long result = x;
    switch(n){
        
    case 60: 
        
    case 62: result = 8 * x;
             break;
                 
    case 63: result = result >> 3;
             break;

    case 64: result = (result << 4) - x;
             x = result;
             
    case 65: x = x * x;
                 
    default: result = x + 0x4b;
    }
    return result;
}

3.64

A: &A[i][j][k] = Xa + L * {T * (S * i + j) + k}

B: 
    由题可知:
        S * T = 65
        T = 13
        S * T * R * 8 = 3640
        故解得
        R = 7, S = 5, T = 13

3.65

A: %rdx

B: %rax

C: 由题可知:
     M * 8 = 120
     解得 M = 15

3.66

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

3.67

A:

相对于%rsp的偏移量 存储的值
%rsp+24 z
%rsp+16 &z
%rsp+8 y
%rsp x

B:传递了%rsp + 64 ,是栈地址,不是结构体

C:通过%rsp+偏移量访问栈地址来访问结构参数s的元素

D:通过访问栈地址的参数来设置结果结构r的字段

E:

相对于%rsp的偏移量 存储的值
%rsp+80 z
%rsp+72 x
%rsp+64 y
%rsp+56
%rsp+48
%rsp+40
%rsp+32
%rsp+24 z
%rsp+16 &z
%rsp+8 y
%rsp x

E:传递或者返回不能使用寄存器的结构体,都是通过栈来进行的。

3.68

movq %rax, 184(%rdi) 可知: 176 < 4*A*B <= 184 解得44 < A*B <= 46
movslq 8(%rsi), %rax 可知: 4 < B < 8
addq 32(%rsi), %rax 可知:7 <= A <= 10
综上所述, 可解得A = 9, B = 5

3.69

mov    0x120(%rsi), %ecx
add    (%rsi), &ecx
# 这两行说明first和a[CNT]占288个字节, %rcx = n
lea    (%rdi, %rdi, 4), %rax    # rax = 5 * i
lea    (%rsi, %rax, 8), %rax    # rax = 40 * i + bp,说明a占据的字节为40
mov    0x8(%rax), %rdx      # ap->idx = %rax + 8说明了first占8个字节,a的第一个元素也占8个字节
movslq %ecx, %rcx          # 将做了符号扩展的双字传递到四字,说明x的数组是long类型
mov    %rcx, 0x10(%rax, %rdx, 8) 
# 这行说明了ap->x[ap->idx]的地址计算公式是&ap + 16 + idx * 8
# +16是因为包含了first和idx,由于first占8个字节,所以idx占8个字节,为long类型
# 由于a占40个字节,减去idx占的8个字节,数组x的元素为(40 - 8) / 8 = 4
retq

A:CNT * 40 = 280,解得CNT = 7

B: 
typedef a_struct{
    long idx;
    long x[4];
}

3.70

A:

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

B:16

C:

1   proc:
2       movq  8(%rdi), %rax
3       movq  (%rax), %rdx
4       movq  (%rdx), %rdx
5       subq  8(%rax), %rdx
6       movq  %rdx, (%rdi)
7       ret

首先我们看一下第5行,说明2-4行都是在传递被减数,由于3,4行是传递值的参数,则加2次*号,
故被减数的形式应该为 *(*(A).B),然后我们再看第2行,偏移量为8,结合被减数的形式,
需要指针,故应该是 *next。然后再看第3行,偏移量为0,需要指针,则为 *p
故被减数应该为 *(*(up->e2.next).e1.p),继续看第5行,减去偏移量为8的数,由于在第
2行%rax变成了 *(up->e2.next),则减数为 *(up->e2.next).e1.y
最后只剩左边的未知,结合C代码和第6行,偏移量为0,传递的是地址的参数,则为 up->e2.x
综上所述:

void proc(union ele *up){
    up->e2.x = *(*(up->e2.next).e1.p) - *(up->e2.next).e1.y
}

3.71

定义文档都找不到,写个屁啊

3.72

A:第5行计算8n+30,第6行的andq指令把该数向下舍入到最接近16倍数的值。
若n为奇数,则为8n+24;若n为偶数,则为8n+16

B:将s2舍入到最接近16倍数的值。(s2+15) & 0xffffff0

C:1.若要使e1的值最小,那么e2的值最大。要e2最大,则p最小,当p为16的倍数值加1时,e2=15,
然后使e1+e2的值最小,则n为偶数,8n+16-8n = 16,故e1为1最小时,n为偶数,s1%16=1。
2.若要使e1的值最大,那么e2的值最小。要e2最小,则p最大,当p为16的倍数值时,e2=0最小,
然后使e1+e2的值最大,故当n为奇数时,8n+24-8n=24,当e1最大为24时,n为奇数,s1%16=0。

D:s2的计算方式会保留s1的偏移量为最接近16的倍数值,p会以16的倍数对齐。

3.73

find_range:
    vxorps    %xmm1, %xmm1, %xmm1
    vucomiss  %xmm1, %xmm0
    jp  .L1
    ja  .L2
    jb  .L3
    je  .L4
   .L2:
     movl $2, %eax
     jmp  .Done
   .L3:
     movl $0, %eax
     jmp  .Done
   .L4:
     movl $1, %eax
     jmp  .Done
   .L1:
     movl $3, %eax
   .Done
       

3.74

find_range:
    vxorps %xmm1, %xmm1, %xmm1
    movq $0, %r8
    movq $1, %r9
    movq $2, %r10
    movq $3, %rax
    vucomiss %xmm1, %xmm0
    cmovl %r8, %rax
    cmove %r9, %rax
    cmova %r10, %rax

3.75

A:对于第n个参数,虚部传%xmm(2n-1),实部传%xmm(2n-2)

B: 虚部返回到%xmm1,实部返回到%xmm0

你可能感兴趣的:(深入理解计算机系统(第三版))