1. 程式人生 > >深入理解計算機系統 第三版 第三章 家庭作業 答案

深入理解計算機系統 第三版 第三章 家庭作業 答案

3.58

long decode2(long x,long y,long z)
{
	int ret;
	y=y-z;
	x=x*y;
	ret=y;
	ret<<=63;
	ret>>=63;
    return ret^x;
}

算術左移63再右移63,得到的要麼是全0,要麼全1,取決於y的最低位

3.59

畫了個簡單的圖便於理解,要不很難說明白,圖中每個XY都是64位


現在分析彙編程式碼

movq rdx,rax    //rdx為x

cqto                //rdx被設定為rax的符號位擴充套件,也就是要麼0要麼-1(ffffffff),說白了現在rdx是x_h,rax是x_l

movq rsi,rcx    //rsi為y_l

sarq $63,rcx    //rcx為y_h,也是要麼0要麼-1

imulq rax,rcx    //rcx=y_h*x_l

imulq rsi,rdx    //rdx=x_h*y_l

addq rdx,rcx    //將前面兩個結果相加

mulq rsi            //x_l*y_l,得到,rax為低64位結果,rdx為進位

addq rcx,rdx    //進位rdx的值加上之前計算得到的兩個高位結果,得到最終的高64位

movq rax,(rdi)    //低64位結果賦給dest

movq rdx,8(rdi)    //高64位結果賦給dest+8開始地址

ret

3.60

long loop(long x,int n)
{
	long result=0;
	long mask;
	for(mask=1;maks!=0;mask=mask<<(n%256))
	{
		result|=(x+mask);
	}
	return result;
}

程式都寫出來了,下面ABCDE是個問題就明瞭了,不再贅敘

3.61

搞清楚函式在幹嘛就像簡單呢,xp地址為空,就返回0,要麼返回地址裡面的值也就是*xp,但是xp有可能為空,那麼用*xp就存在風險

所以,只能操作xp,不操作*xp,程式碼如下:

long cread_alt(long  *xp)
 {
     long x = 0;
     long *p = xp?xp:&x;
     return *p;
 }
3.62
MODE_A: result = *p2 ;*p2=*p1; break;
MODE_B: result = *p1 + *p2; *p1 = result; break;
MODE_C: *p1 = 59; result = *p2; break;
MODE_D: *p1 = *p2; result=27; break;
MODE_E: result = 27; break;
default: result = 12; break;

3.63

int switch_prob(int x, int n)
 {
     int result = x;
     switch(n)
     {
        case 60:
        case 62:
            result *= 8; break;
        case 63:
            result >>= 3; break;
        case 64:
            result <<= 4; 
            result -= x;
	    x=result;
        case 65:
            x *= x;
        case 61:
        default:
            result = x+0x4b; break;
     }
     return result;
 }

3.64

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

B:可以很容易看出rdx=65i+13j+k,所以T=13;S=5,R=3640/(8*65)=7

3.65

A:rdx

B:rax

C:8M=120,M=15

3.66

NR(n)=3n

NC(n)=1+4n 不是1+4n再<<3這是乘以8是因為long每個8位元組

3.67

A:呼叫process之前,棧結構:(呼叫進入時會多壓入一個返回地址,要注意區別,rsp會減8)


B:結構體strA s

CDE,其實看圖也看的出來,只是區別在於多壓進去一個返回地址,所以圖中的rsp都要少8,來訪問

F:允許我略

3.68

這題關鍵在於理解資料對齊,這兩個結構體都是8位元組對齊

首先t偏移位8,知道1<=B<=8

然後u偏移32,知道32-8-4=20,頭兩個short(4位元組)和int對齊8位元組,剩下的16位元組佔了兩排,7<=A<=10

最後184偏移是y,int兩個兩個佔一排(一排8位元組),最後一排可能滿也可能缺一,所以可能有184/4=46,或45個int,那麼結合前面的知道B=5,A=9;

3.69

注意還是8位元組對齊

首先0x120=288,偏移位last

int first和浪費的4位元組佔一排,那麼中間288-8=280位元組位結構體陣列a

然後bp+40*i+8為結構體的初始地址也就是ap的地址也是ap->idx的地址,這裡的8是int first和4位元組剩餘的

這裡我們知道了每個結構體是40位元組,那麼cnt=280/40=7

然後注意到movslq指令,猜測idx為int,x為long陣列

最後0x10+rax+rdx*8這裡乘8說明了是long型,變形一下,8+bp+40*i+8+rdx*8,這裡rdx就是idx,8+bp+40*i什麼意思上面已經解釋了,再加8是假的int idx和剩餘的4位元組

那麼long陣列的個數是多少,40-8/8=4所以:

a_struct{int idx ; long x[4];}

3.70

A:0,8,0,8

B:16

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

3.71

不可能申請一個無窮大的空間給你一次讀進來,所以只能一次讀有限個位元組分多次讀取,然後一個個輸出

void good_echo()
 {
     const int BufferSize = 0x8;
     char buf[BufferSize];
     int i;
     while(fgets(buf, BufferSize, stdin)!=NULL)
     {
         for(i=0;buf[i];i++)
            putchar(buf[i]);
         if(i<BufferSize-1) break;
     }
     return;
 }

3.72

A:n為奇數的時候取8n+24,為偶數取8n+16,向16取整數倍

B:向上取16的整數倍

C:n=0,s1=16時候,e1最大為16

n=1,s1=1時候,e1最小為1

D:都是16對齊

3.73

vxorps xmm0,xmm0,xmm0
movl $3,eax
vucomiss xmm0,xmm1 	//cmp x:0
 ja .L1			//大於0
 je .L2			//等於0
 jb .L3			//小於0
 jp .L4
 .L3:
	subl $1,eax
 .L2:
	subl $1,eax
 .L1:
	subl $1,eax
 .L4:
	rep;ret

3.74

vxorps xmm0,xmm0,xmm0
movl $3,eax
movl $2,ebx
movl $1,ecx
movl $0,edx
vucomiss xmm0,xmm1 	//cmp x:0
cmova ebx,eax			//大於0
cmove ecx,eax			//等於0
cmovb edx,eax			//小於0
.L4:
	rep;ret

3.75

A:單個引數時候xmm0是實部,xmm1是虛部,兩個時候第一個一樣,第二個的實部在xmm2,虛部在xmm3

B:xmm0返回實部,xmm1返回虛部.