Friday, September 26, 10pm
See Assignment 3 on Canvas for the Github Classroom link.
Submit the contents of your repository via Gradescope. See Deliverables below for what to submit.
This is an individual assignment.
This assignment will take you through 2 tasks implementing and using functions in assembly. You will be also asked to write some C (pseudo-)code as a blueprint for your assembly. The C code does not need to compile or run, but needs to reflect the functionality. Feel free to rely on your Java knowledge here. If in doubt, leave comments.
This assignment will also introduce separate compilation.
For one of the tasks you will write a function called by an already
implemented main
function. For the other, your task will be
to write a main
function for an already implemented
function. Read the instruction carefully to make sure you understand
what is being asked in each of the tasks.
For each of the required functions, you need to follow the Assembly Design Recipe which we went, or will go over in class. You can optimize your code once you’ve written it – if, for example, there is some repetition that can be trivially removed, but it still needs to be clear that the recipe was followed.
You are provided with a “mystery library”. This pre-compiled library
contains a single function, crunch
, which takes two signed
long integers and returns a long integer.
Your task is to complete the mystery
program by
implementing the main
function in
mystery-main.s
, which needs to call the provided
crunch
function. This is also called a “driver”. When
compiled, the program should have the following features and
behaviour:
Accept exactly two arguments. You can assume that, when provided, these arguments are valid signed long integers.
The provided crunch
function should be called with
these two numbers, converting them from strings as necessary.
Based on the result from the function, the program should print
one of the following strings (with a newline at the end) and exit with
an exit status of 0
:
hat
, if crunch
returned a negative
integertea
, if crunch
returned
0
beer
, if crunch
returned a positive
integer.If fewer or more than 2 arguments are provided, the program
should print “Two arguments required.
”, followed by a
newline, and exit with a status of 1
.
First, write the main
function in C
and save it in mystery-main.c
, where we provided a “stub”
for you. The program does not have to compile, but it should be a fairly
accurate high-level representation of the assembly program. Do not spend
too much time on this, but give it your best shot. Try to use your
knowledge of Java and provide comments if you are struggling with C.
Second, implement an assembly version of the main
function in
mystery-main.s
. Your program must compile using the
provided Makefile by running make mystery
. The
command make mystery
will combine libmystery.a
(provided by us) and mystery-main.s
(written by you) into
the executable mystery
.
Sample test cases with mystery
:
$ $ ./mystery 1 2
tea
$ ./mystery 2344 12
beer
$ ./mystery -1345 321
hat
$ ./mystery 1
Two arguments required.
The provided library libmystery.a
should work in
Codespaces (and Gradescope, of course). We cannot guarantee that it will
also work on your local Linux, but please let us know if it does work
in, e.g., WSL2.
The second task is to write the function:
unsigned long array_max(unsigned long n, unsigned long *items)
This function will return the maximum value of an array of long integers ≥ 0. The first argument provided is the number of elements, the second argument is the address of the first element.
You do not need to write a C version of this function, but we recommend doing so.
We have provided the driver program in array-max-main.c
,
which processes the command line arguments and calls the
array_max
function. The Makefile will compile both
array-max-main.c
and your implementation of the
array_max
function to produce the executable
array-max
. Once compiled, the interactions with
array-max
should look as follows:
$ ./array-max 1 2
2
$ ./array-max 42 1
42
$ ./array-max 3 1 5 8 2 4 8 20 1
20
Your program must compile without any modification to the
provided array-max-main.c
file, using the provided
Makefile. The command make array-max
will combine
array-max-main.c
(provided by us) and
array-max.s
(written by you) into the executable
array-max
.
We have provided a Makefile for you. You can use it as follows on the command line:
make
: compile all programs (mystery
,
array-max
)make clean
: basic cleanup, remove binariesmake mystery
: compile the mystery
program
using mystery-main.s
and libmystery.a
make array-max
: compile the array-max
program using array-max.s
and
array-max-main.c
Modify the files mystery-main.s
(implementation) and
mystery-main.c
(blueprint) and commit them to your
repository.
Modify the file array-max.s
and commit it to your
repository.
Do not include any executables, object files, or any other binary, intermediate or hidden files.
Finally, go to our Gradescope and submit a ZIP archive of your repository (which can be downloaded from Github).
While inspecting C compiler output to learn about assembly is a good
approach, you are not, under any circumstances, allowed to submit
compiler (or any other machine-generated) output as your .s
files. Doing so will result in an automatic 0 for the assignment. The
code must be clearly written by you, following the Assembly Design
Recipe
Read the assignment carefully and make sure you understand what is being asked in each Task.
Start early. This doesn’t mean you start writing code right away, but you should at least read the description, clone the assignment repository, and look for “missing links”.
Make sure you understand the provided starter code. Ask questions early if not.
Each argument to a program is a string, that is, the value is actually a memory address pointing to the first character of the string in memory.
The above is reflected in the signature of main
,
which is int main(int argc, char *argv[])
– argc
is the argument count, and argv
is an
array of strings. Each string is an array of characters, ending with a
null byte/character (i.e., a character whose numeric ASCII
value is 0). An array is represented as the address of (= a pointer to)
its first element.
The first element of argv
is always the path and
name of the executable. This means the actual arguments start at
argv[1]
.
The return value of main
is the exit code or exit
status of the program. We return 0 by default to signal
success.
You can use standard C functions like atol
where
needed.
Pay close attention to assembly calling conventions and the use of registers when calling C functions, or when writing functions.
Use examples from the lectures and the labs to help you get unstuck and ask questions.
Learn more about Makefiles: https://makefiletutorial.com/