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

来源:互联网 发布:v2视频会议软件下载 编辑:程序博客网 时间:2024/04/29 03:09
/*
***3.54
***写出decode2的原型

*/

int decode2(int x ,int y, int z){int a = z - y;int b = (a << 15) >> 15;return (x ^ a) * b;}

/*
***3.55
*/
typedef long long ll_t;


void store_prod(ll_t *dest, ll_t x, int y){
*dest = x*y;
}


// dest at %ebp+8, x at %ebp + 12, y at %ebp + 20movl   12(%ebp), %esi        //将x的低位存到%esimovl   20(%ebp), %eax       //将y存到%eaxmovl   %eax, %edx   sarl   $31, %edx                  //将(y >> 31)存到%edxmovl   %edx, %ecximull   %esi, %ecx             //计算x_low * (y >> 31)存到%ecxmovl   16(%ebp), %ebx    //将x的高位存到%ebpimull   %eax, %ebx           //计算x_high * yaddl   %ebx, %ecx           //计算 x_high * y + x_low * (y >> 31) 存到%ecxmull   %esi                       //计算y * x_low 的无符号64位乘积leal   (%ecx, %edx), %edx    //将64位乘积的高位与x_high * y + x_low * (y >> 31)得到最终结果的高位movl   8(%ebp), %ecxmovl   %eax, (%ecx)movl   %edx, 4(%ecx)          //将结果写入目的内存地址

说明:

该汇编代码其实是y扩展至64位再进行两个64位数的乘积然后进行截断得到的。

事实上有:

y *{signed} x =
(y_high * 2^32 + y_low) *{signed} (x_high * 2^32 + x_low) =
y_high *{signed} x_high * 2^64 +
y_high *{signed} x_low * 2^32 +
y_low *{signed} x_high * 2^32 +
y_low *{signed} x_low(有符号的x_low与无符号的x_low相等,故可用mull指令)

而y_high *{signed} x_high由于乘以2^64,所以对结果不会产生影响。


/*
***3.56写出loop函数原型
*/

int loop(int x, int n){int result = 0x55555555;int mask;for(mask = 0x80000000;mask !=0; mask = (unsigned)mask >> (n & 0xFF)){result ^= x & mask;}return result;}

 

/*

***3.57用条件传送指令写函数cread_alt

*/

int cread_alt(int *xp){     int a = 0;     return *(xp ? xp : &t);}

思路:原来函数中的错误就是无论xp是否为NULL,都对其发生了间接引用。将引用符号放在最外面,那么当xp为NULL时,

条件传送指令将临时变量a的地址传送至%eax,故不会产生对xp的间接引用。下面贴上产生的汇编代码:

        subl$16, %esp.cfi_def_cfa_offset 20movl20(%esp), %eaxmovl$0, 12(%esp)leal12(%esp), %edxtestl%eax, %eaxcmove%edx, %eaxmovl(%eax), %eaxaddl$16, %esp.cfi_def_cfa_offset 4 ret

/*

***3.58

*/

int switch3(int *p1,int *p2,mode_t action){int result = 0;switch(action){case MODE_A:result = *p1;*p1 = *p2;break;case MODE_B:result = *p1 + *p2;*p2 = result;break;case MODE_C:*p2 = 15;result = *p1;break;case MODE_D:*p2 = *p1;result = 17;break;case MODE_E:result = 17;break;default:result = -1;break;}return result;}


/*

***3.59根据反汇编代码补全c语言代码

*/

int switch_prob(int x,int n){int result = x;switch(n){case 40:case 42:result <<=3;break;case 43:result >>=3break;case 44:result = (result<<3) - result;case 45:result *= result;result += 17;break;default:result += 17;break;}return result;}


/*

***3.60

*/

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

B.  根据汇编代码可得,9*j存在寄存器%eax中,63*i存在寄存器%edx中,对照公式可得S=7,T=9;

      最后一句movl     $2772    %eax   可知R = 2772/S/T/4 = 11


/*

***循环中的值的数量从6个减少到5个

*/

int car_prod_ele(int n,int A[n][n],int B[n][n],int i,int k){int j;int result = 0;int *ap = A[i];int *bp = &B[0][k];for(j = 0; j < n; j++){result += *ap * *bp;ap++;bp += n;}return result;}

这题没有想到很好的解法,以上代码经测试是将4n放到寄存器%ebp当中,实际上并没有减少循环值的数量,望高人指点。


/*

***3.62

*/

A.    M的值为19

B.    %edi保存i,%ecx保存j

C.  

void transpose(int A[M][M]){int i,j;for(i = 0;i < M;i++){int *p1 = &A[0][i];for(j = 0;j < i;j++){int *p2 = &A[i][0];int t = *p1;                 //交换对称的两个值*p1 = *p2;*p2 = t;p1 += M;                     //改变两个元素的指针p2 += 1;}}}

/*

***3.63

*/

E1 = 3n

E2 = 2n - 1

说明:%esi中存放的值为3n,再对照18行可知E1 = 3n;

            每次指针的值变化为8n - 4,可知E2 = 2n - 1。



/*

***3.64

*/

A.     8(%ebp)存放返回值result的地址;12(%ebp)存放s1.p;16(%ebp)存放s1.v。

B.     从高到低依次为s2.sum,s2.prod,s1.v,s1.p,&s2

C.     传递结构体参数时,结构体各参数从高到低依次压入栈中

D.     在8(%ebp)处有一个指向返回值结构体的指针,指针的值作为返回地址,根据返回地址写入值

 

/*

***3.65

*/

A=3

B=7

首先分析B,t的首地址和u的首地址相差20个字节,t本身占4字节,所以short数组s[B]占16个字节,根据四字节对齐的原则,可知B=7或8;

short x[A][B]占44个字节,当B=8时,A无解,当B=7时,可得A=3.

 


 

/*

***3.66

*/

A.   CNT = 7;

B.   struct a_struct{

                int   idx;

                int   x[6];

       }

这个题最难的地方是汇编代码的第十行,对照汇编代码和C代码可知,汇编代码的第十二行对应C代码的第九行,汇编代码的十三行对应C代码的十一行。

经过分析(事实上带有一些猜测),第十行add的第一个操作数就是ap->idx的值,加上7i的原因是a_struct中有7个整型变量(这与我们计算ap->idx的地址

为bp + 28i + 4)也是吻合的;然后我们分析汇编代码的十三行,前面的0x8应该看做0x4 + 0x4,第一个0x4是b_struct中left占的字节数,第二个0x4是a_struct

中idx占的字节数,所以可知idx是结构体第一个变量,另外,x是长度为6的数组。

 

/*

***3.67

*/

A.   下列字段的偏移量值是多少(以字节为单位)

   e1.p:   0

   e1.x:   4

   e2.y:   0

   e2.next:   4

 

B.   这个结构总共需要8个字节

C.  

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


/*

***3.68写一个good_echo函数,对任意长度的输入行都能工作(即时超过了缓冲区)

*/

#define N 50void good_echo(){char buf[N];while(fgets(buf,N,stdin) != NULL){for(int i = 0;i < N;i++){if(buf[i] == '1')return;if(buf[i] == '\0')break;putchar(buf[i]);}}}


 

/*

***3.69写出函数trace

*/

A.   给出该函数的C版本,使用while循环

long trace(tree_ptr tr){long result = 0;while(tp){result = tp->val;tp = tp->left;}return result;}


 

B.    该函数得到最左边叶子的val值。

 

 

/*

***3.70

*/

A.   生成这个函数的C版本

long traverse(tree_ptr tp){if(!tp)return 0x7fffffffffffffff;long min_left = traverse(tp ->left);long min_right = traverse(tp ->right);long min = min_left < min_right ? min_left : min_right;min = min < (tp ->val)? min : (tp ->val);return min;}


B.   这个函数是求树中val的最小值,若为空树,则返回0x7fffffffffffffff;




0 0
原创粉丝点击