跨境派

跨境派

跨境派,专注跨境行业新闻资讯、跨境电商知识分享!

当前位置:首页 > 卖家故事 > HNU-计算机系统-CSAPP作业答案

HNU-计算机系统-CSAPP作业答案

时间:2024-04-24 16:15:27 来源:网络cs 作者:付梓 栏目:卖家故事 阅读:

标签: 作业  答案  系统  计算机 
阅读本书更多章节>>>>

计算机系统CSAPP课后作业答案

计科210X wolf 202108010XXX

在这里插入图片描述

第2章

2.61

在这里插入图片描述

解:

(!~x) || (!x) || (!~(x|0x00ffffff)) || (!(x&0x000000ff))

或者:

(!~x) || (!x) || (!~(x>>24)) || (!(x<<24))

2.71

在这里插入图片描述

A.

实现的是逻辑位移,扩展后前面全是0,不符合符号扩展的要求

B.

int xbyte(packed_t word,int bytenum){  return ((int)word<<((3-bytenum)<<3))>>24;}
2.87

在这里插入图片描述

格式A格式B
1 01110 001-9/161 0110 0010-9/16
0 10110 1012080 1110 1010208
1 00111 110-7/2^101 0000 0111-7/2^10
0 00000 1015/2^170 0000 00011/2^10
1 11011 000-2^121 1111 0000-inf
0 11000 1007680 1111 0000+inf
2.88

在这里插入图片描述

前置知识:

在IEEE754下,

32位包括符号位1位,阶码8位,尾数23位,其阶码偏置量为127;

64位包括符号位1位,阶码11位,尾数52位,其阶码偏置量为1023;

下面的讨论都在上述条件下进行

A. 不总是为1;

该式等价于(double)(float)x==(double)x,但因为将x转换为double和float时有可能发生float无法精确表示该int而double可以精确表示该int的情况,而从float到double这一步不会发生问题,可以精确表示。所以可能等式不成立,下面给出反例。

反例:取x=67,108,863

其64位表示为0 10000011000 11111111111111111111111110……

(尾数有25个1,其阶码E=1048=1023+25,尾数M=1.11……(小数点后25个1))

在这里插入图片描述

而对其进行32位表示时由于32位的尾数只有23位,无法精确表示该数,所以会发生舍入,导致(float)x!=(double)x

B. 不总是为1;

该式等价于(double)x+(double)y==(double)(x+y)

反例:取x=y=(1.11……1)*2^1023,即所能表示最大的数,此时右边溢出,等式不成立
【更正】反例:取x=y=MAX_INT=2^32-1(本机器上),x+y发生溢出,导致产生意外的double结果,实际上等式不成立。

C. 总是为1;

由加法交换律。即使溢出,其溢出值也相同,等式左右相等。

D. 不总是为1;

从一个角度说,若溢出,其溢出值可能不同,等式左右不一定相等。

从另一个角度,double无法精确表示2^64以内的所有整数,所以在第一次乘法后就已经开始产生误差了。

E. 不总是为1;

反例:取x=0,y≠0,有左边=inf≠右边

第3章

3.34

在这里插入图片描述

A.

是调用者接收到的x(也就是未被右移过的x)

B.

int rfun(unsigned x){  if (x == 0)     return 0;  unsigned nx = x >> 1;  int rv = rfun(nx);  return ((x & 0x1) + rv);}

C.

递归计算二进制数x中有多少个1(或表述为计算参数x中位的和)

3.56

在这里插入图片描述

A.

%esi保存x

%ebx保存n

%edi保存result

%edx保存mask

B.

Result初值为0x55555555

Mask初值为0x80000000

C.

测试条件为mask是否为0

D.

Mask右移(n&0x000000ff)位

E.

Result^= (mask & x)

F.代码如下

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

在这里插入图片描述

补全代码如下:

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

在这里插入图片描述

解:

先写答案

A.CNT=7

B.完整声明如下

typedef struct{  int idx;  int x[6];} a_struct;

这题有点意思,我还想写一下****解题的过程****。

第13行的mov将%eax移到一个地址,此时的%eax里应该是计算出的n,所以结合第11和第12行,发现这两行实际上算的是int n = bp->left + bp->right,对应bp->left地址就是一开始存在%ecx中的(bp),而bp->right是(bp+0xc8),也就是(bp+200),所以可以推断a_struct[CNT]共占196字节。(这里bp表示0xc%ebp,为方便简写为bp)

然后我们可以分析含信息量最多的第10行,第9行我们可以看到%edx内是7i。来到第10行,%edx内存入的是【(bp+4+28i)所在内存的值+7i】,这里为什么加上7i有点费解,我留在后面探究,但是(bp+4+28i)应该是比较好看懂的,这个应该就是a[i]所在的地址,由此我们知道a_struct一个应该占28字节,用196÷28=7,可以得知CNT=7。

而且其实从这里也很好看出既然取的是(bp+4+28i),说明这应该就是idx的地址,也就是说在a_struct内部,idx先于x被定义。这一点后面还有验证。

最后我们重新分析第13行,这次我们分析mov的终点。是0x8(%ecx,%edx,4),也就是(4%edx+bp+8),由上面我们知道%dex内是什么,代入后,实际上mov的终点是(bp+4+28i+4+4*【(bp+4+28i)所在内存的值】)。

现在一切都清晰了!!“bp+4+28i”定位到a[i];“+4”是因为有idx是4字节,所以从这里可以验证idx应该在结构中定义在前面;“+4*【(bp+4+28i)所在内存的值】”定位到bp->a[i]->x[bp->a[i]->idx],也就是ap->x[ap->idx]。

再回到解题上,一个a_struct共28字节,int型的x占4字节,剩下24字节应该就是一个6位int数组,故int x[6]。

至此这道题应该就完全理顺了。

第5章

5.19

在这里插入图片描述

#include <bits/stdc++.h>void *my_memset(void *s, int c, size_t n){    size_t K = sizeof(unsigned long);    size_t cnt = 0;    // 开始部分进行字节级的写直到对齐    unsigned char *schar = (unsigned char *)s;    while ((size_t)schar % K != 0 && cnt < n)    {        *schar++ = (unsigned char)c;        cnt++;    }    // 合成longc满足K个字节,每个字节都是c的低位    unsigned long longc;    unsigned char *temp = (unsigned char *)&longc;    size_t i = 0;    while (i < K)    {        *temp++ = (unsigned char)c;        i++;    }    // 对齐后进行字级的写    unsigned long *slong = (unsigned long *)schar;    while (cnt + K < n)    {        *slong++ = longc;        cnt += K;    }    // 结尾部分可能的未成字部分进行字节级的写    schar = (unsigned char *)slong;    while (cnt < n)    {        *schar++ = c;        cnt++;    }    return s;}int main(){    char m[10];    my_memset((void *)m, 0x11223344, sizeof(m));    std::cout << (size_t)m % sizeof(unsigned long) << "\n";    for (size_t i = 0; i < sizeof(m) / sizeof(char); i++)    {        std::cout << "count " << i << ": " << std ::hex << (int)m[i] << "\n";    }    return 0;}

测试结果:1b78b6eb044dda208dc46de4374bb633

5.20

在这里插入图片描述

double Polynomial_summation(double a[], double x, long degree){    long i;    double sum0 = 0, sum1 = 0;    double xpwr0 = 1, xpwr1 = x;    double x_step = x * x;    // 循环展开    for (i = 0; i < degree - 2; i += 2)    {        // 二路并行        sum0 = sum0 + a[i] * xpwr0;        sum1 = sum1 + a[i + 1] * xpwr1;        xpwr0 *= x_step;        xpwr1 *= x_step;    }    // 补充完整剩余的部分    double sum_rest = 0;    for (; i < degree; i++)    {        sum_rest = sum_rest + a[i] * xpwr0;    }    return sum0 + sum1 + sum_rest;}

第6章

6.1

在这里插入图片描述

25%

6.2

在这里插入图片描述

25%

6.3

在这里插入图片描述

25%

6.4

在这里插入图片描述

假设数据块的宽度为B,其生成由cache的容量C绝决定且有2*B^2<C,在此情况下B取最大值。

假设数据块的宽度为B,即每次读入B个数据,其生成由cache的容量C决定且有2*B^2<=C,在此情况下B取最大值。
以下为尝试的代码实现

#define B width_of_Block //2*B^2<=Cvoid transpose_AsSoonAsPossible(int *dst, int *src, int dim){    long border=dim*dim;    for ( int i=0; i<dim; i+=B; )    {        for ( int j=0; j<dim; j+=B; )        {            //确定一次作用的数据块的起始位置(即块的左上角的那个位置)            for ( int m=i; m<i+B; m++)            {                for ( int n=j; n<j+B; n++)                {                    //对数据块的每一个位置进行操作                    int dst_pos = n*dim + m;                    int src_pos = m*dim + n;                    if ( dst_pos<border && src_pos<border)                     //必须保证不能超出边界(矩阵不一定是阵)                    {                        dst[dst_pos]=src[src_pos];                    }                }            }        }    }}

验证程序:

// 假设数据块的宽度为B,即每次读入B个数据,其生成由cache的容量C决定且有2 *B ^ 2 <= C, 在此情况下B取最大值。// 下为尝试的代码实现#define width_of_Block 4#define B width_of_Block // 2*B^2<=Cvoid transpose_AsSoonAsPossible(int *dst, int *src, int dim){    long border = dim * dim;    for (int i = 0; i < dim; i += B)    {            for (int j = 0; j < dim; j += B)        {                     //确定一次作用的数据块的起始位置(即块的左上角的那个位置)            for (int m = i; m < i + B; m++)            {                for (int n = j; n < j + B; n++)                                {                        //对数据块的每一个位置进行操作                int dst_pos = n * dim + m;                    int src_pos = m * dim + n;                    if (dst_pos < border && src_pos < border)                    //必须保证不能超出边界                    {                        dst[dst_pos] = src[src_pos];                    }                }            }        }    }}int main(){int N=15;    int *src=malloc(sizeof(int)*N*N);    //initializationfor (int i=0;i<N;i++)for (int j=0;j<N;j++)src[i*N+j]=i;printf("original:\n");for (int i=0;i<N;i++){for (int j=0;j<N;j++)printf("%d ",src[i*N+j]);printf("\n");}int *dst=malloc(sizeof(int)*N*N);    transpose_AsSoonAsPossible(dst, src, N);    printf("\nanswer:\n");    for (int i=0;i<N;i++){for (int j=0;j<N;j++)printf("%d ",dst[i*N+j]);printf("\n");}free(dst);free(src);}

在这里插入图片描述

第7章

7.12

在这里插入图片描述

图7-10中的行号地址
150x80483cb0x804945c
160x80483d00x8049458
180x80483d80x8049548
180x80483dc0x8049458
230x80483e70x8049548
7.13

在这里插入图片描述

代码如下

extern int ps(void);int x=1;int *xp=&x;void p2(int y){}void p1(){    p2(*xp+p3());}

将其保存为t2.c文件

使用gcc -c t2.c生成可重定位的目标文件

使用objdump -D t2.o > m.txt反汇编并保存在m.txt内。在m.txt查看.text和.data

Disassembly of section .text:00000000 <p2>:   0:55                   push   %ebp   1:89 e5                mov    %esp,%ebp   3:5d                   pop    %ebp   4:c3                   ret    00000005 <p1>:   5:55                   push   %ebp   6:89 e5                mov    %esp,%ebp   8:53                   push   %ebx   9:83 ec 14             sub    $0x14,%esp   c:a1 00 00 00 00       mov    0x0,%eax  11:8b 18                mov    (%eax),%ebx  13:e8 fc ff ff ff       call   14 <p1+0xf>  18:01 d8                add    %ebx,%eax  1a:89 04 24             mov    %eax,(%esp)  1d:e8 fc ff ff ff       call   1e <p1+0x19>  22:83 c4 14             add    $0x14,%esp  25:5b                   pop    %ebx  26:5d                   pop    %ebp  27:c3                   ret   
Disassembly of section .data:00000000 <x>:   0:01 00                add    %eax,(%eax)...00000004 <xp>:   4:00 00                add    %al,(%eax)...

使用readelf -a t2.o可查看

Relocation section '.rel.text' at offset 0x434 contains 3 entries: Offset     Info    Type            Sym.Value  Sym. Name0000000d  00000901 R_386_32          00000004   xp00000014  00000c02 R_386_PC32        00000000   p30000001e  00000a02 R_386_PC32        00000000   p2Relocation section '.rel.data' at offset 0x44c contains 1 entries: Offset     Info    Type            Sym.Value  Sym. Name00000004  00000801 R_386_32          00000000   x

在这里插入图片描述

根据上述elf信息可推断

A.

节偏移重定位类型符号名字
0xd绝对引用xp
0x14相对引用p3
0x1e相对引用p2

B.

节偏移重定位类型符号名字
0x4绝对引用x
7.14

在这里插入图片描述

题目代码如下:

int relo3(int val){switch(val){case 100:return (val);case 101:return (val+1);case 103: case 104:return (val+3);case 105:return (val+5);default:return (val+6);}}

保存为t3.c文件

使用gcc -c t3.c生成可重定位的目标文件

使用objdump -D t3.o > m.txt反汇编并保存在m.txt内。在m.txt查看.text和.data

截图如下

在这里插入图片描述

查看m.txt中.text与.rodata段

Disassembly of section .text:00000000 <relo3>:   0:55                   push   %ebp   1:89 e5                mov    %esp,%ebp   3:8b 45 08             mov    0x8(%ebp),%eax   6:83 e8 64             sub    $0x64,%eax   9:83 f8 05             cmp    $0x5,%eax   c:77 26                ja     34 <relo3+0x34>   e:8b 04 85 00 00 00 00 mov    0x0(,%eax,4),%eax  15:ff e0                jmp    *%eax  17:8b 45 08             mov    0x8(%ebp),%eax  1a:eb 1e                jmp    3a <relo3+0x3a>  1c:8b 45 08             mov    0x8(%ebp),%eax  1f:83 c0 01             add    $0x1,%eax  22:eb 16                jmp    3a <relo3+0x3a>  24:8b 45 08             mov    0x8(%ebp),%eax  27:83 c0 03             add    $0x3,%eax  2a:eb 0e                jmp    3a <relo3+0x3a>  2c:8b 45 08             mov    0x8(%ebp),%eax  2f:83 c0 05             add    $0x5,%eax  32:eb 06                jmp    3a <relo3+0x3a>  34:8b 45 08             mov    0x8(%ebp),%eax  37:83 c0 06             add    $0x6,%eax  3a:5d                   pop    %ebp  3b:c3                   ret    
00000000 <.rodata>:   0:17                   pop    %ss   1:00 00                add    %al,(%eax)   3:00 1c 00             add    %bl,(%eax,%eax,1)   6:00 00                add    %al,(%eax)   8:34 00                xor    $0x0,%al   a:00 00                add    %al,(%eax)   c:24 00                and    $0x0,%al   e:00 00                add    %al,(%eax)  10:24 00                and    $0x0,%al  12:00 00                add    %al,(%eax)  14:2c 00                sub    $0x0,%al...

使用readelf -a t3.o可查看

Relocation section '.rel.text' at offset 0x42c contains 1 entries: Offset     Info    Type            Sym.Value  Sym. Name00000011  00000501 R_386_32          00000000   .rodataRelocation section '.rel.rodata' at offset 0x434 contains 6 entries: Offset     Info    Type            Sym.Value  Sym. Name00000000  00000201 R_386_32          00000000   .text00000004  00000201 R_386_32          00000000   .text00000008  00000201 R_386_32          00000000   .text0000000c  00000201 R_386_32          00000000   .text00000010  00000201 R_386_32          00000000   .text00000014  00000201 R_386_32          00000000   .text

根据上述elf信息可推断

A.

节偏移重定位类型符号名字
0x11绝对引用.rodata

B.

节偏移重定位类型符号名字
0x0绝对引用.text
0x4绝对引用.text
0x8绝对引用.text
0xc绝对引用.text
0x10绝对引用.text
0x14绝对引用.text

第8章

8.23

在这里插入图片描述

当父进程接收到第一个SIGUSR2信号之后,父进程进入信号处理例程。与此同时,由于隐式阻塞机制,剩余4个该类信号SIGUSR2被阻塞,并没有被接收。其中只有1个被视为待处理信号而被保存,其余的3个被丢弃。因此最终只有2个被处理,counter最终结果为2。

这是书上对于信号的基础概念。简单来说就是同一时间同一信号最多处理一个,挂起一个,丢弃剩余全部。

8.20

在这里插入图片描述

代码如下:

#include <unistd.h>#include <stdio.h>#include <stdlib.h> int main(int argc, const char *argv[], const char *envp[]){    if (execve("/bin/ls", argv, envp) < 0)    {        printf("/lib/ls not found.\n");        return -1;            }    return 0;}

测试结果:

在这里插入图片描述

第9章

第一题

请完成《深入理解计算机系统》(第2版)P586588,9.119.13,请体现你的完成过程。

示例内存系统如下:

在这里插入图片描述

9.11

在这里插入图片描述

答案:在这里插入图片描述

9.12

在这里插入图片描述
答案:
在这里插入图片描述

9.13

在这里插入图片描述

答案:
在这里插入图片描述

第二题

设若有一个输入文件hello.txt,由字符串“Hello,World!\n”组成,编写一个C程序,使用mmap将该txt文件的内容修改为“Hello, HNU!\n”。

代码如下:

#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <sys/mman.h> int main(){    int fd = open("hello.txt",O_RDWR,0);    char *start = mmap(NULL,1,PROT_WRITE,MAP_SHARED,fd,0);    ftruncate(fd,11);    close(fd);    if(start == MAP_FAILED)printf("error!\n");else{char* newstr="Hello,HNU!\n";char *temp = start;int i=0;for (; i<11;temp++,i++)*temp=newstr[i];munmap(start,1);return 0;}}

使用程序前后:
在这里插入图片描述

阅读本书更多章节>>>>

本文链接:https://www.kjpai.cn/gushi/2024-04-24/161887.html,文章来源:网络cs,作者:付梓,版权归作者所有,如需转载请注明来源和作者,否则将追究法律责任!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。

文章评论