COMP 40 — Fall 2017

Memory Template Instructions

The following material was writting by John Huston at UMass Lowell for the Fall 2011 version of Computing II:


Someone had asked how to do a memory template after class the other day; here's a general outline. Don't worry if this seems like jargon, you'll get the hang of it when you see more examples over time.

  1. Take inventory of how many functions you have, including main(). Draw a little box in the code area for each function and label them accordingly.
  2. Add any global variables to the Global+Static Data Area. Draw a little box for each with the variable name under it to represent that memory cell. Fill the cell with the appropriate initialized value, when appropriate. Never initialize these cells if they have not been set to anything.
  3. Begin setup of the main() function on the stack. main will generally always have two arguments which come first, argc and argv. Jim Canning always puts the first argument on the bottom of the stack on his templates, but Prof. Sheldon may choose to do this another way in the future. (Spoilers: It's not technically ultra-important right now. Just be consistent.) [Note from Mark: On the department server, arguments are partly passed in registers and partly stored on the stack. It's helpful to just imagine pushing them all the stack for now. On Intel 32-bit machines, arguments were pushed on the stack left to right, which means that first argument is below subsequent ones in the memory template.] argc will go in the name slot on the bottom row of the stack. Enter in how many arguments there are in this scenario, remembering to count 1 for the name of the program. (e.g, a.out Mel Ott will mean argc is 3.) argv will go in the name slot on the second-to-last row of the stack. Draw a little arrow that points over to the heap to draw out the data structure that argv points to. (As Prof. Sheldon says, the storage for argv may technically be elsewhere in the stack — but this is how most of the other students here were instructed to do the templates, and Prof. Sheldon will instruct you otherwise if we need to change this.)
  4. Draw the argv data structure in the heap. argv is itself a pointer in the stack, which you've drawn, which points to an array of pointers — draw a column of vertical boxes equal to the number in argc. E.g, if argc is 3, draw a column of 3 boxes here to represent this array. This array contains pointers to characters. Draw pointer arrows from each box to the first letter of each argument. For example, for a.out Mel Ott, you'll be drawing arrows to 'a', 'M' and 'O'. Finish the structure by adding the remaining letters, remembering to terminate the sequence with a null byte, written as '\0'.
  5. Add a return address element to the main() function on the stack. Leave the name blank and write “Return address back to unix”, or “Return address back to start()”.
  6. Add any automatic local variables to the stack in the order they appear. E.g, if you have a main() that looks like this:
    int main(int argc, char *argv[]) 
    { 
            int x = 6; 
            int y; 
            int z[3] 
    
            return 0; 
    }
        
    add x to the bottom-most available row, and add y to the next row up, and so on.

    For arrays, count how many cells you will need (3 here) and begin with the bottom. z[2] goes on the bottom, z[1] above it, and z[0] above that. In the address column for z[0], write the letter z above the address and circle it. Remember that z is now a constant that is the address of the 0th element of the array.

    Again, do not initialize these with any value if they are not initialized. In this example, write 6 in the data portion for the row you labelled x.

  7. Draw a thick bar above the record you've created for main(), and down the side to the left, label this “Main's activation record.”
  8. Begin execution of the program. Change any values you are instructed to change in the order the program changes them. Cross off old values with a slash and insert their new values. Create new structures in the heap as instructed by calls to malloc(), etc.
  9. For calls to non-trivial functions (What I'll define here as any function that is defined by the user and not in the C standard library) you immediately cease execution of the current function and begin setup of a new Activation Record on the stack. Follow the same general steps:
    1. Arguments are entered on the stack first. Copies of the arguments are made and passed.
    2. Create an entry that is the “Return address back to ____”. Fill in the blank for the name of the function that called this one. For the first function, this is going to be main().
    3. Local variables come next.
    4. Draw another thick bar and label this activation record. For recursive calls, begin using sequentials — e.g, “Factorial #1's A.R.”, “Factorial #2's A.R.”, and so on.
    5. Execute this function.
  10. When a function reaches a return statement or the implicit return at the end of the function, the function's activation record is popped off the stack and returns its value. Draw a light cross through that activation record to signify it is now off the stack and draw with an arrow on the right-hand side the value being passed back down the stack. For functions that return no value, just pop it off the stack.
  11. Resume execution of the function that called the sub-function, returning values and popping off the stack and so on until you are finished execution of the entire program.
Mark A. Sheldon (msheldon@cs.uml.edu)
Last Modified 16 August 2011