8086d/main.c

343 lines
6.4 KiB
C
Raw Normal View History

2023-11-12 03:13:43 +01:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef enum {
UNDEFINED = 0,
MOV_RM = 0b100010
2023-11-12 03:13:43 +01:00
} OpCodes;
2024-04-16 17:50:55 +02:00
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;
2023-11-12 03:13:43 +01:00
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:
2023-11-12 03:13:43 +01:00
memcpy(instStr, "mov", 3);
break;
case UNDEFINED:
default:
break;
}
}
2024-04-16 17:50:55 +02:00
void regtostr(Registers reg, char* str, _Bool wide)
2023-11-12 03:13:43 +01:00
{
if(wide)
{
switch(reg)
{
case CX:
2024-04-16 17:50:55 +02:00
memcpy(str, "cx", 2);
2023-11-12 03:13:43 +01:00
break;
case DX:
2024-04-16 17:50:55 +02:00
memcpy(str, "dx", 2);
2023-11-12 03:13:43 +01:00
break;
case BX:
2024-04-16 17:50:55 +02:00
memcpy(str, "bx", 2);
2023-11-12 03:13:43 +01:00
break;
case SP:
2024-04-16 17:50:55 +02:00
memcpy(str, "sp", 2);
2023-11-12 03:13:43 +01:00
break;
case BP:
2024-04-16 17:50:55 +02:00
memcpy(str, "bp", 2);
2023-11-12 03:13:43 +01:00
break;
case SI:
2024-04-16 17:50:55 +02:00
memcpy(str, "si", 2);
2023-11-12 03:13:43 +01:00
break;
case DI:
2024-04-16 17:50:55 +02:00
memcpy(str, "di", 2);
2023-11-12 03:13:43 +01:00
break;
2024-04-16 17:50:55 +02:00
case AX:
memcpy(str, "ax", 2);
2023-11-12 03:13:43 +01:00
break;
}
} else
{
switch(reg)
{
case CL:
2024-04-16 17:50:55 +02:00
memcpy(str, "cl", 2);
2023-11-12 03:13:43 +01:00
break;
case DL:
2024-04-16 17:50:55 +02:00
memcpy(str, "dl", 2);
2023-11-12 03:13:43 +01:00
break;
case BL:
2024-04-16 17:50:55 +02:00
memcpy(str, "bl", 2);
2023-11-12 03:13:43 +01:00
break;
case AH:
2024-04-16 17:50:55 +02:00
memcpy(str, "ah", 2);
2023-11-12 03:13:43 +01:00
break;
case CH:
2024-04-16 17:50:55 +02:00
memcpy(str, "ch", 2);
2023-11-12 03:13:43 +01:00
break;
case DH:
2024-04-16 17:50:55 +02:00
memcpy(str, "dh", 2);
2023-11-12 03:13:43 +01:00
break;
case BH:
2024-04-16 17:50:55 +02:00
memcpy(str, "bh", 2);
2023-11-12 03:13:43 +01:00
break;
2024-04-16 17:50:55 +02:00
case AL:
memcpy(str, "al", 2);
2023-11-12 03:13:43 +01:00
break;
}
}
}
2024-04-16 17:50:55 +02:00
void eactostr(EffectiveAddress ea, char* str, unsigned short displacement, _Bool displace, _Bool directaddress)
2023-11-12 03:13:43 +01:00
{
2024-04-16 17:50:55 +02:00
str[0] = '[';
off_t offset = 1;
2023-11-12 03:13:43 +01:00
2024-04-16 17:50:55 +02:00
if(!directaddress)
2023-11-12 03:13:43 +01:00
{
2024-04-16 17:50:55 +02:00
switch(ea)
2023-11-12 03:13:43 +01:00
{
2024-04-16 17:50:55 +02:00
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)
2023-11-12 03:13:43 +01:00
{
2024-04-16 17:50:55 +02:00
memcpy(str + offset, " + ", 3);
offset += 3;
2023-11-12 03:13:43 +01:00
}
2024-04-16 17:50:55 +02:00
offset += snprintf(str + offset + 1, 6, "%hu", displacement);
2023-11-12 03:13:43 +01:00
}
2024-04-16 17:50:55 +02:00
str[offset + 1] = ']';
2023-11-12 03:13:43 +01:00
}
2024-04-16 17:50:55 +02:00
void print_instructions(unsigned char* bytes, size_t nbytes)
2023-11-12 03:13:43 +01:00
{
2024-04-16 17:50:55 +02:00
2023-11-12 03:13:43 +01:00
size_t bytes_used = 0;
for(size_t i = 0, iindx = 0; i < nbytes; i += bytes_used, ++iindx)
{
bytes_used = 0;
2024-04-16 17:50:55 +02:00
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' };
2024-04-16 17:50:55 +02:00
char tmp1, tmp2;
switch(opcode)
2023-11-12 03:13:43 +01:00
{
2024-04-16 17:50:55 +02:00
case MOV_RM: // Register/Memory
switch(bytes[i + 1] >> 6) // MOD field
{
2024-04-16 17:50:55 +02:00
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:
2024-04-16 17:50:55 +02:00
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
{
2024-04-16 17:50:55 +02:00
insttostr(opcode, inststr);
regtostr(tmp1, srcostr, wide);
regtostr(tmp2, dstostr, wide);
} else {
2024-04-16 17:50:55 +02:00
insttostr(opcode, inststr);
regtostr(tmp2, srcostr, wide);
regtostr(tmp1, dstostr, wide);
}
2024-04-16 17:50:55 +02:00
printf("%s %s, %s\n", inststr, dstostr, srcostr);
break;
}
2023-11-12 03:13:43 +01:00
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);
2024-04-16 17:50:55 +02:00
unsigned char* bytes = calloc(1, fsize); // TODO: check if allocation failed
2023-11-12 03:13:43 +01:00
const size_t bytes_read = fread(bytes, 1, fsize, f);
2024-04-16 17:50:55 +02:00
printf("; disassembly for file %s\nbits 16\n\n", argv[argi]);
2023-11-12 03:13:43 +01:00
2024-04-16 17:50:55 +02:00
print_instructions(bytes, bytes_read);
2023-11-12 03:13:43 +01:00
2024-04-16 17:50:55 +02:00
printf("\n");
2023-11-12 03:13:43 +01:00
free(bytes);
LOOP_END_NOFREE_CLOSE:
fclose(f);
LOOP_END_NOFREE_NOCLOSE:
++argi;
}
return 0;
}