CPSC 220, Fall 2022
Lab 11: Functions in x86-64 Assembly

This lab is about writing and using functions in assembly language. The lab has two parts. In Part A, you will write some functions in assembly language that are called from a program written in C. In Part B, you will write an assembly language program that calls functions from the C standard library. The two parts of the lab are completely independent. You can work on them in either order.

You will need to use the Linux C calling convention, which was summarized in this handout.

You have the option of working on this lab with a partner of your choice. Two people working together should submit just one copy of their work, to the homework folder for either partner. Both names must be in a comment at the top of the programs.

Work from this lab is due by 3:00 PM next Friday, November 11 Monday, November 14 (later than usual because of the test on Wednesday). You will turn in two assembly language programs named lab11A.asm and lab11B.asm. Copy your files to your folder in /classes/cs220/homework

Part A: Writing Functions in Assembly for Use in C

For this part of the lab, you should create a new file named lab11A.asm to hold your assembly language code. You will write three functions in that file named sum8, arraySearch, and fibonacci. These functions will be called from a program written in C. To work with that program, they must follow the C calling convention for passing arguments and returning a value.

The C program that will test your functions is lab11main.c, which you can get from /classes/cs220 or through the above link.

The functions are declared extern in the C program. To make them available for use in that program, you need to declare sum8, arraySearch, and fibonacci to be global in lab11A.asm.

You can assemble lab11A.asm in the usual way with yasm, to get the object file lab11A.o. But to link it with the C program, you will have to complile and link it using the gcc compiler and linker. The command to compile and link and create an executable program named lab11 is:

gcc -g -o lab11 lab11main.c lab11A.o

You can then use the command ./lab11 to run the program. (If you get a some error mentioning PIE when you use gcc, try using this command instead:

gcc -g -no-pie -o lab11 lab11main.c lab11A.o

but that should only happen if the assembly language code has a data, rodata, or bss section, and you don't need those sections for this lab.)

Debugging problems. You might want to run the debugger on the program. It has become clear that there is a bug in some combination of the yasm assembler and the debugger. The alternative assembler, nasm, doesn't have the same problem. If you want to use the debugger, try assembling your code with nasm using

nasm  -felf64  -gdwarf  lab11A.asm

Note the use of "-gdwarf" instead of "-gdwarf2"; that is not a typo. Unfortunately, the syntax rules for nasm are not quite identical to yasm syntax rules. It should work, but if you have problems, ask for help.


Here is a specification of the three functions:

First function: sum8(a,b,c,d,e,f,g,h). The first function is simple. It just adds up its eight arguments and returns the sum. It can be implemented with a mov instruction and eight add instructions. The problem is knowing where the arguments are, and for that you need to understand the calling convention. The arguments and return value are of type long. (Note: Remember that values on the stack can be accessed relative to the stack pointer, rsp.)

Second function: long arraySearch(long A[], long len, long x). This function searches an array for a given value. It returns -1 if the value is not in the array, and it returns the array index of the item if it is found. The first argument is (a pointer to) the array. The second is the number of items in the array. And the third is the item that you are searching for.

Third function: unsigned long fibonacci(unsigned long N). You should write a recursive function to compute the Nth Fibonacci number. (This is a terrible idea, since the recursive implementation is horribly inefficient, and you shouldn't call the function for N bigger than maybe 25 because the run time increases exponentially with N.) In pseduocode, the recursive algorithm is:

if (N < 2)
   return 1
else
   return fibonacci(N-1) + fibonacci(N-2)

For the recursive case, you will need to save at least one value on the stack.


Here is what the program should output"

sum8(10,-3,7,20,-15,2,15,6) = 42

Is  10 in list1?  yes
Is  42 in list1?  no
Is 636 in list2?  yes
Is -17 in list2?  no
Is 211 in list2?  yes
Is 238 in list2?  yes

Fibonacci(0) is 1
Fibonacci(1) is 1
Fibonacci(2) is 2
Fibonacci(3) is 3
Fibonacci(4) is 5
Fibonacci(5) is 8
Fibonacci(6) is 13
Fibonacci(7) is 21
Fibonacci(8) is 34
Fibonacci(9) is 55

Part B: Calling Standard C Functions

For this part of the lab, you should create a new file named lab11B.asm to hold your program. You will write an assembly language program that is a direct translation of a program written in C. The program lets the user play a guessing game. It is given below and in the file guessing-game.c. If you would like to try the program before you work on the translation, you can compile and run it with the commands

gcc -o game guessing-game.c
./game

The program includes calls to the standard C functions printf, scanf, getchar, time, srand, and rand. Don't forget to declare those names as extern in your program. And remember, if you work with 32-bit integer values, use the 32-bit registers such as eax, esi, and r12d.

To compile and link your program, you should use the build script build.sh, which can be found in /classes/cs220. You can run it from that folder:

/classes/cs220/build.sh  -c  lab11B.asm

You can also copy it into the same directory as lab11B.asm and run it from there:

./build.sh  -c  lab11B.asm

In any case, don't forget to include the "-c" option. That option is needed for the linker to find the C standard libraries. You will get link errors if you don't include it.

It is possible to use the ddd debugger for this part of the lab, but you should use the nasm assembler instead of yasm to the avoid the yasm bugs. To use nasm with the build script, add the "-n" option:

./build.sh  -c  -n  lab11B.asm

Here is the program written in C:

#include <time.h>
#include <stdio.h>
#include <stdlib.h>

/* Guessing game.  Computer picks a random number in the range 1 to 100.
 * The user tries to guess it.  The computer tells the user if their guess
 * is high or low.  The user has 6 tries to guess the number.
 */

int main() {

    // initialize the random number generator with the current time.
    unsigned long now = time(0);
    srand(now);
    
    int N = (rand() % 100) + 1; // random number in the range 1 to 100
    
    printf("I picked a number in the range 1 to 100.  Try to guess it.\n\n");
    
    int guessCount = 0;  // Count the user's guesses.
    int userGuess;       // The user's guess;
    
    while (1) {
        guessCount++;
        printf("What is your guess? ");
        int i = scanf("%i", &userGuess);
        if ( i != 1 ) {
            printf("Please enter an integer!\n");
            guessCount--; // don't count this guess
            int ch;
            do { // eat the rest of the input line
               ch = getchar();
            } while (ch != 10);
        }
        else if (userGuess == N) {
           printf("You got it in %d tries.\n", guessCount);
           break;
        }
        else if (guessCount == 6) {
           printf("Sorry, you used up your 6 guesses.\n");
           printf("My number was %i.\n", N);
           break;
        }
        else if (userGuess > N) {
            printf("Too high!  Try again.");
        }
        else {
            printf("Too low!  Try again.");
        }
    }

}