Assignment #6: ARM Assembly, Control Flow, Functions, and the Stack

Assigned:   Wednesday, Nov. 14
Due:   Monday, Nov. 26   Wednesday, Nov. 28   by midnight

Contents:


Overview

Topic: The ARM v7 ISA, ARM Assembly Programming, Control Flow (conditions & loops), Function Calls, the Stack, and Stack Frames
Related Reading: Chapter 6 and class notes


Practice Problems

Odd-numbered exercises at the end of Chapter .
      Answers can be found on the book's website


Problems to be Submitted (25 points)

When you turn in your assignment, you must include a signed cover sheet (PDF version) with your assignment (you're assignment will not be graded without a completed cover sheet).

You are allowed to submit your assignment via email, but if you choose to do so, you must bring a hardcopy of your assignment along with a completed cover sheet to the instructor at the next class. (Note: Do not email the instructor any .zip file attachments, as SLU's email may not accept these emails; i.e. the instructor may not receive your email.)

  1.   (2 points)

    Given the four major sections of a process' memory organization (Text, Data, Heap, and Stack), indicate which area each of the following are stored in:

    1.   global variables
    2.   dynamically-allocated variables, instantiated via new or malloc()
    3.   program code
    4.   local variables

  2.   (5 points)

    Given the following assembly program, hw6_prob2.s, determine the equivalent C code corresponding to the function hw6_prob2(), and fill in the blanks below:

    These blanks may include assignment statements, comparisons, conditional statements, or loops. Also, you may not need to use all the blanks.

    Many of the blanks will be of the form:   result = ...

        int hw6_prob2 (int x, int y)
        {
            int result = ________________________________________;
    
            if (( x ___________________________) || ( ___________________________))
            {
                _________________________________________________;
    
                _________________________________________________;
    
                _________________________________________________;
    
                _________________________________________________;
    
                _________________________________________________;
            }
            else
            {
                _________________________________________________;
    
                _________________________________________________;
    
                _________________________________________________;
    
                _________________________________________________;
    
                _________________________________________________;
            }
    
            return result;
        }
    

  3.   (5 points)

    Create a function that computes the total annual cost of parking for an individual that works 5 days per week, and spends $X per workday on parking.

    Your function for computing annual parking cost should take two input arguments: the cost to park each day, and the total number of weeks the employee worked that year, as follows:

        totCost = annualParkingFees (cost_per_day, weeks_worked);

    For example, John has to pay $3 per day for parking. Between vacations and holidays, John has about 4 weeks of time off, so he effectively works 48 weeks in the year. For John, executing annualParkingFees(3, 48) should produce a result of $720.

    Assume: All variables, such as cost_per_day, weeks_worked, totCost, etc., are of type int.

    You're welcome to use a similar program, like abs_asm.s, as a starting point for your answer. Remember, the commands to build an assembly file like abs_asm.s are:

          gcc abs_asm.s -o abs_asm
    

  4.   (5 points)

    Assume you have a set of functions with the following characteristics:

       main:
            push	{r5, r8, r11, sp, lr}
    
            ...
    
            push	{r2, r12}
            bl      procA
            pop	{r2, r12}
    
            ...
    
            pop	{r5, r8, r11, sp, pc}
    
    
       procA:
            push	{r4, r10, sp, lr}
    
            ...
    
            bl      procX
    
            ...
    
            pop	{r4, r10, sp, pc}
    
    
       procX:
            push	{r6, r8}
    
            ...
    
            pop	{r6, r8}
            mov     pc, lr
    
    

    Questions:

    1.   (2 points)

      Draw the state of the stack, assuming that the processor is currently in the middle of executing function procX(). Identify the bounds of the stack frames for main(), procA(), and procX(), and the contents of each.

    2.   (2 points)

      Which, if any, of the push and pop instructions correspond to caller-saving? Which, if any, correspond to callee-saving?

    3.   (1 point)

      Which, if any, of the functions are leaf functions?

  5.   (8 points)

    In the Assembly and Debugger Tutorial, you examined the execution of the tut_asmprog.s assembly program. Recall that the second loop — and the code immediately before and after it — prints out the contents of an array. This is a useful tool, so let's separate out that code into it's own function.

    1.   (4 points)

      First, within the tut_asmprog.s file, create an assembly function, print_array(), that contains all the code for printing the contents of an array.

      The print_array() function should take two input arguments, the first being the base address of the array, and the second being the size (number of elements) of the array.

    2.   (2 points)

      Next, remove the original print code from the main() function, and then have main() call the print_array() function instead.

    3.   (2 points)

      Finally, be sure to perform caller-saving and/or callee-saving to ensure that the appropriate registers are saved and restored by each function.