____ ___________ ______ _ _______ _______ ______ _/ ___\/ _ \_ __ \_/ __ \ \/ \/ /\__ \\_ __ \/ ___/ \ \__( <_> ) | \/\ ___/\ / / __ \| | \/\___ \ \___ >____/|__| \___ >\/\_/ (____ /__| /____ > \/ \/ \/ \/ The object of this homework is to destroy your fellow students' code. We have provided you with a harness that simulates a multi-core machine. It loads two MIPS programs onto separate cores. Both cores start executing at the same time. Your task is to write a program that will cause your opponent's core to crash by executing an illegal instruction. The trick, of course, is to tamper with your opponent's memory so that her code executes a bad instruction and crashes. Normally, you would be writing code that always performs accesses to its own address space. Now, you need to write code that goes out of its way to write to illegal addresses, on the off-chance that your opponent's code is about to execute instructions there. One simple strategy might be to randomly select addresses and write bad values there, being careful to not overwrite your own instructions and data. Or you might pick a location, carefully examine the address space to see if your opponent's code could be there, and then concentrate on that small area. Or anything in between. There is no virtual memory; you will be working on bare physical RAM with no protection, in a 4 MiB (4*1024*1024 B) address space. Address accesses are implemented in modular arithmetic, so if you write, read, or execute off either end of the address space you will loop around the other end. You will implement your warrior in C (use the asm keyword to get closer to the machine; look at test-include.h for examples of usage) and build it using the provided Makefile. Edit the Makefile and add the name of your program (the name of your source file with .c removed) to the line defining TARGETS, which initially includes "killer victim spawn". Include somewhere in your file a line such as the following: #define LOAD_ADDRESS 0x400 Your program's code will be loaded at that memory location and its stack will grow down from that point. Keep in mind that, if your opponent is using her stack, destroying her activation record is as effective as destroying her instruction segment. The header test-include.h defines several useful system calls. You can use them to create additional contexts, up to 500 per player, and introduce non-deterministic random values. Since this is a single-threaded simulator, in reality, each player gets 1000 instructions on a single core initially, then the simulator alternates between the two players every 500 instructions. If you have multiple contexts, your 500 instructions will be divided between them such that all your cores get an equal number of instructions and the total does not exceed 500. The grading for this project will be based on a 5-tier single-elimination tournament. Everyone who submits a warrior will receive 50 points out of 100. For every round your warrior passes, you gain an additional 10 points. If you do not pass many rounds, do not sweat it---this assignment will be weighted at most a tenth of the others. It's for fun and profit, as they say, so have fun with it! The harness may be run with the command /usr/local/cs316/pa5/corewars, and the example programs and Makefile are in /usr/local/cs316/pa5/tests. By the tournament, we will provide you with a pre-defined LOAD_ADDRESS your warrior must use (remember rand() to introduce some unpredictability in your warrior's behavior), and a final version of the corewars program to run your own test rounds with the same harness we will be using. Passing the -p option to corewars causes it to print a visualization of memory. Each character corresponds to a large (1 MiB) chunk of memory; any chunk represented by a '.' has never been touched by either player. Any left-pointing character ('<' or '{') indicates that the first player has read that memory, and any right-pointing character ('>' or '}') indicates that the second player has read that memory. The angle brackets ('<' and '>') indicate that the player reading memory is the one who last wrote a value into that chunk, and the curly brackets ('{' and '}') indicate that the player is reading from a chunk most recently written by the other player. You may work in pairs for this project; let the games begin!