Lab 3. Stack/Procedure Call

For the activities in this lab, first launch your Linux. Perform a git pull on your repository to make sure it is up to date. Also, print the Question Sheet in hard copy.

After this lab, you will learn:

Answer the questions in the Question Sheet as you go through the lab!

Part 1. Examine Program with GDB

Install GEF (GDB Enhanced Features)

GEF (pronounced ʤɛf - "Jeff") is the old school GDB but with fancy features. To install GEF,

Understand the GEF Interface

Once the installation finished, you can go to lab3/part1 folder. Then type vim part1.c to quick examine the source code to understand the functions in the code.

Quit vim and back to the terminal. Then run make run-gdb to execute the code in GDB. If the installation is successful, you should be able to see some colorful output similar to the screenshot shown below:

From top to bottom, you should see the four panels which show 1) registers, 2) stack, 3) ARM code and 4) C code. Those panels will be updated instantly while the coding is running.

Stack Panel

The stack is the memory space that stores the information for function calls, including local variables, input arguments, etc. As shown in the picture below, GEF labels two kinds of addresses for data stored on the stack.

All addresses are in hexadecimal. The absolute address is the address of the data in the entire memory space. The relative address is the address with respect to the stack pointer register $sp. For example, a relative address 0x0004 means the address is sp + 4.

ARM Panel

The ARM panel shows the Assembly code of the program.

The Assembly code (a.k.a., instructions) is stored in the memory space. Therefore, you can see the memory address of instructions labelled. Also, the green arrow indicates the current line that is about to run but not running yet.

Source Code Panel

This panel shows the C code of the program. You can see the line number of the code. Also, similar to the ARM panel, the green arrow indicates the current line that is about to run but not running yet.

Debug with GEF/GDB

Once the program is running in gdb (by typing make run-gdb), we can use various commands to debug the code. Check this GDB Quick Reference for usages/instructions of various GDB commands.

Try out these commands and answer the questions on the Question Sheet in Part1.

Part 2: Stack/Procedure Call: Local Variables

The goal of this part of the lab is to discover how local variables in functions are organized.

  1. cd into the lab3/part2 directory.
  2. Open the do_nothing.c file using vim.
  3. Pay attention to the values of the local variable a and b in both main and do_nothing function. They have the same variable names but with different values. How? Let's find out.
  4. Type make do_nothing.s to generate the Assembly code. Open the do_nothing.s file using vim. And skim thru the code to get a rough idea of the various numbers that are stored in memory space.
  5. Type make run-gdb to execute the program in gdb.
  6. Set break points in the following places:

    There are questions you need to answer on the Question Sheet for EACH of the break points below. Please complete all questions for a break point before running to the next break point in GDB.

    • The beginning of main: Line 9 (It may have been set already by default)
    • After assigning a, b in main: Line 11
    • The beginning of do_nothing: Line 4
    • The end of do_nothing: Line 6
    • The end of main: Line 12
  7. Run the code and answer the questions on the Question Sheet in Part2.

Part 3: Stack/Procedure Call: Function Input Arguments

The goal of this part of the lab is to discover input arguments are passed to functions.

  1. cd into the lab3/part3 directory.
  2. Open the add.c file using vim.
  3. Pay attention to the values of the input arguments a and b of add function passed from main.
  4. Type make add.s to generate the Assembly code. Open the add.s file using vim. And skim thru the code to get a rough idea of the various local variables that are stored in memory space.
  5. Type make run-gdb to execute the program in gdb.
  6. Set break points in the following places:

    There are questions you need to answer on the Question Sheet for EACH of the break points below. Please complete all questions for a break point before running to the next break point in GDB.

    • Right before calling add function in main: Line 12
    • The beginning of add: Line 4
    • The end of add: Line 7
  7. Run the code and answer the questions on the Question Sheet in Part3.

Part 4: Stack/Procedure Call: Function Return

The goal of this part of the lab is to discover how a function returns to where it was called after finishing running the function.

  1. cd into the lab3/part4 directory.
  2. Open the simple.c file using vim. Skim thru the code to get a basic idea of the functions.
  3. Pay attention to callers and callees of different functions, i.e., which function(s) is called by which function(s).
  4. Type make simple.s to generate the Assembly code. Open the simple.s file using vim. Pay attention to the bl and bx instructions that are used to branch to/from different functions.
  5. Type make run-gdb to execute the program in gdb.
  6. Set break points in the following places:

    There are questions you need to answer on the Question Sheet for EACH of the break points below. Please complete all questions for a break point before running to the next break point in GDB.

    • Right before calling the add function in main: Line 17
    • At the beginning of the add function: Line 8
    • Right before calling the do_nothing function in add: Line 10
    • At the beginning of the do_nothing function: Line 4
    • At the end of the do_nothing function: Line 5
  7. Run the code and answer the questions on the Question Sheet in Part4.

Finishing the Lab

  1. Scan and Upload the signed Question Sheet to GradeScope.