1. Looking at the x86 code derived from fact.c, what is the offset from %rbp of: A. the caller's %rbp value : 0 B. the parameter "n" : -0x14 C. the variable "answer" : -0x4 D. the return address if a lower level function is invoked: -0x28 2. If you look at the stack.txt file produced by the Makefile, you will notice that the first stack dump that is produced occurs when factorial(1) has been called, even though main called factorial(4). Why is this true? : Because printStackInfo is invoked after all recursive invocations have completed, and the first invocation of factorial for which all recursive invocation have completed is factorial(1). 3. Looking at stack.txt at the top, when n==1, the top (highest address) stack frame is main's stack frame. Look at the next stack frame, the first frame that represents an invocation of the factorial function. A. What is the value of the parameter, "n" : 4 B. What is the value of the "answer" variable (in hex) : 0xbadddadd 4. Looking at stack.txt when n==1, the bottom (lowest address) stack frame is also an invocation of the factorial function. In this frame, A. What is the value of the parameter, "n" : 1 B. What is the value of the "answer" variable (in hex) : 0x1 5. Looking at stack.txt when n=4, the bottom (lowest address) stack frame is still an invocation of the factorial function. In this frame, A. What is the value of the parameter, "n" : 4 B. What is the value of the "answer" variable (in hex) : 0x18 (=24) 6. The stack.c code that prints lines of stack frames prints several values on a single line. First, it prints the address of the memory, followed by an arrow (->), followed by the 8 byte (64 bit) big endian interpretation of the value at that memory, followed by an equals sign (=), followed by the big endian interpretation of two 4 byte (32 bit) values at that memory. If one line of output looks like: 0x7ffcd76991d8 -> badddadd00000000 = 00000000 badddadd Why do the 4 byte values look reversed? : Because we are on a little endian machine. In the 8 byte value, all 8 bytes are reversed. In the two 4 byte values, only chunks of 4 bytes are reversed. 7. If you run "make stack.txt" twice, will you get the same results? Why or why not? : You will not get the same results because Unix loads the code at a different (randomized) location each time. Also, the top of the stack when your program starts may be different each time you run. 8. In stack.c, in the printStackInfo function, when we print the frames, we use the statement "for(j=nptrs-3;j>0; j--)". A. Why do we start with the frame at nptrs-3? : Because nptrs is the result of the C library "backtrace" function, which returns the number of stack frames from the current frame to the caller of the caller of main. The top two frames are not interesting, so we start at main's stack frame. B. Why do we end with the frame at 1, and not 0? : Because frame 0 is the printStackInfo frame, and that is not interesting either. 9. The Makefile builds the fact binary using the -rdynamic flag as a gcc compiler option. If we do not specify that flag when we compile, will the code still compile and run? If so, does anything change in the output? : Yes, the code still compiles and runs, but we lose the function/offset information in the stack descriptions, but instead print the offset in fact. 10. In stack.c, we used the special keyword 'asm ("rbp")' to enable us to use the %rbp register as a C variable. Can you think of any other reasons to get access to x86 registers in C code? If so, name one or two... : Yes, as an alternative to get parameters (rdi, rsi, etc.) to find the lowest address in the current stack frame (rsp), as an alternative to get access to the return code (rax), or just as an optimization to keep often used values in registers rather than sending them back and forth to memory. (Note... an answer of "no" is acceptable.)