This lab consists of two parts and is due after Fall Break Due by 11:59 pm, Wednesday, October 23, 2024.

  • Part 1: Write a sum.s function that is used in C program, sum_prog.c.

  • Part 2: Write a compare.s function that is used in C program, compare_prog.c.

Partnerships can be found here: Lab 5 Partners. Please review the CS31 Partner Etiquette and Expectations.

1. Lab Goals

  • Gain experience translating C code to x86_64 Assembly to enhance your understanding of underlying data structure access, and function calls.

  • Understand in more detail the mechanics of C "pass-by-pointer" style parameters and function calls.

2. Getting Your Lab 5 Repository

Both you and your partner should clone your Lab 5 repository ("repo") into your cs31/labs subdirectory:

  1. get your Lab ssh-URL from the CS31 git org. The repository to clone is named Lab5-userID1-userID2, where user1 and user2 are the user names of you and your lab partner.

  2. cd into your cs31/labs subdirectory:

    $ cd ~/cs31/labs
    $ pwd
  3. clone your repository:

    $ git clone [your Lab5-userID1-userID2 url]
    $ cd Lab5-userID1-userID2
    $ ls
    Makefile  README.adoc  compare.s
    compare_prog.c  sum.s  sum_prog.c
    • The README.adoc contains details of what you’re expected to fill in for each of these other files.

    • Part 1 files are: sum.s, sum_prog.c

    • Part 2 files are: compare.s, compare_prog.c

There are more detailed instructions about getting your lab repo from the "Getting Lab Starting Point Code" section of the Using Git for CS31 Labs page.

3. Part 1: Sum Function

For Part 1, you will implement a sum function in x86_64 in sum.s, which has the starting point of this function. Then sum.s is compiled into a program (sum_prog) that you can use test your code.

The starting point handles the stack set-up and function return. As a result, you just need to implement the x86_64 translation of the function body. See the comments in sum.s about where on the stack there is space for local variables, and where the parameter n is located.

The C function you will implement in x86_64 is:

/* computes the sum of the values 1-n
 * n: an int value
 * returns: the sum of values from 1-n, or -1 if n is not positive
 */
long int sum(long int n) {

  long int i, res;

  if( n <= 0 ) {
     return -1;
  }
  res = 0;
  for(i=1; i <= n; i++) {
    res = res + i; 
  }
  return res;
}

The program sum_prog.c makes a call to this sum function (do not modify sum_prog.c, but you can open it in vim to see what it is doing).

3.1. Compiling and Running

The files for Part 1 are:

  • The sum.s file contains the starting point x86_64 code for the sum function that you will complete for Part 1. Your Part 1 solution should be implemented in this file.

  • sum_prog.c: a main program for testing your sum implementation, Do not modify this program.

The Makefile is set up to compile both the x86_64 sum.s and sum_prog.c files into an executable named sum_prog that you can use to run and test your x86_64 implementation.

$ make     # compiles sum_prog from sum.s and sum_prog.c
$ ./sum_prog

3.2. Sample Output

When run, the sum_prog reads in user input for the value n, that is passed as a parameter to your sum function, and then prints out the result (you can see this main control flow in the sum_prog.c file’s main function, which you should not modify). Some sample inputs and outputs of the program are provided below:

$ ./prog
This program computes the sum of 1-N
Enter an value for n: 10
The sum of 1 to 10 is 55

$ ./prog
This program computes the sum of 1-N
Enter an value for n: 50
The sum of 1 to 50 is 1275

3.3. Requirements

  • Your x86_64 implementation of the sum function should be added to the sum.s starting point file.

  • Your code should be well-commented.

  • Do not edit sum_prog.c, but looking at it in vim might help you understand how your sum function is being called.

  • Your solution must include a loop. It is well known that the sum of the first n positive integers is n*(n+1)/2, but you can not use that in your answer.

3.4. Tips

  • Write C goto versions of the sum function, the if and for loop parts in particular, to help you with the translations of those parts.

  • Remeber that instructions can access at most one memory location and one register in x86_64, e.g., mov -8(%rbp), %rax is allowed but mov -8(%rbp), -16(%rbp) is not allowed. If you need to do something with two memory locations, you will need to move one of them into a register first.

  • Try adding a little bit of x86_64 code to sum.s at a time, then compile and test it out by running prog, and add some more. Parts of that you test out do not even have to be parts of the solution, for example:

    1. First see if you can just return the value of n.

    2. Next, see if you can initialize res to 0 and return the value of res.

    3. Next, try the if statement, and test passing positive and negative values to see if your function returns -1 when n is not positive.

    4. Then try implementing the for loop.

  • To help debug, trace through the instructions on paper, drawing memory contents and register contents as you go.

  • You can also test out some code snippets using the {visualizerurl}[assembly visualization tool] to check if your logic is correct without having to compile and run your entire program.

  • Use Ctrl-C to kill a running program stuck in an infinite loop.

4. Part 2: Compare Function

For Part 2, you will implement a compare function in x86_64 in compare.s, that conditionally changes the value pointed to by x. Then compare.s is compiled into a program (compare_prog) that you can use test.

The starting point code handles the stack set-up and function return. As a result, you just need to implement the x86_64 translation of the function body. See the comments in compare.s about where on the stack there is space for local variables, and where the parameters *x and y are located.

void compare(long int *x, long int y);

This function takes one long int pointer, x, passed by pointer (the parameter points to the storage location of its argument), and one long int, y, passed by value.

If the <value pointed to by x> is greater than <y>, set the <value pointed by x> to be <y>. Otherwise, it should be unchanged by the call.

The program compare_prog.c makes a call to this sum function (do not modify compare_prog.c, but you can open it in vim to see what it is doing).

To write compare.s, you will have to write out the function definition for compare() in C, then write its go-to equivalent, followed by the x86_64 Assembly version.

4.1. Compiling and Running

The files for Part 2 are:

  • The compare.s file contains the starting point x86_64 code for the compare function that you will complete for Part 2. Your Part 2 solution should be implemented in this file.

  • compare_ prog.c: a main program for testing your compare implementation, Do not modify this program.

The Makefile is set up to compile both the x86_64 compare.s and compare_prog.c files into an executable named compare_prog that you can use to run and test your x86_64 implementation.

$ make     # compiles compare_prog from compare.s and compare_prog.c
$ ./compare_prog <num1> <num2>

4.2. Sample Output

When run, the compare_prog takes in two numbers from the command line (<num1> and <num2>). They are passed as parameters to the compare function, <num1> is passed by pointer and <num2> is passed by value. The program then prints out the values of <num1> and <num2> before and after the call to compare (you can see this main control flow in the compare_prog.c file’s main function, which you should not modify). Some sample inputs and outputs of the program are provided below:

$ ./compare_prog -10 1
Before compare(): a = -10, b =   1
After compare(): a = -10, b =   1

$ ./compare_prog 200 199
Before compare(): a = 200, b = 199
After compare(): a = 199, b = 199

$ ./compare_prog 650 777
Before compare(): a = 650, b = 777
After compare(): a = 650, b = 777

4.3. Requirements

  • Your x86_64 implementation of the compare function should be added to compare.s starting point file.

  • Your code should be well-commented.

  • Do not edit compare_prog.c, but looking at it in vim might help you understand how your compare function is being called.

  • Your solution must include any one of the conditional or unconditional jump instructions, as needed.

4.4. Tips

  • Write C goto versions of the sum function, the if and for loop parts in particular, to help you with the translations of those parts.

  • The parameter values of x and y are on stored in the registers, x is in %rdi and y is in %rsi. Note that x is a long int pointer and y is a long int.

  • Remeber that instructions can access at most one memory location and one register in x86_64, e.g., mov -8(%rbp), %rax is allowed but mov -8(%rbp), -16(%rbp) is not allowed. If you need to do something with two memory locations, you will need to move one of them into a register first.

  • Draw a picture of the registers, including where parameter and argument values are and trace through the instruction execution to help you determine what x86_64 instructions you need to use to implement compare.

  • To help debug, trace through the instructions on paper, drawing memory contents and register contents as you go.

  • You can also test out some code snippets using the {visualizerurl}[assembly visualization tool] to check if your logic is correct without having to compile and run your entire program.

  • Use Ctrl-C to kill a running program stuck in an infinite loop.

5. Partner Feedback Survey

Finally, submit the required Lab 5 Questionnaire (each lab partner must do this).

6. Handy Resources