You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
166 lines
3.3 KiB
166 lines
3.3 KiB
#include <stdint.h> /* uint32_t etc */ |
|
#include <stdlib.h> /* exit */ |
|
#include <stdio.h> /* perror, fprintf */ |
|
#include <fcntl.h> /* open */ |
|
#include <unistd.h> /* read */ |
|
#include <sys/stat.h> /* fstat */ |
|
|
|
typedef uint8_t u8; |
|
typedef uint16_t u16; |
|
typedef uint32_t u32; |
|
typedef uint64_t u64; |
|
|
|
typedef int8_t s8; |
|
typedef int16_t s16; |
|
typedef int32_t s32; |
|
typedef int64_t s64; |
|
|
|
#define MAX_INSTRUCTIONS 1024 |
|
#define MAX_LABELS 128 |
|
|
|
enum regs_w { |
|
AX = 0, |
|
CX = 1, |
|
DX = 2, |
|
BX = 3, |
|
SP = 4, |
|
BP = 5, |
|
SI = 6, |
|
DI = 7, |
|
}; |
|
|
|
enum regs_h { |
|
AL = 0, |
|
CL = 1, |
|
DL = 2, |
|
BL = 3, |
|
AH = 4, |
|
CH = 5, |
|
DH = 6, |
|
BH = 7, |
|
}; |
|
|
|
enum mov_mod { |
|
MOD_MEMORY = 0x00, |
|
MOD_MEMORY_8 = 0x01, |
|
MOD_MEMORY_16 = 0x02, |
|
MOD_REGISTER = 0x03, |
|
}; |
|
|
|
enum mov_opcode { |
|
OPCODE_REG_RM = 0x88, |
|
OPCODE_IMM_RM = 0xC6, |
|
OPCODE_IMM_REG = 0xB0, |
|
OPCODE_MEM_ACC = 0xA0, |
|
OPCODE_ACC_MEM = 0xA2, |
|
}; |
|
|
|
enum mov_opcode_mask { |
|
MASK_REG_RM = 0xFC, |
|
MASK_IMM_RM = 0xFE, |
|
MASK_IMM_REG = 0xF0, |
|
MASK_MEM_ACC = 0xFE, |
|
MASK_ACC_MEM = 0xFE, |
|
|
|
MASK_ADD_SUB_CMP = 0xFC, |
|
}; |
|
|
|
struct rm { |
|
s8 reg1; // -1 here means it's an immediate |
|
s8 reg2; // -1 means no second |
|
s16 disp; // 0 means no displacement |
|
s16 imm; // if it's not an immediate - imm indicates if there is a displacement |
|
}; |
|
|
|
struct instruction { |
|
u8 size; |
|
u8 opcode; |
|
u8 wide; |
|
u8 swap; |
|
|
|
/* for mov, add, sub, cmp */ |
|
struct rm dst; |
|
struct rm src; |
|
|
|
/* for control-flow instructions */ |
|
s8 jump_offset; |
|
}; |
|
|
|
static const s8 NO_REGISTER = -1; |
|
static const u8 ANTIOP_MASK = 0xC4; |
|
|
|
static const char *REGS_W0[] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" }; |
|
static const char *REGS_W1[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" }; |
|
|
|
static const s8 MOD_PAIRS_FIRST[] = { BX, BX, BP, BP, SI, DI, BP, BX }; |
|
static const s8 MOD_PAIRS_SECOND[] = { SI, DI, SI, DI, NO_REGISTER, NO_REGISTER, NO_REGISTER, NO_REGISTER }; |
|
|
|
static const char *OP_NAMES[] = { |
|
[0x0] = "add", |
|
[0x5] = "sub", |
|
[0x7] = "cmp", |
|
[0xF] = "mov", /* Source? I made it up */ |
|
|
|
[0x74] = "je", |
|
[0x7C] = "jl", |
|
[0x7E] = "jle", |
|
[0x72] = "jb", |
|
[0x76] = "jbe", |
|
[0x7A] = "jp", |
|
[0x70] = "jo", |
|
[0x78] = "js", |
|
[0x75] = "jne", |
|
[0x7D] = "jnl", |
|
[0x7F] = "jg", |
|
[0x73] = "jnb", |
|
[0x77] = "ja", |
|
[0x7B] = "jnp", |
|
[0x71] = "jno", |
|
[0x79] = "jns", |
|
|
|
[0xE2] = "loop", |
|
[0xE1] = "loopz", |
|
[0xE0] = "loopnz", |
|
[0xE3] = "jcxz", |
|
}; |
|
|
|
#define CRASH_NOTIMPL() do { fprintf(stderr, "line: %d. not implemented\n", __LINE__); exit(1); } while (0) |
|
#define CRASH_SHOULDNOT() do { fprintf(stderr, "line: %d. should not happen\n", __LINE__); exit(1); } while (0) |
|
|
|
static u64 |
|
file_size(int fd) |
|
{ |
|
struct stat st = { 0 }; |
|
|
|
if (fstat(fd, &st) == -1) { |
|
perror("fstat"); |
|
exit(1); |
|
} |
|
|
|
return(st.st_size); |
|
} |
|
|
|
static u8 * |
|
read_file(int fd, u64 size) |
|
{ |
|
u8 *buf = malloc(size); |
|
|
|
if (!buf) { |
|
perror("malloc"); |
|
exit(1); |
|
} |
|
|
|
int rt = read(fd, buf, size); |
|
|
|
if (rt == -1) { |
|
perror("read"); |
|
exit(1); |
|
} |
|
|
|
if (rt != (int) size) { |
|
fprintf(stderr, "short read: %d < %lu\n", rt, size); |
|
exit(1); |
|
} |
|
|
|
return(buf); |
|
} |