2.68
题目:构建函数int lower_bits(int n)将int 变量的低n位置1,其余位置0。
-
思路:将~0左移n位与-1异或可得结果。
-
函数代码:
- 运行结果:
3.67
解析:
-
联合体的所有成员相对于基地址的偏移量都为0;
-
此结构空间要大到足够容纳最"宽"的成员
-
其对其方式要适合其中所有成员(4字节补齐)
-
对于2、3两点的解释:
-
联合体所占的空间不仅取决于最宽成员,还跟所有成员有关系,即其大小必须满足两个条件:1)大小足够容纳最宽的成员;2)大小能被其包含的所有基本数据类型的大小所整除。
-
具体例子:
union U1
{
char s[10];
int n;
double d;
};
- s占10字节,n占4字节,d占8字节,因此其至少需10字节的空间。然而其实际大小并不是10,用运算符sizeof测试其大小为16.这是因为这里存在字节对齐的问题,10既不能被4整除,也不能被8整除。因此补充字节到16,这样就符合所有成员的自身对齐了。
答案
A:
- 根据联合体的所有成员相对于基地址的偏移量都为0这一点,加上int占有4个字节,而地址(*next)也占有四个字节,即可做出此题。
- e1.p:0
- e1.x:4
- e2.y:0
- e2.next:4
B:
- 根据联合体的字节补齐和其满足的两个条件即可做出此题。
e1中int *p --4字节 int x---4字节 和为8字节
e2中int y --4字节 union ele *next --4字节 和为8字节
因为两个结构体所占有的字节大小均为8且符合字节补齐规则,所以该联合体结构总共需要8个字节。
C:
- 在做此题前先明确该联合体中,需要先访问成员才可以访问成员中的变量这一点,即你要获取x,必须要先获得e1,而后进入e1结构体访问x,最终形成e1.x。
1.很明显的movl 8(%ebp),%edx 此语句作用为get up at %edx
2.试着按顺序写出语句,但发现并不能确定每一个语句准确表示的是什么,所以就观察其中有特点的语句进行分析。
3.发现语句中subl (%edx), %eax表示为%eax = eax - (%edx),(%edx)为整数,并且%edx保存的是up,满足条件且偏移量为0的情况只有e2.y即,减数为up->e2.y。同时可得被减数存储在%eax中。
4.题目中有*(up->__)表示一个整数这个信息,再对应联合体结构中仅有int *p满足该条件,并且在汇编代码中,由上一步可知被减数存储在%eax中,可知movl (%eax), %eax是对被减数赋值的语句,可得在此语句之前%eax为地址,并且应该为up->e1.p,即被减数应该为up->e1.p。
5.但再往上看发现第三行的%eax是由(%ecx)获得,并且%ecx由4(%edx)获得,但%edx指向了up->e2.y,所以被减数应该是有4的偏移量,明显的%ecx应该为up->e2.next,对应的%eax为up->e2.next->e1.p。
6.最终只剩下得数的表示了,明显对应的是movl %eax,4(%ecx)这条语句,%ecx为up->e2.next,%ecx+4应该为up->e2.next->e1.x,即得数为up->e2.next->e1.x。
- 最终的结果:
up->e2.next->e1.x = *(up->e2.next->e1.p) - up->e2.y
4.47题:
- leave指令等价于如下代码序列:
rrmovl %ebp,%esp
popl %ebp
-
也就是说它要执行的动作是,将帧指针ebp的内容赋给栈指针esp,然后弹出ebp,栈指针+4,结果是消灭这个栈。
-
参照pop指令的格式,可以得出如下的过程:
取指阶段 icode:ifun<--M1[PC] = D:0
valP <= PC + 1 ;下一条指令地址
译码阶段 valB <= R[%ebp] ;得到ebp的值,这个值就是新的栈指针esp的值
执行阶段 valE <= valB + 4 ;栈指针的值+4
访存阶段 valM <= M4[valB] ;读ebp中的值
写回阶段 R[%esp] <= valE ;把更新后的指针赋值给esp
R[%ebp] <= valM ;弹出的ebp的值
6.31
A.E=4,B=4,S=8
所以C=EBS=128
B.
家庭作业7.11
题目
解答:
- 3、4行是数据段,开始于存储器地址0x08049448的位置,总的存储器大小是0x194字节,从文件偏移的0x448处开始的0xe8个字节初始化。
- 在加载之前,未初始化的全局变量不会在目标文件中分配存储空间,但是在加载之后,像.bss中的符号等数据需要占用空间,所以剩下的字节对应运行时将被初始化为0的.bss数据。
8.10
答案:
A. 调用一次,返回两次: fork
B. 调用一次,从不返回: execve, longjmp
C. 调用一次,返回一次或者多次: setjmp
9.13
A.虚拟地址:0x0040
13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0
B.地址翻译
参数 值
VPN 0x01
TLB索引 0x01
TLB标记 0x00
TLB命中 No
缺页 Yes
PPN -
家庭作业10.6
题目:
解答:
分析:
每一步输出。
1.打开文件一;2.打开文件二;3.关闭文件二;4.打开文件二
Unix外壳创建每个进程开始时都有三个打开的文件:
- 0:标准输入
- 1:标准输出
- 2:标准错误
打开fd1时描述符为3,打开fd2时描述符为4,关闭fd2之后再打开还是4。
第十一章家庭作业 11.7
11.7 拓展TINY,使它可以提供MPG视频文件。用一个真正的浏览器来检验你的工作。
- 答:在get_filetype函数里面添加:
else if(strstr(filename, ".mpg") || strstr(filename, ".mp4"))
strcpy(filetype, "video/mpg");
源代码:
#include "csapp.h"
void doit(int fd);
void read_requesthdrs(rio_t *rp);
int parse_uri(char *uri, char *filename, char *cgiargs);
void serve_static(int fd, char *filename, int filesize);
void get_filetype(char *filename, char *filetype);
void serve_dynamic(int fd, char *filename, char *cgiargs);
void clienterror(int fd, char *cause, char *errnum,
char *shorting,char *longmsg);
int main(int argc,char *argv[])
{
int listenfd,connfd,port,clientlen;
struct sockaddr_in clientaddr;
if(argc != 2)
{
fprintf(stderr,"usage: %s <port>
",argv[0]);
exit(0);
}
port = atoi(argv[1]);
listenfd = Open_listenfd(port);
while(1)
{
clientlen = sizeof(clientaddr);
connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);
doit(connfd);
Close(connfd);
}
}
void doit(int fd)
{
int is_static;
struct stat sbuf;
char buf[MAXLINE], method[MAXLINE],uri[MAXLINE],version[MAXLINE];
char filename[MAXLINE],cgiargs[MAXLINE];
rio_t rio;
/*read request line and headers*/
Rio_readinitb(&rio, fd);
Rio_readlineb(&rio, buf, MAXLINE);
sscanf(buf, "%s %s %s", method, uri, version);
if(strcasecmp(method,"GET"))
{
clienterror(fd, method, "501","Not Implemented",
"Tiny does not implement this method");
return;
}
read_requesthdrs(&rio);
/*prase URI from GET request*/
is_static = parse_uri(uri, filename, cgiargs);
if(stat(filename, &sbuf) < 0)
{
clienterror(fd, filename, "404","Not Found",
"Tiny couldn't find this file");
return;
}
if(is_static)//server static content
{
if(!(S_ISREG(sbuf.st_mode) || !(S_IRUSR & sbuf.st_mode)))
{
clienterror(fd, filename, "403","Forbidden",
"Tiny couldn't read the file");
return;
}
serve_static(fd, filename, sbuf.st_size);
}
else//server dynamic content
{
if(!(S_ISREG(sbuf.st_mode) || !(S_IXUSR & sbuf.st_mode)))
{
clienterror(fd, filename, "403","Forbidden",
"Tiny couldn't run the CGI program");
return;
}
serve_dynamic(fd, filename, cgiargs);
}
}
void clienterror(int fd, char *cause, char *errnum,
char *shortmsg, char *longmsg)
{
char buf[MAXLINE], body[MAXBUF];
/*Build the HTTP response body*/
sprintf(body, "<html><title>Tiny Error</title>");
sprintf(body, "%s<body bgcolor=""ffffff"">
",body);
sprintf(body, "%s%s: %s
",body,errnum,shortmsg);
sprintf(body, "%s<p>%s: %s
", body, longmsg, cause);
sprintf(body, "%s<hr><em>The Tiny Web Server</em><>
",body);
/*Print the HTTP response*/
sprintf(buf, "HTTP/1.0 %s %s
",errnum, shortmsg);
Rio_writen(fd, buf, strlen(buf));
sprintf(buf, "Content-type: text/html
");
Rio_writen(fd, buf, strlen(buf));
sprintf(buf, "Content-length: %d
",(int)strlen(body));
Rio_writen(fd, buf, strlen(buf));
Rio_writen(fd, body, strlen(body));
}
//read_requesthdrs()来跳过请求报头的信息,直到遇见表示报头结束的空文本行。
void read_requesthdrs(rio_t *rp)
{
char buf[MAXLINE];
Rio_readlineb(rp, buf, MAXLINE);
while(strcmp(buf, "
"))
{
Rio_readlineb(rp, buf, MAXLINE);
printf("%s", buf);
}
return;
}
int parse_uri(char *uri, char *filename, char *cgiargs)
{
char *ptr;
if(!strstr(uri, "cgi-bin"))//static content
{
strcpy(cgiargs, "");
strcpy(filename, ".");
strcat(filename, uri);
if(uri[strlen(uri)-1] == '/')
strcat(uri, "home.html");
return 1;
}
else
{
ptr = index(uri, '?');
if(ptr)
{
strcpy(cgiargs, ptr+1);
*ptr = ' ';
}
else
strcpy(cgiargs, "");
strcpy(filename, ".");
strcat(filename, uri);
return 0;
}
}
void serve_static(int fd, char *filename, int filesize)
{
int srcfd;
char *srcp, filetype[MAXLINE], buf[MAXBUF];
/*Send response headers to client*/
get_filetype(filename,filetype);
sprintf(buf, "HTTP/1.0 200 OK
");
sprintf(buf, "%sServer: Tiny Web Server
", buf);
sprintf(buf, "%sContent-lenght: %d
", buf, filesize);
sprintf(buf, "%sContent-type: %s
", buf, filetype);
Rio_writen(fd, buf, strlen(buf));
/*Send response body to client*/
srcfd = Open(filename, O_RDONLY, 0);
srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE,srcfd,0);
close(srcfd);
Rio_writen(fd, srcp, filesize);
Munmap(srcp, filesize);
}
void get_filetype(char *filename, char *filetype)
{
if(strstr(filename, ".html"))
strcpy(filetype, "text/html");
else if(strstr(filename, ".gif"))
strcpy(filetype, "image/gif");
else if(strstr(filename, ".jpg"))
strcpy(filetype, "image/jpeg");
else
strcpy(filetype, "text/plain");
}
void serve_dynamic(int fd, char *filename, char *cgiargs)
{
char buf[MAXLINE], *emptylist[]={NULL};
/*Return first part of HTTP response*/
sprintf(buf, "HTTP/1.0 200 OK
");
Rio_writen(fd, buf,strlen(buf));
sprintf(buf, "Server: Tiny Web Server
");
Rio_writen(fd, buf,strlen(buf));
if(Fork()==0)
{
setenv("QUERY_STRING", cgiargs, 1);
Dup2(fd, STDOUT_FILENO);
Execve(filename, emptylist,environ);
}
Wait(NULL);
}
12.18
A.(F)
B.(T)
C.(F)