CPSC 220, Fall 2022
Lab 10: Control Structures in x86-64 Assembly

In this lab, you will work on several exercises that ask you to implement control structures in x86-64 assembly language, using jump instructions. All operations will be done on unsigned qwords or on strings. You will really be doing the work of a compiler—translating a higher level description of an algorithm into low-level assembly code.

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 program.

Work from this lab is due at the start of next week's lab as usual. You will turn in one assembly language program named lab10.asm. Copy your file to your folder in /classes/cs220/homework

Procedures

Start with a copy of the file lab10.asm, which you can get from this page or from /classes/cs220. That file contains an outline for all the exercises that you will work on for this lab. All of your work for the lab will be in lab10.asm. You should submit a copy of the completed file to your homework folder.

You will also need a copy of basicprint.o. You should already have a copy in your work from last week's lab. Or you can get a copy of basicprint.asm from this page or from /classes/cs220, and assemble it to get basicprint.o. The assembled file lab10.o has to be linked with basicprint.o to produce an executable. You should make no changes to basicprint.asm; your program must work with the original version.

You will use the functions printlong and printstring from basicprint.asm to output numbers and strings. Keep in mind that these functions use many registers internally. When you call the function, you should expect the values in those registers to change. It should always be safe to use r12, r13, r14, r15, and rbx. You can do all of the exercises for the lab using just those five registers.


You are not required to use the ddd debugger for this lab, but you might want to do so to help find errors in your code. You might want to examine the contents of memory while running your program under ddd. You can do that with the x command in the panel at the bottom of the ddd windows. The x command is discussed on page 64 of Jorgensen.

You can use x to print out strings and numbers that are pointed to by variables in the program. The variable name must always be preceded by a &; this is related to syntax used in the C programming language. To print out the value of a variable A as a 64-bit decimal integer, use the command

     x/dg  &A

If A points to an array of 64-bit integers, you can print out the first 12 values in the array with

     x/12dg  &A

If A is a string, display it using

     x/s  &A

Some extra info. The file /classes/cs220/build.sh is a build script that can create an executable from .asm and .o files. For example,

    /classes/cs220/build.sh  lab10.asm  basicprint.o

will assemble lab10.asm and link lab10.o with basicprint.o to produce an executable named lab10. Each input file can be either an .asm or a .o file. Exactly one of the input files should define _start as a global label. The name of the executable is the name of the first input file with the .o or .asm extension removed. You can optionally copy build.sh into your working directory and run it using ./build.sh.

It can be annoying to type the long commands that you need to assemble and link assembly language programs. In Linux, you can define "aliases", or abbreviations, for commands. The alias definitions can be added to a file named .bashrc in your home directory. Since the name of that file begins with a period, it is a hidden file, but you can edit it using the following command in your home directory:

    xed  .bashrc

For example, you might want to add the following alias definitions to .bashrc

    alias y='yasm -felf64 -gdwarf2'
    alias b='/classes/cs220/build.sh'

Changes don't take effect until you open a new Terminal window, since .bashrc is only executed when you open a Terminal or log in remotely. With these aliases, you could type "y lab10.asm" instead of "yasm -felf64 -gdwarf2 lab10.asm" and "b lab10.asm basicprint.o" instead of "/classes/cs220/build.sh lab10.asm basicprint.o"

Exercises

The file lab10.asm contains a label for each exercise, named Exercise1:, Exercise2:, Exercise3:, and so on. You should add your solution for each exercise after the corresponding label. You might want to use local lables in the code that you write. A local label is a label whose name begins with a period. You can use local labels with the same name in different exercises without conflict. Remember that local labels expire at the next regular label.

Please add some labels and blank lines to the output from your program to make it look nicer. Sample output is shown below. The full specification for what each exercise should do is given here:


Exercise 1: Simple loop. Write a loop that will print the integers from 1 to 10, all on one line, separated by spaces. The output should look like this, with an end-of-line at the end:

     1 2 3 4 5 6 7 8 9 10

Note that lab10.asm already defines a string that contains a single space character and a string that contains an end-of-line character.


Exercise 2: Count the E's. There is already a variable named advice that points to a string. You should write some code to find and output the number of times the letter E occurs in the string. You should count both upper and lower case E's. Pseudocode for the algorithm is given by

     count = 0     ; for counting the e's
     ptr = advice  ; pointer to next char from string
     while (char at address ptr is not zero) {
         if the char is 'e'
            count++
         else if the char is 'E'
            count++
         ptr++
     }
     output count

When comparing a byte to 'e' or 'E', you actually need to compare the ASCII codes, which represent the characters in memory. But yasm has a nice feature that lets you to use a character constant to represent a byte value. For example, if register r12 holds the address of a character in memory and you want to compare that character to 'E', you can simply say

     cmp byte [r12], 'E'

Exercise 3: Fizz-Buzz. For this exercises, you should write code to solve the well-known fizz-buzz coding problem: output the numbers from 1 to 100, but if the number is divisible by 3 output Fizz instead, if the number is divisible by 5 output Buzz instead, and if the number is divisible by both, output Fizz Buzz. That is, implement the following pseudocode:

     count = 1
     while count <= 100 {
        if (count % 15)
            output "Fizz Buzz"
        else if (count % 3)
            output "Fizz"
        else if (count % 5)
            output "Buzz"
        else
            output count
        output an end-of-line
        count = count + 1
     }

Exercise 4: Array Max. LIST is already defined in lab10.asm as a label for an array of numbers. Also, LISTlen is a variable giving the number of items in the array. Write code to find and output the largest value in the array. Your code should work for any array, but you can assume that the number of items is at least one.

(Note: The definition of LIST uses a yasm feature I haven't mentioned: If a line in the program ends with a backslash character ("\"), then the next line in the file is considered to be a continuation of that line. That is, an end-of-line after a "\" is essentially ignored.)


Exercise 5: Selection Sort. Sort the array that LIST points to, using the following Selection Sort algorithm, and then output the list.

for ( top = LISTlen - 1; top > 0; top-- ) {
    maxLoc = 0
    max = LIST[0]
    for ( i = 0; i <= top; i++ ) {
       if ( LIST[i] > max ) {
           maxLoc = i
           max = LIST[i]
       }
    }
    temp = LIST[top]   // (These two lines implement LIST[maxLoc] = LIST[top].)
    LIST[maxLoc] = temp
    LIST[top] = max
}
for ( i = 0; i < LISTlen; i++ ) {
    output LIST[i]
}

Remember that you can use [LIST+r15*8] to implement a reference to an array element that in Java would be LIST[r15].

Sample Output

Here is the output from my solution to this lab, with part of the FizzBuzz output and part of the sorted list omitted:

1 2 3 4 5 6 7 8 9 10 

The number of E's in the string is 6

The Fizz-Buzz problem:
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
Fizz Buzz
16
17
   .
   .
   .
97
98
Fizz
Buzz

The maximum of the array is 830

The array in sorted order:
21
34
62
73
77
82
94
100
108
137
   .
   .
   .