In: Computer Science
Consider the following C code:
long fact(long x) { if (x <= 1) {
return 1; }
long px = x; long fx = fact(x - 1); return px * fx;
}
Copy the above C code into a C file. For each line of C code responsible for a push or pop operation (either directly or as a result of a call or return), add a comment describing the stack operation and its purpose.
Hint: try compiling the C code to x86-64 using Arch gcc with the -S, -Og flags.
long fact(long x) {        // BEFORE
ENTERING fact: push the value of x onto the stack
          
           
    // BEFORE ENTERING fact: push the return address
of next statement (from wherever fact is called) on stack
   if (x <= 1) {
       return 1;   
        // WHILE RETURNING from fact:
pop local variable px off the stack  
   
          
           
    // WHILE RETURNING from fact: pop return address
and save this so that jmp can be done to this address
          
           
    // WHILE RETURNING FROM fact: pop parameter
(value of x) from stack
   }
long px = x;          
    // push local variable px onto the stack
long fx = fact(x - 1);    // BEFORE ENTERING fact: push
the value of (x - 1) onto the stack
          
           
    // BEFORE ENTERING fact: push the return address
of next statement (i.e. return px * fx) on stack
          
           
    // WHILE RETURNING: pop local variable px off
the stack
          
           
    // WHILE RETURNING from fact: pop return address
and save this so that jmp can be done to this address
          
           
    // WHILE RETURNING FROM fact: pop parameter
(value of x - 1) from stack
          
           
   
return px * fx;          
// WHILE RETURNING from fact: pop local variable px off the
stack
          
           
    // WHILE RETURNING from fact: pop return address
and save this so that jmp can be done to this address
          
           
    // WHILE RETURNING FROM fact: pop parameter
(value of x) from stack
}