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
2 years ago
|
#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);
|
||
|
}
|