for (a = 0 ; a < N ; a += 8) { for (b = 0 ; b < M ; b += 8) { for (c = b ; c < b + 8 ; ++c) { for (d = a + c - b ; d >= a ; --d) { B[c][d] = A[d][c]; } for (d = a + c - b + 1 ; d < a + 8 ; ++d) { B[c][d] = A[d][c]; } } } }
for (a = 0 ; a < M ; a += 8) { for (b = 0 ; b < N ; b += 8) { for (c = a ; c < a + 4 ; ++c) { for (d = b + c - a ; d >= b ; -- d) { B[c][d] = A[d][c]; } for (d = b + c - a + 1; d < b + 4 ; ++d) { B[c][d] = A[d][c]; } }
for (c = a + 4; c < a + 8 ; ++c) { for (d = b + c - a ; d >= b + 4 ; --d) { B[c][d] = A[d][c]; } for (d = b + c - a + 1 ; d < b + 8 ; ++d) { B[c][d] = A[d][c]; } }
for (a = 0 ; a < N ; a += 16) { for (b = 0 ; b < M ; b += 16) { for (c = b ; (c < b + 16) && (c < M) ; ++c) { for (d = a ; (d < a + 16) && (d < N) ; ++d) { B[c][d] = A[d][c]; } } } }
实际测试的缓存不命中数是1847次。
实验结果
自动评分脚本给出的输出如下:
1 2 3 4 5 6 7
Cache Lab summary: Points Max pts Misses Csim correctness 27.0 27 Trans perf 32x32 8.0 8 287 Trans perf 64x64 8.0 8 1219 Trans perf 61x67 10.0 10 1847 Total points 53.0 53
voideval(char *cmdline) { char * argv[MAXARGS]; char buf[MAXLINE]; int bg; /* if run in background */ pid_t pid;
sigset_t mask_all, mask_chld, prev_chld;
/*initialize signal sets*/ Sigfillset(&mask_all); Sigemptyset(&mask_chld); Sigaddset(&mask_chld, SIGCHLD);
strcpy(buf, cmdline); bg = parseline(buf, argv); /* parse the command line */ if (argv[0] == NULL) { return; } /* handles if there is empty input */
if (!builtin_cmd(argv)) { /* if the command line is builtin command */ Sigprocmask(SIG_BLOCK, &mask_chld, &prev_chld); /* block SIGCHLD to avoid potential race between addjob and deletejob */ if ((pid = Fork()) == 0) { Setpgid(0, 0); /* give the child process a new group id to handle SIGINT correctly */ Sigprocmask(SIG_SETMASK, &prev_chld, NULL); /* unblock SIGCHLD */ Execve(argv[0], argv, environ); } Sigprocmask(SIG_BLOCK, &mask_all, NULL); /* mask all signals to avoid potential races */ addjob(jobs, pid, bg + 1, cmdline); /* add job to joblist */ Sigprocmask(SIG_SETMASK, &prev_chld, NULL); if (!bg) { /* if the process should be exeuted in foreground */ waitfg(pid); /* fg wait explictly */ } else { printf("[%d] (%d) %s", pid2jid(pid), pid, cmdline); /* bg print message*/ } }
return; }
intbuiltin_cmd(char **argv) { /* handles the builtin command in current context */ if (!strcmp(argv[0], "quit")) { exit(0); /* quit: exit directly*/ } if (!strcmp(argv[0], "jobs")) { listjobs(jobs); /* jobs: print the current job list */ return1; } if (!strcmp(argv[0], "bg") || !strcmp(argv[0], "fg")) { do_bgfg(argv); /* bg|fg: handles in function do_bgfg */ return1; } if (!strcmp(argv[0], "&")) { return1; /* returns 1 for empty & */ } return0; /* not a builtin command */ }
voiddo_bgfg(char **argv) { int number = 0; /* used to store the converted number */ char * ptr = argv[1]; /* get the pointer to argument 1 */ char * endptr = NULL; /* used for error handling */ structjob_t * job = NULL;/* used to store job pointer */ if (!argv[1]) { /* returns if missing argument */ printf("%s command requires PID or %%jobid argument\n", argv[0]); return; } if (*ptr == '%') { /* if argument 1 is job ID */ ptr++; /* adjust pointer */ number = strtol(ptr, &endptr, 10); if (ptr == endptr) { /* handles convert error */ printf("%s: argument must be a PID or %%jobid\n", argv[0]); return; } job = getjobjid(jobs, number); /* get the job */ if (!job) {/* handles if there is no such job */ printf("%%%d: No such job\n", number); return; } } else {/* if argument 1 is pid */ number = strtol(ptr, &endptr, 10); if (ptr == endptr) { /* handles convert error */ printf("%s: argument must be a PID or %%jobid\n", argv[0]); return; } job = getjobpid(jobs, (pid_t)number); /* get the job */ if (!job) {/* handles if there is no such job */ printf("(%d): No such process\n", number); return; } } /* change process state and update the job list*/ if (!strcmp(argv[0], "bg")) { /*bg: turns ST to BG, send SIGCONT */ if(job->state == ST) { Kill(-(job->pid), SIGCONT); printf("[%d] (%d) %s", job->jid, job->pid, job->cmdline); job->state = BG; } } elseif (!strcmp(argv[0], "fg")) {/* fg: turns ST/BG to FG, sent SIGCONT */ if(job->state == ST) { Kill(-(job->pid), SIGCONT); job->state = BG; } if(job->state == BG) { job->state = FG; waitfg(job->pid); } } return; }
voidwaitfg(pid_t pid) { while(fgpid(jobs)) { /* handles all zombie processes in signal handler */ sleep(0.01); /* busy loop only */ } return; }
voidsigchld_handler(int sig) { int olderrno = errno; /* store old errno */ int status; /* used to trace pid's status */ sigset_t mask_all, prev_all; pid_t pid;
Sigfillset(&mask_all);
while((pid = Waitpid(-1, &status, WUNTRACED | WNOHANG)) > 0) { /* waitpid without waiting(WNOHANG) */ if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTSTP || WSTOPSIG(status) == SIGSTOP)) { /* if the process is stopped */ structjob_t * job = getjobpid(jobs, pid); if (job && job->state != ST) { /* if the stop signal hasn't been catched */ printf("Job [%d] (%d) stopped by signal %d\n", pid2jid(pid), pid, WSTOPSIG(status)); structjob_t * stpjob = getjobpid(jobs, pid); stpjob->state = ST;/* handles here */ } } if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT) { /* it the terminate signal hasn't been catched */ structjob_t * job = getjobpid(jobs, pid); if (job) { printf("Job [%d] (%d) terminated by signal %d\n", pid2jid(pid), pid, WTERMSIG(status)); /* handles here */ } } if (WIFEXITED(status) || WIFSIGNALED(status)) { Sigprocmask(SIG_BLOCK, &mask_all, &prev_all); deletejob(jobs, pid); Sigprocmask(SIG_SETMASK, &prev_all, NULL); }/* remove the job in job list accordingly */ } errno = olderrno; return; }
voidsigint_handler(int sig) { int olderrno = errno; /* store old errno */ sigset_t mask_all, prev_all; Sigfillset(&mask_all); Sigprocmask(SIG_BLOCK, &mask_all, &prev_all); /* block all signal in case the race between SIGINT and SIGCHLD */
pid_t pid; pid = fgpid(jobs); Kill(-pid, SIGINT); /* kill processes in fg job's process group */
printf("Job [%d] (%d) terminated by signal %d\n", pid2jid(pid), pid, sig); /* print the message */
deletejob(jobs, pid); /* delete job in joblist */
Sigprocmask(SIG_SETMASK, &prev_all, NULL);
errno = olderrno; return; }
voidsigtstp_handler(int sig) { int olderrno = errno; /* store old errno */ sigset_t mask_all, prev_all; Sigfillset(&mask_all); Sigprocmask(SIG_BLOCK, &mask_all, &prev_all); /* block all signal in case the race between SIGTSTP and SIGCHLD */
pid_t pid; pid = fgpid(jobs); Kill(-pid, SIGTSTP); /* send SIGTSTP to fg job's process group */
printf("Job [%d] (%d) stopped by signal %d\n", pid2jid(pid), pid, sig); /* print the message */
structjob_t * stpjob = getjobpid(jobs, pid); stpjob->state = ST; /* modify the job list */
The core data structure deals with image representation. A pixel is a structasshownbelow: typedefstruct { unsignedshort red; /* R value */ unsignedshort green; /* G value */ unsignedshort blue; /* B value */ } pixel;
此外,为了简化起见,还定义了如下的宏:
1
#define RIDX(i,j,n) ((i)*(n)+(j))
旋转操作的朴素版本如下:
1 2 3 4 5 6 7
voidnaive_rotate(int dim, pixel *src, pixel *dst){ int i, j; for(i=0; i < dim; i++) for(j=0; j < dim; j++) dst[RIDX(dim-1-j,i,dim)] = src[RIDX(i,j,dim)]; return; }
平滑操作的朴素版本如下(辅助函数未列出):
1 2 3 4 5 6 7
voidnaive_smooth(int dim, pixel *src, pixel *dst){ int i, j; for(i=0; i < dim; i++) for(j=0; j < dim; j++) dst[RIDX(i,j,dim)] = avg(dim, i, j, src); /* Smooth the (i,j)th pixel */ return; }
voidblock_rotate(int dim, pixel * src, pixel * dst){ int i, j, k, l; int cst0 = dim - 1; for (i = 0 ; i < dim ; i += 8) { for (j = 0 ; j < dim ; j += 8) { for (k = i ; k < i + 8 ; k++) { for (l = j ; l < j + 8 ; l++) { dst[RIDX(cst0 - l, k, dim)] = src[RIDX(k, l, dim)]; } } } } }
Usage: ./csim-ref [-hv] -s <s> -E <E> -b <b> -t <tracefile> • -h: Optional help flag that prints usage info • -v: Optional verbose flag that displays trace info • -s <s>: Number of set index bits (S = 2 s is the number of sets) • -E <E>: Associativity (number of lines per set) • -b <b>: Number of block bits (B = 2 b is the block size) • -t <tracefile>: Name of the valgrind trace to replay
linux> ./csim-ref -v -s 4 -E 1 -b 4 -t traces/yi.trace L 10,1 miss M 20,1 miss hit L 22,1 hit S 18,1 hit L 110,1 miss eviction L 210,1 miss eviction M 12,1 miss eviction hit hits:4 misses:5 evictions:3
user@BlackDragon ~/C/B/buflab-handout> cat level0.txt|./hex2raw|./bufbomb -u BlackDragon Userid: BlackDragon Cookie: 0x3dde924c Type string:Smoke!: You called smoke() VALID NICE JOB! run with level1
voidfizz(int val) { if (val == cookie) { printf("Fizz!: You called fizz(0x%x)\n", val); validate(1); } else printf("Misfire: You called fizz(0x%x)\n", val); exit(0); }
user@BlackDragon ~/C/B/buflab-handout> gdb bufbomb GNU gdb (GDB) 7.12.1 Copyright (C) 2017 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty"for details. This GDB was configured as "x86_64-pc-linux-gnu". Type "show configuration"for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type"help". Type "apropos word" to search for commands related to "word"... Reading symbols from bufbomb...(no debugging symbols found)...done. (gdb) break getbuf Breakpoint 1 at 0x80491fa (gdb) run -u BlackDragon Starting program: /home/user/CSAPPLabs/BufferLab/buflab-handout/bufbomb -u BlackDragon Userid: BlackDragon Cookie: 0x3dde924c
user@BlackDragon ~/C/B/buflab-handout> cat level2.txt|./hex2raw|./bufbomb -u BlackDragon Userid: BlackDragon Cookie: 0x3dde924c Type string:Bang!: You set global_value to 0x3dde924c VALID NICE JOB!
user@BlackDragon ~/C/B/buflab-handout> cat level4.txt|./hex2raw -n|./bufbomb -u BlackDragon -n Userid: BlackDragon Cookie: 0x3dde924c Type string:KABOOM!: getbufn returned 0x3dde924c Keep going Type string:KABOOM!: getbufn returned 0x3dde924c Keep going Type string:KABOOM!: getbufn returned 0x3dde924c Keep going Type string:KABOOM!: getbufn returned 0x3dde924c Keep going Type string:KABOOM!: getbufn returned 0x3dde924c VALID NICE JOB!
/* Compare string to hex represention of unsigned value */ inthexmatch(unsigned val, char *sval) { char cbuf[110]; /* Make position of check string unpredictable */ char *s = cbuf + random() % 100; sprintf(s, "%.8x", val); returnstrncmp(sval, s, 9) == 0; }
voidtouch3(char *sval) { vlevel = 3; /* Part of validation protocol */ if (hexmatch(cookie,sval)) { printf("Touch3!: You called touch3(\"%s\")\n", sval); validate(3); } else { printf("Misfire: You called touch3(\"%s\")\n", sval); fail(3); } exit(0); }
user@BlackDragon ~/C/A/target1> cat solutions/ctarget/level3/level3-2.txt|./hex2raw > weirdError user@BlackDragon ~/C/A/target1> gdb ctarget GNU gdb (GDB) 7.12.1 Copyright (C) 2017 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty"for details. This GDB was configured as "x86_64-pc-linux-gnu". Type "show configuration"for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type"help". Type "apropos word" to search for commands related to "word"... Reading symbols from ctarget...done. (gdb) break getbuf Breakpoint 1 at 0x4017a8: file buf.c, line 12. (gdb) run -i weirdError -q Starting program: /home/zhihaochen/CSAPPLabs/AttackLab/target1/ctarget -i weirdError -q Cookie: 0x59b997fa
(gdb) break explode_bomb Breakpoint 1 at 0x40143a (gdb) break phase_1 Breakpoint 2 at 0x400ee0
然后是运行程序及输入测试字符串的相关命令及结果:
1 2 3 4 5 6 7
(gdb) run Starting program: /home/blackdragon/CSAPPLabs/BombLab/bomb Welcome to my fiendish little bomb. You have 6 phases with which to blow yourself up. Have a nice day! Test
voidphase_2(char * input){ int a[6]; read_six_numbers(input, a); if (a[0] == 1) explode_bomb(); int * b = &a[1], * bEnd = &a[6]; do { int val = (*(b-1)) * 2; if (*b != val) explode_bomb(); b++; } while (b != bEnd); return; }
(gdb) break explode_bomb Breakpoint 1 at 0x40143a (gdb) break phase_2 Breakpoint 2 at 0x400efc (gdb) break read_six_numbers Breakpoint 3 at 0x40145c (gdb) run test.txt Starting program: /home/blackdragon/CSAPPLabs/BombLab/bomb test.txt Welcome to my fiendish little bomb. You have 6 phases with which to blow yourself up. Have a nice day! Phase 1 defused. How about the next one? 1 2 4 8 16 32
Breakpoint 2, 0x0000000000400efc in phase_2 () (gdb) continue Continuing.
voidphase_3(char * input){ int a, b; int val = sscanf(input, "%d %d", &a, &b); if (val <= 1) explode_bomb(); switch (a) { case0: a = 207; break; case1: a = 311; break; case2: a = 707; break; case3: a = 256; break; case4: a = 389; break; case5: a = 206; break; case6: a = 682; break; case7: a = 327; break; default: explode_bomb(); a = 0; break; } if (a != b) explode_bomb(); return; }
voidphase_4(char * input){ int a, b; int val = sscanf(input, "%d %d", &a, &b); if (val != 2 || ((unsigned)a > 14)) explode_bomb(); val = func4(a, 0, 14); if (val != 0 || b != 0) explode_bomb(); return;
intfunc4(int a, int b, int c){ int returnVal = (c - b) / 2; int val = returnVal + b; if (val == a) return0; if (val < a) { return2 * func4(a, val + 1, c) + 1; } else { return2 * func4(a, b, val - 1); } }
voidphase_5(char * input){ char a[7]; if (strlen(input) != 6) explode_bomb(); for (int i = 0 ; i < 6 ; i++) a[i] = 0x4024b0[input[i] & 0xf]; a[6] = '\0'; int val = strings_not_equal(a, 0x40245e); if (val != 0) explode_bomb(); return;
在GDB中打印0x4024b0和0x40245e所对应的字符串,命令和结果如下所示:
1 2 3 4
(gdb) print (char *)0x4024b0 $1 = 0x4024b0 <array> "maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?" (gdb) print (char *)0x40245e $2 = 0x40245e "flyers"
总共花了五天时间完成了《深入理解计算机系统》(Computer Science A Programmer’s Perspective)的第一个Lab - Data Lab,深感这次实验的效率低下。一方面是由于清明假期自己有所惰怠,另一方面也是由于在做题的时候采取了不正确的方法,在已经明知不会的情况下我还继续投入大量无意义的时间,没有取得很好的学习效果。
实验简介
Data Lab - Manipulating Bits主要是关于位操作的实验,对应于书本的第2章:信息的表示和处理。
intgetByte(int x, int n){ /* right shift in order to avoid boring arithmatic shift and try to get specific byte using bitAnd and mask. */ return ((x >> (n << 3)) & 0xFF); }
intbang(int x){ /* for x != 0, the highest bit of x | (-x) will always become 1 while when x == 0, the result is the opposite */ return (~((x | (~x + 1)) >> 31) & 1); }
intfitsBits(int x, int n){ /* if fitsBits then from highest bit to n bit will all become 1 - negative number or 0 - positive number * then can construct a mask to implement fitsBits with the help of ^ and ! */ return !((x >> (n + (~1) + 1)) ^ (((1 << 31) & x) >> 31)); }
intdivpwr2(int x, int n){ /* add bias when x is negative, which is controlled by a sign-related mask */ int mask = x >> 31; int add = ((1 << n) + (~1) + 1) & mask; return (x + add) >> n; }
intisLessOrEqual(int x, int y){ /* different processing ways when x and y have the same signs or different signs */ int diff = y + (~x) + 1; int not_diff_sign = !(diff >> 31); int mask = !((x ^ y) >> 31); int result_not_overflow = mask & not_diff_sign; int result_overflow = (!mask) & (x >> 31); return result_overflow | result_not_overflow; }