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:
-
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. -
cd
into yourcs31/labs
subdirectory:$ cd ~/cs31/labs $ pwd
-
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 thesum.s
starting point file. -
Your code should be well-commented.
-
Do not edit
sum_prog.c
, but looking at it invim
might help you understand how yoursum
function is being called. -
Your solution must include a loop. It is well known that the sum of the first
n
positive integers isn*(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
andfor
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 runningprog
, and add some more. Parts of that you test out do not even have to be parts of the solution, for example:-
First see if you can just return the value of n.
-
Next, see if you can initialize res to 0 and return the value of res.
-
Next, try the if statement, and test passing positive and negative values to see if your function returns -1 when n is not positive.
-
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 tocompare.s
starting point file. -
Your code should be well-commented.
-
Do not edit
compare_prog.c
, but looking at it invim
might help you understand how yourcompare
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 forloop
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
General Lab Resources
-
Class EdSTEM page for questions and answers about lab assignment
-
man and Manual pages documentation for libraries and commands