8086d/main.c

343 lines
6.4 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef enum {
UNDEFINED = 0,
MOV_RM = 0b100010
} OpCodes;
typedef enum {
BX_SI = 0b000,
BX_DI = 0b001,
BP_SI = 0b010,
BP_DI = 0b011,
SI___ = 0b100,
DI___ = 0b101,
BP___ = 0b110,
Di_Ad = 0b110,
BX___ = 0b111
} EffectiveAddress;
typedef enum {
AX = 0b000,
AL = 0b000,
AH = 0b100,
CX = 0b001,
CL = 0b001,
CH = 0b101,
DX = 0b010,
DL = 0b010,
DH = 0b110,
BX = 0b011,
BL = 0b011,
BH = 0b111,
SP = 0b100,
BP = 0b101,
SI = 0b110,
DI = 0b111
} Registers;
void insttostr(OpCodes opcode, char* instStr)
{
switch(opcode)
{
case MOV_RM:
memcpy(instStr, "mov", 3);
break;
case UNDEFINED:
default:
break;
}
}
void regtostr(Registers reg, char* str, _Bool wide)
{
if(wide)
{
switch(reg)
{
case CX:
memcpy(str, "cx", 2);
break;
case DX:
memcpy(str, "dx", 2);
break;
case BX:
memcpy(str, "bx", 2);
break;
case SP:
memcpy(str, "sp", 2);
break;
case BP:
memcpy(str, "bp", 2);
break;
case SI:
memcpy(str, "si", 2);
break;
case DI:
memcpy(str, "di", 2);
break;
case AX:
memcpy(str, "ax", 2);
break;
}
} else
{
switch(reg)
{
case CL:
memcpy(str, "cl", 2);
break;
case DL:
memcpy(str, "dl", 2);
break;
case BL:
memcpy(str, "bl", 2);
break;
case AH:
memcpy(str, "ah", 2);
break;
case CH:
memcpy(str, "ch", 2);
break;
case DH:
memcpy(str, "dh", 2);
break;
case BH:
memcpy(str, "bh", 2);
break;
case AL:
memcpy(str, "al", 2);
break;
}
}
}
void eactostr(EffectiveAddress ea, char* str, unsigned short displacement, _Bool displace, _Bool directaddress)
{
str[0] = '[';
off_t offset = 1;
if(!directaddress)
{
switch(ea)
{
case BX_SI:
memcpy(str + offset + 1, "bx + si", 7);
offset += 7;
break;
case BX_DI:
memcpy(str + offset + 1, "bx + di", 7);
offset += 7;
break;
case BP_SI:
memcpy(str + offset + 1, "bp + si", 7);
offset += 7;
break;
case BP_DI:
memcpy(str + offset + 1, "bp + di", 7);
offset += 7;
break;
case SI___:
memcpy(str + offset + 1, "si", 2);
offset += 2;
break;
case DI___:
memcpy(str + offset + 1, "di", 2);
offset += 2;
break;
case BP___:
memcpy(str + offset + 1, "bp", 2);
offset += 2;
break;
case BX___:
memcpy(str + offset + 1, "bx", 2);
offset += 2;
break;
}
}
if(displace)
{
if(!directaddress)
{
memcpy(str + offset, " + ", 3);
offset += 3;
}
offset += snprintf(str + offset + 1, 6, "%hu", displacement);
}
str[offset + 1] = ']';
}
void print_instructions(unsigned char* bytes, size_t nbytes)
{
size_t bytes_used = 0;
for(size_t i = 0, iindx = 0; i < nbytes; i += bytes_used, ++iindx)
{
bytes_used = 0;
OpCodes opcode = (OpCodes)(bytes[i] >> 2);
_Bool direction = (bytes[i] >> 1) & 0b1;
_Bool wide = bytes[i] & 0b1;
unsigned short displacement;
++bytes_used;
char inststr[16] = { '\0' };
char srcostr[16] = { '\0' };
char dstostr[16] = { '\0' };
char tmp1, tmp2;
switch(opcode)
{
case MOV_RM: // Register/Memory
switch(bytes[i + 1] >> 6) // MOD field
{
case 0b00: // register to memory, no disp, 16-bit disp if R\M = 110
tmp1 = bytes[i + 1] & 0b111; // R/M field
tmp2 = (bytes[i + 1] >> 3) & 0b111; // REG field
++bytes_used;
if(!direction)
{
insttostr(opcode, inststr);
regtostr(tmp2, srcostr, wide);
if(tmp1 == Di_Ad)
{
displacement = bytes[i + 2] ^ (bytes[i + 3] << 4);
eactostr(tmp1, dstostr, displacement, 1, 1);
} else {
eactostr(tmp1, dstostr, 0, 0, 0);
}
} else {
insttostr(opcode, inststr);
regtostr(tmp2, dstostr, wide);
if(tmp1 == Di_Ad)
{
displacement = bytes[i + 2] ^ (bytes[i + 3] << 4);
eactostr(tmp1, srcostr, displacement, 1, 1);
} else {
eactostr(tmp1, srcostr, 0, 0, 0);
}
}
break;
case 0b01: // register to memory, 8-bit disp
tmp1 = bytes[i + 1] & 0b111; // R/M field
tmp2 = (bytes[i + 1] >> 3) & 0b111; // REG field
displacement = bytes[i + 2];
bytes_used += 2;
if(!direction)
{
insttostr(opcode, inststr);
regtostr(tmp2, srcostr, wide);
eactostr(tmp1, dstostr, displacement, 1, 0);
} else {
insttostr(opcode, inststr);
regtostr(tmp2, dstostr, wide);
eactostr(tmp1, srcostr, displacement, 1, 0);
}
break;
case 0b10: // register to memory, 16-bit disp
tmp1 = bytes[i + 1] & 0b111; // R/M field
tmp2 = (bytes[i + 1] >> 3) & 0b111; // REG field
displacement = bytes[i + 2] ^ (bytes[i + 3] << 4); // get displacement bytes
bytes_used += 3;
if(!direction)
{
insttostr(opcode, inststr);
regtostr(tmp2, srcostr, wide);
eactostr(tmp1, dstostr, displacement, 1, 0);
} else {
insttostr(opcode, inststr);
regtostr(tmp2, dstostr, wide);
eactostr(tmp1, srcostr, displacement, 1, 0);
}
break;
//case 0b11:
default: // register to register
tmp1 =(bytes[i + 1] >> 3) & 0b111; // REG field
tmp2 = bytes[i + 1] & 0b111; // R/M field
if(!direction) // 0 = REG is source
{
insttostr(opcode, inststr);
regtostr(tmp1, srcostr, wide);
regtostr(tmp2, dstostr, wide);
} else {
insttostr(opcode, inststr);
regtostr(tmp2, srcostr, wide);
regtostr(tmp1, dstostr, wide);
}
printf("%s %s, %s\n", inststr, dstostr, srcostr);
break;
}
break;
default:
break;
}
}
}
int main(int argc, char** argv)
{
if(argc < 2)
{
fputs("No input provided", stderr);
return -1;
}
int argi = 1;
while(argi < argc)
{
FILE* f = fopen(argv[argi], "r");
if(f == NULL)
{
perror(argv[argi]);
goto LOOP_END_NOFREE_NOCLOSE;
}
fseek(f, 0, SEEK_END);
const long fsize = ftell(f);
if(fsize < 2)
{
fprintf(stderr, "%s: file too small", argv[argi]);
goto LOOP_END_NOFREE_CLOSE;
}
rewind(f);
unsigned char* bytes = calloc(1, fsize); // TODO: check if allocation failed
const size_t bytes_read = fread(bytes, 1, fsize, f);
printf("; disassembly for file %s\nbits 16\n\n", argv[argi]);
print_instructions(bytes, bytes_read);
printf("\n");
free(bytes);
LOOP_END_NOFREE_CLOSE:
fclose(f);
LOOP_END_NOFREE_NOCLOSE:
++argi;
}
return 0;
}