Initial commit
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
BasedOnStyle: LLVM
|
||||
BreakBeforeBraces: Attach
|
||||
IndentCaseLabels: true
|
||||
IndentWidth: 4
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
ColumnLimit: 80
|
||||
@@ -0,0 +1,51 @@
|
||||
#
|
||||
# Simple Makefile
|
||||
# Mike Lam, James Madison University, August 2016
|
||||
#
|
||||
# This makefile builds a simple application that contains a main module
|
||||
# (specified by the EXE variable) and a predefined list of additional modules
|
||||
# (specified by the MODS variable). If there are any external library
|
||||
# dependencies (e.g., the math library, "-lm"), list them in the LIBS variable.
|
||||
# If there are any precompiled object files, list them in the OBJS variable.
|
||||
#
|
||||
# By default, this makefile will build the project with debugging symbols and
|
||||
# without optimization. To change this, edit or remove the "-g" and "-O0"
|
||||
# options in CFLAGS and LDFLAGS accordingly.
|
||||
#
|
||||
# By default, this makefile build the application using the GNU C compiler,
|
||||
# adhering to the C99 standard with all warnings enabled.
|
||||
|
||||
|
||||
# application-specific settings and run target
|
||||
|
||||
EXE=y86
|
||||
MODS=p3-disas.o
|
||||
OBJS=p1-check.o p2-load.o
|
||||
LIBS=
|
||||
|
||||
default: $(EXE)
|
||||
|
||||
test: $(EXE)
|
||||
TPREFIX=tests/ make -C tests test
|
||||
|
||||
# compiler/linker settings
|
||||
|
||||
CC=gcc
|
||||
CFLAGS=-g -O0 -Wall --std=c99 -pedantic
|
||||
LDFLAGS=-g -O0
|
||||
|
||||
|
||||
# build targets
|
||||
|
||||
$(EXE): main.o $(MODS) $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $(EXE) $^ $(LIBS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) $<
|
||||
|
||||
clean:
|
||||
rm -f $(EXE) main.o $(MODS)
|
||||
make -C tests clean
|
||||
|
||||
.PHONY: default clean
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
#ifndef __CS261_ELF__
|
||||
#define __CS261_ELF__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "y86.h"
|
||||
|
||||
/*
|
||||
Mini-ELF file format (byte 0 = first byte of the file)
|
||||
+----------------------------------------------+
|
||||
| header (elf_hdr_t) - 16 bytes |
|
||||
+----------------------------------------------+
|
||||
| program headers (elf_phdr_t) - 20 bytes each |
|
||||
+----------------------------------------------+
|
||||
| program segments - variable length of bytes |
|
||||
+----------------------------------------------+
|
||||
| symbol table - each entry is 4 bytes each |
|
||||
+----------------------------------------------+
|
||||
| string table - variable length of strings |
|
||||
+----------------------------------------------+
|
||||
|
||||
ELF header structure:
|
||||
+----------------------------------------------------------------------------+
|
||||
| 0 1 | 2 3 | 4 5 | 6 7 | 8 9 | 10 11 | 12 13 14 15 |
|
||||
| version | entry | phdr | numphdr | symtab | strtab | magic number |
|
||||
+----------------------------------------------------------------------------+
|
||||
|
||||
Sample ELF header (all entries in hex, format is little endian):
|
||||
+----------------------------------------------------------------------------+
|
||||
| 01 00 | 00 01 | 10 00 | 05 00 | ac 00 | c2 00 | 45 4c 46 00 |
|
||||
| version | entry | phdr | numphdr | symtab | strtab | magic number |
|
||||
+----------------------------------------------------------------------------+
|
||||
|
||||
version = 0x0001 entry = 0x0100 phdr = 0x0010 numphdr = 0x0005
|
||||
symtab = 0x00ac strtab = 0x00c2 magic = "ELF\0"
|
||||
|
||||
Interpretation:
|
||||
This file was created under version 1 of this format. When the program is
|
||||
loaded into memory, the instruct at address 0x100 (256) will be executed
|
||||
first. The first program header (which indicates segments in this file)
|
||||
starts at offset 0x10 (16) into the file, and there are 5 program headers
|
||||
total. The symbol table starts at offset 0xac (172) into this file, and the
|
||||
string table starts at offset 0xc2 (194). The magic number is the string
|
||||
"ELF\0" and is for error checking.
|
||||
*/
|
||||
typedef struct __attribute__((__packed__)) elf {
|
||||
uint16_t e_version; /* version should be 1 */
|
||||
uint16_t e_entry; /* entry point of program */
|
||||
uint16_t e_phdr_start; /* start of program headers */
|
||||
uint16_t e_num_phdr; /* number of program headers */
|
||||
uint16_t e_symtab; /* start of symbol table */
|
||||
uint16_t e_strtab; /* start of string table */
|
||||
uint32_t magic; /* ELF */
|
||||
} elf_hdr_t;
|
||||
|
||||
typedef enum {
|
||||
DATA, CODE, STACK, HEAP, UNKNOWN
|
||||
} elf_segtype_t;
|
||||
|
||||
/*
|
||||
ELF program header structure (describing segments):
|
||||
+-----------------------------------------------------------------------+
|
||||
| 0 1 2 3 | 4 5 6 7 | 8 9 10 11 | 12 13 | 14 15 | 16 17 18 19 |
|
||||
| offset | size | virt addr | type | flags | magic number|
|
||||
+-----------------------------------------------------------------------+
|
||||
|
||||
Flags store segment permissions as RWX (read/write/execute) in binary.
|
||||
Examples: 100 (binary) = 4 (decimal/hex) = read-only (R )
|
||||
101 (binary) = 5 (decimal/hex) = read-execute (R X)
|
||||
110 (binary) = 6 (decimal/hex) = read-write (RW )
|
||||
|
||||
Sample ELF program header (all entries in hex, format is little endian):
|
||||
+-----------------------------------------------------------------------+
|
||||
| 74 00 00 00 | 12 00 00 00 | 00 01 00 00 | 01 00 | 05 00 | ef be ad de |
|
||||
| offset | size | virt addr | type | flags | magic number|
|
||||
+-----------------------------------------------------------------------+
|
||||
|
||||
offset = 0x00000074 size = 0x00000012 virt addr = 0x00000100
|
||||
type = 0x0001 (CODE) flags = 0x0005 (RX) magic = 0xDEADBEEF
|
||||
|
||||
Interpretation:
|
||||
The segment starts at offset 0x74 (116) in the file, and it is 0x12 (18)
|
||||
bytes in size. It will be loaded into memory address 0x100 (256). Since it
|
||||
is a CODE segment, it needs to have read-execute (RX) permissions attached.
|
||||
The magic number is the value 0xDEADBEEF and is for error checking.
|
||||
*/
|
||||
typedef struct __attribute__((__packed__)) elf_phdr {
|
||||
uint32_t p_offset; /* beginning of the segment in the file (in bytes) */
|
||||
uint32_t p_size; /* number of bytes in the segment */
|
||||
uint32_t p_vaddr; /* intended virtual address of the beginning of
|
||||
the segment in a running program's memory */
|
||||
uint16_t p_type; /* segment type (e.g., code, data, etc.) */
|
||||
uint16_t p_flags; /* permissions flags */
|
||||
uint32_t magic; /* DEADBEEF */
|
||||
} elf_phdr_t;
|
||||
|
||||
#endif
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* CS 261: Main driver
|
||||
*
|
||||
* Name: Nicholas Tamassia
|
||||
*
|
||||
* This code was developed in compliance with the JMU Honor code.
|
||||
*/
|
||||
|
||||
#include "p1-check.h"
|
||||
#include "p2-load.h"
|
||||
#include "p3-disas.h"
|
||||
|
||||
/*
|
||||
* helper function for printing help text
|
||||
*/
|
||||
void usage(char **argv) {
|
||||
printf("Usage: %s <option(s)> mini-elf-file\n", argv[0]);
|
||||
printf(" Options are:\n");
|
||||
printf(" -h Display usage\n");
|
||||
printf(" -H Show the Mini-ELF header\n");
|
||||
printf(" -a Show all with brief memory\n");
|
||||
printf(" -f Show all with full memory\n");
|
||||
printf(" -s Show the program headers\n");
|
||||
printf(" -m Show the memory contents (brief)\n");
|
||||
printf(" -M Show the memory contents (full)\n");
|
||||
printf(" -d Disassemble code contents\n");
|
||||
printf(" -D Disassemble data contents\n");
|
||||
}
|
||||
|
||||
void exit_file_error(FILE *file) {
|
||||
if (file) {
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
printf("Failed to read file\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int c;
|
||||
bool show_elf_header = false;
|
||||
bool show_program_header = false;
|
||||
bool show_memory_brief = false;
|
||||
bool show_memory_full = false;
|
||||
bool show_code = false;
|
||||
bool show_data = false;
|
||||
|
||||
while ((c = getopt(argc, argv, "hHafsmMdD")) != -1) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage(argv);
|
||||
return EXIT_SUCCESS;
|
||||
case 'H':
|
||||
show_elf_header = true;
|
||||
break;
|
||||
case 'a':
|
||||
show_elf_header = true;
|
||||
show_program_header = true;
|
||||
show_memory_brief = true;
|
||||
break;
|
||||
case 'f':
|
||||
show_elf_header = true;
|
||||
show_program_header = true;
|
||||
show_memory_full = true;
|
||||
break;
|
||||
case 's':
|
||||
show_program_header = true;
|
||||
break;
|
||||
case 'm':
|
||||
show_memory_brief = true;
|
||||
break;
|
||||
case 'M':
|
||||
show_memory_full = true;
|
||||
break;
|
||||
case 'd':
|
||||
show_code = true;
|
||||
break;
|
||||
case 'D':
|
||||
show_data = true;
|
||||
break;
|
||||
default:
|
||||
usage(argv);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/* File path was not the last argument */
|
||||
bool invalid_arguments = optind != argc - 1;
|
||||
/* Attempted to ask for brief and full memory at same time */
|
||||
bool memory_flag_conflict = show_memory_brief && show_memory_full;
|
||||
|
||||
if (invalid_arguments || memory_flag_conflict) {
|
||||
usage(argv);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
elf_hdr_t header = {0};
|
||||
FILE *header_file = fopen(argv[optind], "r");
|
||||
|
||||
/* Read contents of header_file into header */
|
||||
if (!read_header(header_file, &header)) {
|
||||
exit_file_error(header_file);
|
||||
}
|
||||
|
||||
if (show_elf_header) {
|
||||
dump_header(&header);
|
||||
}
|
||||
|
||||
elf_phdr_t phdrs[header.e_num_phdr];
|
||||
memset(phdrs, 0, sizeof(phdrs));
|
||||
|
||||
/* Read program headers into phdrs array */
|
||||
for (int i = 0; i < header.e_num_phdr; i++) {
|
||||
uint16_t offset = header.e_phdr_start + i * sizeof(elf_phdr_t);
|
||||
if (!read_phdr(header_file, offset, &phdrs[i])) {
|
||||
exit_file_error(header_file);
|
||||
}
|
||||
}
|
||||
|
||||
if (show_program_header) {
|
||||
dump_phdrs(header.e_num_phdr, phdrs);
|
||||
}
|
||||
|
||||
byte_t memory[MEMSIZE];
|
||||
memset(memory, 0, MEMSIZE);
|
||||
|
||||
/* Read memory segments into memory array */
|
||||
for (int i = 0; i < header.e_num_phdr; i++) {
|
||||
if (!load_segment(header_file, memory, &phdrs[i])) {
|
||||
exit_file_error(header_file);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(header_file);
|
||||
|
||||
if (show_memory_brief) {
|
||||
for (int i = 0; i < header.e_num_phdr; i++) {
|
||||
uint32_t start = phdrs[i].p_vaddr;
|
||||
uint32_t end = start + phdrs[i].p_size;
|
||||
|
||||
dump_memory(memory, start, end);
|
||||
}
|
||||
} else if (show_memory_full) {
|
||||
dump_memory(memory, 0, MEMSIZE);
|
||||
}
|
||||
|
||||
if (show_code) {
|
||||
printf("Disassembly of executable contents:\n");
|
||||
|
||||
for (int i = 0; i < header.e_num_phdr; i++) {
|
||||
if (phdrs[i].p_type == CODE) {
|
||||
disassemble_code(memory, &phdrs[i], &header);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (show_data) {
|
||||
printf("Disassembly of data contents:\n");
|
||||
|
||||
for (int i = 0; i < header.e_num_phdr; i++) {
|
||||
if (phdrs[i].p_type == DATA && phdrs[i].p_flags == 4) {
|
||||
disassemble_rodata(memory, &phdrs[i]);
|
||||
} else if (phdrs[i].p_type == DATA) {
|
||||
disassemble_data(memory, &phdrs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,29 @@
|
||||
#ifndef __CS261_P1__
|
||||
#define __CS261_P1__
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "elf.h"
|
||||
|
||||
/**
|
||||
* @brief Load a Mini-ELF header from an open file stream
|
||||
*
|
||||
* @param file File stream to use for input
|
||||
* @param hdr Pointer to region where the Mini-ELF header should be loaded
|
||||
* @returns True if the header was successfully loaded and verified, false otherwise
|
||||
*/
|
||||
bool read_header (FILE *file, elf_hdr_t *hdr);
|
||||
|
||||
/**
|
||||
* @brief Print Mini-ELF header information to standard out
|
||||
*
|
||||
* @param hdr Header with info to print
|
||||
*/
|
||||
void dump_header (elf_hdr_t *hdr);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,52 @@
|
||||
#ifndef __CS261_P2__
|
||||
#define __CS261_P2__
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "elf.h"
|
||||
#include "y86.h"
|
||||
|
||||
/**
|
||||
* @brief Load a Mini-ELF program header from an open file stream
|
||||
*
|
||||
* @param file File stream to use for input
|
||||
* @param offset Byte offset in file where the program header is located
|
||||
* @param phdr Pointer to memory where the Mini-ELF program header should be loaded
|
||||
* @returns True if the header was successfully loaded and verified, false otherwise
|
||||
*/
|
||||
bool read_phdr (FILE *file, uint16_t offset, elf_phdr_t *phdr);
|
||||
|
||||
/**
|
||||
* @brief Load a Mini-ELF program segment from an open file stream
|
||||
*
|
||||
* @param file File stream to use for input
|
||||
* @param memory Pointer to the beginning of the Y86 address space into which
|
||||
* the segment should be loaded
|
||||
* @param phdr Pointer to the program header for the segment that should be loaded
|
||||
* @returns True if the segment was successfully loaded, false otherwise
|
||||
*/
|
||||
bool load_segment (FILE *file, byte_t *memory, elf_phdr_t *phdr);
|
||||
|
||||
/**
|
||||
* @brief Print Mini-ELF program header information to standard out
|
||||
*
|
||||
* @param numphdrs Number of program headers to print
|
||||
* @param phdrs Pointer to array of program headers with info to print
|
||||
*/
|
||||
void dump_phdrs (uint16_t numphdrs, elf_phdr_t *phdrs);
|
||||
|
||||
/**
|
||||
* @brief Print a portion of a Y86 address space
|
||||
*
|
||||
* @param memory Pointer to the beginning of the Y86 address space
|
||||
* @param start Byte offset where printing should begin
|
||||
* @param end Byte offset where printing should end
|
||||
*/
|
||||
void dump_memory (byte_t *memory, uint16_t start, uint16_t end);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,574 @@
|
||||
/*
|
||||
* CS 261 PA3: Mini-ELF disassembler
|
||||
*
|
||||
* Name: Nicholas Tamassia
|
||||
*
|
||||
* This code was developed in compliance with the JMU Honor code.
|
||||
*/
|
||||
|
||||
#include "p3-disas.h"
|
||||
|
||||
/**********************************************************************
|
||||
* REQUIRED FUNCTIONS
|
||||
*********************************************************************/
|
||||
|
||||
bool has_register_byte(y86_inst_t ins);
|
||||
|
||||
bool has_register_byte(y86_inst_t ins) {
|
||||
switch (ins.icode) {
|
||||
case CMOV:
|
||||
case IRMOVQ:
|
||||
case RMMOVQ:
|
||||
case MRMOVQ:
|
||||
case OPQ:
|
||||
case PUSHQ:
|
||||
case POPQ:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool has_valc_bytes(y86_inst_t ins);
|
||||
|
||||
bool has_valc_bytes(y86_inst_t ins) {
|
||||
switch (ins.icode) {
|
||||
case IRMOVQ:
|
||||
case RMMOVQ:
|
||||
case MRMOVQ:
|
||||
case JUMP:
|
||||
case CALL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void validate_opcode(y86_inst_t *ins, byte_t *current_byte);
|
||||
|
||||
void validate_opcode(y86_inst_t *ins, byte_t *current_byte) {
|
||||
if (ins == NULL || current_byte == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
y86_icode_t opcode_high = *current_byte >> 4;
|
||||
byte_t opcode_low = *current_byte & 0xF;
|
||||
ins->icode = opcode_high;
|
||||
|
||||
switch (ins->icode) {
|
||||
case CMOV:
|
||||
if (opcode_low >= BADCMOV) {
|
||||
ins->icode = INVALID;
|
||||
}
|
||||
ins->ifun.cmov = opcode_low;
|
||||
break;
|
||||
|
||||
case OPQ:
|
||||
if (opcode_low >= BADOP) {
|
||||
ins->icode = INVALID;
|
||||
}
|
||||
ins->ifun.op = opcode_low;
|
||||
break;
|
||||
|
||||
case JUMP:
|
||||
if (opcode_low >= BADJUMP) {
|
||||
ins->icode = INVALID;
|
||||
}
|
||||
ins->ifun.jump = opcode_low;
|
||||
break;
|
||||
|
||||
case IOTRAP:
|
||||
if (opcode_low >= BADTRAP) {
|
||||
ins->icode = INVALID;
|
||||
}
|
||||
ins->ifun.trap = opcode_low;
|
||||
break;
|
||||
|
||||
case HALT:
|
||||
case NOP:
|
||||
case IRMOVQ:
|
||||
case RMMOVQ:
|
||||
case MRMOVQ:
|
||||
case CALL:
|
||||
case RET:
|
||||
case PUSHQ:
|
||||
case POPQ:
|
||||
if (opcode_low != 0x0) {
|
||||
ins->icode = INVALID;
|
||||
}
|
||||
ins->ifun.b = opcode_low;
|
||||
break;
|
||||
|
||||
default:
|
||||
ins->icode = INVALID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void validate_registers(y86_inst_t *ins, byte_t *current_byte);
|
||||
|
||||
void validate_registers(y86_inst_t *ins, byte_t *current_byte) {
|
||||
if (ins == NULL || current_byte == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ins->ra = *current_byte >> 4;
|
||||
ins->rb = *current_byte & 0xF;
|
||||
|
||||
switch (ins->icode) {
|
||||
case IRMOVQ:
|
||||
if (ins->ra != NOREG || ins->rb == NOREG) {
|
||||
ins->icode = INVALID;
|
||||
}
|
||||
break;
|
||||
|
||||
case PUSHQ:
|
||||
case POPQ:
|
||||
if (ins->ra == NOREG || ins->rb != NOREG) {
|
||||
ins->icode = INVALID;
|
||||
}
|
||||
break;
|
||||
|
||||
case RMMOVQ:
|
||||
case MRMOVQ:
|
||||
if (ins->ra == NOREG) {
|
||||
ins->icode = INVALID;
|
||||
}
|
||||
break;
|
||||
|
||||
case CMOV:
|
||||
case OPQ:
|
||||
if (ins->ra == NOREG || ins->rb == NOREG) {
|
||||
ins->icode = INVALID;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void assign_valc(y86_inst_t *ins, byte_t *current_byte);
|
||||
|
||||
void assign_valc(y86_inst_t *ins, byte_t *current_byte) {
|
||||
if (ins == NULL || current_byte == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t valc = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
valc |= (uint64_t) * (current_byte + i) << (8 * i);
|
||||
}
|
||||
|
||||
switch (ins->icode) {
|
||||
case IRMOVQ:
|
||||
ins->valC.v = valc;
|
||||
break;
|
||||
case RMMOVQ:
|
||||
case MRMOVQ:
|
||||
ins->valC.d = valc;
|
||||
break;
|
||||
case JUMP:
|
||||
case CALL:
|
||||
ins->valC.dest = valc;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
y86_inst_t fetch(y86_t *cpu, byte_t *memory) {
|
||||
y86_inst_t ins = {0};
|
||||
|
||||
if (cpu == NULL || memory == NULL) {
|
||||
ins.icode = INVALID;
|
||||
return ins;
|
||||
}
|
||||
|
||||
if (cpu->pc > MEMSIZE - 10) {
|
||||
ins.icode = INVALID;
|
||||
cpu->stat = ADR;
|
||||
return ins;
|
||||
}
|
||||
|
||||
byte_t *current_byte = &memory[cpu->pc];
|
||||
|
||||
validate_opcode(&ins, current_byte);
|
||||
if (ins.icode == INVALID) {
|
||||
cpu->stat = INS;
|
||||
return ins;
|
||||
}
|
||||
|
||||
current_byte++;
|
||||
|
||||
if (has_register_byte(ins)) {
|
||||
validate_registers(&ins, current_byte);
|
||||
|
||||
if (ins.icode == INVALID) {
|
||||
cpu->stat = INS;
|
||||
return ins;
|
||||
}
|
||||
|
||||
current_byte++;
|
||||
}
|
||||
|
||||
if (has_valc_bytes(ins)) {
|
||||
assign_valc(&ins, current_byte);
|
||||
current_byte += 8;
|
||||
}
|
||||
|
||||
ins.valP = current_byte - memory;
|
||||
|
||||
if (ins.icode == HALT) {
|
||||
cpu->stat = HLT;
|
||||
} else {
|
||||
cpu->stat = AOK;
|
||||
}
|
||||
|
||||
return ins;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* OPTIONAL FUNCTIONS
|
||||
*********************************************************************/
|
||||
|
||||
void print_register(y86_regnum_t y86_register);
|
||||
|
||||
void print_register(y86_regnum_t y86_register) {
|
||||
switch (y86_register) {
|
||||
case RAX:
|
||||
printf("%%rax");
|
||||
break;
|
||||
case RCX:
|
||||
printf("%%rcx");
|
||||
break;
|
||||
case RDX:
|
||||
printf("%%rdx");
|
||||
break;
|
||||
case RBX:
|
||||
printf("%%rbx");
|
||||
break;
|
||||
case RSP:
|
||||
printf("%%rsp");
|
||||
break;
|
||||
case RBP:
|
||||
printf("%%rbp");
|
||||
break;
|
||||
case RSI:
|
||||
printf("%%rsi");
|
||||
break;
|
||||
case RDI:
|
||||
printf("%%rdi");
|
||||
break;
|
||||
case R8:
|
||||
case R9:
|
||||
case R10:
|
||||
case R11:
|
||||
case R12:
|
||||
case R13:
|
||||
case R14:
|
||||
printf("%%r%d", y86_register);
|
||||
break;
|
||||
case NOREG:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void print_cmov(y86_cmov_t cmov);
|
||||
|
||||
void print_cmov(y86_cmov_t cmov) {
|
||||
switch (cmov) {
|
||||
case RRMOVQ:
|
||||
printf("rrmovq");
|
||||
break;
|
||||
case CMOVLE:
|
||||
printf("cmovle");
|
||||
break;
|
||||
case CMOVL:
|
||||
printf("cmovl");
|
||||
break;
|
||||
case CMOVE:
|
||||
printf("cmove");
|
||||
break;
|
||||
case CMOVNE:
|
||||
printf("cmovne");
|
||||
break;
|
||||
case CMOVGE:
|
||||
printf("cmovge");
|
||||
break;
|
||||
case CMOVG:
|
||||
printf("cmovg");
|
||||
break;
|
||||
case BADCMOV:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void print_opq(y86_op_t opq);
|
||||
|
||||
void print_opq(y86_op_t opq) {
|
||||
switch (opq) {
|
||||
case ADD:
|
||||
printf("addq");
|
||||
break;
|
||||
case SUB:
|
||||
printf("subq");
|
||||
break;
|
||||
case AND:
|
||||
printf("andq");
|
||||
break;
|
||||
case XOR:
|
||||
printf("xorq");
|
||||
break;
|
||||
case BADOP:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void print_jump(y86_jump_t jump);
|
||||
|
||||
void print_jump(y86_jump_t jump) {
|
||||
switch (jump) {
|
||||
case JMP:
|
||||
printf("jmp");
|
||||
break;
|
||||
case JLE:
|
||||
printf("jle");
|
||||
break;
|
||||
case JL:
|
||||
printf("jl");
|
||||
break;
|
||||
case JE:
|
||||
printf("je");
|
||||
break;
|
||||
case JNE:
|
||||
printf("jne");
|
||||
break;
|
||||
case JGE:
|
||||
printf("jge");
|
||||
break;
|
||||
case JG:
|
||||
printf("jg");
|
||||
break;
|
||||
case BADJUMP:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void disassemble(y86_inst_t *inst) {
|
||||
if (inst == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (inst->icode) {
|
||||
case HALT:
|
||||
printf("halt");
|
||||
break;
|
||||
case NOP:
|
||||
printf("nop");
|
||||
break;
|
||||
case CMOV:
|
||||
print_cmov(inst->ifun.cmov);
|
||||
printf(" ");
|
||||
print_register(inst->ra);
|
||||
printf(", ");
|
||||
print_register(inst->rb);
|
||||
break;
|
||||
case IRMOVQ:
|
||||
printf("irmovq 0x%lx, ", inst->valC.v);
|
||||
print_register(inst->rb);
|
||||
break;
|
||||
case RMMOVQ:
|
||||
printf("rmmovq ");
|
||||
print_register(inst->ra);
|
||||
printf(", ");
|
||||
printf("0x%lx", inst->valC.d);
|
||||
if (inst->rb != NOREG) {
|
||||
printf("(");
|
||||
print_register(inst->rb);
|
||||
printf(")");
|
||||
}
|
||||
break;
|
||||
case MRMOVQ:
|
||||
printf("mrmovq 0x%lx", inst->valC.d);
|
||||
if (inst->rb != NOREG) {
|
||||
printf("(");
|
||||
print_register(inst->rb);
|
||||
printf(")");
|
||||
}
|
||||
printf(", ");
|
||||
print_register(inst->ra);
|
||||
break;
|
||||
case OPQ:
|
||||
print_opq(inst->ifun.op);
|
||||
printf(" ");
|
||||
print_register(inst->ra);
|
||||
printf(", ");
|
||||
print_register(inst->rb);
|
||||
break;
|
||||
case JUMP:
|
||||
print_jump(inst->ifun.jump);
|
||||
printf(" 0x%lx", inst->valC.dest);
|
||||
break;
|
||||
case CALL:
|
||||
printf("call 0x%lx", inst->valC.dest);
|
||||
break;
|
||||
case RET:
|
||||
printf("ret");
|
||||
break;
|
||||
case PUSHQ:
|
||||
printf("pushq ");
|
||||
print_register(inst->ra);
|
||||
break;
|
||||
case POPQ:
|
||||
printf("popq ");
|
||||
print_register(inst->ra);
|
||||
break;
|
||||
case IOTRAP:
|
||||
printf("iotrap %d", inst->ifun.trap);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void disassemble_code(byte_t *memory, elf_phdr_t *phdr, elf_hdr_t *hdr) {
|
||||
if (memory == NULL || phdr == NULL || hdr == NULL) {
|
||||
printf("Failed to disassemble code\n");
|
||||
return;
|
||||
}
|
||||
|
||||
y86_t cpu = {0};
|
||||
y86_inst_t ins = {0};
|
||||
uint32_t p_vaddr_end = phdr->p_vaddr + phdr->p_size;
|
||||
cpu.pc = phdr->p_vaddr;
|
||||
|
||||
printf(" 0x%03lx:%*s| .pos 0x%03lx code\n", cpu.pc, 31, "", cpu.pc);
|
||||
|
||||
while (cpu.pc < p_vaddr_end) {
|
||||
if (cpu.pc == hdr->e_entry) {
|
||||
printf(" 0x%03lx:%*s| _start:\n", cpu.pc, 31, "");
|
||||
}
|
||||
|
||||
ins = fetch(&cpu, memory);
|
||||
|
||||
if (ins.icode == INVALID) {
|
||||
printf("Invalid opcode: 0x%02x\n", memory[cpu.pc]);
|
||||
break;
|
||||
}
|
||||
|
||||
printf(" 0x%03lx: ", cpu.pc);
|
||||
|
||||
int bytes_printed = 1;
|
||||
printf("%02x ", ins.icode << 4 | ins.ifun.b);
|
||||
|
||||
if (has_register_byte(ins)) {
|
||||
printf("%02x ", (ins.ra << 4 | ins.rb));
|
||||
bytes_printed++;
|
||||
}
|
||||
|
||||
if (has_valc_bytes(ins)) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
printf("%02lx ", (ins.valC.d >> (8 * i)) & 0xFF);
|
||||
}
|
||||
|
||||
bytes_printed += 8;
|
||||
}
|
||||
|
||||
/* Print #x spaces to align the "|" */
|
||||
printf("%*s| ", 30 - 3 * bytes_printed, "");
|
||||
disassemble(&ins);
|
||||
printf("\n");
|
||||
|
||||
cpu.pc = ins.valP;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void disassemble_data(byte_t *memory, elf_phdr_t *phdr) {
|
||||
if (memory == NULL || phdr == NULL) {
|
||||
printf("Failed to disassemble data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t pc = phdr->p_vaddr;
|
||||
uint32_t p_vaddr_end = phdr->p_vaddr + phdr->p_size;
|
||||
|
||||
printf(" 0x%03x:%*s| .pos 0x%03x data\n", pc, 31, "", pc);
|
||||
|
||||
while (pc < p_vaddr_end) {
|
||||
uint64_t byte_string = 0;
|
||||
|
||||
printf(" 0x%03x: ", pc);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
byte_string |= (uint64_t)(memory[pc + i]) << (8 * i);
|
||||
printf("%02x ", memory[pc + i]);
|
||||
}
|
||||
printf(" | .quad 0x%lx\n", byte_string);
|
||||
|
||||
pc += 8;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void disassemble_rodata(byte_t *memory, elf_phdr_t *phdr) {
|
||||
if (memory == NULL || phdr == NULL) {
|
||||
printf("Failed to disassemble read-only data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t pc = phdr->p_vaddr;
|
||||
uint32_t p_vaddr_end = phdr->p_vaddr + phdr->p_size;
|
||||
|
||||
printf(" 0x%03x:%*s| .pos 0x%03x rodata\n", pc, 31, "", pc);
|
||||
|
||||
uint32_t string_address = pc; /* Address of current .string */
|
||||
uint32_t char_count = 0;
|
||||
|
||||
while (pc < p_vaddr_end) {
|
||||
bool on_line_start = (char_count + 1) % 10 == 1;
|
||||
bool on_null_terminator = memory[pc] == 0x00;
|
||||
bool break_line = on_null_terminator || (char_count + 1) % 10 == 0;
|
||||
|
||||
if (on_line_start) {
|
||||
printf(" 0x%03x: ", pc);
|
||||
}
|
||||
|
||||
printf("%02x ", memory[pc]);
|
||||
|
||||
/* If reached end of line, print #x spaces to align the "|" */
|
||||
if (break_line) {
|
||||
int spaces = 27 - (char_count % 10) * 3;
|
||||
printf("%*s| ", spaces, "");
|
||||
}
|
||||
|
||||
/* Prints out the full string if reached the end of the first line */
|
||||
if (break_line && char_count <= 9) {
|
||||
byte_t *current_byte = &memory[string_address];
|
||||
|
||||
printf(" .string \"");
|
||||
while (*current_byte != 0x00) {
|
||||
printf("%c", *current_byte);
|
||||
current_byte++;
|
||||
}
|
||||
printf("\"");
|
||||
}
|
||||
|
||||
if (break_line) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* Reset char count to indicate new word on null terminator */
|
||||
if (on_null_terminator) {
|
||||
string_address = pc + 1;
|
||||
char_count = 0;
|
||||
} else {
|
||||
char_count++;
|
||||
}
|
||||
|
||||
pc++;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#ifndef __CS261_P3__
|
||||
#define __CS261_P3__
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "elf.h"
|
||||
#include "y86.h"
|
||||
|
||||
/**
|
||||
* @brief Load a Y86 instruction from memory
|
||||
*
|
||||
* @param cpu Pointer to Y86 CPU structure with the PC address to be loaded
|
||||
* @param memory Pointer to the beginning of the Y86 address space
|
||||
* @returns Populated Y86 instruction structure
|
||||
*/
|
||||
y86_inst_t fetch (y86_t *cpu, byte_t *memory);
|
||||
|
||||
/**
|
||||
* @brief Print the disassembly of a Y86 instruction to standard out
|
||||
*
|
||||
* @param inst Pointer to Y86 instruction structure to be printed
|
||||
*/
|
||||
void disassemble (y86_inst_t *inst);
|
||||
|
||||
/**
|
||||
* @brief Print the disassembly of a Y86 code segment
|
||||
*
|
||||
* @param memory Pointer to the beginning of the Y86 address space
|
||||
* @param phdr Program header of segment to be printed
|
||||
* @param hdr File header (needed to detect the entry point)
|
||||
*/
|
||||
void disassemble_code (byte_t *memory, elf_phdr_t *phdr, elf_hdr_t *hdr);
|
||||
|
||||
/**
|
||||
* @brief Print the disassembly of a Y86 read/write data segment
|
||||
*
|
||||
* @param memory Pointer to the beginning of the Y86 address space
|
||||
* @param phdr Program header of segment to be printed
|
||||
*/
|
||||
void disassemble_data (byte_t *memory, elf_phdr_t *phdr);
|
||||
|
||||
/**
|
||||
* @brief Print the disassembly of a Y86 read-only data segment
|
||||
*
|
||||
* @param memory Pointer to the beginning of the Y86 address space
|
||||
* @param phdr Program header of segment to be printed
|
||||
*/
|
||||
void disassemble_rodata (byte_t *memory, elf_phdr_t *phdr);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,81 @@
|
||||
#
|
||||
# Simple Test Makefile
|
||||
# Mike Lam, James Madison University, August 2016
|
||||
#
|
||||
# This version of the Makefile includes support for building a test suite. The
|
||||
# recommended framework is Check (http://check.sourceforge.net/). To build and
|
||||
# run the test suite, execute the "test" target. The test suite must be located
|
||||
# in a module called "testsuite". The MODS, LIBS, and OBJS variables work as
|
||||
# they do in the main Makefile.
|
||||
#
|
||||
# To change the default build target (which executes when you just type
|
||||
# "make"), change the right-hand side of the definition of the "default"
|
||||
# target.
|
||||
#
|
||||
# By default, this makefile will build the project with debugging symbols and
|
||||
# without optimization. To change this, edit or remove the "-g" and "-O0"
|
||||
# options in CFLAGS and LDFLAGS accordingly.
|
||||
#
|
||||
# By default, this makefile build the application using the GNU C compiler,
|
||||
# adhering to the C99 standard with all warnings enabled.
|
||||
|
||||
|
||||
# application-specific settings and run target
|
||||
|
||||
EXE=../y86
|
||||
TEST=testsuite
|
||||
MODS=public.o
|
||||
OBJS=../p1-check.o ../p2-load.o ../p3-disas.o private.o
|
||||
LIBS=
|
||||
|
||||
UTESTOUT=utests.txt
|
||||
ITESTOUT=itests.txt
|
||||
|
||||
default: $(TEST)
|
||||
|
||||
$(EXE):
|
||||
make -C ../
|
||||
|
||||
test: utest itest
|
||||
@echo "========================================"
|
||||
|
||||
utest: $(EXE) $(TEST)
|
||||
@echo "========================================"
|
||||
@echo " UNIT TESTS"
|
||||
@./$(TEST) 2>/dev/null >$(UTESTOUT)
|
||||
@cat $(UTESTOUT) | sed -n -e '/Checks/,$$p' | sed -e 's/^private.*:[EF]://g'
|
||||
|
||||
itest: $(EXE)
|
||||
@echo "========================================"
|
||||
@echo " INTEGRATION TESTS"
|
||||
@./integration.sh | tee $(ITESTOUT)
|
||||
|
||||
|
||||
# compiler/linker settings
|
||||
|
||||
CC=gcc
|
||||
CFLAGS=-g -O0 -Wall --std=c99 -pedantic
|
||||
LDFLAGS=-g -O0
|
||||
|
||||
CFLAGS+=-I/opt/homebrew/include -Wno-gnu-zero-variadic-macro-arguments
|
||||
LDFLAGS+=-L/opt/homebrew/lib
|
||||
LIBS+=-lcheck -lm -lpthread
|
||||
|
||||
ifeq ($(shell uname -s),Linux)
|
||||
LIBS+=-lrt -lsubunit
|
||||
endif
|
||||
|
||||
|
||||
# build targets
|
||||
|
||||
$(TEST): $(TEST).o $(MODS) $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $(TEST) $^ $(LIBS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) $<
|
||||
|
||||
clean:
|
||||
rm -rf $(TEST) $(TEST).o $(MODS) $(UTESTOUT) $(ITESTOUT) outputs valgrind
|
||||
|
||||
.PHONY: default clean test unittest inttest
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Failed to read file
|
||||
@@ -0,0 +1 @@
|
||||
Failed to read file
|
||||
@@ -0,0 +1 @@
|
||||
Failed to read file
|
||||
@@ -0,0 +1 @@
|
||||
Failed to read file
|
||||
@@ -0,0 +1 @@
|
||||
Failed to read file
|
||||
@@ -0,0 +1,6 @@
|
||||
Disassembly of data contents:
|
||||
0x200: | .pos 0x200 data
|
||||
0x200: 88 77 66 55 44 33 22 11 | .quad 0x1122334455667788
|
||||
0x208: 78 56 34 12 00 00 00 00 | .quad 0x12345678
|
||||
0x210: 42 00 00 00 00 00 00 00 | .quad 0x42
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
Disassembly of executable contents:
|
||||
0x100: | .pos 0x100 code
|
||||
0x100: | _start:
|
||||
0x100: 00 | halt
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Usage: ../y86 <option(s)> mini-elf-file
|
||||
Options are:
|
||||
-h Display usage
|
||||
-H Show the Mini-ELF header
|
||||
-a Show all with brief memory
|
||||
-f Show all with full memory
|
||||
-s Show the program headers
|
||||
-m Show the memory contents (brief)
|
||||
-M Show the memory contents (full)
|
||||
-d Disassemble code contents
|
||||
-D Disassemble data contents
|
||||
@@ -0,0 +1,22 @@
|
||||
Disassembly of executable contents:
|
||||
0x100: | .pos 0x100 code
|
||||
0x100: | _start:
|
||||
0x100: 00 | halt
|
||||
|
||||
0x400: | .pos 0x400 code
|
||||
0x400: 10 | nop
|
||||
0x401: 00 | halt
|
||||
|
||||
Disassembly of data contents:
|
||||
0x200: | .pos 0x200 data
|
||||
0x200: 10 00 00 00 00 00 00 00 | .quad 0x10
|
||||
|
||||
0x300: | .pos 0x300 rodata
|
||||
0x300: 74 65 73 74 00 | .string "test"
|
||||
|
||||
0x500: | .pos 0x500 data
|
||||
0x500: 78 56 34 12 00 00 00 00 | .quad 0x12345678
|
||||
|
||||
0x600: | .pos 0x600 rodata
|
||||
0x600: 61 67 61 69 6e 00 | .string "again"
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
Disassembly of executable contents:
|
||||
0x100: | .pos 0x100 code
|
||||
0x100: | _start:
|
||||
0x100: 30 f3 0f 00 00 00 20 31 40 13 | irmovq 0x134031200000000f, %rbx
|
||||
Invalid opcode: 0xfd
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Usage: ../y86 <option(s)> mini-elf-file
|
||||
Options are:
|
||||
-h Display usage
|
||||
-H Show the Mini-ELF header
|
||||
-a Show all with brief memory
|
||||
-f Show all with full memory
|
||||
-s Show the program headers
|
||||
-m Show the memory contents (brief)
|
||||
-M Show the memory contents (full)
|
||||
-d Disassemble code contents
|
||||
-D Disassemble data contents
|
||||
@@ -0,0 +1,4 @@
|
||||
Disassembly of data contents:
|
||||
0x200: | .pos 0x200 rodata
|
||||
0x200: 68 65 6c 6c 6f 00 | .string "hello"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
Disassembly of executable contents:
|
||||
0x100: | .pos 0x100 code
|
||||
0x100: | _start:
|
||||
0x100: 00 | halt
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
Disassembly of data contents:
|
||||
0x200: | .pos 0x200 rodata
|
||||
0x200: 30 31 32 33 34 35 36 37 38 39 | .string "0123456789"
|
||||
0x20a: 00 |
|
||||
0x20b: 68 65 6c 6c 6f 20 77 6f 72 6c | .string "hello world"
|
||||
0x215: 64 00 |
|
||||
0x217: 61 62 63 64 65 66 67 68 69 6a | .string "abcdefghijklmnopqrstuvwxyz"
|
||||
0x221: 6b 6c 6d 6e 6f 70 71 72 73 74 |
|
||||
0x22b: 75 76 77 78 79 7a 00 |
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
Disassembly of data contents:
|
||||
0x200: | .pos 0x200 rodata
|
||||
0x200: 66 6f 6f 00 | .string "foo"
|
||||
0x204: 77 30 30 74 00 | .string "w00t"
|
||||
0x209: 75 70 20 64 6f 77 6e 00 | .string "up down"
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
Disassembly of data contents:
|
||||
0x200: | .pos 0x200 rodata
|
||||
0x200: 54 6f 20 62 65 2c 20 6f 72 20 | .string "To be, or not to be: that is the question"
|
||||
0x20a: 6e 6f 74 20 74 6f 20 62 65 3a |
|
||||
0x214: 20 74 68 61 74 20 69 73 20 74 |
|
||||
0x21e: 68 65 20 71 75 65 73 74 69 6f |
|
||||
0x228: 6e 00 |
|
||||
0x22a: 57 68 61 74 27 73 20 69 6e 20 | .string "What's in a name? A rose by any other name would smell as sweet."
|
||||
0x234: 61 20 6e 61 6d 65 3f 20 41 20 |
|
||||
0x23e: 72 6f 73 65 20 62 79 20 61 6e |
|
||||
0x248: 79 20 6f 74 68 65 72 20 6e 61 |
|
||||
0x252: 6d 65 20 77 6f 75 6c 64 20 73 |
|
||||
0x25c: 6d 65 6c 6c 20 61 73 20 73 77 |
|
||||
0x266: 65 65 74 2e 00 |
|
||||
0x26b: 42 75 74 2c 20 66 6f 72 20 6d | .string "But, for my own part, it was Greek to me."
|
||||
0x275: 79 20 6f 77 6e 20 70 61 72 74 |
|
||||
0x27f: 2c 20 69 74 20 77 61 73 20 47 |
|
||||
0x289: 72 65 65 6b 20 74 6f 20 6d 65 |
|
||||
0x293: 2e 00 |
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
01 00 18 01 10 00 03 00 00 00 00 00 45 4c 46 00
|
||||
Mini-ELF version 1
|
||||
Entry point 0x118
|
||||
There are 3 program headers, starting at offset 16 (0x10)
|
||||
There is no symbol table present
|
||||
There is no string table present
|
||||
Segment Offset Size VirtAddr Type Flags
|
||||
00 0x004c 0x0009 0x0000 CODE R X
|
||||
01 0x0055 0x0002 0x0118 CODE R X
|
||||
02 0x0057 0x0008 0x013a DATA RW
|
||||
Contents of memory from 0000 to 0009:
|
||||
0000 70 18 01 00 00 00 00 00 00
|
||||
Contents of memory from 0118 to 011a:
|
||||
0110 10 00
|
||||
Contents of memory from 013a to 0142:
|
||||
0130 39 30 00 00 00 00
|
||||
0140 00 00
|
||||
Disassembly of executable contents:
|
||||
0x000: | .pos 0x000 code
|
||||
0x000: 70 18 01 00 00 00 00 00 00 | jmp 0x118
|
||||
|
||||
0x118: | .pos 0x118 code
|
||||
0x118: | _start:
|
||||
0x118: 10 | nop
|
||||
0x119: 00 | halt
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
01 00 55 05 10 00 03 00 00 00 00 00 45 4c 46 00
|
||||
Mini-ELF version 1
|
||||
Entry point 0x555
|
||||
There are 3 program headers, starting at offset 16 (0x10)
|
||||
There is no symbol table present
|
||||
There is no string table present
|
||||
Segment Offset Size VirtAddr Type Flags
|
||||
00 0x004c 0x0009 0x0000 CODE R X
|
||||
01 0x0055 0x001f 0x0555 CODE R X
|
||||
02 0x0074 0x0008 0x0987 DATA RW
|
||||
Contents of memory from 0000 to 0009:
|
||||
0000 70 55 05 00 00 00 00 00 00
|
||||
Contents of memory from 0555 to 0574:
|
||||
0550 30 f0 4d 01 00 00 00 00 00 00 30
|
||||
0560 f3 de 00 00 00 00 00 00 00 30 f1 6f 00 00 00 00
|
||||
0570 00 00 00 00
|
||||
Contents of memory from 0987 to 098f:
|
||||
0980 dd cc bb aa 00 00 00 00
|
||||
Disassembly of executable contents:
|
||||
0x000: | .pos 0x000 code
|
||||
0x000: 70 55 05 00 00 00 00 00 00 | jmp 0x555
|
||||
|
||||
0x555: | .pos 0x555 code
|
||||
0x555: | _start:
|
||||
0x555: 30 f0 4d 01 00 00 00 00 00 00 | irmovq 0x14d, %rax
|
||||
0x55f: 30 f3 de 00 00 00 00 00 00 00 | irmovq 0xde, %rbx
|
||||
0x569: 30 f1 6f 00 00 00 00 00 00 00 | irmovq 0x6f, %rcx
|
||||
0x573: 00 | halt
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
Disassembly of executable contents:
|
||||
0x100: | .pos 0x100 code
|
||||
0x100: | _start:
|
||||
0x100: c0 | iotrap 0
|
||||
0x101: c1 | iotrap 1
|
||||
0x102: c2 | iotrap 2
|
||||
0x103: c3 | iotrap 3
|
||||
0x104: c4 | iotrap 4
|
||||
0x105: c5 | iotrap 5
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Disassembly of executable contents:
|
||||
0x100: | .pos 0x100 code
|
||||
0x100: | _start:
|
||||
0x100: 70 88 77 66 55 44 33 22 11 | jmp 0x1122334455667788
|
||||
0x109: 71 77 66 55 44 33 22 11 88 | jle 0x8811223344556677
|
||||
0x112: 72 66 55 44 33 22 11 88 77 | jl 0x7788112233445566
|
||||
0x11b: 73 55 44 33 22 11 88 77 66 | je 0x6677881122334455
|
||||
0x124: 74 44 33 22 11 88 77 66 55 | jne 0x5566778811223344
|
||||
0x12d: 75 33 22 11 88 77 66 55 44 | jge 0x4455667788112233
|
||||
0x136: 76 22 11 88 77 66 55 44 33 | jg 0x3344556677881122
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
Disassembly of executable contents:
|
||||
0x100: | .pos 0x100 code
|
||||
0x100: | _start:
|
||||
0x100: 70 88 77 66 55 44 33 22 11 | jmp 0x1122334455667788
|
||||
0x109: 80 11 22 33 44 55 66 77 88 | call 0x8877665544332211
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
01 00 00 01 10 00 01 00 00 00 00 00 45 4c 46 00
|
||||
Mini-ELF version 1
|
||||
Entry point 0x100
|
||||
There are 1 program headers, starting at offset 16 (0x10)
|
||||
There is no symbol table present
|
||||
There is no string table present
|
||||
Segment Offset Size VirtAddr Type Flags
|
||||
00 0x0024 0x0017 0x0100 CODE R X
|
||||
Contents of memory from 0100 to 0117:
|
||||
0100 30 f0 68 24 00 00 00 00 00 00 30 f3 34 12 00 00
|
||||
0110 00 00 00 00 60 03 00
|
||||
Disassembly of executable contents:
|
||||
0x100: | .pos 0x100 code
|
||||
0x100: | _start:
|
||||
0x100: 30 f0 68 24 00 00 00 00 00 00 | irmovq 0x2468, %rax
|
||||
0x10a: 30 f3 34 12 00 00 00 00 00 00 | irmovq 0x1234, %rbx
|
||||
0x114: 60 03 | addq %rax, %rbx
|
||||
0x116: 00 | halt
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
Disassembly of executable contents:
|
||||
0x100: | .pos 0x100 code
|
||||
0x100: 10 | nop
|
||||
0x101: 10 | nop
|
||||
0x102: 10 | nop
|
||||
0x103: | _start:
|
||||
0x103: 30 f0 68 24 00 00 00 00 00 00 | irmovq 0x2468, %rax
|
||||
0x10d: 30 f3 34 12 00 00 00 00 00 00 | irmovq 0x1234, %rbx
|
||||
0x117: 60 03 | addq %rax, %rbx
|
||||
0x119: 70 00 02 00 00 00 00 00 00 | jmp 0x200
|
||||
|
||||
0x200: | .pos 0x200 code
|
||||
0x200: 30 f1 78 56 00 00 00 00 00 00 | irmovq 0x5678, %rcx
|
||||
0x20a: 30 f2 14 15 00 00 00 00 00 00 | irmovq 0x1514, %rdx
|
||||
0x214: 61 21 | subq %rdx, %rcx
|
||||
0x216: 00 | halt
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
Disassembly of executable contents:
|
||||
0x100: | .pos 0x100 code
|
||||
0x100: | _start:
|
||||
0x100: 30 f0 88 77 66 55 44 33 22 11 | irmovq 0x1122334455667788, %rax
|
||||
0x10a: 40 12 21 43 65 87 78 56 34 12 | rmmovq %rcx, 0x1234567887654321(%rdx)
|
||||
0x114: 50 12 78 56 34 12 21 43 65 87 | mrmovq 0x8765432112345678(%rdx), %rcx
|
||||
0x11e: 40 1f 21 43 65 87 78 56 34 12 | rmmovq %rcx, 0x1234567887654321
|
||||
0x128: 50 1f 78 56 34 12 21 43 65 87 | mrmovq 0x8765432112345678, %rcx
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Disassembly of executable contents:
|
||||
0x100: | .pos 0x100 code
|
||||
0x100: | _start:
|
||||
0x100: 20 01 | rrmovq %rax, %rcx
|
||||
0x102: 21 23 | cmovle %rdx, %rbx
|
||||
0x104: 22 45 | cmovl %rsp, %rbp
|
||||
0x106: 23 67 | cmove %rsi, %rdi
|
||||
0x108: 24 89 | cmovne %r8, %r9
|
||||
0x10a: 25 ab | cmovge %r10, %r11
|
||||
0x10c: 26 ce | cmovg %r12, %r14
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Usage: ../y86 <option(s)> mini-elf-file
|
||||
Options are:
|
||||
-h Display usage
|
||||
-H Show the Mini-ELF header
|
||||
-a Show all with brief memory
|
||||
-f Show all with full memory
|
||||
-s Show the program headers
|
||||
-m Show the memory contents (brief)
|
||||
-M Show the memory contents (full)
|
||||
-d Disassemble code contents
|
||||
-D Disassemble data contents
|
||||
@@ -0,0 +1,8 @@
|
||||
Disassembly of executable contents:
|
||||
0x100: | .pos 0x100 code
|
||||
0x100: | _start:
|
||||
0x100: 60 23 | addq %rdx, %rbx
|
||||
0x102: 61 01 | subq %rax, %rcx
|
||||
0x104: 62 45 | andq %rsp, %rbp
|
||||
0x106: 63 67 | xorq %rsi, %rdi
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
Disassembly of executable contents:
|
||||
0x100: | .pos 0x100 code
|
||||
0x100: | _start:
|
||||
0x100: 20 01 | rrmovq %rax, %rcx
|
||||
0x102: 60 23 | addq %rdx, %rbx
|
||||
0x104: a0 6f | pushq %rsi
|
||||
0x106: b0 7f | popq %rdi
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
Disassembly of executable contents:
|
||||
0x100: | .pos 0x100 code
|
||||
0x100: | _start:
|
||||
0x100: 00 | halt
|
||||
0x101: 10 | nop
|
||||
0x102: 90 | ret
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash
|
||||
|
||||
# extract executable name from Makefile
|
||||
EXE=$(grep "EXE=" Makefile | sed -e "s/EXE=//")
|
||||
|
||||
# detect timeout utility (i.e., "timeout" on Linux and "gtimeout" on MacOS)
|
||||
# and set timeout interval
|
||||
TIMEOUT="timeout"
|
||||
TIMEOUT_INTERVAL="3s"
|
||||
$TIMEOUT --help &>/dev/null
|
||||
if [[ $? -ne 0 ]]; then
|
||||
TIMEOUT="gtimeout"
|
||||
fi
|
||||
|
||||
# Valgrind additional output flags
|
||||
VG_FLAGS="--leak-check=full --track-origins=yes"
|
||||
|
||||
function run_test {
|
||||
|
||||
# parameters
|
||||
TAG=$1
|
||||
ARGS=$2
|
||||
PTAG=$(printf '%-30s' "$TAG")
|
||||
|
||||
# file paths
|
||||
OUTPUT=outputs/$TAG.txt
|
||||
DIFF=outputs/$TAG.diff
|
||||
EXPECT=expected/$TAG.txt
|
||||
VALGRND=valgrind/$TAG.txt
|
||||
|
||||
# run test with timeout
|
||||
$TIMEOUT $TIMEOUT_INTERVAL $EXE $ARGS 2>/dev/null >"$OUTPUT"
|
||||
if [ "$?" -lt 124 ]; then
|
||||
|
||||
# no timeout; compare output to the expected version
|
||||
diff -u "$OUTPUT" "$EXPECT" >"$DIFF"
|
||||
if [ -s "$DIFF" ]; then
|
||||
|
||||
# try alternative solution (if it exists)
|
||||
EXPECT=expected/$TAG-2.txt
|
||||
if [ -e "$EXPECT" ]; then
|
||||
diff -u "$OUTPUT" "$EXPECT" >"$DIFF"
|
||||
if [ -s "$DIFF" ]; then
|
||||
echo "$PTAG FAIL (see ${TPREFIX}$DIFF for details)"
|
||||
else
|
||||
echo "$PTAG pass"
|
||||
fi
|
||||
else
|
||||
echo "$PTAG FAIL (see ${TPREFIX}$DIFF for details)"
|
||||
fi
|
||||
else
|
||||
echo "$PTAG pass"
|
||||
fi
|
||||
|
||||
# run valgrind
|
||||
$TIMEOUT $TIMEOUT_INTERVAL valgrind $VG_FLAGS $EXE $ARGS &>$VALGRND
|
||||
else
|
||||
echo "$PTAG FAIL (crash or timeout)"
|
||||
fi
|
||||
}
|
||||
|
||||
# initialize output folders
|
||||
mkdir -p outputs
|
||||
mkdir -p valgrind
|
||||
rm -f outputs/* valgrind/*
|
||||
|
||||
# run individual tests
|
||||
source itests.include
|
||||
|
||||
# check for memory leaks
|
||||
LEAK=`cat valgrind/*.txt | grep 'definitely lost' | grep -v ' 0 bytes in 0 blocks'`
|
||||
if [ -z "$LEAK" ]; then
|
||||
echo "No memory leak found."
|
||||
else
|
||||
echo "Memory leak(s) found. See files listed below for details."
|
||||
grep 'definitely lost' valgrind/*.txt | sed -e 's/:.*$//g' | awk "{print \" - ${TPREFIX}\" \$0}"
|
||||
fi
|
||||
|
||||
# check for uninitialized values
|
||||
LEAK=`cat valgrind/*.txt | grep 'uninitialised value'`
|
||||
if [ -z "$LEAK" ]; then
|
||||
echo "No uninitialized value found."
|
||||
else
|
||||
echo "Uninitialized value(s) found. See files listed below for details."
|
||||
grep 'uninitialised value' valgrind/*.txt | sed -e 's/:.*$//g' | awk "{print \" - ${TPREFIX}\" \$0}"
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# list of integration tests
|
||||
# format: run_test <TAG> <ARGS>
|
||||
# <TAG> used as the root for all filenames (i.e., "expected/$TAG.txt")
|
||||
# <ARGS> command-line arguments to test
|
||||
|
||||
run_test D_onebyte "-d inputs/onebyte.o"
|
||||
run_test C_help "-h"
|
||||
run_test C_twobyte "-d inputs/twobyte.o"
|
||||
run_test C_cmov "-d inputs/cmov.o"
|
||||
run_test C_opq "-d inputs/opq.o"
|
||||
run_test B_ninebyte "-d inputs/ninebyte.o"
|
||||
run_test B_jmp "-d inputs/jmp.o"
|
||||
run_test B_tenbyte "-d inputs/tenbyte.o"
|
||||
run_test B_simple "-a -d inputs/simple.o"
|
||||
run_test B_simple_multi "-d inputs/simple_multi.o"
|
||||
run_test B_iotrap "-d inputs/iotrap.o"
|
||||
run_test A_data_code "-d inputs/data.o"
|
||||
run_test A_rodata_code "-d inputs/rodata.o"
|
||||
run_test A_data "-D inputs/data.o"
|
||||
run_test A_rodata "-D inputs/rodata.o"
|
||||
run_test A_rodata_multi "-D inputs/rodata_multi.o"
|
||||
run_test A_interleaved "-d -D inputs/interleaved.o"
|
||||
run_test A_invalid "-d inputs/invalid.o"
|
||||
run_test A_bad_no_elf "-d inputs/bad-no_elf.o"
|
||||
run_test A_bad_phdr "-d inputs/bad-phdr.o"
|
||||
run_test A_bad_short_header "-d inputs/bad-short_header.o"
|
||||
run_test A_bad_short_phdr "-d inputs/bad-short_phdr.o"
|
||||
run_test A_bad_filename "-d inputs/bad-nonexist.o"
|
||||
run_test A_missing_file "-d"
|
||||
run_test A_extra_params "-d inputs/onebyte.o extra params"
|
||||
run_test A_unaligned1 "-a -d inputs/unaligned.o"
|
||||
run_test A_unaligned2 "-a -d inputs/unaligned2.o"
|
||||
run_test A_rodata_long "-D inputs/rodata_long.o"
|
||||
run_test A_rodata_shakespeare "-D inputs/rodata_shakespeare.o"
|
||||
@@ -0,0 +1,31 @@
|
||||
D_onebyte pass
|
||||
C_help pass
|
||||
C_twobyte pass
|
||||
C_cmov pass
|
||||
C_opq pass
|
||||
B_ninebyte pass
|
||||
B_jmp pass
|
||||
B_tenbyte pass
|
||||
B_simple pass
|
||||
B_simple_multi pass
|
||||
B_iotrap pass
|
||||
A_data_code pass
|
||||
A_rodata_code pass
|
||||
A_data pass
|
||||
A_rodata pass
|
||||
A_rodata_multi pass
|
||||
A_interleaved pass
|
||||
A_invalid pass
|
||||
A_bad_no_elf pass
|
||||
A_bad_phdr pass
|
||||
A_bad_short_header pass
|
||||
A_bad_short_phdr pass
|
||||
A_bad_filename pass
|
||||
A_missing_file pass
|
||||
A_extra_params pass
|
||||
A_unaligned1 pass
|
||||
A_unaligned2 pass
|
||||
A_rodata_long pass
|
||||
A_rodata_shakespeare pass
|
||||
No memory leak found.
|
||||
No uninitialized value found.
|
||||
@@ -0,0 +1 @@
|
||||
Failed to read file
|
||||
@@ -0,0 +1 @@
|
||||
Failed to read file
|
||||
@@ -0,0 +1 @@
|
||||
Failed to read file
|
||||
@@ -0,0 +1 @@
|
||||
Failed to read file
|
||||
@@ -0,0 +1 @@
|
||||
Failed to read file
|
||||
@@ -0,0 +1,6 @@
|
||||
Disassembly of data contents:
|
||||
0x200: | .pos 0x200 data
|
||||
0x200: 88 77 66 55 44 33 22 11 | .quad 0x1122334455667788
|
||||
0x208: 78 56 34 12 00 00 00 00 | .quad 0x12345678
|
||||
0x210: 42 00 00 00 00 00 00 00 | .quad 0x42
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
Disassembly of executable contents:
|
||||
0x100: | .pos 0x100 code
|
||||
0x100: | _start:
|
||||
0x100: 00 | halt
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Usage: ../y86 <option(s)> mini-elf-file
|
||||
Options are:
|
||||
-h Display usage
|
||||
-H Show the Mini-ELF header
|
||||
-a Show all with brief memory
|
||||
-f Show all with full memory
|
||||
-s Show the program headers
|
||||
-m Show the memory contents (brief)
|
||||
-M Show the memory contents (full)
|
||||
-d Disassemble code contents
|
||||
-D Disassemble data contents
|
||||
@@ -0,0 +1,22 @@
|
||||
Disassembly of executable contents:
|
||||
0x100: | .pos 0x100 code
|
||||
0x100: | _start:
|
||||
0x100: 00 | halt
|
||||
|
||||
0x400: | .pos 0x400 code
|
||||
0x400: 10 | nop
|
||||
0x401: 00 | halt
|
||||
|
||||
Disassembly of data contents:
|
||||
0x200: | .pos 0x200 data
|
||||
0x200: 10 00 00 00 00 00 00 00 | .quad 0x10
|
||||
|
||||
0x300: | .pos 0x300 rodata
|
||||
0x300: 74 65 73 74 00 | .string "test"
|
||||
|
||||
0x500: | .pos 0x500 data
|
||||
0x500: 78 56 34 12 00 00 00 00 | .quad 0x12345678
|
||||
|
||||
0x600: | .pos 0x600 rodata
|
||||
0x600: 61 67 61 69 6e 00 | .string "again"
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
Disassembly of executable contents:
|
||||
0x100: | .pos 0x100 code
|
||||
0x100: | _start:
|
||||
0x100: 30 f3 0f 00 00 00 20 31 40 13 | irmovq 0x134031200000000f, %rbx
|
||||
Invalid opcode: 0xfd
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Usage: ../y86 <option(s)> mini-elf-file
|
||||
Options are:
|
||||
-h Display usage
|
||||
-H Show the Mini-ELF header
|
||||
-a Show all with brief memory
|
||||
-f Show all with full memory
|
||||
-s Show the program headers
|
||||
-m Show the memory contents (brief)
|
||||
-M Show the memory contents (full)
|
||||
-d Disassemble code contents
|
||||
-D Disassemble data contents
|
||||
@@ -0,0 +1,4 @@
|
||||
Disassembly of data contents:
|
||||
0x200: | .pos 0x200 rodata
|
||||
0x200: 68 65 6c 6c 6f 00 | .string "hello"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
Disassembly of executable contents:
|
||||
0x100: | .pos 0x100 code
|
||||
0x100: | _start:
|
||||
0x100: 00 | halt
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
Disassembly of data contents:
|
||||
0x200: | .pos 0x200 rodata
|
||||
0x200: 30 31 32 33 34 35 36 37 38 39 | .string "0123456789"
|
||||
0x20a: 00 |
|
||||
0x20b: 68 65 6c 6c 6f 20 77 6f 72 6c | .string "hello world"
|
||||
0x215: 64 00 |
|
||||
0x217: 61 62 63 64 65 66 67 68 69 6a | .string "abcdefghijklmnopqrstuvwxyz"
|
||||
0x221: 6b 6c 6d 6e 6f 70 71 72 73 74 |
|
||||
0x22b: 75 76 77 78 79 7a 00 |
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
Disassembly of data contents:
|
||||
0x200: | .pos 0x200 rodata
|
||||
0x200: 66 6f 6f 00 | .string "foo"
|
||||
0x204: 77 30 30 74 00 | .string "w00t"
|
||||
0x209: 75 70 20 64 6f 77 6e 00 | .string "up down"
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
Disassembly of data contents:
|
||||
0x200: | .pos 0x200 rodata
|
||||
0x200: 54 6f 20 62 65 2c 20 6f 72 20 | .string "To be, or not to be: that is the question"
|
||||
0x20a: 6e 6f 74 20 74 6f 20 62 65 3a |
|
||||
0x214: 20 74 68 61 74 20 69 73 20 74 |
|
||||
0x21e: 68 65 20 71 75 65 73 74 69 6f |
|
||||
0x228: 6e 00 |
|
||||
0x22a: 57 68 61 74 27 73 20 69 6e 20 | .string "What's in a name? A rose by any other name would smell as sweet."
|
||||
0x234: 61 20 6e 61 6d 65 3f 20 41 20 |
|
||||
0x23e: 72 6f 73 65 20 62 79 20 61 6e |
|
||||
0x248: 79 20 6f 74 68 65 72 20 6e 61 |
|
||||
0x252: 6d 65 20 77 6f 75 6c 64 20 73 |
|
||||
0x25c: 6d 65 6c 6c 20 61 73 20 73 77 |
|
||||
0x266: 65 65 74 2e 00 |
|
||||
0x26b: 42 75 74 2c 20 66 6f 72 20 6d | .string "But, for my own part, it was Greek to me."
|
||||
0x275: 79 20 6f 77 6e 20 70 61 72 74 |
|
||||
0x27f: 2c 20 69 74 20 77 61 73 20 47 |
|
||||
0x289: 72 65 65 6b 20 74 6f 20 6d 65 |
|
||||
0x293: 2e 00 |
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user