Lab 4: Assembly language

In this lab, we’ll explore the assembly code generated by different C programs. Your goal is not to understand everything you see, but rather to list what you don’t, explore, and have fun!

Setup and experimentation

We’ll use the Compiler Explorer in this lab to look a bit at how C code gets translated into “assembly”.

To start, open the Compiler Explorer, click the Settings button near the top of the right half, and deselect “Intel asm syntax”. Your screen should look like this:

Setting up Compiler Explorer

For each experiment in this lab, you should:

  • Write some C code in Compiler Explorer.
  • See what the corresponding assembly language output looks like.
  • Ponder the assembly; is the assembly code that’s generated bizarrely short and baffling? Play around with compiler flags–what do you get if you specify the flags -Og or -O0? (Note that -O0 is a capital letter O followed by a zero.)

Before:
Before setting compiler flags

After:
After setting compiler flags

  • Write down any questions and instructions/notations that confuse you; let’s get those questions answered for you!

In the future, you should be able to:

  • Understand what different C structures look like (generally) in assembly.
  • Understand how values are represented in assembly, e.g., in registers or on the stack.
  • Walk through the assembly language code by hand on paper, making suitable adjustments to the registers and EFLAGS bits as you go; get clarity about what every single instruction is doing.

Experiment #1

Write a function that computes and returns the maximum value of two int parameters. It could look like this at first, before you fill in the function:

// Returns the max of two numbers
int max(int a, int b)
{
    // TODO
    return 0;
}

Experiment #2

Write a function that contains a loop. For example, write the function:

// Returns the sum 1 + 2 + 3 + ... + n
int triangular_number(int n)
{
    // TODO
    return 0;
}

(The nth triangular number is also just n * (n-1) / 2, which is simpler and faster to compute, but you should write the loop anyway so you can see how x86-64 does loops.)

Experiment #3

Write a function that calls another function. For example, you could take your maximum-value function from Experiment #1 and call it twice to implement max(int a, int b, int c).

Experiment #4

Go wild. Grab one of your recent assignments (bits.c, queue.c, etc.) and stick it into Compiler Explorer. Can you make sense of the result?