Part 1: b -- you are making lots of write() calls on small values, resulting in too much system call overhead.
Part 2: Fill the buffer incrementally, and then write it either when it gets full, or at the end of write_ints: The answer is in the file p1.c.
#include <stdio.h> #include <unistd.h> #include <fcntl.h> int buf[1024]; void write_ints(int fd, int size, int *ints, char *select) { int i, j; j = 0; for (i = 0; i < size; i++) { if (select[i] != 0) { buf[j] = ints[i]; j++; if (j == 1024) { write(fd, buf, 1024*sizeof(int)); j = 0; } } } if (j != 0) write(fd, buf, j*sizeof(int)); return; } |
B. You call stat() and look at the "mode", which is in the variable st_mode. There is a macro which tells you whether the mode specifies that the file is a directory.
C. Directories hold bindings of names to inode numbers.
D. If you use r2, you will have to spill it, so that you can reset it when your procedure is done. An example is when you are implementing an arithmetic expression that requires more than two registers.
E. One reason is that you don't have write permissions on f1. A second reason is that f1 is a directory, so you aren't allowed to write to it. A third reason is that your program has too many open files. A fourth reason, is that someone deleted the file between your ls call and your program (which you had to specify).
b: push #4 / Allocate i st %g0 -> [fp] / Set i to zero b l2 / Go to the boolean expression of the for loop. l1: ld [fp] -> %r0 / i++ add %r0, %g1 -> %r0 st %r0 -> [fp] l2: ld [fp] -> %r0 / Do (i < 10) and branch on the negation mov #10 -> %r1 cmp %r0, %r1 bge l3 ld [fp+12] -> %r0 / j += i ld [fp] -> %r1 add %r0, %r1 -> %r0 st %r0 -> [fp+12]; b l1 l3: ld [fp+12] -> %r0 / return j ret c: / ld ld [fp+16] -> %r0 / | mov #4 -> %r1 / + -- This gives you &(p[k]) mul %r0, %r1 -> %r0 / / \ ld [fp+12] -> %r1 / p * add %r0, %r1 -> %r0 / / \ ld [r0] -> %r0 / k 4 ret / d: st %r2 -> [sp]-- / Spill r2 jsr g / Push g() onto the stack st %r0 -> [sp]-- / mov #5 -> %r0 / Push 5 onto the stack st %r0 -> [sp]-- / jsr e / Call e(5, g()) pop #8 / Pop the arguments off the stack mov %r0 -> %r2 / Move the return value to r2, so that f() doesn't overwrite it jsr f / Call f() add %r0, %r2 -> %r0 / Add f() to e(5, g()) ld ++[sp] -> %r2 / Unspill r2 ret /
Address Value Description -------- -------- --------------------- 0x300438 unknown unused <-----------sp 0x30043c 11 First argument to y 0x300440 7 Second argument to y 0x300444 5 m in z() <-----------fp -------- -------- --------------------- pc = 0x3458We call y() which pushes fp and pc+4 onto the stack. y() allocates four bytes for i, then changes i to 77 and k to 6. It returns 77. So, at the point where y() returns, we have:
Address Value Description -------- -------- --------------------- 0x30042c unknown unused <-----------sp 0x300430 77 i in y() <-----------fp 0x300434 0x300444 Saved fp in z() 0x300438 0x345c Saved pc in z() 0x30043c 11 j in y() 0x300440 6 k in y() 0x300444 5 m in z() r0 = 77 -------- -------- --------------------- pc = ?So, the following are the answers:
Address Size Flink Blink ---------- --------- ---------- ---------- 0x78649d48 0x10 = 16 0x78649da0 0x0 (NULL) 0x78649da0 0x18 = 24 0x78649d30 0x78649d48 0x78649d30 0x18 = 24 0x78649df8 0x78649da0 0x78649df8 0x18 = 24 0x0 (NULL) 0x78649d30 ---------- --------- ---------- ----------Part B: We simply walk through the blocks of memory. Add the size to the address to get the address of the next block. The lines in black are the allocated blocks. The colored lines are blocks that are on the free list.
Address Size Address of the next block: ---------- --------- -------------------------- 0x78649d20 0x10 = 16 0x7864930 0x78649d30 0x18 = 24 0x7864948 0x78649d48 0x10 = 16 0x7864958 0x78649d58 0x18 = 24 0x7864970 0x78649d70 0x20 = 32 0x7864990 0x78649d90 0x10 = 16 0x78649a0 0x78649da0 0x18 = 24 0x78649b8 0x78649db8 0x10 = 16 0x78649c8 0x78649dc8 0x18 = 24 0x78649e0 0x78649de0 0x18 = 24 0x78649f8 0x78649df8 0x18 = 24 0x7864e10 ---------- --------- --------------------------Part C: You'll need a block whose size is at least 24 bytes, so the first free block will not do. The second one, starting at 0x78649da0 will work, so you need to return a pointer eight bytes greater than the beginning of the block. The answer is: 0x78649da8.
Part D: It will not segfault, because it is in the same page as the end of the heap (0x78649e0c), and the operating system / hardware do address protection checks at the page granularity. For that reason addresses 0x78649e10 to 0x78649fff are all valid.
Part E: This is a problem, because we have a block of free memory that is "after" the end of the heap. The problem will manifest in the following sequence of operations:
Eight points for parts A and B. Three points for part C, giving half credit for da0, and 0.5 for d4c, dfc and d38. Three points for part D and two for part E. You had to say "No" and something about paging for full credit on part D. If you gave a good explanation for part E, given that you said "yes" to part D, you received full credit.