Initial commit

This commit is contained in:
2025-10-06 00:14:04 -04:00
commit d98bdabb74
553 changed files with 32764 additions and 0 deletions

574
p3-disas/p3-disas.c Normal file
View File

@@ -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");
}