University of Minnesota
Machine Architecture and Organization (sec 010)
index.php

CSCI 2021 lab0x8


Y86-64 Architecture Simulators

In this week's lab you will also be writing and running Y86-64 code.

Writing Y86-64 Code

You can copy the files for this lab using the following command:

    cp /web/classes/Spring-2020/csci2021/labs/0x8/{example.ys,sum.ys,yas,yis} .
  

First, let's get some practice reading and executing a Y86-64 program: example.ys. Start by opening the file example.ys in your text editor of choice. Below is the corresponding C code to example.ys

long example (long x, long y) {
  if(x < y) {
    x = x - 8;
  }
  else {
    y = y + 8;
  }
  return(2 * x + y);
}

There are comments given to help you understand which portions of the Y86-64 corresponds to the C. Notice that Y86-64 is a bit different from the X86-64 assembly you have worked with before break. First, there is no comparision instruction, so comparisions must be replaced by subtractions to get the same effect. Also, in Y86-64, there is not instruction that can add a constant value to a register. So instead, we first have to store the constant in an unused register, then add the two registers together.

There are two tools you can use together to execute Y86-64 code. We don't have a compiler to generate Y86-64 code from C. We write Y86-64 assembly code in files with the extension .ys. The program yas is an assembler that converts Y86-64 assembly language into hexadecimal bytes in an object file with the extension .yo. There is also no linker, standard library, or operating system. Instead a single object file representing a complete program and its input can be run by the interpreter yis. When the program's execution finishes, yis prints information about any registers or memory locations that have changed, some of which can represent the programs output.

Next let's run example.ys to see what happens. To assemble the program, use the command:

./yas example.ys

This will create the object file example.yo that we can execute. To execute the program:

./yis example.yo

The output here might seem pretty strange, but it will make sense after some careful examination. Instead of actually seeing the program run, we are given a summary of what happend. The main sections of this summary are 'Changes to registers:' and 'Changes to memory:'. Only focus on the registers for now (since the program didn't do anything very interesting with the stack).

  • %rax: 0x00...018 = 24. This is the result or return value of example.c
  • %rsi: 0x00...014 = 20. y
  • %rdi: 0x00...004 = 4. (x - 8) * 2
  • %r8: 0x00...08 = 8. Stored constant 8
  • %r9: 0xff...f6 = -10. Result of x - y

After examining all of the registers, it seems that our program is behaving just like the C version. You can try passing other arugments to the function if you would like to confirm this further.

Now that you have some experice with Y86-64, it is time to write your first program (really just a single function). Your task is to write a Y86-64 program sum.ys that iterativelty sums the elements of a linked list. The complete program will consist of some code that sets up the stack sturcture, invokes a function, and then halts (Most of this is already given in sum.ys). You need to fill in the function sum_list. (We've written a version that always returns 1.) Test your program using the three-element list defined at the top of sum.ys.

The linked-list data structure has nodes containing a 8-bit value and a pointer to the next element; a null next pointer indicates the end of the list. This layout is like what would be generated for the following C struct on x86-64:

struct list_node {
    long data;              /* offset 0 */
    struct list_node *next; /* offset 8 */
};
      

Since the three data values in the example linked list are 0xa00, 0xb0, and 0xc, a correct version of the program should finish with %rax = 0x00...0abc.

If you are unsure of where to start, first try writing a C function that does the same thing as what the Y86-64 code should do. Then look at the x86-64 code generated for your function, and think about how each of the x86-64 instructions can be translated in to one or more Y86-64 instructions.