_ Problem 1. COMP 210 Example Question Exam 2 (Solutions at the bottom) This question will test your ability to reconstruct C code from the assembled output. On the opposing page, there is asm code for a routine called bunny. It comes from a C routine with the following outline. Don t fill in the outline yet. static int bunny(int l, int r, int *A){ int x = ; int i = ; int j = ; while( ) do j--; while( ); do i++; while( ); if( ){ int t = A[i]; A[i] = A[j]; A[j] = t; _return ; _ A. (3 points): Fill in the following table of register usage. Use the variable names from the outline. If a register gets used to store two different things, just list both of them. I ve filled in two blanks to show examples. This will help you understand the code; do this before part C. Register Variable %eax %ebx %ecx %edx %esi %edi %esp %ebp B. (3 points): Why does bunny push %edi, %esi, and %ebx on to the stack?
bunny:.l16:.l7: jl.l7.l3: pushl %ebp movl %esp, %ebp pushl %edi pushl %esi pushl %ebx movl 8(%ebp), %eax movl 16(%ebp), %esi movl (%esi,%eax,4), %edi leal -1(%eax), %ecx movl 12(%ebp), %ebx incl %ebx cmpl %ebx, %ecx jge.l3 decl %ebx cmpl %edi, (%esi,%ebx,4) jg.l16 incl %ecx cmpl %edi, (%esi,%ecx,4) cmpl %ebx, %ecx jge.l3 movl (%esi,%ecx,4), %edx movl (%esi,%ebx,4), %eax movl %eax, (%esi,%ecx,4) movl %edx, (%esi,%ebx,4) jmp.l16 movl %ebx, %eax popl %ebx popl %esi popl %edi popl %ebp ret
C. (5 points): Fill in the blanks on the outline (on the previous page). D. (4 points): Look at draft_horse and write out the control flow structure. As an example, the control flow structure of bunny would be: bunny() { while() { while() { while() { if() { return; I want to know about any if, while, function calls, and returns, but I don t care about anything else. Do not use goto. draft_horse() { E. (bragging rights): What algorithm is this code implementing?
draft_horse: pushl %ebp movl %esp, %ebp subl $28, %esp movl %ebx, -12(%ebp) movl %esi, -8(%ebp) movl %edi, -4(%ebp) movl 8(%ebp), %ebx movl 12(%ebp), %esi movl 16(%ebp), %edi cmpl %esi, %ebx jge.l17 movl %edi, 8(%esp) movl %esi, 4(%esp) movl %ebx, (%esp) call bunny movl %eax, -16(%ebp) movl %edi, 8(%esp) movl %eax, 4(%esp) movl %ebx, (%esp) call draft_horse movl %edi, 8(%esp) movl %esi, 4(%esp) movl -16(%ebp), %eax incl %eax movl %eax, (%esp) call draft_horse.l17: movl -12(%ebp), %ebx movl -8(%ebp), %esi movl -4(%ebp), %edi movl %ebp, %esp popl %ebp ret
Fill in the run time stack for the subroutine f (and only f) just before the assembly code call instruction corresponding to the return statement is exectued. Assume that the registers %rax, %rbx, and %r12 will be used in the body of the subroutine for f. Include the parameters, return address, and any other conventions that gcc will follow. Assume that the return address to main will be 0x08048f6e. Assume that %rsp contains 0xbffffa30 and %rbp contains 0xbffffbec just before line 1 is executed. This is shown on the chart. Assume there is no code optimization. Put any actual value on the stack that you can determine. Use the value that is actually on the stack in hex in little endian format. If you can t determine the value put three question marks:??? Addresses stored on the stack should not be in little endian format. Assume that z (in f) is stored on the runtime stack, not just in a register. Assume that the assembly code for f saves the parameters on the stack at the beginning of the subroutine Label the stack with any memory address that you can calculate (you can calculate just about all). Label each value on the stack with the corresponding variable name from the C program if it can be determined. Label each entry on the stack with its relative distance from the %rbp pointer in its stack frame (recall that each call to a subroutine produces a new stack frame), i.e., +0x08, 0x00, -0x08, -0x10, etc. Your values must be in hexadecimal! Assume that space is allocated on the run-time stack only when it is required by convention (i.e., to follow stack discipline). In other words, the compiler will change %rsp only when needed for some value like a parameter, saved register, return address, or local variable. Show where %rbp and %rsp will be pointing just before line 1 is executed, and just before the return is executed.
long f(long a, long b) { long sum; sum = a + b; return sum; // write out the runtime stack just before this return is executed int main() { long a, b, c; a = 5; b = 10; c = f(a, b); // line 1 print( %d + %d = %d\n, a, b, c); return 0;
Memory Address offset from %ebp value C variable name 0xbffffa30 %rsp before line 1
Solutions: A. Register Variable %eax l, A[j], j %ebx r, j %ecx i %edx A[i], t %esi A %edi x %esp stack pointer %ebp stack frame pointer B. These are callee save registers. C. static int bunny(int l, int r, int *A) { int x = A[l]; int i = l - 1; int j = r + 1; while(i < j) { do { j--; while(a[j] > x); do { i++; while(a[i] < x); if(i < j) { int t = A[i]; A[i] = A[j]; A[j] = t; return j; D. draft_horse() { if() { bunny(); draft_horse(); draft_horse(); return; E. This is the code for quicksort.