CS360 Midterm 2. March 21, 2017. Answers and Grading

Question 1 - 16 Points

The code is in q1.c in case you want to test it for yourself.

Grading

Two points per part.


Question 2 - 16 Points

The code for the complete program is in q2_real.c. The idea is to keep track of the first file that you see with at least 6 links, as denoted by the st_nlink field of the file's stat() buffer. You keep track of its name in p1 and its inode in number. When you see a second file with the same inode number, you print out the stored filename, and the new file's filename.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>

void find_6l(char *dir, char **p1, ino_t *number)
{
  DIR *d;
  struct dirent *de;
  struct stat buf;
  char *pn;
  int length;

  length = strlen(dir);
  pn = (char *) malloc(sizeof(char) * (length + 258));
  strcpy(pn, dir);
  d = opendir(dir);
  if (d == NULL) { perror(dir); exit(1); }

  for (de = readdir(d); de != NULL; de = readdir(d)) {

    sprintf(pn+length, "/%s", de->d_name);
    if (stat(pn, &buf) != 0) { perror(pn); exit(1); }

    printf("pn: %s\n", pn);

    if (buf.st_mode & S_IFDIR) {
      if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0) {         
        find_6l(pn, p1, number);
      }
    } else {
      if (buf.st_nlink >= 6) {
        if (*p1 == NULL) {
          *p1 = strdup(pn);
          *number = buf.st_ino;
        } else if (buf.st_ino == *number) {
          printf("%s\n%s\n", *p1, pn);
          exit(0);
        }
      }
    }
  }
  closedir(d);
  free(pn);
}

int main()
{
  ino_t num;
  char *firstpn;

  firstpn = NULL;
  find_6l(".", &firstpn, &num);
  return 0;
}

Now the questions:

Grading

2 points per part, with the exception of part D, which was worth 6 points.


Question 3 - 10 Points

Program B makes two system calls, read() and write(), for each character on standard input. If there are a lot of characters on standard input, this will make Program B slow, because system calls are expensive. On the other hand, fread() and fwrite() use buffers to mitigate the overhead of the system calls. For example, fread() will read 8K characters at a time into a buffer, with a single read() call, and it will satisfy the next 8K-1 fread() calls from the buffer. Fwrite() copies each character to a buffer, and only calls write() on the buffer when it is full, or when the program ends.

Grading

10 points.


Question 4 - 20 Points

These are all straightforward from the "Assembler 3" lecture.

In b(), you need to load the pointer, add 12 to it, and dereference it into r0:

b:
    ld [fp+12] -> %r0
    mov #12 -> %r1
    add %r0, %r1 -> %r0
    ld [r0] -> %r0.
    ret
In f(), you first call "push #16" to allocate g. The first byte of g will be (fp-12). So, you need to calculate fp-12, then add four times i to it, and store 10 at that memory location. Here's an expression tree:

If you process this right to left and bottom up, you don't need to spill r2:

f:
    push #16
    mv #4 -> %r0
    ld [fp+12] -> %r1
    mul %r0, %r1 -> %r0
    mov #-12 -> %r1
    add %r1, %fp -> %r1
    add %r0, %r1 -> %r0
    mov #10 - %r1
    st %r1 -> [r0]
    ret
In d(), we have the following: Here's an expression tree.

Again, if you process this right to left and bottom up, you don't need to spill r2:

d:
    mov #4 -> %r0
    ld [fp+16] -> %r1
    mul %r0, %r1 -> %r0
    ld [fp+12] -> %r1
    add %r0, %r1 -> %r0
    ld [r0] -> %r0
    mov #12 -> %r1
    add %r0, %r1 -> %r0
    mov #5 -> %r1
    st %r1 -> [r0]
    ret

Grading


Question 5 - 10 Points

First, the following statement forces you to spill r2:

k = c(e(i)+e(j));

So, the first four statements will be:

  1. push #8: Allocate the local variables on the stack.
  2. st %r2 -> [sp]--: Spill r2.
  3. mov #5 -> %r0: This and the next statement push the argument to f(5) onto the stack.
  4. st %r0 -> [sp]--.
The last two statements are going to be to move 3 to r0 and return. You need to unspill r2, so you should do that, either just before or just after moving 3 to r0. The two statments previous to that are going to be the ones after the jsr call in "l = f(k)" -- one to pop the argument off the stack, and one to store the return value into l:
    pop #4
    st %r0 -> [fp]
    mov #3 -> %r0
    ld ++[sp] -> %r2
    ret

Grading

push #8 1 point
st %r2 -> [sp]-- 1.5 points
mov #5 -> %r0 1 point
st %r0 -> [sp]-- 1 point
pop #4 1.5 points
%r0 -> [fp] 1 point
mov #3 -> %r0 1 point
ld ++[sp] -> %r2 1.5 points
ret 0.5 points


Question 6

As for the rest, this is a matter of starting with the current fp equaling 0x7ff800 and unwinding the stack to put in all the values and labels for h(). Just a note -- we know that the jsr statement in h is at memory location 0x161c. So, the stored pc on the stack should be four bytes after that, at 0x1620.

Grading