refactor
This commit is contained in:
parent
92a7e5853c
commit
e3d2e31377
18 changed files with 2600 additions and 2696 deletions
500
include/mips.h
500
include/mips.h
|
@ -3,18 +3,502 @@
|
||||||
#ifndef __MIPS_H__
|
#ifndef __MIPS_H__
|
||||||
#define __MIPS_H__
|
#define __MIPS_H__
|
||||||
|
|
||||||
#include <mips32.h>
|
#include <mlimits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
enum mips_isa {
|
/* all mips registers $0-$31 */
|
||||||
ISA_MIPS32
|
enum mips_register {
|
||||||
|
MIPS_REG_ZERO = 0,
|
||||||
|
MIPS_REG_AT = 1,
|
||||||
|
MIPS_REG_V0 = 2,
|
||||||
|
MIPS_REG_V1 = 3,
|
||||||
|
MIPS_REG_A0 = 4,
|
||||||
|
MIPS_REG_A1 = 5,
|
||||||
|
MIPS_REG_A2 = 6,
|
||||||
|
MIPS_REG_A3 = 7,
|
||||||
|
MIPS_REG_T0 = 8,
|
||||||
|
MIPS_REG_T1 = 9,
|
||||||
|
MIPS_REG_T2 = 10,
|
||||||
|
MIPS_REG_T3 = 11,
|
||||||
|
MIPS_REG_T4 = 12,
|
||||||
|
MIPS_REG_T5 = 13,
|
||||||
|
MIPS_REG_T6 = 14,
|
||||||
|
MIPS_REG_T7 = 15,
|
||||||
|
MIPS_REG_S0 = 16,
|
||||||
|
MIPS_REG_S1 = 17,
|
||||||
|
MIPS_REG_S2 = 18,
|
||||||
|
MIPS_REG_S3 = 19,
|
||||||
|
MIPS_REG_S4 = 20,
|
||||||
|
MIPS_REG_S5 = 21,
|
||||||
|
MIPS_REG_S6 = 22,
|
||||||
|
MIPS_REG_S7 = 23,
|
||||||
|
MIPS_REG_T8 = 24,
|
||||||
|
MIPS_REG_T9 = 25,
|
||||||
|
MIPS_REG_K0 = 26,
|
||||||
|
MIPS_REG_K1 = 27,
|
||||||
|
MIPS_REG_GP = 28,
|
||||||
|
MIPS_REG_SP = 29,
|
||||||
|
MIPS_REG_FP = 30,
|
||||||
|
MIPS_REG_RA = 31,
|
||||||
};
|
};
|
||||||
|
|
||||||
union mips_instruction {
|
/* mips instruction format */
|
||||||
struct mips32_instruction mips32;
|
enum mips_instruction_format {
|
||||||
|
MIPS_FORMAT_R,
|
||||||
|
MIPS_FORMAT_I,
|
||||||
|
MIPS_FORMAT_J,
|
||||||
|
MIPS_FORMAT_B,
|
||||||
};
|
};
|
||||||
|
|
||||||
union mips_directive {
|
/* mips instructions */
|
||||||
struct mips32_directive mips32;
|
enum mips_instruction_type {
|
||||||
|
MIPS_INS_ADD,
|
||||||
|
MIPS_INS_ADDI,
|
||||||
|
MIPS_INS_ADDIU,
|
||||||
|
MIPS_INS_ADDU,
|
||||||
|
MIPS_INS_AND,
|
||||||
|
MIPS_INS_ANDI,
|
||||||
|
MIPS_INS_BAL,
|
||||||
|
MIPS_INS_BALC,
|
||||||
|
MIPS_INS_BC,
|
||||||
|
MIPS_INS_BEQ,
|
||||||
|
MIPS_INS_BEQL,
|
||||||
|
MIPS_INS_BGEZ,
|
||||||
|
MIPS_INS_BGEZAL,
|
||||||
|
MIPS_INS_BGEZALL,
|
||||||
|
MIPS_INS_BGEZL,
|
||||||
|
MIPS_INS_BGTZ,
|
||||||
|
MIPS_INS_BGTZL,
|
||||||
|
MIPS_INS_BLEZ,
|
||||||
|
MIPS_INS_BLEZL,
|
||||||
|
MIPS_INS_BLTZ,
|
||||||
|
MIPS_INS_BLTZAL,
|
||||||
|
MIPS_INS_BLTZALL,
|
||||||
|
MIPS_INS_BLTZL,
|
||||||
|
MIPS_INS_BNE,
|
||||||
|
MIPS_INS_BNEL,
|
||||||
|
MIPS_INS_DDIV,
|
||||||
|
MIPS_INS_DDIVU,
|
||||||
|
MIPS_INS_DIV,
|
||||||
|
MIPS_INS_DIVU,
|
||||||
|
MIPS_INS_J,
|
||||||
|
MIPS_INS_JAL,
|
||||||
|
MIPS_INS_JALR,
|
||||||
|
MIPS_INS_JALX,
|
||||||
|
MIPS_INS_JR,
|
||||||
|
MIPS_INS_LB,
|
||||||
|
MIPS_INS_LBU,
|
||||||
|
MIPS_INS_LH,
|
||||||
|
MIPS_INS_LHU,
|
||||||
|
MIPS_INS_LUI,
|
||||||
|
MIPS_INS_LW,
|
||||||
|
MIPS_INS_LWL,
|
||||||
|
MIPS_INS_LWR,
|
||||||
|
MIPS_INS_MFHI,
|
||||||
|
MIPS_INS_MFLO,
|
||||||
|
MIPS_INS_MTHI,
|
||||||
|
MIPS_INS_MTLO,
|
||||||
|
MIPS_INS_MULT,
|
||||||
|
MIPS_INS_MULTU,
|
||||||
|
MIPS_INS_SB,
|
||||||
|
MIPS_INS_SH,
|
||||||
|
MIPS_INS_SW,
|
||||||
|
MIPS_INS_SWL,
|
||||||
|
MIPS_INS_SWR,
|
||||||
|
MIPS_INS_SLL,
|
||||||
|
MIPS_INS_SLLV,
|
||||||
|
MIPS_INS_SLT,
|
||||||
|
MIPS_INS_SLTI,
|
||||||
|
MIPS_INS_SLTIU,
|
||||||
|
MIPS_INS_SLTU,
|
||||||
|
MIPS_INS_SRA,
|
||||||
|
MIPS_INS_SRAV,
|
||||||
|
MIPS_INS_SRL,
|
||||||
|
MIPS_INS_SRLV,
|
||||||
|
MIPS_INS_SUB,
|
||||||
|
MIPS_INS_SUBU,
|
||||||
|
MIPS_INS_SYSCALL,
|
||||||
|
MIPS_INS_OR,
|
||||||
|
MIPS_INS_ORI,
|
||||||
|
MIPS_INS_NOR,
|
||||||
|
MIPS_INS_XOR,
|
||||||
|
MIPS_INS_XORI,
|
||||||
|
// gets the size of the enum
|
||||||
|
__MIPS_INS_LEN,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __MIPS_H */
|
/* mips instruction R TYPE */
|
||||||
|
struct mips_instruction_r_data {
|
||||||
|
uint32_t funct : 6;
|
||||||
|
uint32_t shamt : 5;
|
||||||
|
uint32_t rd : 5;
|
||||||
|
uint32_t rt : 5;
|
||||||
|
uint32_t rs : 5;
|
||||||
|
uint32_t op : 6;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/* mips instruction I TYPE */
|
||||||
|
struct mips_instruction_i_data {
|
||||||
|
uint32_t immd : 16;
|
||||||
|
uint32_t rt : 5;
|
||||||
|
uint32_t rs : 5;
|
||||||
|
uint32_t op : 6;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/* mips instruction J TYPE */
|
||||||
|
struct mips_instruction_j_data {
|
||||||
|
uint32_t target : 26;
|
||||||
|
uint32_t op : 6;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/* mips instruction BRANCH TYPE */
|
||||||
|
struct mips_instruction_branch_data {
|
||||||
|
int32_t offset : 16;
|
||||||
|
uint32_t funct : 5;
|
||||||
|
uint32_t rs : 5;
|
||||||
|
uint32_t op : 6;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/* mips instruction information */
|
||||||
|
struct mips_instruction {
|
||||||
|
// metadata
|
||||||
|
enum mips_instruction_type type;
|
||||||
|
enum mips_instruction_format format;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
// data
|
||||||
|
union {
|
||||||
|
uint32_t data;
|
||||||
|
struct mips_instruction_r_data R_data;
|
||||||
|
struct mips_instruction_i_data I_data;
|
||||||
|
struct mips_instruction_j_data J_data;
|
||||||
|
struct mips_instruction_branch_data B_data;
|
||||||
|
} __attribute__((packed));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define MIPS_INS(ins, format, ...) \
|
||||||
|
[MIPS_INS_ ##ins] = { \
|
||||||
|
MIPS_INS_ ##ins, \
|
||||||
|
MIPS_FORMAT_ ##format, \
|
||||||
|
#ins, \
|
||||||
|
.format##_data = { __VA_ARGS__ } \
|
||||||
|
}, \
|
||||||
|
|
||||||
|
static const struct mips_instruction mips_instructions[] = {
|
||||||
|
/* ADD - add */
|
||||||
|
#define MIPS_OP_SPECIAL 0b000000
|
||||||
|
#define MIPS_FUNCT_ADD 0b100000
|
||||||
|
MIPS_INS(ADD, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_ADD)
|
||||||
|
|
||||||
|
/* ADDI - add immediate */
|
||||||
|
#define MIPS_OP_ADDI 0b001000
|
||||||
|
MIPS_INS(ADDI, I, .op = MIPS_OP_ADDI)
|
||||||
|
|
||||||
|
/* ADDIU - add immediate unsigned */
|
||||||
|
#define MIPS_OP_ADDIU 0b001001
|
||||||
|
MIPS_INS(ADDIU, I, .op = MIPS_OP_ADDIU)
|
||||||
|
|
||||||
|
/* ADDU - add unsigned */
|
||||||
|
#define MIPS_FUNCT_ADDU 0b100001
|
||||||
|
MIPS_INS(ADDU, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_ADDU)
|
||||||
|
|
||||||
|
/* AND - and */
|
||||||
|
#define MIPS_FUNCT_AND 0b100100
|
||||||
|
MIPS_INS(AND, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_AND)
|
||||||
|
|
||||||
|
/* ANDI - and immediate */
|
||||||
|
#define MIPS_OP_ANDI 0b001100
|
||||||
|
MIPS_INS(ANDI, I, .op = MIPS_OP_ANDI)
|
||||||
|
|
||||||
|
/* BAL - branch and link */
|
||||||
|
#define MIPS_OP_REGIMM 0b000001
|
||||||
|
#define MIPS_FUNCT_BAL 0b10001
|
||||||
|
MIPS_INS(BAL, B, .op = MIPS_OP_REGIMM, .funct = MIPS_FUNCT_BAL)
|
||||||
|
|
||||||
|
/* BALC - branch and link, compact */
|
||||||
|
#define MIPS_OP_BALC 0b111010
|
||||||
|
MIPS_INS(BALC, J, .op = MIPS_OP_BALC)
|
||||||
|
|
||||||
|
/* BC - branch, compact */
|
||||||
|
#define MIPS_OP_BC 0b110010
|
||||||
|
MIPS_INS(BC, J, .op = MIPS_OP_BC)
|
||||||
|
|
||||||
|
/* BEQ - branch on equal */
|
||||||
|
#define MIPS_OP_BEQ 0b000100
|
||||||
|
MIPS_INS(BEQ, I, .op = MIPS_OP_BEQ)
|
||||||
|
|
||||||
|
/* BEQL - branch on equal likely */
|
||||||
|
#define MIPS_OP_BEQL 0b010100
|
||||||
|
MIPS_INS(BEQL, I, .op = MIPS_OP_BEQL)
|
||||||
|
|
||||||
|
/* BGEZ - branch on greater than or equal to zero */
|
||||||
|
#define MIPS_FUNCT_BGEZ 0b00001
|
||||||
|
MIPS_INS(BGEZ, B, .op = MIPS_OP_REGIMM, .funct = MIPS_FUNCT_BGEZ)
|
||||||
|
|
||||||
|
/* BGEZAL - branch on greater than or equal to zero and link */
|
||||||
|
#define MIPS_FUNCT_BGEZAL 0b10001
|
||||||
|
MIPS_INS(BGEZAL, B, .op = MIPS_OP_REGIMM, .funct = MIPS_FUNCT_BGEZAL)
|
||||||
|
|
||||||
|
/* BGEZAL - branch on greater than or equal to zero and link likely */
|
||||||
|
#define MIPS_FUNCT_BGEZALL 0b10011
|
||||||
|
MIPS_INS(BGEZALL, B, .op = MIPS_OP_REGIMM, .funct = MIPS_FUNCT_BGEZALL)
|
||||||
|
|
||||||
|
/* BGEZL - branch on greater than or equal to zero likely */
|
||||||
|
#define MIPS_FUNCT_BGEZL 0b00011
|
||||||
|
MIPS_INS(BGEZL, B, .op = MIPS_OP_REGIMM, .funct = MIPS_FUNCT_BGEZL)
|
||||||
|
|
||||||
|
/* BGTZ - branch on greater than zero */
|
||||||
|
#define MIPS_OP_BGTZ 0b000111
|
||||||
|
MIPS_INS(BGTZ, I, .op = MIPS_OP_BGTZ)
|
||||||
|
|
||||||
|
/* BGTZL - branch on greater than zero likely */
|
||||||
|
#define MIPS_OP_BGTZL 0b010111
|
||||||
|
MIPS_INS(BGTZL, I, .op = MIPS_OP_BGTZL)
|
||||||
|
|
||||||
|
/* BLEZ - branch on less than or equal to zero */
|
||||||
|
#define MIPS_OP_BLEZ 0b000110
|
||||||
|
MIPS_INS(BLEZ, I, .op = MIPS_OP_BLEZ)
|
||||||
|
|
||||||
|
/* BLEZL - branch on less than or equal to zero likely */
|
||||||
|
#define MIPS_OP_BLEZL 0b010110
|
||||||
|
MIPS_INS(BLEZL, I, .op = MIPS_OP_BLEZL)
|
||||||
|
|
||||||
|
/* BLTZ - branch on less than zero */
|
||||||
|
#define MIPS_FUNCT_BLTZ 0b00000
|
||||||
|
MIPS_INS(BLTZ, B, .op = MIPS_OP_REGIMM, .funct = MIPS_FUNCT_BLTZ)
|
||||||
|
|
||||||
|
/* BLTZAL - branch on less than zero and link */
|
||||||
|
#define MIPS_FUNCT_BLTZAL 0b10000
|
||||||
|
MIPS_INS(BLTZAL, B, .op = MIPS_OP_REGIMM, .funct = MIPS_FUNCT_BLTZAL)
|
||||||
|
|
||||||
|
/* BLTZALL - branch on less than zero and link likely */
|
||||||
|
#define MIPS_FUNCT_BLTZALL 0b10010
|
||||||
|
MIPS_INS(BLTZALL, B, .op = MIPS_OP_REGIMM, .funct = MIPS_FUNCT_BLTZALL)
|
||||||
|
|
||||||
|
/* BLTZL - branch on less than zero likely */
|
||||||
|
#define MIPS_FUNCT_BLTZL 0b00010
|
||||||
|
MIPS_INS(BLTZL, B, .op = MIPS_OP_REGIMM, .funct = MIPS_FUNCT_BLTZL)
|
||||||
|
|
||||||
|
/* BNE - branch on not equal */
|
||||||
|
#define MIPS_OP_BNE 0b000101
|
||||||
|
MIPS_INS(BNE, I, .op = MIPS_OP_BNE)
|
||||||
|
|
||||||
|
/* BNEL - branch on not equal likely */
|
||||||
|
#define MIPS_OP_BNEL 0b010101
|
||||||
|
MIPS_INS(BNEL, I, .op = MIPS_OP_BNEL)
|
||||||
|
|
||||||
|
/* DDIV - doubleword divide */
|
||||||
|
#define MIPS_FUNCT_DDIV 0b011110
|
||||||
|
MIPS_INS(DDIV, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_DDIV)
|
||||||
|
|
||||||
|
/* DDIVU - doubleword divide unsigned */
|
||||||
|
#define MIPS_FUNCT_DDIVU 0b011111
|
||||||
|
MIPS_INS(DDIVU, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_DDIVU)
|
||||||
|
|
||||||
|
/* DIV - divide */
|
||||||
|
#define MIPS_FUNCT_DIV 0b011010
|
||||||
|
MIPS_INS(DIV, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_DIV)
|
||||||
|
|
||||||
|
/* DIVU - divide unsigned */
|
||||||
|
#define MIPS_FUNCT_DIVU 0b011011
|
||||||
|
MIPS_INS(DIVU, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_DIVU)
|
||||||
|
|
||||||
|
/* J - jump */
|
||||||
|
#define MIPS_OP_J 0b000010
|
||||||
|
MIPS_INS(J, J, .op = MIPS_OP_J)
|
||||||
|
|
||||||
|
/* JAL - jump and link */
|
||||||
|
#define MIPS_OP_JAL 0b000011
|
||||||
|
MIPS_INS(JAL, J, .op = MIPS_OP_JAL)
|
||||||
|
|
||||||
|
/* JALR - jump and link register */
|
||||||
|
#define MIPS_FUNCT_JALR 0b001001
|
||||||
|
MIPS_INS(JALR, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_JALR)
|
||||||
|
|
||||||
|
/* JALX - jump and link exchange */
|
||||||
|
#define MIPS_OP_JALX 0b011101
|
||||||
|
MIPS_INS(JALX, J, .op = MIPS_OP_JALX)
|
||||||
|
|
||||||
|
/* JR - jump register */
|
||||||
|
#define MIPS_FUNCT_JR 0b001000
|
||||||
|
MIPS_INS(JR, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_JR)
|
||||||
|
|
||||||
|
/* LB - load byte */
|
||||||
|
#define MIPS_OP_LB 0b100000
|
||||||
|
MIPS_INS(LB, I, .op = MIPS_OP_LB)
|
||||||
|
|
||||||
|
/* LBU - load byte unsigned */
|
||||||
|
#define MIPS_OP_LBU 0b100100
|
||||||
|
MIPS_INS(LBU, I, .op = MIPS_OP_LBU)
|
||||||
|
|
||||||
|
/* LH - load half */
|
||||||
|
#define MIPS_OP_LH 0b100001
|
||||||
|
MIPS_INS(LH, I, .op = MIPS_OP_LH)
|
||||||
|
|
||||||
|
/* LHU - load half unsigned */
|
||||||
|
#define MIPS_OP_LHU 0b100101
|
||||||
|
MIPS_INS(LHU, I, .op = MIPS_OP_LHU)
|
||||||
|
|
||||||
|
/* LUI - load upper immediate */
|
||||||
|
#define MIPS_OP_LUI 0b001111
|
||||||
|
MIPS_INS(LUI, I, .op = MIPS_OP_LUI)
|
||||||
|
|
||||||
|
/* LW - load word */
|
||||||
|
#define MIPS_OP_LW 0b100011
|
||||||
|
MIPS_INS(LW, I, .op = MIPS_OP_LW)
|
||||||
|
|
||||||
|
/* LWL - load word left */
|
||||||
|
#define MIPS_OP_LWL 0b100010
|
||||||
|
MIPS_INS(LWL, I, .op = MIPS_OP_LWL)
|
||||||
|
|
||||||
|
/* LWR - load word right */
|
||||||
|
#define MIPS_OP_LWR 0b100110
|
||||||
|
MIPS_INS(LWR, I, .op = MIPS_OP_LWR)
|
||||||
|
|
||||||
|
/* MFHI - move from hi */
|
||||||
|
#define MIPS_FUNCT_MFHI 0b010000
|
||||||
|
MIPS_INS(MFHI, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_MFHI)
|
||||||
|
|
||||||
|
/* MFLO - move from hi */
|
||||||
|
#define MIPS_FUNCT_MFLO 0b010010
|
||||||
|
MIPS_INS(MFLO, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_MFLO)
|
||||||
|
|
||||||
|
/* MTHI - move from hi */
|
||||||
|
#define MIPS_FUNCT_MTHI 0b010001
|
||||||
|
MIPS_INS(MTHI, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_MTHI)
|
||||||
|
|
||||||
|
/* MTLO - move from hi */
|
||||||
|
#define MIPS_FUNCT_MTLO 0b010011
|
||||||
|
MIPS_INS(MTLO, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_MTLO)
|
||||||
|
|
||||||
|
/* MULT - multiply */
|
||||||
|
#define MIPS_FUNCT_MULT 0b011000
|
||||||
|
MIPS_INS(MULT, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_MULT)
|
||||||
|
|
||||||
|
/* MULTU - multiply unsigned */
|
||||||
|
#define MIPS_FUNCT_MULTU 0b011001
|
||||||
|
MIPS_INS(MULTU, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_MULTU)
|
||||||
|
|
||||||
|
/* SB - store byte */
|
||||||
|
#define MIPS_OP_SB 0b101000
|
||||||
|
MIPS_INS(SB, I, .op = MIPS_OP_SB)
|
||||||
|
|
||||||
|
/* SH - store half */
|
||||||
|
#define MIPS_OP_SH 0b101001
|
||||||
|
MIPS_INS(SH, I, .op = MIPS_OP_SH)
|
||||||
|
|
||||||
|
/* SW - store word */
|
||||||
|
#define MIPS_OP_SW 0b101011
|
||||||
|
MIPS_INS(SW, I, .op = MIPS_OP_SW)
|
||||||
|
|
||||||
|
/* SWL - store word left */
|
||||||
|
#define MIPS_OP_SWL 0b101010
|
||||||
|
MIPS_INS(SWL, I, .op = MIPS_OP_SWL)
|
||||||
|
|
||||||
|
/* SWR - store word right */
|
||||||
|
#define MIPS_OP_SWR 0b101110
|
||||||
|
MIPS_INS(SWR, I, .op = MIPS_OP_SWR)
|
||||||
|
|
||||||
|
/* SLL - shift left logical */
|
||||||
|
#define MIPS_FUNCT_SLL 0b000000
|
||||||
|
MIPS_INS(SLL, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SLL)
|
||||||
|
|
||||||
|
/* SLLV - shift left logical variable */
|
||||||
|
#define MIPS_FUNCT_SLLV 0b000100
|
||||||
|
MIPS_INS(SLLV, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SLLV)
|
||||||
|
|
||||||
|
/* SLT - set less then */
|
||||||
|
#define MIPS_FUNCT_SLT 0b101010
|
||||||
|
MIPS_INS(SLT, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SLT)
|
||||||
|
|
||||||
|
/* SLTI - set less then immediate */
|
||||||
|
#define MIPS_OP_SLTI 0b001010
|
||||||
|
MIPS_INS(SLTI, I, .op = MIPS_OP_SLTI)
|
||||||
|
|
||||||
|
/* SLTIU - set less then imemdiate unsigned */
|
||||||
|
#define MIPS_OP_SLTIU 0b001011
|
||||||
|
MIPS_INS(SLTIU, I, .op = MIPS_OP_SLTIU)
|
||||||
|
|
||||||
|
/* SLTU - set less than unsigned */
|
||||||
|
#define MIPS_FUNCT_SLTU 0b101011
|
||||||
|
MIPS_INS(SLTU, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SLTU)
|
||||||
|
|
||||||
|
/* SRA - shift right arithmetic */
|
||||||
|
#define MIPS_FUNCT_SRA 0b000011
|
||||||
|
MIPS_INS(SRA, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SRA)
|
||||||
|
|
||||||
|
/* SRAV - shift right arithmetic variable */
|
||||||
|
#define MIPS_FUNCT_SRAV 0b000111
|
||||||
|
MIPS_INS(SRAV, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SRAV)
|
||||||
|
|
||||||
|
/* SRL - shift right logical */
|
||||||
|
#define MIPS_FUNCT_SRL 0b000010
|
||||||
|
MIPS_INS(SRL, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SRL)
|
||||||
|
|
||||||
|
/* SRLV - shift right logical variable */
|
||||||
|
#define MIPS_FUNCT_SRLV 0b000110
|
||||||
|
MIPS_INS(SRLV, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SRLV)
|
||||||
|
|
||||||
|
/* SUB - subtract */
|
||||||
|
#define MIPS_FUNCT_SUB 0b100010
|
||||||
|
MIPS_INS(SUB, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SUB)
|
||||||
|
|
||||||
|
/* SUBU - subtract unsigned */
|
||||||
|
#define MIPS_FUNCT_SUBU 0b100011
|
||||||
|
MIPS_INS(SUBU, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SUBU)
|
||||||
|
|
||||||
|
/* SYSCALL - syscall */
|
||||||
|
#define MIPS_FUNCT_SYSCALL 0b001100
|
||||||
|
MIPS_INS(SYSCALL, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SYSCALL)
|
||||||
|
|
||||||
|
/* OR - or */
|
||||||
|
#define MIPS_FUNCT_OR 0b100101
|
||||||
|
MIPS_INS(OR, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_OR)
|
||||||
|
|
||||||
|
/* ORI - or imemdiate */
|
||||||
|
#define MIPS_OP_ORI 0b001101
|
||||||
|
MIPS_INS(ORI, I, .op = MIPS_OP_ORI)
|
||||||
|
|
||||||
|
/* NOR - not or */
|
||||||
|
#define MIPS_FUNCT_NOR 0b100111
|
||||||
|
MIPS_INS(NOR, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_NOR)
|
||||||
|
|
||||||
|
/* XOR - exclusive or */
|
||||||
|
#define MIPS_FUNCT_XOR 0b100110
|
||||||
|
MIPS_INS(XOR, R, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_XOR)
|
||||||
|
|
||||||
|
/* XORI - exclusive or immediate */
|
||||||
|
#define MIPS_OP_XORI 0b001110
|
||||||
|
MIPS_INS(XORI, I, .op = MIPS_OP_XORI)
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef MIPS_INS
|
||||||
|
|
||||||
|
/* mips directive types */
|
||||||
|
enum mips_directive_type {
|
||||||
|
MIPS_DIRECTIVE_ALIGN,
|
||||||
|
MIPS_DIRECTIVE_SPACE,
|
||||||
|
MIPS_DIRECTIVE_WORD,
|
||||||
|
MIPS_DIRECTIVE_HALF,
|
||||||
|
MIPS_DIRECTIVE_BYTE,
|
||||||
|
MIPS_DIRECTIVE_SECTION,
|
||||||
|
MIPS_DIRECTIVE_EXTERN,
|
||||||
|
MIPS_DIRECTIVE_GLOBL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* mip32 directive */
|
||||||
|
struct mips_directive {
|
||||||
|
enum mips_directive_type type;
|
||||||
|
uint32_t len; // used for words, halfs, bytes
|
||||||
|
union {
|
||||||
|
uint16_t align;
|
||||||
|
uint16_t space;
|
||||||
|
uint32_t words[MAX_ARG_LENGTH];
|
||||||
|
uint16_t halfs[MAX_ARG_LENGTH];
|
||||||
|
uint8_t bytes[MAX_ARG_LENGTH];
|
||||||
|
char name[MAX_ARG_LENGTH];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __MIPS_H__ */
|
||||||
|
|
504
include/mips32.h
504
include/mips32.h
|
@ -1,504 +0,0 @@
|
||||||
/* Copyright (c) 2024 Freya Murphy */
|
|
||||||
|
|
||||||
#ifndef __MIPS32_H__
|
|
||||||
#define __MIPS32_H__
|
|
||||||
|
|
||||||
#include <mlimits.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
/* all mips registers $0-$31 */
|
|
||||||
enum mips32_register {
|
|
||||||
MIPS32_REG_ZERO = 0,
|
|
||||||
MIPS32_REG_AT = 1,
|
|
||||||
MIPS32_REG_V0 = 2,
|
|
||||||
MIPS32_REG_V1 = 3,
|
|
||||||
MIPS32_REG_A0 = 4,
|
|
||||||
MIPS32_REG_A1 = 5,
|
|
||||||
MIPS32_REG_A2 = 6,
|
|
||||||
MIPS32_REG_A3 = 7,
|
|
||||||
MIPS32_REG_T0 = 8,
|
|
||||||
MIPS32_REG_T1 = 9,
|
|
||||||
MIPS32_REG_T2 = 10,
|
|
||||||
MIPS32_REG_T3 = 11,
|
|
||||||
MIPS32_REG_T4 = 12,
|
|
||||||
MIPS32_REG_T5 = 13,
|
|
||||||
MIPS32_REG_T6 = 14,
|
|
||||||
MIPS32_REG_T7 = 15,
|
|
||||||
MIPS32_REG_S0 = 16,
|
|
||||||
MIPS32_REG_S1 = 17,
|
|
||||||
MIPS32_REG_S2 = 18,
|
|
||||||
MIPS32_REG_S3 = 19,
|
|
||||||
MIPS32_REG_S4 = 20,
|
|
||||||
MIPS32_REG_S5 = 21,
|
|
||||||
MIPS32_REG_S6 = 22,
|
|
||||||
MIPS32_REG_S7 = 23,
|
|
||||||
MIPS32_REG_T8 = 24,
|
|
||||||
MIPS32_REG_T9 = 25,
|
|
||||||
MIPS32_REG_K0 = 26,
|
|
||||||
MIPS32_REG_K1 = 27,
|
|
||||||
MIPS32_REG_GP = 28,
|
|
||||||
MIPS32_REG_SP = 29,
|
|
||||||
MIPS32_REG_FP = 30,
|
|
||||||
MIPS32_REG_RA = 31,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* mips instruction format */
|
|
||||||
enum mips32_instruction_format {
|
|
||||||
MIPS32_FORMAT_R,
|
|
||||||
MIPS32_FORMAT_I,
|
|
||||||
MIPS32_FORMAT_J,
|
|
||||||
MIPS32_FORMAT_B,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* mips instructions */
|
|
||||||
enum mips32_instruction_type {
|
|
||||||
MIPS32_INS_ADD,
|
|
||||||
MIPS32_INS_ADDI,
|
|
||||||
MIPS32_INS_ADDIU,
|
|
||||||
MIPS32_INS_ADDU,
|
|
||||||
MIPS32_INS_AND,
|
|
||||||
MIPS32_INS_ANDI,
|
|
||||||
MIPS32_INS_BAL,
|
|
||||||
MIPS32_INS_BALC,
|
|
||||||
MIPS32_INS_BC,
|
|
||||||
MIPS32_INS_BEQ,
|
|
||||||
MIPS32_INS_BEQL,
|
|
||||||
MIPS32_INS_BGEZ,
|
|
||||||
MIPS32_INS_BGEZAL,
|
|
||||||
MIPS32_INS_BGEZALL,
|
|
||||||
MIPS32_INS_BGEZL,
|
|
||||||
MIPS32_INS_BGTZ,
|
|
||||||
MIPS32_INS_BGTZL,
|
|
||||||
MIPS32_INS_BLEZ,
|
|
||||||
MIPS32_INS_BLEZL,
|
|
||||||
MIPS32_INS_BLTZ,
|
|
||||||
MIPS32_INS_BLTZAL,
|
|
||||||
MIPS32_INS_BLTZALL,
|
|
||||||
MIPS32_INS_BLTZL,
|
|
||||||
MIPS32_INS_BNE,
|
|
||||||
MIPS32_INS_BNEL,
|
|
||||||
MIPS32_INS_DDIV,
|
|
||||||
MIPS32_INS_DDIVU,
|
|
||||||
MIPS32_INS_DIV,
|
|
||||||
MIPS32_INS_DIVU,
|
|
||||||
MIPS32_INS_J,
|
|
||||||
MIPS32_INS_JAL,
|
|
||||||
MIPS32_INS_JALR,
|
|
||||||
MIPS32_INS_JALX,
|
|
||||||
MIPS32_INS_JR,
|
|
||||||
MIPS32_INS_LB,
|
|
||||||
MIPS32_INS_LBU,
|
|
||||||
MIPS32_INS_LH,
|
|
||||||
MIPS32_INS_LHU,
|
|
||||||
MIPS32_INS_LUI,
|
|
||||||
MIPS32_INS_LW,
|
|
||||||
MIPS32_INS_LWL,
|
|
||||||
MIPS32_INS_LWR,
|
|
||||||
MIPS32_INS_MFHI,
|
|
||||||
MIPS32_INS_MFLO,
|
|
||||||
MIPS32_INS_MTHI,
|
|
||||||
MIPS32_INS_MTLO,
|
|
||||||
MIPS32_INS_MULT,
|
|
||||||
MIPS32_INS_MULTU,
|
|
||||||
MIPS32_INS_SB,
|
|
||||||
MIPS32_INS_SH,
|
|
||||||
MIPS32_INS_SW,
|
|
||||||
MIPS32_INS_SWL,
|
|
||||||
MIPS32_INS_SWR,
|
|
||||||
MIPS32_INS_SLL,
|
|
||||||
MIPS32_INS_SLLV,
|
|
||||||
MIPS32_INS_SLT,
|
|
||||||
MIPS32_INS_SLTI,
|
|
||||||
MIPS32_INS_SLTIU,
|
|
||||||
MIPS32_INS_SLTU,
|
|
||||||
MIPS32_INS_SRA,
|
|
||||||
MIPS32_INS_SRAV,
|
|
||||||
MIPS32_INS_SRL,
|
|
||||||
MIPS32_INS_SRLV,
|
|
||||||
MIPS32_INS_SUB,
|
|
||||||
MIPS32_INS_SUBU,
|
|
||||||
MIPS32_INS_SYSCALL,
|
|
||||||
MIPS32_INS_OR,
|
|
||||||
MIPS32_INS_ORI,
|
|
||||||
MIPS32_INS_NOR,
|
|
||||||
MIPS32_INS_XOR,
|
|
||||||
MIPS32_INS_XORI,
|
|
||||||
// gets the size of the enum
|
|
||||||
__MIPS32_INS_LEN,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* mips instruction R TYPE */
|
|
||||||
struct mips32_instruction_r_data {
|
|
||||||
uint32_t funct : 6;
|
|
||||||
uint32_t shamt : 5;
|
|
||||||
uint32_t rd : 5;
|
|
||||||
uint32_t rt : 5;
|
|
||||||
uint32_t rs : 5;
|
|
||||||
uint32_t op : 6;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
/* mips instruction I TYPE */
|
|
||||||
struct mips32_instruction_i_data {
|
|
||||||
uint32_t immd : 16;
|
|
||||||
uint32_t rt : 5;
|
|
||||||
uint32_t rs : 5;
|
|
||||||
uint32_t op : 6;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
/* mips instruction J TYPE */
|
|
||||||
struct mips32_instruction_j_data {
|
|
||||||
uint32_t target : 26;
|
|
||||||
uint32_t op : 6;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
/* mips instruction BRANCH TYPE */
|
|
||||||
struct mips32_instruction_branch_data {
|
|
||||||
int32_t offset : 16;
|
|
||||||
uint32_t funct : 5;
|
|
||||||
uint32_t rs : 5;
|
|
||||||
uint32_t op : 6;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
/* mips instruction information */
|
|
||||||
struct mips32_instruction {
|
|
||||||
// metadata
|
|
||||||
enum mips32_instruction_type type;
|
|
||||||
enum mips32_instruction_format format;
|
|
||||||
const char *name;
|
|
||||||
|
|
||||||
// data
|
|
||||||
union {
|
|
||||||
uint32_t data;
|
|
||||||
struct mips32_instruction_r_data R_data;
|
|
||||||
struct mips32_instruction_i_data I_data;
|
|
||||||
struct mips32_instruction_j_data J_data;
|
|
||||||
struct mips32_instruction_branch_data B_data;
|
|
||||||
} __attribute__((packed));
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define MIPS32_INS(ins, format, ...) \
|
|
||||||
[MIPS32_INS_ ##ins] = { \
|
|
||||||
MIPS32_INS_ ##ins, \
|
|
||||||
MIPS32_FORMAT_ ##format, \
|
|
||||||
#ins, \
|
|
||||||
.format##_data = { __VA_ARGS__ } \
|
|
||||||
}, \
|
|
||||||
|
|
||||||
static const struct mips32_instruction mips32_instructions[] = {
|
|
||||||
/* ADD - add */
|
|
||||||
#define MIPS32_OP_SPECIAL 0b000000
|
|
||||||
#define MIPS32_FUNCT_ADD 0b100000
|
|
||||||
MIPS32_INS(ADD, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_ADD)
|
|
||||||
|
|
||||||
/* ADDI - add immediate */
|
|
||||||
#define MIPS32_OP_ADDI 0b001000
|
|
||||||
MIPS32_INS(ADDI, I, .op = MIPS32_OP_ADDI)
|
|
||||||
|
|
||||||
/* ADDIU - add immediate unsigned */
|
|
||||||
#define MIPS32_OP_ADDIU 0b001001
|
|
||||||
MIPS32_INS(ADDIU, I, .op = MIPS32_OP_ADDIU)
|
|
||||||
|
|
||||||
/* ADDU - add unsigned */
|
|
||||||
#define MIPS32_FUNCT_ADDU 0b100001
|
|
||||||
MIPS32_INS(ADDU, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_ADDU)
|
|
||||||
|
|
||||||
/* AND - and */
|
|
||||||
#define MIPS32_FUNCT_AND 0b100100
|
|
||||||
MIPS32_INS(AND, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_AND)
|
|
||||||
|
|
||||||
/* ANDI - and immediate */
|
|
||||||
#define MIPS32_OP_ANDI 0b001100
|
|
||||||
MIPS32_INS(ANDI, I, .op = MIPS32_OP_ANDI)
|
|
||||||
|
|
||||||
/* BAL - branch and link */
|
|
||||||
#define MIPS32_OP_REGIMM 0b000001
|
|
||||||
#define MIPS32_FUNCT_BAL 0b10001
|
|
||||||
MIPS32_INS(BAL, B, .op = MIPS32_OP_REGIMM, .funct = MIPS32_FUNCT_BAL)
|
|
||||||
|
|
||||||
/* BALC - branch and link, compact */
|
|
||||||
#define MIPS32_OP_BALC 0b111010
|
|
||||||
MIPS32_INS(BALC, J, .op = MIPS32_OP_BALC)
|
|
||||||
|
|
||||||
/* BC - branch, compact */
|
|
||||||
#define MIPS32_OP_BC 0b110010
|
|
||||||
MIPS32_INS(BC, J, .op = MIPS32_OP_BC)
|
|
||||||
|
|
||||||
/* BEQ - branch on equal */
|
|
||||||
#define MIPS32_OP_BEQ 0b000100
|
|
||||||
MIPS32_INS(BEQ, I, .op = MIPS32_OP_BEQ)
|
|
||||||
|
|
||||||
/* BEQL - branch on equal likely */
|
|
||||||
#define MIPS32_OP_BEQL 0b010100
|
|
||||||
MIPS32_INS(BEQL, I, .op = MIPS32_OP_BEQL)
|
|
||||||
|
|
||||||
/* BGEZ - branch on greater than or equal to zero */
|
|
||||||
#define MIPS32_FUNCT_BGEZ 0b00001
|
|
||||||
MIPS32_INS(BGEZ, B, .op = MIPS32_OP_REGIMM, .funct = MIPS32_FUNCT_BGEZ)
|
|
||||||
|
|
||||||
/* BGEZAL - branch on greater than or equal to zero and link */
|
|
||||||
#define MIPS32_FUNCT_BGEZAL 0b10001
|
|
||||||
MIPS32_INS(BGEZAL, B, .op = MIPS32_OP_REGIMM, .funct = MIPS32_FUNCT_BGEZAL)
|
|
||||||
|
|
||||||
/* BGEZAL - branch on greater than or equal to zero and link likely */
|
|
||||||
#define MIPS32_FUNCT_BGEZALL 0b10011
|
|
||||||
MIPS32_INS(BGEZALL, B, .op = MIPS32_OP_REGIMM, .funct = MIPS32_FUNCT_BGEZALL)
|
|
||||||
|
|
||||||
/* BGEZL - branch on greater than or equal to zero likely */
|
|
||||||
#define MIPS32_FUNCT_BGEZL 0b00011
|
|
||||||
MIPS32_INS(BGEZL, B, .op = MIPS32_OP_REGIMM, .funct = MIPS32_FUNCT_BGEZL)
|
|
||||||
|
|
||||||
/* BGTZ - branch on greater than zero */
|
|
||||||
#define MIPS32_OP_BGTZ 0b000111
|
|
||||||
MIPS32_INS(BGTZ, I, .op = MIPS32_OP_BGTZ)
|
|
||||||
|
|
||||||
/* BGTZL - branch on greater than zero likely */
|
|
||||||
#define MIPS32_OP_BGTZL 0b010111
|
|
||||||
MIPS32_INS(BGTZL, I, .op = MIPS32_OP_BGTZL)
|
|
||||||
|
|
||||||
/* BLEZ - branch on less than or equal to zero */
|
|
||||||
#define MIPS32_OP_BLEZ 0b000110
|
|
||||||
MIPS32_INS(BLEZ, I, .op = MIPS32_OP_BLEZ)
|
|
||||||
|
|
||||||
/* BLEZL - branch on less than or equal to zero likely */
|
|
||||||
#define MIPS32_OP_BLEZL 0b010110
|
|
||||||
MIPS32_INS(BLEZL, I, .op = MIPS32_OP_BLEZL)
|
|
||||||
|
|
||||||
/* BLTZ - branch on less than zero */
|
|
||||||
#define MIPS32_FUNCT_BLTZ 0b00000
|
|
||||||
MIPS32_INS(BLTZ, B, .op = MIPS32_OP_REGIMM, .funct = MIPS32_FUNCT_BLTZ)
|
|
||||||
|
|
||||||
/* BLTZAL - branch on less than zero and link */
|
|
||||||
#define MIPS32_FUNCT_BLTZAL 0b10000
|
|
||||||
MIPS32_INS(BLTZAL, B, .op = MIPS32_OP_REGIMM, .funct = MIPS32_FUNCT_BLTZAL)
|
|
||||||
|
|
||||||
/* BLTZALL - branch on less than zero and link likely */
|
|
||||||
#define MIPS32_FUNCT_BLTZALL 0b10010
|
|
||||||
MIPS32_INS(BLTZALL, B, .op = MIPS32_OP_REGIMM, .funct = MIPS32_FUNCT_BLTZALL)
|
|
||||||
|
|
||||||
/* BLTZL - branch on less than zero likely */
|
|
||||||
#define MIPS32_FUNCT_BLTZL 0b00010
|
|
||||||
MIPS32_INS(BLTZL, B, .op = MIPS32_OP_REGIMM, .funct = MIPS32_FUNCT_BLTZL)
|
|
||||||
|
|
||||||
/* BNE - branch on not equal */
|
|
||||||
#define MIPS32_OP_BNE 0b000101
|
|
||||||
MIPS32_INS(BNE, I, .op = MIPS32_OP_BNE)
|
|
||||||
|
|
||||||
/* BNEL - branch on not equal likely */
|
|
||||||
#define MIPS32_OP_BNEL 0b010101
|
|
||||||
MIPS32_INS(BNEL, I, .op = MIPS32_OP_BNEL)
|
|
||||||
|
|
||||||
/* DDIV - doubleword divide */
|
|
||||||
#define MIPS32_FUNCT_DDIV 0b011110
|
|
||||||
MIPS32_INS(DDIV, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_DDIV)
|
|
||||||
|
|
||||||
/* DDIVU - doubleword divide unsigned */
|
|
||||||
#define MIPS32_FUNCT_DDIVU 0b011111
|
|
||||||
MIPS32_INS(DDIVU, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_DDIVU)
|
|
||||||
|
|
||||||
/* DIV - divide */
|
|
||||||
#define MIPS32_FUNCT_DIV 0b011010
|
|
||||||
MIPS32_INS(DIV, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_DIV)
|
|
||||||
|
|
||||||
/* DIVU - divide unsigned */
|
|
||||||
#define MIPS32_FUNCT_DIVU 0b011011
|
|
||||||
MIPS32_INS(DIVU, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_DIVU)
|
|
||||||
|
|
||||||
/* J - jump */
|
|
||||||
#define MIPS32_OP_J 0b000010
|
|
||||||
MIPS32_INS(J, J, .op = MIPS32_OP_J)
|
|
||||||
|
|
||||||
/* JAL - jump and link */
|
|
||||||
#define MIPS32_OP_JAL 0b000011
|
|
||||||
MIPS32_INS(JAL, J, .op = MIPS32_OP_JAL)
|
|
||||||
|
|
||||||
/* JALR - jump and link register */
|
|
||||||
#define MIPS32_FUNCT_JALR 0b001001
|
|
||||||
MIPS32_INS(JALR, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_JALR)
|
|
||||||
|
|
||||||
/* JALX - jump and link exchange */
|
|
||||||
#define MIPS32_OP_JALX 0b011101
|
|
||||||
MIPS32_INS(JALX, J, .op = MIPS32_OP_JALX)
|
|
||||||
|
|
||||||
/* JR - jump register */
|
|
||||||
#define MIPS32_FUNCT_JR 0b001000
|
|
||||||
MIPS32_INS(JR, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_JR)
|
|
||||||
|
|
||||||
/* LB - load byte */
|
|
||||||
#define MIPS32_OP_LB 0b100000
|
|
||||||
MIPS32_INS(LB, I, .op = MIPS32_OP_LB)
|
|
||||||
|
|
||||||
/* LBU - load byte unsigned */
|
|
||||||
#define MIPS32_OP_LBU 0b100100
|
|
||||||
MIPS32_INS(LBU, I, .op = MIPS32_OP_LBU)
|
|
||||||
|
|
||||||
/* LH - load half */
|
|
||||||
#define MIPS32_OP_LH 0b100001
|
|
||||||
MIPS32_INS(LH, I, .op = MIPS32_OP_LH)
|
|
||||||
|
|
||||||
/* LHU - load half unsigned */
|
|
||||||
#define MIPS32_OP_LHU 0b100101
|
|
||||||
MIPS32_INS(LHU, I, .op = MIPS32_OP_LHU)
|
|
||||||
|
|
||||||
/* LUI - load upper immediate */
|
|
||||||
#define MIPS32_OP_LUI 0b001111
|
|
||||||
MIPS32_INS(LUI, I, .op = MIPS32_OP_LUI)
|
|
||||||
|
|
||||||
/* LW - load word */
|
|
||||||
#define MIPS32_OP_LW 0b100011
|
|
||||||
MIPS32_INS(LW, I, .op = MIPS32_OP_LW)
|
|
||||||
|
|
||||||
/* LWL - load word left */
|
|
||||||
#define MIPS32_OP_LWL 0b100010
|
|
||||||
MIPS32_INS(LWL, I, .op = MIPS32_OP_LWL)
|
|
||||||
|
|
||||||
/* LWR - load word right */
|
|
||||||
#define MIPS32_OP_LWR 0b100110
|
|
||||||
MIPS32_INS(LWR, I, .op = MIPS32_OP_LWR)
|
|
||||||
|
|
||||||
/* MFHI - move from hi */
|
|
||||||
#define MIPS32_FUNCT_MFHI 0b010000
|
|
||||||
MIPS32_INS(MFHI, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_MFHI)
|
|
||||||
|
|
||||||
/* MFLO - move from hi */
|
|
||||||
#define MIPS32_FUNCT_MFLO 0b010010
|
|
||||||
MIPS32_INS(MFLO, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_MFLO)
|
|
||||||
|
|
||||||
/* MTHI - move from hi */
|
|
||||||
#define MIPS32_FUNCT_MTHI 0b010001
|
|
||||||
MIPS32_INS(MTHI, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_MTHI)
|
|
||||||
|
|
||||||
/* MTLO - move from hi */
|
|
||||||
#define MIPS32_FUNCT_MTLO 0b010011
|
|
||||||
MIPS32_INS(MTLO, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_MTLO)
|
|
||||||
|
|
||||||
/* MULT - multiply */
|
|
||||||
#define MIPS32_FUNCT_MULT 0b011000
|
|
||||||
MIPS32_INS(MULT, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_MULT)
|
|
||||||
|
|
||||||
/* MULTU - multiply unsigned */
|
|
||||||
#define MIPS32_FUNCT_MULTU 0b011001
|
|
||||||
MIPS32_INS(MULTU, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_MULTU)
|
|
||||||
|
|
||||||
/* SB - store byte */
|
|
||||||
#define MIPS32_OP_SB 0b101000
|
|
||||||
MIPS32_INS(SB, I, .op = MIPS32_OP_SB)
|
|
||||||
|
|
||||||
/* SH - store half */
|
|
||||||
#define MIPS32_OP_SH 0b101001
|
|
||||||
MIPS32_INS(SH, I, .op = MIPS32_OP_SH)
|
|
||||||
|
|
||||||
/* SW - store word */
|
|
||||||
#define MIPS32_OP_SW 0b101011
|
|
||||||
MIPS32_INS(SW, I, .op = MIPS32_OP_SW)
|
|
||||||
|
|
||||||
/* SWL - store word left */
|
|
||||||
#define MIPS32_OP_SWL 0b101010
|
|
||||||
MIPS32_INS(SWL, I, .op = MIPS32_OP_SWL)
|
|
||||||
|
|
||||||
/* SWR - store word right */
|
|
||||||
#define MIPS32_OP_SWR 0b101110
|
|
||||||
MIPS32_INS(SWR, I, .op = MIPS32_OP_SWR)
|
|
||||||
|
|
||||||
/* SLL - shift left logical */
|
|
||||||
#define MIPS32_FUNCT_SLL 0b000000
|
|
||||||
MIPS32_INS(SLL, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_SLL)
|
|
||||||
|
|
||||||
/* SLLV - shift left logical variable */
|
|
||||||
#define MIPS32_FUNCT_SLLV 0b000100
|
|
||||||
MIPS32_INS(SLLV, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_SLLV)
|
|
||||||
|
|
||||||
/* SLT - set less then */
|
|
||||||
#define MIPS32_FUNCT_SLT 0b101010
|
|
||||||
MIPS32_INS(SLT, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_SLT)
|
|
||||||
|
|
||||||
/* SLTI - set less then immediate */
|
|
||||||
#define MIPS32_OP_SLTI 0b001010
|
|
||||||
MIPS32_INS(SLTI, I, .op = MIPS32_OP_SLTI)
|
|
||||||
|
|
||||||
/* SLTIU - set less then imemdiate unsigned */
|
|
||||||
#define MIPS32_OP_SLTIU 0b001011
|
|
||||||
MIPS32_INS(SLTIU, I, .op = MIPS32_OP_SLTIU)
|
|
||||||
|
|
||||||
/* SLTU - set less than unsigned */
|
|
||||||
#define MIPS32_FUNCT_SLTU 0b101011
|
|
||||||
MIPS32_INS(SLTU, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_SLTU)
|
|
||||||
|
|
||||||
/* SRA - shift right arithmetic */
|
|
||||||
#define MIPS32_FUNCT_SRA 0b000011
|
|
||||||
MIPS32_INS(SRA, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_SRA)
|
|
||||||
|
|
||||||
/* SRAV - shift right arithmetic variable */
|
|
||||||
#define MIPS32_FUNCT_SRAV 0b000111
|
|
||||||
MIPS32_INS(SRAV, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_SRAV)
|
|
||||||
|
|
||||||
/* SRL - shift right logical */
|
|
||||||
#define MIPS32_FUNCT_SRL 0b000010
|
|
||||||
MIPS32_INS(SRL, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_SRL)
|
|
||||||
|
|
||||||
/* SRLV - shift right logical variable */
|
|
||||||
#define MIPS32_FUNCT_SRLV 0b000110
|
|
||||||
MIPS32_INS(SRLV, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_SRLV)
|
|
||||||
|
|
||||||
/* SUB - subtract */
|
|
||||||
#define MIPS32_FUNCT_SUB 0b100010
|
|
||||||
MIPS32_INS(SUB, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_SUB)
|
|
||||||
|
|
||||||
/* SUBU - subtract unsigned */
|
|
||||||
#define MIPS32_FUNCT_SUBU 0b100011
|
|
||||||
MIPS32_INS(SUBU, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_SUBU)
|
|
||||||
|
|
||||||
/* SYSCALL - syscall */
|
|
||||||
#define MIPS32_FUNCT_SYSCALL 0b001100
|
|
||||||
MIPS32_INS(SYSCALL, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_SYSCALL)
|
|
||||||
|
|
||||||
/* OR - or */
|
|
||||||
#define MIPS32_FUNCT_OR 0b100101
|
|
||||||
MIPS32_INS(OR, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_OR)
|
|
||||||
|
|
||||||
/* ORI - or imemdiate */
|
|
||||||
#define MIPS32_OP_ORI 0b001101
|
|
||||||
MIPS32_INS(ORI, I, .op = MIPS32_OP_ORI)
|
|
||||||
|
|
||||||
/* NOR - not or */
|
|
||||||
#define MIPS32_FUNCT_NOR 0b100111
|
|
||||||
MIPS32_INS(NOR, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_NOR)
|
|
||||||
|
|
||||||
/* XOR - exclusive or */
|
|
||||||
#define MIPS32_FUNCT_XOR 0b100110
|
|
||||||
MIPS32_INS(XOR, R, .op = MIPS32_OP_SPECIAL, .funct = MIPS32_FUNCT_XOR)
|
|
||||||
|
|
||||||
/* XORI - exclusive or immediate */
|
|
||||||
#define MIPS32_OP_XORI 0b001110
|
|
||||||
MIPS32_INS(XORI, I, .op = MIPS32_OP_XORI)
|
|
||||||
};
|
|
||||||
|
|
||||||
#undef MIPS32_INS
|
|
||||||
|
|
||||||
/* mips32 directive types */
|
|
||||||
enum mips32_directive_type {
|
|
||||||
MIPS32_DIRECTIVE_ALIGN,
|
|
||||||
MIPS32_DIRECTIVE_SPACE,
|
|
||||||
MIPS32_DIRECTIVE_WORD,
|
|
||||||
MIPS32_DIRECTIVE_HALF,
|
|
||||||
MIPS32_DIRECTIVE_BYTE,
|
|
||||||
MIPS32_DIRECTIVE_SECTION,
|
|
||||||
MIPS32_DIRECTIVE_EXTERN,
|
|
||||||
MIPS32_DIRECTIVE_GLOBL,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* mip32 directive */
|
|
||||||
struct mips32_directive {
|
|
||||||
enum mips32_directive_type type;
|
|
||||||
uint32_t len; // used for words, halfs, bytes
|
|
||||||
union {
|
|
||||||
uint16_t align;
|
|
||||||
uint16_t space;
|
|
||||||
uint32_t words[MAX_ARG_LENGTH];
|
|
||||||
uint16_t halfs[MAX_ARG_LENGTH];
|
|
||||||
uint8_t bytes[MAX_ARG_LENGTH];
|
|
||||||
char name[MAX_ARG_LENGTH];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* __MIPS32_H__ */
|
|
724
masm/asm.c
724
masm/asm.c
|
@ -1,77 +1,717 @@
|
||||||
#include <merror.h>
|
#include <merror.h>
|
||||||
|
#include <mips.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <elf.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "asm.h"
|
#include "asm.h"
|
||||||
|
#include "mlimits.h"
|
||||||
|
#include "parse.h"
|
||||||
|
|
||||||
|
extern char *current_file;
|
||||||
|
|
||||||
|
#define SYMSEC_STUB -1
|
||||||
|
#define SYMSEC_EXTERN -1
|
||||||
|
|
||||||
|
static int create_symbol(struct assembler *assembler,
|
||||||
|
const char name[MAX_LEX_LENGTH],
|
||||||
|
ssize_t section_idx,
|
||||||
|
size_t section_offset,
|
||||||
|
unsigned char bind)
|
||||||
|
{
|
||||||
|
size_t str_off;
|
||||||
|
if (strtab_write_str(&assembler->strtab, name, &str_off))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
Elf32_Sym symbol = {
|
||||||
|
.st_name = str_off,
|
||||||
|
.st_value = section_offset,
|
||||||
|
.st_size = 0,
|
||||||
|
.st_info = ELF32_ST_INFO(bind, STT_NOTYPE),
|
||||||
|
.st_other = ELF32_ST_VISIBILITY(STV_DEFAULT),
|
||||||
|
.st_shndx = section_idx,
|
||||||
|
};
|
||||||
|
|
||||||
|
// dont put magic flag values inside symbol, only real indexes
|
||||||
|
if (section_idx < 0)
|
||||||
|
symbol.st_shndx = 0;
|
||||||
|
|
||||||
|
if (symtab_push(&assembler->symtab, symbol, section_idx))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_symbol_or_stub(struct assembler *assembler,
|
||||||
|
const char name[MAX_LEX_LENGTH],
|
||||||
|
Elf32_Sym **res,
|
||||||
|
size_t *res2)
|
||||||
|
{
|
||||||
|
if (symtab_find(&assembler->symtab, res, res2, name) == M_SUCCESS)
|
||||||
|
return M_SUCCESS;
|
||||||
|
|
||||||
|
if (create_symbol(assembler, name, SYMSEC_STUB, 0, STB_LOCAL))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
size_t idx = assembler->symtab.len - 1;
|
||||||
|
|
||||||
|
if (res != NULL)
|
||||||
|
*res = &assembler->symtab.symbols[idx];
|
||||||
|
if (res2 != NULL)
|
||||||
|
*res2 = idx;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_directive(struct assembler *assembler,
|
||||||
|
struct mips_directive *directive)
|
||||||
|
{
|
||||||
|
switch (directive->type) {
|
||||||
|
case MIPS_DIRECTIVE_SECTION: {
|
||||||
|
struct section_table *sec_tbl = &assembler->sectab;
|
||||||
|
struct section *sec;
|
||||||
|
if (sectab_get(sec_tbl, &sec, directive->name)
|
||||||
|
== M_SUCCESS) {
|
||||||
|
sec_tbl->current = sec;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sectab_alloc(sec_tbl, &sec, directive->name))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
sec_tbl->current = sec;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MIPS_DIRECTIVE_ALIGN: {
|
||||||
|
assembler->sectab.current->alignment =
|
||||||
|
1 << directive->align;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MIPS_DIRECTIVE_SPACE: {
|
||||||
|
struct section_entry entry;
|
||||||
|
entry.type = ENT_NO_DATA;
|
||||||
|
entry.size = directive->space;
|
||||||
|
if (sec_push(assembler->sectab.current, entry))
|
||||||
|
return M_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MIPS_DIRECTIVE_WORD: {
|
||||||
|
for (uint32_t i = 0; i < directive->len; i++) {
|
||||||
|
struct section_entry entry;
|
||||||
|
entry.type = ENT_WORD;
|
||||||
|
entry.word = directive->words[i];
|
||||||
|
if (sec_push(assembler->sectab.current,
|
||||||
|
entry))
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MIPS_DIRECTIVE_HALF: {
|
||||||
|
for (uint32_t i = 0; i < directive->len; i++) {
|
||||||
|
struct section_entry entry;
|
||||||
|
entry.type = ENT_HALF;
|
||||||
|
entry.half = directive->halfs[i];
|
||||||
|
if (sec_push(assembler->sectab.current,
|
||||||
|
entry))
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MIPS_DIRECTIVE_BYTE: {
|
||||||
|
for (uint32_t i = 0; i < directive->len; i++) {
|
||||||
|
struct section_entry entry;
|
||||||
|
entry.type = ENT_BYTE;
|
||||||
|
entry.byte = directive->bytes[i];
|
||||||
|
if (sec_push(assembler->sectab.current,
|
||||||
|
entry))
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MIPS_DIRECTIVE_EXTERN: {
|
||||||
|
if (symtab_find(&assembler->symtab, NULL, NULL,
|
||||||
|
directive->name) == M_SUCCESS) {
|
||||||
|
ERROR("cannot extern local symbol '%s'",
|
||||||
|
directive->name);
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (create_symbol(assembler, directive->name, SYMSEC_EXTERN, 0,
|
||||||
|
STB_GLOBAL))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MIPS_DIRECTIVE_GLOBL: {
|
||||||
|
Elf32_Sym *sym;
|
||||||
|
if (symtab_find(&assembler->symtab, &sym, NULL,
|
||||||
|
directive->name) == M_SUCCESS) {
|
||||||
|
sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (create_symbol(assembler, directive->name, SYMSEC_STUB, 0,
|
||||||
|
STB_GLOBAL))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_label(struct assembler *assembler,
|
||||||
|
const char name[MAX_LEX_LENGTH])
|
||||||
|
{
|
||||||
|
struct section *cur = assembler->sectab.current;
|
||||||
|
|
||||||
|
Elf32_Sym *ref;
|
||||||
|
size_t symidx;
|
||||||
|
|
||||||
|
if (symtab_find(&assembler->symtab, &ref, &symidx, name) == M_SUCCESS) {
|
||||||
|
ssize_t *sec = &assembler->symtab.sections[symidx];
|
||||||
|
|
||||||
|
// check if the symbol is acutally jus a stub, if so
|
||||||
|
// we need to update it
|
||||||
|
if (*sec == SYMSEC_STUB) {
|
||||||
|
*sec = cur->index;
|
||||||
|
ref->st_value = sec_size(cur);
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERROR("redefined symbol '%s'", name);
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (create_symbol(assembler, name, cur->index, sec_size(cur),
|
||||||
|
STB_LOCAL))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_ins(struct assembler *assembler,
|
||||||
|
struct ins_expr *expr)
|
||||||
|
{
|
||||||
|
struct section *sec = assembler->sectab.current;
|
||||||
|
size_t secidx = sec->len;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < expr->ins_len; i++) {
|
||||||
|
struct mips_instruction *ins =
|
||||||
|
&expr->ins[i];
|
||||||
|
struct reference *ref =
|
||||||
|
&expr->ref[i];
|
||||||
|
struct section_entry entry;
|
||||||
|
|
||||||
|
entry.type = ENT_INS;
|
||||||
|
entry.size = sizeof(struct mips_instruction);
|
||||||
|
entry.ins = *ins;
|
||||||
|
|
||||||
|
if (sec_push(sec, entry))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
unsigned char type = 0;
|
||||||
|
switch (ref->type) {
|
||||||
|
case REF_NONE:
|
||||||
|
continue;
|
||||||
|
case REF_OFFESET:
|
||||||
|
type = R_MIPS_PC16;
|
||||||
|
break;
|
||||||
|
case REF_TARGET:
|
||||||
|
type = R_MIPS_26;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t symidx;
|
||||||
|
if (find_symbol_or_stub(assembler, ref->name, NULL, &symidx))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
Elf32_Rela rel = {
|
||||||
|
.r_info = ELF32_R_INFO(symidx, type),
|
||||||
|
.r_addend = ref->addend,
|
||||||
|
.r_offset = sec_index(sec, secidx + i),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (reltab_push(&sec->reltab, rel))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_file(struct assembler *assembler)
|
||||||
|
{
|
||||||
|
struct parser *parser = &assembler->parser;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
struct expr expr;
|
||||||
|
int res = parser_next(parser, &expr);
|
||||||
|
|
||||||
|
if (res == M_ERROR)
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (res == M_EOF)
|
||||||
|
return M_SUCCESS;
|
||||||
|
|
||||||
|
switch (expr.type) {
|
||||||
|
case EXPR_INS:
|
||||||
|
if (handle_ins(assembler, &expr.ins))
|
||||||
|
return M_ERROR;
|
||||||
|
break;
|
||||||
|
case EXPR_DIRECTIVE:
|
||||||
|
if (handle_directive(assembler,
|
||||||
|
&expr.directive))
|
||||||
|
return M_ERROR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXPR_LABEL:
|
||||||
|
if (handle_label(assembler, expr.label))
|
||||||
|
return M_ERROR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXPR_CONSTANT:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int assemble_phdr(struct assembler *assembler, Elf32_Phdr **res,
|
||||||
|
uint32_t *res2)
|
||||||
|
{
|
||||||
|
Elf32_Phdr *phdr = malloc(sizeof(Elf32_Phdr) *
|
||||||
|
assembler->sectab.len);
|
||||||
|
if (phdr == NULL) {
|
||||||
|
ERROR("cannot alloc");
|
||||||
|
return M_ERROR;;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < assembler->sectab.len; i++) {
|
||||||
|
Elf32_Phdr *hdr = &phdr[i];
|
||||||
|
struct section *sec = &assembler->sectab.sections[i];
|
||||||
|
size_t size = sec_size(sec);
|
||||||
|
hdr->p_type = PT_LOAD;
|
||||||
|
hdr->p_flags = (sec->execute << 0) |
|
||||||
|
(sec->write << 1) |
|
||||||
|
(sec->read << 2);
|
||||||
|
hdr->p_offset = 0;
|
||||||
|
hdr->p_vaddr = 0;
|
||||||
|
hdr->p_paddr = 0;
|
||||||
|
hdr->p_filesz = size;
|
||||||
|
hdr->p_memsz = size;
|
||||||
|
hdr->p_align = sec->alignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
*res = phdr;
|
||||||
|
*res2 = assembler->sectab.len;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int assemble_shdr(struct assembler *assembler, Elf32_Shdr **res,
|
||||||
|
uint32_t *res2)
|
||||||
|
{
|
||||||
|
uint32_t max_entries = 4; // symtab, strtab, shstrtab
|
||||||
|
max_entries += assembler->sectab.len; // sections
|
||||||
|
max_entries += assembler->sectab.len; // reltabs per section
|
||||||
|
|
||||||
|
Elf32_Shdr *shdr = malloc(sizeof(Elf32_Shdr) * max_entries);
|
||||||
|
|
||||||
|
size_t str_off;
|
||||||
|
uint32_t count = 0;
|
||||||
|
|
||||||
|
// eeltables
|
||||||
|
for (uint32_t i = 0; i < assembler->sectab.len; i++) {
|
||||||
|
struct section *sec = &assembler->sectab.sections[i];
|
||||||
|
const char *prefix = ".reltab.";
|
||||||
|
char reltab_name[MAX_LEX_LENGTH + 8];
|
||||||
|
|
||||||
|
if (sec->reltab.len == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
strcpy(reltab_name, prefix);
|
||||||
|
strcat(reltab_name, sec->name);
|
||||||
|
|
||||||
|
if (strtab_write_str(&assembler->shstrtab,
|
||||||
|
reltab_name, &str_off)) {
|
||||||
|
free(shdr);
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
sec->reltab_shidx = count;
|
||||||
|
shdr[count++] = (Elf32_Shdr) {
|
||||||
|
.sh_name = str_off,
|
||||||
|
.sh_type = SHT_RELA,
|
||||||
|
.sh_flags = 0,
|
||||||
|
.sh_addr = 0,
|
||||||
|
.sh_offset = 0,
|
||||||
|
.sh_size = 0,
|
||||||
|
.sh_link = 0,
|
||||||
|
.sh_info = 0,
|
||||||
|
.sh_addralign = 1,
|
||||||
|
.sh_entsize = sizeof(Elf32_Rela),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// for each section
|
||||||
|
for (uint32_t i = 0; i < assembler->sectab.len; i++) {
|
||||||
|
struct section *sec = &assembler->sectab.sections[i];
|
||||||
|
char name[MAX_LEX_LENGTH+1] = ".";
|
||||||
|
|
||||||
|
strcat(name, sec->name);
|
||||||
|
if (strtab_write_str(&assembler->shstrtab, name, &str_off)) {
|
||||||
|
free(shdr);
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
sec->shdr_idx = count;
|
||||||
|
if (sec->reltab.len != 0)
|
||||||
|
shdr[sec->reltab_shidx].sh_info = count;
|
||||||
|
|
||||||
|
shdr[count++] = (Elf32_Shdr){
|
||||||
|
.sh_name = str_off,
|
||||||
|
.sh_type = SHT_PROGBITS,
|
||||||
|
.sh_flags = (sec->write << 0) | (sec->execute << 2) |
|
||||||
|
SHF_ALLOC,
|
||||||
|
.sh_addr = 0,
|
||||||
|
.sh_offset = 0,
|
||||||
|
.sh_size = 0,
|
||||||
|
.sh_link = 0,
|
||||||
|
.sh_info = 0,
|
||||||
|
.sh_addralign = sec->alignment,
|
||||||
|
.sh_entsize = sizeof(struct mips_instruction),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// symbol table
|
||||||
|
if (strtab_write_str(&assembler->shstrtab, ".symtab", &str_off)) {
|
||||||
|
free(shdr);
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
assembler->symtab_shidx = count;
|
||||||
|
shdr[count++] = (Elf32_Shdr) {
|
||||||
|
.sh_name = str_off,
|
||||||
|
.sh_type = SHT_SYMTAB,
|
||||||
|
.sh_flags = 0,
|
||||||
|
.sh_addr = 0,
|
||||||
|
.sh_offset = 0,
|
||||||
|
.sh_size = 0,
|
||||||
|
.sh_link = 1,
|
||||||
|
.sh_info = 0,
|
||||||
|
.sh_addralign = 1,
|
||||||
|
.sh_entsize = sizeof(Elf32_Sym),
|
||||||
|
};
|
||||||
|
|
||||||
|
// string table
|
||||||
|
if (strtab_write_str(&assembler->shstrtab, ".strtab", &str_off)) {
|
||||||
|
free(shdr);
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
assembler->strtab_shidx = count;
|
||||||
|
shdr[count++] = (Elf32_Shdr) {
|
||||||
|
.sh_name = str_off,
|
||||||
|
.sh_type = SHT_STRTAB,
|
||||||
|
.sh_flags = SHF_STRINGS,
|
||||||
|
.sh_addr = 0,
|
||||||
|
.sh_offset = 0,
|
||||||
|
.sh_size = 0,
|
||||||
|
.sh_link = 0,
|
||||||
|
.sh_info = 0,
|
||||||
|
.sh_addralign = 1,
|
||||||
|
.sh_entsize = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// sh string table
|
||||||
|
if (strtab_write_str(&assembler->shstrtab, ".shstrtab", &str_off)) {
|
||||||
|
free(shdr);
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
assembler->shstrtab_shidx = count;
|
||||||
|
shdr[count++] = (Elf32_Shdr) {
|
||||||
|
.sh_name = str_off,
|
||||||
|
.sh_type = SHT_STRTAB,
|
||||||
|
.sh_flags = SHF_STRINGS,
|
||||||
|
.sh_addr = 0,
|
||||||
|
.sh_offset = 0,
|
||||||
|
.sh_size = 0,
|
||||||
|
.sh_link = 0,
|
||||||
|
.sh_info = 0,
|
||||||
|
.sh_addralign = 1,
|
||||||
|
.sh_entsize = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < assembler->sectab.len; i++) {
|
||||||
|
struct section *sec = &assembler->sectab.sections[i];
|
||||||
|
if (sec->reltab.len == 0)
|
||||||
|
continue;
|
||||||
|
shdr[sec->reltab_shidx].sh_link =
|
||||||
|
assembler->symtab_shidx;
|
||||||
|
}
|
||||||
|
|
||||||
|
*res = shdr;
|
||||||
|
*res2 = count;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_offsets(struct assembler *assembler, Elf32_Ehdr *ehdr)
|
||||||
|
{
|
||||||
|
Elf32_Shdr *shdr = (Elf32_Shdr *) assembler->shdr;
|
||||||
|
Elf32_Phdr *phdr = (Elf32_Phdr *) assembler->phdr;
|
||||||
|
uint32_t ptr = 0;
|
||||||
|
|
||||||
|
// we must now correct offets and sizes inside the ehdr, phdr,
|
||||||
|
// and shdr
|
||||||
|
ptr += sizeof(Elf32_Ehdr);
|
||||||
|
|
||||||
|
// phdr
|
||||||
|
ehdr->e_phoff = ptr;
|
||||||
|
ptr += assembler->phdr_len * sizeof(Elf32_Phdr);
|
||||||
|
|
||||||
|
// reltbls
|
||||||
|
for (uint32_t i = 0; i < assembler->sectab.len; i++) {
|
||||||
|
struct section *sec = &assembler->sectab.sections[i];
|
||||||
|
if (sec->reltab.len == 0)
|
||||||
|
continue;
|
||||||
|
int idx = sec->reltab_shidx;
|
||||||
|
int len = sec->reltab.len;
|
||||||
|
shdr[idx].sh_offset = ptr;
|
||||||
|
shdr[idx].sh_size = len * sizeof(Elf32_Rela);
|
||||||
|
ptr += len * sizeof(Elf32_Rela);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sections
|
||||||
|
for (uint32_t i = 0; i < assembler->sectab.len; i++) {
|
||||||
|
struct section *sec = &assembler->sectab.sections[i];
|
||||||
|
int idx = sec->shdr_idx;
|
||||||
|
phdr[i].p_offset = ptr;
|
||||||
|
phdr[i].p_vaddr = ptr;
|
||||||
|
phdr[i].p_paddr = ptr;
|
||||||
|
shdr[idx].sh_offset = ptr;
|
||||||
|
shdr[idx].sh_size = phdr[i].p_filesz;
|
||||||
|
shdr[idx].sh_addr = phdr[i].p_vaddr;
|
||||||
|
shdr[idx].sh_addralign = phdr[i].p_align;
|
||||||
|
ptr += phdr[i].p_filesz;
|
||||||
|
}
|
||||||
|
|
||||||
|
// symtab
|
||||||
|
shdr[assembler->symtab_shidx].sh_offset = ptr;
|
||||||
|
shdr[assembler->symtab_shidx].sh_link = assembler->strtab_shidx;
|
||||||
|
shdr[assembler->symtab_shidx].sh_size =
|
||||||
|
assembler->symtab.len * sizeof(Elf32_Sym);
|
||||||
|
ptr += assembler->symtab.len * sizeof(Elf32_Sym);
|
||||||
|
|
||||||
|
// strtab
|
||||||
|
shdr[assembler->strtab_shidx].sh_offset = ptr;
|
||||||
|
shdr[assembler->strtab_shidx].sh_size = assembler->strtab.size;
|
||||||
|
ptr += assembler->strtab.size;
|
||||||
|
|
||||||
|
// shstrtab
|
||||||
|
shdr[assembler->shstrtab_shidx].sh_offset = ptr;
|
||||||
|
shdr[assembler->shstrtab_shidx].sh_size = assembler->shstrtab.size;
|
||||||
|
ptr += assembler->shstrtab.size;
|
||||||
|
|
||||||
|
// shdr
|
||||||
|
ehdr->e_shoff = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_sym_shindx(struct assembler *assembler)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < assembler->symtab.len; i++)
|
||||||
|
{
|
||||||
|
Elf32_Sym *sym = &assembler->symtab.symbols[i];
|
||||||
|
ssize_t sec = assembler->symtab.sections[i];
|
||||||
|
|
||||||
|
if (sec >= 0) {
|
||||||
|
sym->st_shndx = assembler->
|
||||||
|
sectab.sections[sec].shdr_idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_file(struct assembler *assembler, Elf32_Ehdr *ehdr,
|
||||||
|
const char *path)
|
||||||
|
{
|
||||||
|
FILE *out = fopen(path, "w");
|
||||||
|
|
||||||
|
if (out == NULL) {
|
||||||
|
ERROR("cannot write '%s'", path);
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ehdr
|
||||||
|
fwrite(ehdr, sizeof(Elf32_Ehdr), 1, out);
|
||||||
|
|
||||||
|
// phdr
|
||||||
|
fwrite(assembler->phdr, sizeof(Elf32_Phdr), assembler->phdr_len, out);
|
||||||
|
|
||||||
|
// reltbls
|
||||||
|
for (uint32_t i = 0; i < assembler->sectab.len; i++) {
|
||||||
|
struct section *sec = &assembler->sectab.sections[i];
|
||||||
|
if (sec->reltab.len == 0)
|
||||||
|
continue;
|
||||||
|
void *ptr = sec->reltab.data;
|
||||||
|
int len = sec->reltab.len;
|
||||||
|
fwrite(ptr, sizeof(Elf32_Rela), len, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sections
|
||||||
|
for (uint32_t i = 0; i < assembler->sectab.len; i++) {
|
||||||
|
struct section *sec = &assembler->sectab.sections[i];
|
||||||
|
for (uint32_t j = 0; j < sec->len; j++) {
|
||||||
|
struct section_entry *entry = &sec->entries[j];
|
||||||
|
size_t size = entry->size;
|
||||||
|
fwrite(&entry->data, size, 1, out);
|
||||||
|
while(size % sec->alignment) {
|
||||||
|
uint8_t zero = 0;
|
||||||
|
fwrite(&zero, 1, 1, out);
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sym tbl
|
||||||
|
fwrite(assembler->symtab.symbols, sizeof(Elf32_Sym),
|
||||||
|
assembler->symtab.len, out);
|
||||||
|
|
||||||
|
// str tbl
|
||||||
|
fwrite(assembler->strtab.ptr, assembler->strtab.size, 1, out);
|
||||||
|
|
||||||
|
// shstr tbl
|
||||||
|
fwrite(assembler->shstrtab.ptr, assembler->shstrtab.size, 1, out);
|
||||||
|
|
||||||
|
// shdr
|
||||||
|
fwrite(assembler->shdr, sizeof(Elf32_Shdr), assembler->shdr_len, out);
|
||||||
|
|
||||||
|
fclose(out);
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int assemble_elf(struct assembler *assembler, const char *out)
|
||||||
|
{
|
||||||
|
if (assemble_phdr(assembler, (Elf32_Phdr **) &assembler->phdr,
|
||||||
|
&assembler->phdr_len)) {
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assemble_shdr(assembler, (Elf32_Shdr **) &assembler->shdr,
|
||||||
|
&assembler->shdr_len)) {
|
||||||
|
return M_ERROR;
|
||||||
|
};
|
||||||
|
|
||||||
|
Elf32_Ehdr ehdr = {
|
||||||
|
.e_ident = {
|
||||||
|
[EI_MAG0] = ELFMAG0,
|
||||||
|
[EI_MAG1] = ELFMAG1,
|
||||||
|
[EI_MAG2] = ELFMAG2,
|
||||||
|
[EI_MAG3] = ELFMAG3,
|
||||||
|
[EI_CLASS] = ELFCLASS32,
|
||||||
|
[EI_DATA] = ELFDATA2LSB,
|
||||||
|
[EI_VERSION] = EV_CURRENT,
|
||||||
|
[EI_OSABI] = ELFOSABI_NONE,
|
||||||
|
[EI_ABIVERSION] = 0x00,
|
||||||
|
[EI_PAD] = 0x00,
|
||||||
|
},
|
||||||
|
.e_type = ET_REL,
|
||||||
|
.e_machine = EM_MIPS,
|
||||||
|
.e_version = EV_CURRENT,
|
||||||
|
.e_entry = 0x00,
|
||||||
|
.e_phoff = 0x00,
|
||||||
|
.e_shoff = 0x00,
|
||||||
|
.e_flags = EF_MIPS_ARCH_32R6,
|
||||||
|
.e_ehsize = sizeof(Elf32_Ehdr),
|
||||||
|
.e_phentsize = sizeof(Elf32_Phdr),
|
||||||
|
.e_phnum = assembler->phdr_len,
|
||||||
|
.e_shentsize = sizeof(Elf32_Shdr),
|
||||||
|
.e_shnum = assembler->shdr_len,
|
||||||
|
.e_shstrndx = assembler->shstrtab_shidx,
|
||||||
|
};
|
||||||
|
|
||||||
|
update_offsets(assembler, &ehdr);
|
||||||
|
update_sym_shindx(assembler);
|
||||||
|
|
||||||
|
if (write_file(assembler, &ehdr, out))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int assemble_file(struct assembler_arguments args)
|
||||||
|
{
|
||||||
|
struct assembler assembler;
|
||||||
|
int res = M_SUCCESS;
|
||||||
|
|
||||||
|
current_file = args.in_file;
|
||||||
|
|
||||||
|
if (assembler_init(&assembler, args.in_file))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (res == M_SUCCESS)
|
||||||
|
res = parse_file(&assembler);
|
||||||
|
|
||||||
|
if (res == M_SUCCESS)
|
||||||
|
res = assemble_elf(&assembler, args.out_file);
|
||||||
|
|
||||||
|
assembler_free(&assembler);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
int assembler_init(struct assembler *assembler, const char *path)
|
int assembler_init(struct assembler *assembler, const char *path)
|
||||||
{
|
{
|
||||||
if (lexer_init(path, &assembler->lexer))
|
if (lexer_init(path, &assembler->lexer))
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
|
|
||||||
if (parser_init(&assembler->lexer, &assembler->parser)) {
|
if (parser_init(&assembler->lexer, &assembler->parser))
|
||||||
lexer_free(&assembler->lexer);
|
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
if (strtbl_init(&assembler->shstr_tbl)) {
|
if (strtab_init(&assembler->shstrtab))
|
||||||
parser_free(&assembler->parser);
|
|
||||||
lexer_free(&assembler->lexer);
|
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
if (strtbl_init(&assembler->str_tbl)) {
|
if (strtab_init(&assembler->strtab))
|
||||||
strtbl_free(&assembler->shstr_tbl);
|
|
||||||
parser_free(&assembler->parser);
|
|
||||||
lexer_free(&assembler->lexer);
|
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
if (symtbl_init(&assembler->sym_tbl)) {
|
if (symtab_init(&assembler->symtab))
|
||||||
strtbl_free(&assembler->str_tbl);
|
|
||||||
strtbl_free(&assembler->shstr_tbl);
|
|
||||||
parser_free(&assembler->parser);
|
|
||||||
lexer_free(&assembler->lexer);
|
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
assembler->meta = NULL;
|
if (sectab_init(&assembler->sectab))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
assembler->symtab.strtab = &assembler->strtab;
|
||||||
assembler->phdr = NULL;
|
assembler->phdr = NULL;
|
||||||
assembler->shdr = NULL;
|
assembler->shdr = NULL;
|
||||||
assembler->symtab = NULL;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
return M_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void assembler_free(struct assembler *assembler)
|
void assembler_free(struct assembler *assembler)
|
||||||
{
|
{
|
||||||
if (assembler->meta) {
|
|
||||||
for (uint32_t i = 0; i < assembler->parser.sec_tbl.count; i++) {
|
|
||||||
if (assembler->meta[i].reltbl != NULL) {
|
|
||||||
free(assembler->meta[i].reltbl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(assembler->meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (assembler->phdr)
|
if (assembler->phdr)
|
||||||
free(assembler->phdr);
|
free(assembler->phdr);
|
||||||
if (assembler->shdr)
|
if (assembler->shdr)
|
||||||
free(assembler->shdr);
|
free(assembler->shdr);
|
||||||
if (assembler->symtab)
|
|
||||||
free(assembler->symtab);
|
|
||||||
|
|
||||||
symtbl_free(&assembler->sym_tbl);
|
sectab_free(&assembler->sectab);
|
||||||
strtbl_free(&assembler->str_tbl);
|
symtab_free(&assembler->symtab);
|
||||||
strtbl_free(&assembler->shstr_tbl);
|
strtab_free(&assembler->strtab);
|
||||||
|
strtab_free(&assembler->shstrtab);
|
||||||
|
|
||||||
parser_free(&assembler->parser);
|
parser_free(&assembler->parser);
|
||||||
lexer_free(&assembler->lexer);
|
lexer_free(&assembler->lexer);
|
||||||
}
|
}
|
||||||
|
|
||||||
int assemble_file(struct assembler_arguments args) {
|
|
||||||
switch (args.isa) {
|
|
||||||
case ISA_MIPS32:
|
|
||||||
return assemble_file_mips32(args);
|
|
||||||
}
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
248
masm/asm.h
248
masm/asm.h
|
@ -4,101 +4,235 @@
|
||||||
#define __ASM_H__
|
#define __ASM_H__
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <elf.h>
|
||||||
|
#include <mips.h>
|
||||||
|
|
||||||
#include "lex.h"
|
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
|
#include "lex.h"
|
||||||
|
|
||||||
enum symbol_flag {
|
///
|
||||||
SYM_LOCAL,
|
/// ELF string table
|
||||||
SYM_GLOBAL,
|
///
|
||||||
SYM_EXTERNAL,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct symbol {
|
|
||||||
char name[MAX_LEX_LENGTH];
|
|
||||||
uint32_t index;
|
|
||||||
struct section *sec;
|
|
||||||
enum symbol_flag flag;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct symbol_table {
|
|
||||||
uint32_t count;
|
|
||||||
uint32_t len;
|
|
||||||
struct symbol *symbols;
|
|
||||||
};
|
|
||||||
|
|
||||||
int symtbl_init(struct symbol_table *sym_tbl);
|
|
||||||
void symtbl_free(struct symbol_table *sym_tbl);
|
|
||||||
|
|
||||||
int symtbl_push(struct symbol_table *sym_tbl, struct symbol sym);
|
|
||||||
int symtbl_find(struct symbol_table *sym_tbl, struct symbol **sym,
|
|
||||||
const char name[MAX_LEX_LENGTH]);
|
|
||||||
|
|
||||||
|
|
||||||
struct str_table {
|
struct str_table {
|
||||||
char *ptr;
|
// size of the ptr in bytes
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
|
// pointer that contains
|
||||||
|
// the strings
|
||||||
|
char *ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* initalize a string table */
|
/* initalize a string table */
|
||||||
int strtbl_init(struct str_table *str_tbl);
|
int strtab_init(struct str_table *strtab);
|
||||||
|
|
||||||
/* free a string table */
|
/* free a string table */
|
||||||
void strtbl_free(struct str_table *str_tbl);
|
void strtab_free(struct str_table *strtab);
|
||||||
|
|
||||||
/* get a string form the string table */
|
/* get a string form the string table */
|
||||||
int strtbl_get_str(struct str_table *str_tbl, const char *str, size_t *res);
|
int strtab_get_str(struct str_table *strtab, const char *str, size_t *res);
|
||||||
|
|
||||||
/* get or append a string into the string table */
|
/* get or append a string into the string table */
|
||||||
int strtbl_write_str(struct str_table *str_tbl, const char *str, size_t *res);
|
int strtab_write_str(struct str_table *strtab, const char *str, size_t *res);
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// ELF symbol table
|
||||||
|
///
|
||||||
|
|
||||||
|
struct symbol_table {
|
||||||
|
// length in size in sym ammt
|
||||||
|
size_t len;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
// the Elf symbols
|
||||||
|
Elf32_Sym *symbols;
|
||||||
|
|
||||||
|
// keeps track of what section each ELF symbol is in
|
||||||
|
// *!!this is NOT the section header index in the ELF ehdr!!*
|
||||||
|
ssize_t *sections;
|
||||||
|
|
||||||
|
// symbols reference a string table that acutally
|
||||||
|
// holds the strings
|
||||||
|
//
|
||||||
|
// *weak* ptr, we do not own this!!!
|
||||||
|
struct str_table *strtab;
|
||||||
|
|
||||||
struct section_meta {
|
|
||||||
void *reltbl;
|
|
||||||
uint32_t reltbl_len;
|
|
||||||
uint32_t reltbl_idx; // reltbl idx in shdr
|
|
||||||
uint32_t shdr_idx; // sec idx in shdr
|
|
||||||
uint32_t v_addr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* initalize a symbol table */
|
||||||
|
int symtab_init(struct symbol_table *symtab);
|
||||||
|
|
||||||
|
/* free the symbol table */
|
||||||
|
void symtab_free(struct symbol_table *symtab);
|
||||||
|
|
||||||
|
/* add a symbol to the symbol tbl */
|
||||||
|
int symtab_push(struct symbol_table *symtab, const Elf32_Sym sym,
|
||||||
|
ssize_t sec_idx);
|
||||||
|
|
||||||
|
/* find a symbol by name in the symbol table */
|
||||||
|
int symtab_find(struct symbol_table *symtab, Elf32_Sym **sym, size_t *idx,
|
||||||
|
const char name[MAX_LEX_LENGTH]);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// ELF relocation table
|
||||||
|
///
|
||||||
|
|
||||||
|
struct relocation_table {
|
||||||
|
size_t len;
|
||||||
|
size_t size;
|
||||||
|
Elf32_Rela *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* initalize a relocation table */
|
||||||
|
int reltab_init(struct relocation_table *reltab);
|
||||||
|
|
||||||
|
/* free the relocation table */
|
||||||
|
void reltab_free(struct relocation_table *reltab);
|
||||||
|
|
||||||
|
/* add a entry to the relocation table */
|
||||||
|
int reltab_push(struct relocation_table *reltab, const Elf32_Rela rel);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// section entry
|
||||||
|
///
|
||||||
|
|
||||||
|
enum section_entry_type {
|
||||||
|
ENT_INS,
|
||||||
|
ENT_WORD,
|
||||||
|
ENT_HALF,
|
||||||
|
ENT_BYTE,
|
||||||
|
ENT_NO_DATA,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* holds a entry inside the section, i.e. a instruction, raw data,
|
||||||
|
* special directives */
|
||||||
|
struct section_entry {
|
||||||
|
size_t size;
|
||||||
|
enum section_entry_type type;
|
||||||
|
|
||||||
|
union {
|
||||||
|
// to get memory address
|
||||||
|
char data;
|
||||||
|
|
||||||
|
// data
|
||||||
|
struct mips_instruction ins;
|
||||||
|
int32_t word;
|
||||||
|
int16_t half;
|
||||||
|
int8_t byte;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// section
|
||||||
|
///
|
||||||
|
|
||||||
|
/* holds a section of the asm file (i.e. .text, .bss, .data) */
|
||||||
|
struct section {
|
||||||
|
// length and size of amount of entries
|
||||||
|
size_t len;
|
||||||
|
size_t size;
|
||||||
|
struct section_entry *entries;
|
||||||
|
|
||||||
|
// section name
|
||||||
|
char name[MAX_LEX_LENGTH];
|
||||||
|
|
||||||
|
// index of the section in
|
||||||
|
// all the sections
|
||||||
|
size_t index;
|
||||||
|
|
||||||
|
// index of the sectio in
|
||||||
|
// the ELF shdr
|
||||||
|
size_t shdr_idx;
|
||||||
|
|
||||||
|
// ELF section data
|
||||||
|
bool read;
|
||||||
|
bool write;
|
||||||
|
bool execute;
|
||||||
|
uint16_t alignment;
|
||||||
|
|
||||||
|
// ELF tables
|
||||||
|
size_t reltab_shidx;
|
||||||
|
struct relocation_table reltab;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* get the size of the section in bytes */
|
||||||
|
size_t sec_size(struct section *section);
|
||||||
|
|
||||||
|
/* get the index of a entry in bytes */
|
||||||
|
size_t sec_index(struct section *section, size_t index);
|
||||||
|
|
||||||
|
/* add a section entry to the section */
|
||||||
|
int sec_push(struct section *section, struct section_entry entry);
|
||||||
|
|
||||||
|
/* holds eachs section */
|
||||||
|
struct section_table {
|
||||||
|
// length and size of amount of sections
|
||||||
|
size_t len;
|
||||||
|
size_t size;
|
||||||
|
struct section *sections;
|
||||||
|
|
||||||
|
// the current section
|
||||||
|
struct section *current;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* initalize the section table */
|
||||||
|
int sectab_init(struct section_table *sec_tbl);
|
||||||
|
|
||||||
|
/* free the section table */
|
||||||
|
void sectab_free(struct section_table *sec_tbl);
|
||||||
|
|
||||||
|
/* create a new section in the section table */
|
||||||
|
int sectab_alloc(struct section_table *sec_tbl, struct section **sec,
|
||||||
|
const char name[MAX_LEX_LENGTH]);
|
||||||
|
|
||||||
|
/* get a section by name from the section table */
|
||||||
|
int sectab_get(struct section_table *sec_tbl, struct section **sec,
|
||||||
|
const char name[MAX_LEX_LENGTH]);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// assembler
|
||||||
|
///
|
||||||
|
|
||||||
struct assembler {
|
struct assembler {
|
||||||
// the token lexer
|
// the token lexer
|
||||||
struct lexer lexer;
|
struct lexer lexer;
|
||||||
// the expression parser
|
// the expression parser
|
||||||
struct parser parser;
|
struct parser parser;
|
||||||
|
|
||||||
// shdr indexes
|
/// ELF tables
|
||||||
struct section_meta *meta;
|
size_t symtab_shidx;
|
||||||
size_t shstrtbl_idx;
|
struct symbol_table symtab;
|
||||||
size_t strtbl_idx;
|
size_t strtab_shidx;
|
||||||
size_t symtab_idx;
|
struct str_table strtab;
|
||||||
|
size_t shstrtab_shidx;
|
||||||
|
struct str_table shstrtab;
|
||||||
|
|
||||||
// symbols and strings
|
/// Segments
|
||||||
struct symbol_table sym_tbl;
|
struct section_table sectab;
|
||||||
struct str_table shstr_tbl;
|
|
||||||
struct str_table str_tbl;
|
|
||||||
|
|
||||||
// elf data
|
/// program header
|
||||||
void *phdr; // void* since could be Elf32 or Elf64
|
Elf32_Phdr *phdr;
|
||||||
void *shdr;
|
|
||||||
void *symtab;
|
|
||||||
uint32_t phdr_len;
|
uint32_t phdr_len;
|
||||||
|
|
||||||
|
/// section header
|
||||||
|
Elf32_Shdr *shdr;
|
||||||
uint32_t shdr_len;
|
uint32_t shdr_len;
|
||||||
uint32_t symtab_len;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* defines arguments to the assembler */
|
||||||
struct assembler_arguments {
|
struct assembler_arguments {
|
||||||
char *in_file;
|
char *in_file;
|
||||||
char *out_file;
|
char *out_file;
|
||||||
enum mips_isa isa;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* initalize the assembler */
|
||||||
int assembler_init(struct assembler *assembler, const char *path);
|
int assembler_init(struct assembler *assembler, const char *path);
|
||||||
|
|
||||||
|
/* free the assembler */
|
||||||
void assembler_free(struct assembler *assembler);
|
void assembler_free(struct assembler *assembler);
|
||||||
|
|
||||||
|
/* assemble a file */
|
||||||
int assemble_file(struct assembler_arguments args);
|
int assemble_file(struct assembler_arguments args);
|
||||||
|
|
||||||
/* assemble a mips32 file*/
|
|
||||||
int assemble_file_mips32(struct assembler_arguments args);
|
|
||||||
|
|
||||||
#endif /* __ASM_H__ */
|
#endif /* __ASM_H__ */
|
||||||
|
|
|
@ -1,746 +0,0 @@
|
||||||
#include <merror.h>
|
|
||||||
#include <mips.h>
|
|
||||||
#include <mips32.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <elf.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#include "asm.h"
|
|
||||||
#include "mlimits.h"
|
|
||||||
#include "parse.h"
|
|
||||||
#include "parse_mips32.h"
|
|
||||||
|
|
||||||
extern char *current_file;
|
|
||||||
|
|
||||||
static int handle_directive(struct assembler *assembler,
|
|
||||||
struct mips32_directive *directive)
|
|
||||||
{
|
|
||||||
switch (directive->type) {
|
|
||||||
case MIPS32_DIRECTIVE_SECTION: {
|
|
||||||
struct section_table *sec_tbl = &assembler->parser.sec_tbl;
|
|
||||||
struct section *sec;
|
|
||||||
if (sectbl_get(sec_tbl, &sec, directive->name)
|
|
||||||
== M_SUCCESS) {
|
|
||||||
sec_tbl->current = sec;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sectbl_alloc(sec_tbl, &sec, directive->name))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
sec_tbl->current = sec;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MIPS32_DIRECTIVE_ALIGN: {
|
|
||||||
assembler->parser.sec_tbl.current->alignment =
|
|
||||||
1 << directive->align;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MIPS32_DIRECTIVE_SPACE: {
|
|
||||||
struct section_entry entry;
|
|
||||||
entry.type = ENT_NO_DATA;
|
|
||||||
entry.size = directive->space;
|
|
||||||
if (sec_push(assembler->parser.sec_tbl.current, entry))
|
|
||||||
return M_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MIPS32_DIRECTIVE_WORD: {
|
|
||||||
for (uint32_t i = 0; i < directive->len; i++) {
|
|
||||||
struct section_entry entry;
|
|
||||||
entry.type = ENT_WORD;
|
|
||||||
entry.word = directive->words[i];
|
|
||||||
if (sec_push(assembler->parser.sec_tbl.current,
|
|
||||||
entry))
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MIPS32_DIRECTIVE_HALF: {
|
|
||||||
for (uint32_t i = 0; i < directive->len; i++) {
|
|
||||||
struct section_entry entry;
|
|
||||||
entry.type = ENT_HALF;
|
|
||||||
entry.half = directive->halfs[i];
|
|
||||||
if (sec_push(assembler->parser.sec_tbl.current,
|
|
||||||
entry))
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MIPS32_DIRECTIVE_BYTE: {
|
|
||||||
for (uint32_t i = 0; i < directive->len; i++) {
|
|
||||||
struct section_entry entry;
|
|
||||||
entry.type = ENT_BYTE;
|
|
||||||
entry.byte = directive->bytes[i];
|
|
||||||
if (sec_push(assembler->parser.sec_tbl.current,
|
|
||||||
entry))
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MIPS32_DIRECTIVE_EXTERN: {
|
|
||||||
struct symbol symbol;
|
|
||||||
if (symtbl_find(&assembler->sym_tbl, NULL, directive->name)
|
|
||||||
== M_SUCCESS) {
|
|
||||||
ERROR("cannot extern local symbol '%s'",
|
|
||||||
directive->name);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
symbol = (struct symbol) {
|
|
||||||
.name = "",
|
|
||||||
.sec = NULL,
|
|
||||||
.index = 0,
|
|
||||||
.flag = SYM_EXTERNAL,
|
|
||||||
};
|
|
||||||
strcpy(symbol.name, directive->name);
|
|
||||||
|
|
||||||
if (symtbl_push(&assembler->sym_tbl, symbol))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MIPS32_DIRECTIVE_GLOBL: {
|
|
||||||
struct symbol symbol;
|
|
||||||
if (symtbl_find(&assembler->sym_tbl, NULL, directive->name)
|
|
||||||
== M_SUCCESS) {
|
|
||||||
symbol.flag = SYM_GLOBAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
symbol = (struct symbol) {
|
|
||||||
.name = "",
|
|
||||||
.sec = NULL,
|
|
||||||
.index = 0,
|
|
||||||
.flag = SYM_GLOBAL,
|
|
||||||
};
|
|
||||||
strcpy(symbol.name, directive->name);
|
|
||||||
|
|
||||||
if (symtbl_push(&assembler->sym_tbl, symbol))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int handle_label(struct assembler *assembler,
|
|
||||||
const char name[MAX_LEX_LENGTH])
|
|
||||||
{
|
|
||||||
struct symbol *ref;
|
|
||||||
if (symtbl_find(&assembler->sym_tbl, &ref, name) == M_SUCCESS) {
|
|
||||||
if (ref->flag == SYM_GLOBAL && ref->sec == NULL) {
|
|
||||||
ref->sec = assembler->parser.sec_tbl.current;
|
|
||||||
ref->index = assembler->parser.sec_tbl.current->count;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
ERROR("redefined symbol '%s'", name);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct symbol symbol;
|
|
||||||
symbol = (struct symbol) {
|
|
||||||
.name = "",
|
|
||||||
.sec = assembler->parser.sec_tbl.current,
|
|
||||||
.index = assembler->parser.sec_tbl.current->count,
|
|
||||||
.flag = SYM_LOCAL,
|
|
||||||
};
|
|
||||||
strcpy(symbol.name, name);
|
|
||||||
|
|
||||||
if (symtbl_push(&assembler->sym_tbl, symbol))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_file(struct assembler *assembler)
|
|
||||||
{
|
|
||||||
struct parser *parser = &assembler->parser;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
struct expr expr;
|
|
||||||
if (parser_next(parser, &expr))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
switch (expr.type) {
|
|
||||||
case EXPR_INS:
|
|
||||||
struct section_entry entry;
|
|
||||||
entry.type = ENT_INS;
|
|
||||||
entry.size = sizeof(struct mips32_instruction);
|
|
||||||
entry.ins = expr.ins;
|
|
||||||
if (sec_push(parser->sec_tbl.current, entry))
|
|
||||||
return M_ERROR;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EXPR_DIRECTIVE:
|
|
||||||
if (handle_directive(assembler,
|
|
||||||
&expr.directive.mips32))
|
|
||||||
return M_ERROR;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EXPR_LABEL:
|
|
||||||
if (handle_label(assembler, expr.text))
|
|
||||||
return M_ERROR;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EXPR_CONSTANT:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct section_meta *meta = malloc(sizeof(struct section_meta) *
|
|
||||||
parser->sec_tbl.count);
|
|
||||||
if (meta == NULL) {
|
|
||||||
ERROR("cannot alloc");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
assembler->meta = meta;
|
|
||||||
|
|
||||||
size_t ptr = 0;
|
|
||||||
for (uint32_t i = 0; i < parser->sec_tbl.count; i++) {
|
|
||||||
struct section *sec = &parser->sec_tbl.sections[i];
|
|
||||||
meta[i].v_addr = ptr;
|
|
||||||
ptr += sec_size(sec);
|
|
||||||
}
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int assemble_phdr(struct assembler *assembler, Elf32_Phdr **res,
|
|
||||||
uint32_t *res2)
|
|
||||||
{
|
|
||||||
struct parser *parser = &assembler->parser;
|
|
||||||
Elf32_Phdr *phdr = malloc(sizeof(Elf32_Phdr) *
|
|
||||||
parser->sec_tbl.count);
|
|
||||||
if (phdr == NULL) {
|
|
||||||
ERROR("cannot alloc");
|
|
||||||
return M_ERROR;;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < parser->sec_tbl.count; i++) {
|
|
||||||
Elf32_Phdr *hdr = &phdr[i];
|
|
||||||
struct section *sec = &parser->sec_tbl.sections[i];
|
|
||||||
size_t size = sec_size(sec);
|
|
||||||
hdr->p_type = PT_LOAD;
|
|
||||||
hdr->p_flags = (sec->execute << 0) |
|
|
||||||
(sec->write << 1) |
|
|
||||||
(sec->read << 2);
|
|
||||||
hdr->p_offset = 0;
|
|
||||||
hdr->p_vaddr = 0;
|
|
||||||
hdr->p_paddr = 0;
|
|
||||||
hdr->p_filesz = size;
|
|
||||||
hdr->p_memsz = size;
|
|
||||||
hdr->p_align = sec->alignment;
|
|
||||||
}
|
|
||||||
|
|
||||||
*res = phdr;
|
|
||||||
*res2 = parser->sec_tbl.count;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int assemble_symtab(struct assembler *assembler, Elf32_Sym **res,
|
|
||||||
uint32_t *res2)
|
|
||||||
{
|
|
||||||
Elf32_Sym *stbl = malloc(sizeof(Elf32_Sym) * assembler->sym_tbl
|
|
||||||
.count);
|
|
||||||
size_t size = 0;
|
|
||||||
|
|
||||||
if (stbl == NULL)
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < assembler->sym_tbl.count; i++) {
|
|
||||||
struct symbol *sym = &assembler->sym_tbl.symbols[i];
|
|
||||||
size_t str_off;
|
|
||||||
unsigned char bind;
|
|
||||||
unsigned char type = STT_NOTYPE;
|
|
||||||
|
|
||||||
if (strtbl_write_str(&assembler->str_tbl,
|
|
||||||
sym->name, &str_off)) {
|
|
||||||
free(stbl);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sym->flag == SYM_GLOBAL && sym->sec == NULL) {
|
|
||||||
ERROR("never defined global symbol '%s'", sym->name);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sym->flag == SYM_LOCAL)
|
|
||||||
bind = STB_LOCAL;
|
|
||||||
else
|
|
||||||
bind = STB_GLOBAL;
|
|
||||||
|
|
||||||
stbl[i] = (Elf32_Sym) {
|
|
||||||
.st_name = str_off,
|
|
||||||
.st_value = sym->index,
|
|
||||||
.st_size = 0,
|
|
||||||
.st_info = ELF32_ST_INFO(bind, type),
|
|
||||||
.st_other = ELF32_ST_VISIBILITY(STV_DEFAULT),
|
|
||||||
.st_shndx = 0,
|
|
||||||
};
|
|
||||||
size = i + 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
*res = stbl;
|
|
||||||
*res2 = size;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void assemble_symtab_shndx(struct assembler *assembler, Elf32_Sym *tbl)
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < assembler->sym_tbl.count; i++) {
|
|
||||||
struct symbol *sym = &assembler->sym_tbl.symbols[i];
|
|
||||||
if (sym->sec != NULL)
|
|
||||||
tbl[i].st_shndx =
|
|
||||||
assembler->meta[sym->sec->index].shdr_idx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int assemble_reltbl_sec(struct assembler *assembler, Elf32_Sym *symtab,
|
|
||||||
uint32_t symtab_len, struct section *sec)
|
|
||||||
{
|
|
||||||
uint32_t len = 0;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < assembler->parser.ref_tbl.count; i++) {
|
|
||||||
struct reference *ref =
|
|
||||||
&assembler->parser.ref_tbl.references[i];
|
|
||||||
if (ref->section->index == sec->index) {
|
|
||||||
len++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len == 0) {
|
|
||||||
assembler->meta[sec->index].reltbl = NULL;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
Elf32_Rela *reltbl = malloc(sizeof(Elf32_Rela) * len);
|
|
||||||
|
|
||||||
if (reltbl == NULL) {
|
|
||||||
ERROR("cannot alloc");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < assembler->parser.ref_tbl.count; i++) {
|
|
||||||
struct reference *ref =
|
|
||||||
&assembler->parser.ref_tbl.references[i];
|
|
||||||
struct mips32_instruction *ins = &ref->section->
|
|
||||||
entries[ref->index].ins.mips32;
|
|
||||||
|
|
||||||
if (ref->section->index != sec->index) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t addend = 0;
|
|
||||||
unsigned char type = 0;
|
|
||||||
switch (ref->type) {
|
|
||||||
case REF_OFFESET:
|
|
||||||
addend = ins->B_data.offset;
|
|
||||||
type = R_MIPS_PC16;
|
|
||||||
break;
|
|
||||||
case REF_TARGET:
|
|
||||||
addend = ins->J_data.target;
|
|
||||||
type = R_MIPS_26;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t symidx = -1;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < symtab_len; i++) {
|
|
||||||
Elf32_Sym *sym = &symtab[i];
|
|
||||||
const char *str =
|
|
||||||
&assembler->str_tbl.ptr[sym->st_name];
|
|
||||||
if (strcmp(ref->name, str) == 0) {
|
|
||||||
symidx = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (symidx == -1) {
|
|
||||||
ERROR("undefined symbol '%s'", ref->name);
|
|
||||||
free(reltbl);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
reltbl[i] = (Elf32_Rela) {
|
|
||||||
.r_info = ELF32_R_INFO(symidx, type),
|
|
||||||
.r_addend = addend,
|
|
||||||
.r_offset = sec_index(ref->section, ref->index),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
assembler->meta[sec->index].reltbl_len = len;
|
|
||||||
assembler->meta[sec->index].reltbl = reltbl;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int assemble_reltbl(struct assembler *assembler, Elf32_Sym *symtab,
|
|
||||||
uint32_t symtab_len)
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < assembler->parser.sec_tbl.count; i++) {
|
|
||||||
struct section *sec = &assembler->parser.sec_tbl.sections[i];
|
|
||||||
if (assemble_reltbl_sec(assembler, symtab, symtab_len, sec))
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int assemble_shdr(struct assembler *assembler, Elf32_Shdr **res,
|
|
||||||
uint32_t *res2)
|
|
||||||
{
|
|
||||||
uint32_t max_entries = 4; // symtab, strtab, shstrtab
|
|
||||||
max_entries += assembler->parser.sec_tbl.count; // sections
|
|
||||||
max_entries += assembler->parser.sec_tbl.count; // reltabs per section
|
|
||||||
|
|
||||||
Elf32_Shdr *shdr = malloc(sizeof(Elf32_Shdr) * max_entries);
|
|
||||||
|
|
||||||
size_t str_off;
|
|
||||||
uint32_t count = 0;
|
|
||||||
|
|
||||||
// eeltables
|
|
||||||
for (uint32_t i = 0; i < assembler->parser.sec_tbl.count; i++) {
|
|
||||||
|
|
||||||
if (assembler->meta[i].reltbl == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
struct section *sec = &assembler->parser.sec_tbl.sections[i];
|
|
||||||
const char *prefix = ".reltab.";
|
|
||||||
char reltab_name[MAX_LEX_LENGTH + 8];
|
|
||||||
|
|
||||||
strcpy(reltab_name, prefix);
|
|
||||||
strcat(reltab_name, sec->name);
|
|
||||||
|
|
||||||
if (strtbl_write_str(&assembler->shstr_tbl,
|
|
||||||
reltab_name, &str_off)) {
|
|
||||||
free(shdr);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
assembler->meta[i].reltbl_idx = count;
|
|
||||||
shdr[count++] = (Elf32_Shdr) {
|
|
||||||
.sh_name = str_off,
|
|
||||||
.sh_type = SHT_RELA,
|
|
||||||
.sh_flags = 0,
|
|
||||||
.sh_addr = 0,
|
|
||||||
.sh_offset = 0,
|
|
||||||
.sh_size = 0,
|
|
||||||
.sh_link = 0,
|
|
||||||
.sh_info = 0,
|
|
||||||
.sh_addralign = 1,
|
|
||||||
.sh_entsize = sizeof(Elf32_Rela),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// for each section
|
|
||||||
for (uint32_t i = 0; i < assembler->parser.sec_tbl.count; i++) {
|
|
||||||
struct section *sec = &assembler->parser.sec_tbl.sections[i];
|
|
||||||
char name[MAX_LEX_LENGTH+1] = ".";
|
|
||||||
strcat(name, sec->name);
|
|
||||||
if (strtbl_write_str(&assembler->shstr_tbl, name, &str_off)) {
|
|
||||||
free(shdr);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
assembler->meta[i].shdr_idx = count;
|
|
||||||
if (assembler->meta[i].reltbl != NULL)
|
|
||||||
shdr[assembler->meta[i].reltbl_idx].sh_info = count;
|
|
||||||
shdr[count++] = (Elf32_Shdr){
|
|
||||||
.sh_name = str_off,
|
|
||||||
.sh_type = SHT_PROGBITS,
|
|
||||||
.sh_flags = (sec->write << 0) | (sec->execute << 2) |
|
|
||||||
SHF_ALLOC,
|
|
||||||
.sh_addr = 0,
|
|
||||||
.sh_offset = 0,
|
|
||||||
.sh_size = 0,
|
|
||||||
.sh_link = 0,
|
|
||||||
.sh_info = 0,
|
|
||||||
.sh_addralign = sec->alignment,
|
|
||||||
.sh_entsize = sizeof(struct mips32_instruction),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// symbol table
|
|
||||||
if (strtbl_write_str(&assembler->shstr_tbl, ".symtab", &str_off)) {
|
|
||||||
free(shdr);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
assembler->symtab_idx = count;
|
|
||||||
shdr[count++] = (Elf32_Shdr) {
|
|
||||||
.sh_name = str_off,
|
|
||||||
.sh_type = SHT_SYMTAB,
|
|
||||||
.sh_flags = 0,
|
|
||||||
.sh_addr = 0,
|
|
||||||
.sh_offset = 0,
|
|
||||||
.sh_size = 0,
|
|
||||||
.sh_link = 1,
|
|
||||||
.sh_info = 0,
|
|
||||||
.sh_addralign = 1,
|
|
||||||
.sh_entsize = sizeof(Elf32_Sym),
|
|
||||||
};
|
|
||||||
|
|
||||||
// string table
|
|
||||||
if (strtbl_write_str(&assembler->shstr_tbl, ".strtab", &str_off)) {
|
|
||||||
free(shdr);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
assembler->strtbl_idx = count;
|
|
||||||
shdr[count++] = (Elf32_Shdr) {
|
|
||||||
.sh_name = str_off,
|
|
||||||
.sh_type = SHT_STRTAB,
|
|
||||||
.sh_flags = SHF_STRINGS,
|
|
||||||
.sh_addr = 0,
|
|
||||||
.sh_offset = 0,
|
|
||||||
.sh_size = 0,
|
|
||||||
.sh_link = 0,
|
|
||||||
.sh_info = 0,
|
|
||||||
.sh_addralign = 1,
|
|
||||||
.sh_entsize = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
// sh string table
|
|
||||||
if (strtbl_write_str(&assembler->shstr_tbl, ".shstrtab", &str_off)) {
|
|
||||||
free(shdr);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
assembler->shstrtbl_idx = count;
|
|
||||||
shdr[count++] = (Elf32_Shdr) {
|
|
||||||
.sh_name = str_off,
|
|
||||||
.sh_type = SHT_STRTAB,
|
|
||||||
.sh_flags = SHF_STRINGS,
|
|
||||||
.sh_addr = 0,
|
|
||||||
.sh_offset = 0,
|
|
||||||
.sh_size = 0,
|
|
||||||
.sh_link = 0,
|
|
||||||
.sh_info = 0,
|
|
||||||
.sh_addralign = 1,
|
|
||||||
.sh_entsize = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < assembler->parser.sec_tbl.count; i++) {
|
|
||||||
if (assembler->meta[i].reltbl == NULL)
|
|
||||||
continue;
|
|
||||||
shdr[assembler->meta[i].reltbl_idx].sh_link =
|
|
||||||
assembler->symtab_idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
*res = shdr;
|
|
||||||
*res2 = count;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void update_offsets(struct assembler *assembler, Elf32_Ehdr *ehdr)
|
|
||||||
{
|
|
||||||
Elf32_Shdr *shdr = (Elf32_Shdr *) assembler->shdr;
|
|
||||||
Elf32_Phdr *phdr = (Elf32_Phdr *) assembler->phdr;
|
|
||||||
uint32_t ptr = 0;
|
|
||||||
|
|
||||||
// we must now correct offets and sizes inside the ehdr, phdr,
|
|
||||||
// and shdr
|
|
||||||
ptr += sizeof(Elf32_Ehdr);
|
|
||||||
|
|
||||||
// phdr
|
|
||||||
ehdr->e_phoff = ptr;
|
|
||||||
ptr += assembler->phdr_len * sizeof(Elf32_Phdr);
|
|
||||||
|
|
||||||
// reltbls
|
|
||||||
for (uint32_t i = 0; i < assembler->parser.sec_tbl.count; i++) {
|
|
||||||
if (assembler->meta[i].reltbl == NULL)
|
|
||||||
continue;
|
|
||||||
int idx = assembler->meta[i].reltbl_idx;
|
|
||||||
int len = assembler->meta[i].reltbl_len;
|
|
||||||
shdr[idx].sh_offset = ptr;
|
|
||||||
shdr[idx].sh_size = len * sizeof(Elf32_Rela);
|
|
||||||
ptr += len * sizeof(Elf32_Rela);
|
|
||||||
}
|
|
||||||
|
|
||||||
// sections
|
|
||||||
for (uint32_t i = 0; i < assembler->parser.sec_tbl.count; i++) {
|
|
||||||
int idx = assembler->meta[i].shdr_idx;
|
|
||||||
phdr[i].p_offset = ptr;
|
|
||||||
phdr[i].p_vaddr = ptr;
|
|
||||||
phdr[i].p_paddr = ptr;
|
|
||||||
shdr[idx].sh_offset = ptr;
|
|
||||||
shdr[idx].sh_size = phdr[i].p_filesz;
|
|
||||||
shdr[idx].sh_addr = phdr[i].p_vaddr;
|
|
||||||
shdr[idx].sh_addralign = phdr[i].p_align;
|
|
||||||
ptr += phdr[i].p_filesz;
|
|
||||||
}
|
|
||||||
|
|
||||||
// symtab
|
|
||||||
shdr[assembler->symtab_idx].sh_offset = ptr;
|
|
||||||
shdr[assembler->symtab_idx].sh_link = assembler->strtbl_idx;
|
|
||||||
shdr[assembler->symtab_idx].sh_size =
|
|
||||||
assembler->symtab_len * sizeof(Elf32_Sym);
|
|
||||||
ptr += assembler->symtab_len * sizeof(Elf32_Sym);
|
|
||||||
|
|
||||||
// strtbl
|
|
||||||
shdr[assembler->strtbl_idx].sh_offset = ptr;
|
|
||||||
shdr[assembler->strtbl_idx].sh_size = assembler->str_tbl.size;
|
|
||||||
ptr += assembler->str_tbl.size;
|
|
||||||
|
|
||||||
// shstrtbl
|
|
||||||
shdr[assembler->shstrtbl_idx].sh_offset = ptr;
|
|
||||||
shdr[assembler->shstrtbl_idx].sh_size = assembler->shstr_tbl.size;
|
|
||||||
ptr += assembler->shstr_tbl.size;
|
|
||||||
|
|
||||||
// shdr
|
|
||||||
ehdr->e_shoff = ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int write_file(struct assembler *assembler, Elf32_Ehdr *ehdr,
|
|
||||||
const char *path)
|
|
||||||
{
|
|
||||||
FILE *out = fopen(path, "w");
|
|
||||||
|
|
||||||
if (out == NULL) {
|
|
||||||
ERROR("cannot write '%s'", path);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ehdr
|
|
||||||
fwrite(ehdr, sizeof(Elf32_Ehdr), 1, out);
|
|
||||||
|
|
||||||
// phdr
|
|
||||||
fwrite(assembler->phdr, sizeof(Elf32_Phdr), assembler->phdr_len, out);
|
|
||||||
|
|
||||||
// reltbls
|
|
||||||
for (uint32_t i = 0; i < assembler->parser.sec_tbl.count; i++) {
|
|
||||||
if (assembler->meta[i].reltbl == NULL)
|
|
||||||
continue;
|
|
||||||
void *ptr = assembler->meta[i].reltbl;
|
|
||||||
int len = assembler->meta[i].reltbl_len;
|
|
||||||
fwrite(ptr, sizeof(Elf32_Rela), len, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
// sections
|
|
||||||
for (uint32_t i = 0; i < assembler->parser.sec_tbl.count; i++) {
|
|
||||||
struct section *sec = &assembler->parser.sec_tbl.sections[i];
|
|
||||||
for (uint32_t j = 0; j < sec->count; j++) {
|
|
||||||
struct section_entry *entry = &sec->entries[j];
|
|
||||||
size_t size = entry->size;
|
|
||||||
fwrite(&entry->data, size, 1, out);
|
|
||||||
while(size % sec->alignment) {
|
|
||||||
uint8_t zero = 0;
|
|
||||||
fwrite(&zero, 1, 1, out);
|
|
||||||
size++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sym tbl
|
|
||||||
fwrite(assembler->symtab, sizeof(Elf32_Sym),
|
|
||||||
assembler->symtab_len, out);
|
|
||||||
|
|
||||||
// str tbl
|
|
||||||
fwrite(assembler->str_tbl.ptr, assembler->str_tbl.size, 1, out);
|
|
||||||
|
|
||||||
// shstr tbl
|
|
||||||
fwrite(assembler->shstr_tbl.ptr, assembler->shstr_tbl.size, 1, out);
|
|
||||||
|
|
||||||
// shdr
|
|
||||||
fwrite(assembler->shdr, sizeof(Elf32_Shdr), assembler->shdr_len, out);
|
|
||||||
|
|
||||||
fclose(out);
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int assemble_elf(struct assembler *assembler, const char *out)
|
|
||||||
{
|
|
||||||
if (assemble_symtab(assembler, (Elf32_Sym **) &assembler->symtab,
|
|
||||||
&assembler->symtab_len))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (assemble_reltbl(assembler, assembler->symtab,
|
|
||||||
assembler->symtab_len)) {
|
|
||||||
return M_ERROR;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (assemble_phdr(assembler, (Elf32_Phdr **) &assembler->phdr,
|
|
||||||
&assembler->phdr_len)) {
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (assemble_shdr(assembler, (Elf32_Shdr **) &assembler->shdr,
|
|
||||||
&assembler->shdr_len)) {
|
|
||||||
return M_ERROR;
|
|
||||||
};
|
|
||||||
|
|
||||||
// update the symbol tables with their given section
|
|
||||||
assemble_symtab_shndx(assembler, assembler->symtab);
|
|
||||||
|
|
||||||
Elf32_Ehdr ehdr = {
|
|
||||||
.e_ident = {
|
|
||||||
[EI_MAG0] = ELFMAG0,
|
|
||||||
[EI_MAG1] = ELFMAG1,
|
|
||||||
[EI_MAG2] = ELFMAG2,
|
|
||||||
[EI_MAG3] = ELFMAG3,
|
|
||||||
[EI_CLASS] = ELFCLASS32,
|
|
||||||
[EI_DATA] = ELFDATA2LSB,
|
|
||||||
[EI_VERSION] = EV_CURRENT,
|
|
||||||
[EI_OSABI] = ELFOSABI_NONE,
|
|
||||||
[EI_ABIVERSION] = 0x00,
|
|
||||||
[EI_PAD] = 0x00,
|
|
||||||
},
|
|
||||||
.e_type = ET_REL,
|
|
||||||
.e_machine = EM_MIPS,
|
|
||||||
.e_version = EV_CURRENT,
|
|
||||||
.e_entry = 0x00,
|
|
||||||
.e_phoff = 0x00,
|
|
||||||
.e_shoff = 0x00,
|
|
||||||
.e_flags = EF_MIPS_ARCH_32R6,
|
|
||||||
.e_ehsize = sizeof(Elf32_Ehdr),
|
|
||||||
.e_phentsize = sizeof(Elf32_Phdr),
|
|
||||||
.e_phnum = assembler->phdr_len,
|
|
||||||
.e_shentsize = sizeof(Elf32_Shdr),
|
|
||||||
.e_shnum = assembler->shdr_len,
|
|
||||||
.e_shstrndx = assembler->shstrtbl_idx,
|
|
||||||
};
|
|
||||||
|
|
||||||
update_offsets(assembler, &ehdr);
|
|
||||||
|
|
||||||
if (write_file(assembler, &ehdr, out))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int assemble_file_mips32(struct assembler_arguments args)
|
|
||||||
{
|
|
||||||
struct assembler assembler;
|
|
||||||
int res = M_SUCCESS;
|
|
||||||
|
|
||||||
current_file = args.in_file;
|
|
||||||
|
|
||||||
if (assembler_init(&assembler, args.in_file))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
mips32_parser_init(&assembler.parser);
|
|
||||||
|
|
||||||
if (res == M_SUCCESS)
|
|
||||||
res = parse_file(&assembler);
|
|
||||||
|
|
||||||
if (res == M_SUCCESS)
|
|
||||||
res = assemble_elf(&assembler, args.out_file);
|
|
||||||
|
|
||||||
assembler_free(&assembler);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
13
masm/main.c
13
masm/main.c
|
@ -3,27 +3,24 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "asm.h"
|
#include "asm.h"
|
||||||
#include "mips.h"
|
|
||||||
|
|
||||||
void help(void) {
|
void help(void) {
|
||||||
printf("usage: masm [options] source.asm\n\n");
|
printf("usage: masm [options] source.asm\n\n");
|
||||||
printf("options:\n");
|
printf("options:\n");
|
||||||
printf("\t-h\t\tprints this help message\n");
|
printf("\t-h\t\tprints this help message\n");
|
||||||
printf("\t-i isa\t\tselect a ISA to assemble to (mips32)\n");
|
|
||||||
printf("\t-o output\tselect a output file destination\n");
|
printf("\t-o output\tselect a output file destination\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
struct assembler_arguments args = {
|
struct assembler_arguments args = {
|
||||||
.isa = ISA_MIPS32,
|
|
||||||
.in_file = NULL,
|
.in_file = NULL,
|
||||||
.out_file = NULL,
|
.out_file = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "ho:i:")) != 1) {
|
while ((c = getopt(argc, argv, "ho:")) != 1) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
help();
|
help();
|
||||||
|
@ -31,14 +28,6 @@ int main(int argc, char **argv) {
|
||||||
case 'o':
|
case 'o':
|
||||||
args.out_file = optarg;
|
args.out_file = optarg;
|
||||||
break;
|
break;
|
||||||
case 'i':
|
|
||||||
if (strcmp(optarg, "mips32") == 0) {
|
|
||||||
args.isa = ISA_MIPS32;
|
|
||||||
} else {
|
|
||||||
ERROR("invalid isa '%s'", optarg);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '?':
|
case '?':
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
default:
|
default:
|
||||||
|
|
872
masm/parse.c
872
masm/parse.c
|
@ -6,7 +6,7 @@
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
#include "lex.h"
|
#include "lex.h"
|
||||||
|
|
||||||
int next_token(struct parser *parser, struct token *tok)
|
static int next_token(struct parser *parser, struct token *tok)
|
||||||
{
|
{
|
||||||
if (parser->peek.type != TOK_EOF) {
|
if (parser->peek.type != TOK_EOF) {
|
||||||
if (tok != NULL)
|
if (tok != NULL)
|
||||||
|
@ -23,7 +23,7 @@ int next_token(struct parser *parser, struct token *tok)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int peek_token(struct parser *parser, struct token *tok)
|
static int peek_token(struct parser *parser, struct token *tok)
|
||||||
{
|
{
|
||||||
if (parser->peek.type == TOK_EOF) {
|
if (parser->peek.type == TOK_EOF) {
|
||||||
if (next_token(parser, &parser->peek))
|
if (next_token(parser, &parser->peek))
|
||||||
|
@ -35,7 +35,7 @@ int peek_token(struct parser *parser, struct token *tok)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int assert_token(struct parser *parser, enum token_type type,
|
static int assert_token(struct parser *parser, enum token_type type,
|
||||||
struct token *tok)
|
struct token *tok)
|
||||||
{
|
{
|
||||||
struct token token;
|
struct token token;
|
||||||
|
@ -51,7 +51,7 @@ int assert_token(struct parser *parser, enum token_type type,
|
||||||
return M_SUCCESS;
|
return M_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int assert_eol(struct parser *parser)
|
static int assert_eol(struct parser *parser)
|
||||||
{
|
{
|
||||||
struct token token;
|
struct token token;
|
||||||
if (next_token(parser, &token))
|
if (next_token(parser, &token))
|
||||||
|
@ -63,6 +63,856 @@ int assert_eol(struct parser *parser)
|
||||||
return M_SUCCESS;
|
return M_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* each instruction has a given parse format
|
||||||
|
* internal to the parser */
|
||||||
|
enum mips_parse_format {
|
||||||
|
// register type: rs, rt, td
|
||||||
|
MIPS_PARSE_R,
|
||||||
|
// register type: rs, rt
|
||||||
|
MIPS_PARSE_R2,
|
||||||
|
// register type: rd
|
||||||
|
MIPS_PARSE_RD,
|
||||||
|
// register type: rs
|
||||||
|
MIPS_PARSE_RS,
|
||||||
|
// imeediate type: rs, rt, immd
|
||||||
|
MIPS_PARSE_I,
|
||||||
|
// jump type: offset
|
||||||
|
MIPS_PARSE_J,
|
||||||
|
// jump type: register
|
||||||
|
MIPS_PARSE_JR,
|
||||||
|
// offset 16b type: offset
|
||||||
|
MIPS_PARSE_O16,
|
||||||
|
// offset 26b type: offset
|
||||||
|
MIPS_PARSE_O26,
|
||||||
|
// breanch equal type: rs, rt, offset
|
||||||
|
MIPS_PARSE_BE,
|
||||||
|
// branch zero type: rs, offset
|
||||||
|
MIPS_PARSE_BZ,
|
||||||
|
// store and load: rt, offset(base)
|
||||||
|
MIPS_PARSE_SL,
|
||||||
|
// store and load immediate: rt, immediate
|
||||||
|
MIPS_PARSE_SLI,
|
||||||
|
// shift: rd, rt, sa
|
||||||
|
MIPS_PARSE_S,
|
||||||
|
// shift variable: rd, rt, rs
|
||||||
|
MIPS_PARSE_SV,
|
||||||
|
// none:
|
||||||
|
MIPS_PARSE_NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FORMAT(ins, format) \
|
||||||
|
[MIPS_INS_##ins] = MIPS_PARSE_##format, \
|
||||||
|
|
||||||
|
const enum mips_parse_format mips_parse_formats[] = {
|
||||||
|
FORMAT(ADD, R)
|
||||||
|
FORMAT(ADDI, I)
|
||||||
|
FORMAT(ADDIU, I)
|
||||||
|
FORMAT(ADDU, R)
|
||||||
|
FORMAT(AND, R)
|
||||||
|
FORMAT(ANDI, I)
|
||||||
|
FORMAT(BAL, O16)
|
||||||
|
FORMAT(BALC, O26)
|
||||||
|
FORMAT(BC, O26)
|
||||||
|
FORMAT(BEQ, BE)
|
||||||
|
FORMAT(BEQL, BE)
|
||||||
|
FORMAT(BGEZ, BZ)
|
||||||
|
FORMAT(BGEZAL, BZ)
|
||||||
|
FORMAT(BGEZALL, BZ)
|
||||||
|
FORMAT(BGEZL, BZ)
|
||||||
|
FORMAT(BGTZ, BZ)
|
||||||
|
FORMAT(BGTZL, BZ)
|
||||||
|
FORMAT(BLEZ, BZ)
|
||||||
|
FORMAT(BLEZL, BZ)
|
||||||
|
FORMAT(BLTZ, BZ)
|
||||||
|
FORMAT(BLTZAL, BZ)
|
||||||
|
FORMAT(BLTZALL, BZ)
|
||||||
|
FORMAT(BLTZL, BZ)
|
||||||
|
FORMAT(BNE, BE)
|
||||||
|
FORMAT(BNEL, BE)
|
||||||
|
FORMAT(DDIV, R2)
|
||||||
|
FORMAT(DDIVU, R2)
|
||||||
|
FORMAT(DIV, R2)
|
||||||
|
FORMAT(DIVU, R2)
|
||||||
|
FORMAT(J, J)
|
||||||
|
FORMAT(JAL, J)
|
||||||
|
FORMAT(JALR, JR) // TODO: handle rd
|
||||||
|
FORMAT(JALX, J)
|
||||||
|
FORMAT(JR, JR)
|
||||||
|
FORMAT(LB, SL)
|
||||||
|
FORMAT(LBU, SL)
|
||||||
|
FORMAT(LH, SL)
|
||||||
|
FORMAT(LHU, SL)
|
||||||
|
FORMAT(LUI, SLI)
|
||||||
|
FORMAT(LW, SL)
|
||||||
|
FORMAT(LWL, SL)
|
||||||
|
FORMAT(LWR, SL)
|
||||||
|
FORMAT(MFHI, RD)
|
||||||
|
FORMAT(MFLO, RD)
|
||||||
|
FORMAT(MTHI, RS)
|
||||||
|
FORMAT(MTLO, RS)
|
||||||
|
FORMAT(MULT, R2)
|
||||||
|
FORMAT(MULTU, R2)
|
||||||
|
FORMAT(SB, SL)
|
||||||
|
FORMAT(SH, SL)
|
||||||
|
FORMAT(SW, SL)
|
||||||
|
FORMAT(SWL, SL)
|
||||||
|
FORMAT(SLL, S)
|
||||||
|
FORMAT(SLLV, SV)
|
||||||
|
FORMAT(SLT, R)
|
||||||
|
FORMAT(SLTI, I)
|
||||||
|
FORMAT(SLTIU, I)
|
||||||
|
FORMAT(SLTU, R)
|
||||||
|
FORMAT(SRA, S)
|
||||||
|
FORMAT(SRAV, SV)
|
||||||
|
FORMAT(SRL, S)
|
||||||
|
FORMAT(SRLV, SV)
|
||||||
|
FORMAT(SYSCALL, NONE)
|
||||||
|
FORMAT(OR, R)
|
||||||
|
FORMAT(ORI, I)
|
||||||
|
FORMAT(NOR, R)
|
||||||
|
FORMAT(SUB, R)
|
||||||
|
FORMAT(SUBU, R)
|
||||||
|
FORMAT(XOR, R)
|
||||||
|
FORMAT(XORI, I)
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef FORMAT
|
||||||
|
|
||||||
|
#define MAX5 32
|
||||||
|
#define MAX16 65536
|
||||||
|
#define MAX26 67108864
|
||||||
|
|
||||||
|
static int get_reference(struct parser *parser, uint32_t *offset,
|
||||||
|
struct reference *ref, enum reference_type type)
|
||||||
|
{
|
||||||
|
struct token token;
|
||||||
|
|
||||||
|
if (next_token(parser, &token))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (token.type == TOK_NUMBER) {
|
||||||
|
*offset = token.number;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.type != TOK_IDENT) {
|
||||||
|
ERROR_POS(token, "unexpected token of type '%s'",
|
||||||
|
token_str(token.type));
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(ref->name, token.text);
|
||||||
|
ref->type = type;
|
||||||
|
ref->addend = 0;
|
||||||
|
|
||||||
|
// return zero for now
|
||||||
|
*offset = 0;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_offset(struct parser *parser, uint32_t *offset,
|
||||||
|
struct reference *ref)
|
||||||
|
{
|
||||||
|
return get_reference(parser, offset, ref, REF_OFFESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_target(struct parser *parser, uint32_t *offset,
|
||||||
|
struct reference *ref)
|
||||||
|
{
|
||||||
|
return get_reference(parser, offset, ref, REF_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_instruction(const char *ident, struct mips_instruction *res)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < __MIPS_INS_LEN; i++) {
|
||||||
|
struct mips_instruction ins =
|
||||||
|
mips_instructions[i];
|
||||||
|
if (strcasecmp(ident, ins.name) == 0) {
|
||||||
|
if (res != NULL)
|
||||||
|
*res = ins;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_register(struct parser *parser, enum mips_register *reg)
|
||||||
|
{
|
||||||
|
struct token token;
|
||||||
|
if (assert_token(parser, TOK_REG, &token))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
int len = strlen(token.text);
|
||||||
|
int c0 = len > 0 ? token.text[0] : '\0',
|
||||||
|
c1 = len > 1 ? token.text[1] : '\0',
|
||||||
|
c2 = len > 2 ? token.text[2] : '\0',
|
||||||
|
c3 = len > 3 ? token.text[3] : '\0';
|
||||||
|
|
||||||
|
// $zero
|
||||||
|
if (c0 == 'z') {
|
||||||
|
if (c1 == 'e' && c2 == 'r' && c3 == 'o') {
|
||||||
|
*reg = MIPS_REG_ZERO;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// $a0-a3 $at
|
||||||
|
else if (c0 == 'a') {
|
||||||
|
if (c1 == 't') {
|
||||||
|
*reg = MIPS_REG_AT;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
if (c1 >= '0' && c1 <= '3') {
|
||||||
|
*reg = MIPS_REG_A0;
|
||||||
|
*reg += c1 - '0';
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// $v0-v1
|
||||||
|
else if (c0 == 'v') {
|
||||||
|
if (c1 >= '0' && c1 <= '1') {
|
||||||
|
*reg = MIPS_REG_V0;
|
||||||
|
*reg += c1 - '0';
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// $t0-t9
|
||||||
|
else if (c0 == 't') {
|
||||||
|
if (c1 >= '0' && c1 <= '7') {
|
||||||
|
*reg = MIPS_REG_T0;
|
||||||
|
*reg += c1 - '0';
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
// reg T8-T9 are not in order with T0-T7
|
||||||
|
if (c1 >= '8' && c1 <= '9') {
|
||||||
|
*reg = MIPS_REG_T8;
|
||||||
|
*reg += c1 - '8';
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// $s0-s7 $sp
|
||||||
|
else if (c0 == 's') {
|
||||||
|
if (c1 >= '0' && c1 <= '7') {
|
||||||
|
*reg = MIPS_REG_S0;
|
||||||
|
*reg += c1 - '0';
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
if (c1 == 'p') {
|
||||||
|
*reg = MIPS_REG_SP;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// $k0-k1
|
||||||
|
else if (c0 == 'k') {
|
||||||
|
if (c1 >= '0' && c1 <= '1') {
|
||||||
|
*reg = MIPS_REG_K0;
|
||||||
|
*reg += c1 - '0';
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// $gp
|
||||||
|
else if (c0 == 'g') {
|
||||||
|
if (c1 == 'p') {
|
||||||
|
*reg = MIPS_REG_GP;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// $fp
|
||||||
|
else if (c0 == 'f') {
|
||||||
|
if (c1 == 'p') {
|
||||||
|
*reg = MIPS_REG_FP;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// $rp
|
||||||
|
else if (c0 == 'r') {
|
||||||
|
if (c1 == 'p') {
|
||||||
|
*reg = MIPS_REG_RA;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// $0-31 (non aliased register names)
|
||||||
|
else if (c0 >= '0' && c0 <= '9') {
|
||||||
|
int i = c0 - '0';
|
||||||
|
if (c1 >= '0' && c1 <= '9') {
|
||||||
|
i *= 10;
|
||||||
|
i += c1 - '0';
|
||||||
|
}
|
||||||
|
if (i <= 31) {
|
||||||
|
*reg = i;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ERROR_POS(token, "unknown register $%s", token.text);
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_instruction_r(struct parser *parser,
|
||||||
|
struct mips_instruction *ins)
|
||||||
|
{
|
||||||
|
// format: rs, rt, rd
|
||||||
|
enum mips_register reg;
|
||||||
|
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->R_data.rd = reg;
|
||||||
|
|
||||||
|
if (assert_token(parser, TOK_COMMA, NULL))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->R_data.rs = reg;
|
||||||
|
|
||||||
|
if (assert_token(parser, TOK_COMMA, NULL))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->R_data.rt = reg;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_instruction_r2(struct parser *parser,
|
||||||
|
struct mips_instruction *ins)
|
||||||
|
{
|
||||||
|
// format: rs, rt
|
||||||
|
enum mips_register reg;
|
||||||
|
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->R_data.rs = reg;
|
||||||
|
|
||||||
|
if (assert_token(parser, TOK_COMMA, NULL))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->R_data.rt = reg;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_instruction_rs(struct parser *parser,
|
||||||
|
struct mips_instruction *ins)
|
||||||
|
{
|
||||||
|
// format: rs
|
||||||
|
enum mips_register reg;
|
||||||
|
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->R_data.rs = reg;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_instruction_rd(struct parser *parser,
|
||||||
|
struct mips_instruction *ins)
|
||||||
|
{
|
||||||
|
// format: rd
|
||||||
|
enum mips_register reg;
|
||||||
|
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->R_data.rd = reg;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_instruction_i(struct parser *parser,
|
||||||
|
struct mips_instruction *ins)
|
||||||
|
{
|
||||||
|
// format: rs, rt, immd
|
||||||
|
enum mips_register reg;
|
||||||
|
struct token token;
|
||||||
|
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->I_data.rt = reg;
|
||||||
|
|
||||||
|
if (assert_token(parser, TOK_COMMA, NULL))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->I_data.rs = reg;
|
||||||
|
|
||||||
|
if (assert_token(parser, TOK_COMMA, NULL))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (assert_token(parser, TOK_NUMBER, &token))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (token.number >= MAX16)
|
||||||
|
return M_ERROR;
|
||||||
|
ins->I_data.immd = token.number;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_instruction_offset(struct parser *parser,
|
||||||
|
uint32_t max,
|
||||||
|
struct mips_instruction *ins,
|
||||||
|
struct reference *ref)
|
||||||
|
{
|
||||||
|
uint32_t n;
|
||||||
|
if (get_offset(parser, &n, ref) || n > max)
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
switch (max) {
|
||||||
|
case MAX26:
|
||||||
|
ins->J_data.target = n;
|
||||||
|
break;
|
||||||
|
case MAX16:
|
||||||
|
ins->B_data.offset = n;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_instruction_j(struct parser *parser,
|
||||||
|
struct mips_instruction *ins,
|
||||||
|
struct reference *ref)
|
||||||
|
{
|
||||||
|
uint32_t n;
|
||||||
|
if (get_target(parser, &n, ref) || n > MAX26)
|
||||||
|
return M_ERROR;
|
||||||
|
ins->J_data.target = n;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_instruction_jr(struct parser *parser,
|
||||||
|
struct mips_instruction *ins,
|
||||||
|
struct reference *ref)
|
||||||
|
{
|
||||||
|
uint32_t n;
|
||||||
|
if (get_target(parser, &n, ref) || n > MAX26)
|
||||||
|
return M_ERROR;
|
||||||
|
ins->J_data.target = n;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_instruction_branch_equal(struct parser *parser,
|
||||||
|
struct mips_instruction *ins)
|
||||||
|
{
|
||||||
|
enum mips_register reg;
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->R_data.rs = reg;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_instruction_branch(struct parser *parser,
|
||||||
|
struct mips_instruction *ins,
|
||||||
|
struct reference *ref)
|
||||||
|
{
|
||||||
|
enum mips_register reg;
|
||||||
|
uint32_t n;
|
||||||
|
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->B_data.rs = reg;
|
||||||
|
|
||||||
|
if (assert_token(parser, TOK_COMMA, NULL))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (get_offset(parser, &n, ref) || n > MAX16)
|
||||||
|
return M_ERROR;
|
||||||
|
ins->B_data.offset = n;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_instruction_sl(struct parser *parser,
|
||||||
|
struct mips_instruction *ins,
|
||||||
|
struct reference *ref)
|
||||||
|
{
|
||||||
|
enum mips_register reg;
|
||||||
|
uint32_t offset = 0;
|
||||||
|
struct token token;
|
||||||
|
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->I_data.rt = reg;
|
||||||
|
|
||||||
|
if (assert_token(parser, TOK_COMMA, NULL))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (peek_token(parser, &token))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (token.type != TOK_LPAREN)
|
||||||
|
if (get_offset(parser, &offset, ref))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->I_data.immd = offset;
|
||||||
|
|
||||||
|
if (peek_token(parser, &token))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (token.type == TOK_NL) {
|
||||||
|
ins->I_data.rs = MIPS_REG_ZERO;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assert_token(parser, TOK_LPAREN, NULL))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->I_data.rs = reg;
|
||||||
|
|
||||||
|
if (assert_token(parser, TOK_RPAREN, NULL))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_instruction_sli(struct parser *parser,
|
||||||
|
struct mips_instruction *ins)
|
||||||
|
{
|
||||||
|
enum mips_register reg;
|
||||||
|
struct token token;
|
||||||
|
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->I_data.rt = reg;
|
||||||
|
|
||||||
|
if (assert_token(parser, TOK_COMMA, NULL))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (assert_token(parser, TOK_NUMBER, &token) || token.number > MAX16)
|
||||||
|
return M_ERROR;
|
||||||
|
ins->I_data.immd = token.number;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_instruction_s(struct parser *parser,
|
||||||
|
struct mips_instruction *ins)
|
||||||
|
{
|
||||||
|
enum mips_register reg;
|
||||||
|
struct token token;
|
||||||
|
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->R_data.rd = reg;
|
||||||
|
|
||||||
|
if (assert_token(parser, TOK_COMMA, NULL))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->R_data.rt = reg;
|
||||||
|
|
||||||
|
if (assert_token(parser, TOK_COMMA, NULL))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (assert_token(parser, TOK_NUMBER, &token) || token.number > MAX5)
|
||||||
|
return M_ERROR;
|
||||||
|
ins->R_data.shamt = token.number;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_instruction_sv(struct parser *parser,
|
||||||
|
struct mips_instruction *ins)
|
||||||
|
{
|
||||||
|
enum mips_register reg;
|
||||||
|
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->R_data.rd = reg;
|
||||||
|
|
||||||
|
if (assert_token(parser, TOK_COMMA, NULL))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->R_data.rt = reg;
|
||||||
|
|
||||||
|
if (assert_token(parser, TOK_COMMA, NULL))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (parse_register(parser, ®))
|
||||||
|
return M_ERROR;
|
||||||
|
ins->R_data.rs = reg;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_instruction(struct parser *parser,
|
||||||
|
struct ins_expr *expr,
|
||||||
|
struct token ident)
|
||||||
|
{
|
||||||
|
struct mips_instruction instruction;
|
||||||
|
enum mips_parse_format format;
|
||||||
|
int res = M_SUCCESS;
|
||||||
|
|
||||||
|
if (get_instruction(ident.text, &instruction)) {
|
||||||
|
ERROR_POS(ident, "unknown instruction '%s'", ident.text);
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mips_instruction *ins = &expr->ins[0];
|
||||||
|
struct reference *ref = &expr->ref[0];
|
||||||
|
|
||||||
|
// this will only ever generate one instruction
|
||||||
|
expr->ins_len = 1;
|
||||||
|
*ins = instruction;
|
||||||
|
ref->type = REF_NONE;
|
||||||
|
|
||||||
|
format = mips_parse_formats[instruction.type];
|
||||||
|
switch (format) {
|
||||||
|
case MIPS_PARSE_R:
|
||||||
|
res = parse_instruction_r(parser, ins);
|
||||||
|
break;
|
||||||
|
case MIPS_PARSE_R2:
|
||||||
|
res = parse_instruction_r2(parser, ins);
|
||||||
|
break;
|
||||||
|
case MIPS_PARSE_RS:
|
||||||
|
res = parse_instruction_rs(parser, ins);
|
||||||
|
break;
|
||||||
|
case MIPS_PARSE_RD:
|
||||||
|
res = parse_instruction_rd(parser, ins);
|
||||||
|
break;
|
||||||
|
case MIPS_PARSE_I:
|
||||||
|
res = parse_instruction_i(parser, ins);
|
||||||
|
break;
|
||||||
|
case MIPS_PARSE_J:
|
||||||
|
res = parse_instruction_j(parser, ins, ref);
|
||||||
|
break;
|
||||||
|
case MIPS_PARSE_JR:
|
||||||
|
res = parse_instruction_jr(parser, ins, ref);
|
||||||
|
break;
|
||||||
|
case MIPS_PARSE_O16:
|
||||||
|
res = parse_instruction_offset(parser, MAX16, ins, ref);
|
||||||
|
break;
|
||||||
|
case MIPS_PARSE_O26:
|
||||||
|
res = parse_instruction_offset(parser, MAX26, ins, ref);
|
||||||
|
break;
|
||||||
|
case MIPS_PARSE_BE:
|
||||||
|
res = parse_instruction_branch_equal(parser, ins);
|
||||||
|
break;
|
||||||
|
case MIPS_PARSE_BZ:
|
||||||
|
res = parse_instruction_branch(parser, ins, ref);
|
||||||
|
break;
|
||||||
|
case MIPS_PARSE_SL:
|
||||||
|
res = parse_instruction_sl(parser, ins, ref);
|
||||||
|
break;
|
||||||
|
case MIPS_PARSE_SLI:
|
||||||
|
res = parse_instruction_sli(parser, ins);
|
||||||
|
break;
|
||||||
|
case MIPS_PARSE_S:
|
||||||
|
res = parse_instruction_s(parser, ins);
|
||||||
|
break;
|
||||||
|
case MIPS_PARSE_SV:
|
||||||
|
res = parse_instruction_sv(parser, ins);
|
||||||
|
break;
|
||||||
|
case MIPS_PARSE_NONE:
|
||||||
|
res = M_SUCCESS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == M_SUCCESS && assert_eol(parser))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int parse_directive_align(struct parser *parser,
|
||||||
|
struct mips_directive *directive)
|
||||||
|
{
|
||||||
|
struct token token;
|
||||||
|
if (assert_token(parser, TOK_NUMBER, &token))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (token.number < 0) {
|
||||||
|
ERROR_POS(token, "cannot align negative");
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.number > MAX16) {
|
||||||
|
ERROR_POS(token, "cannot align more than 65kb");
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
directive->type = MIPS_DIRECTIVE_ALIGN;
|
||||||
|
directive->align = token.number;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_directive_space(struct parser *parser,
|
||||||
|
struct mips_directive *directive)
|
||||||
|
{
|
||||||
|
struct token token;
|
||||||
|
if (assert_token(parser, TOK_NUMBER, &token))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (token.number < 0) {
|
||||||
|
ERROR_POS(token, "cannot reserve negative");
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.number > MAX16) {
|
||||||
|
ERROR_POS(token, "cannot reserve more than 65kb");
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
directive->type = MIPS_DIRECTIVE_SPACE;
|
||||||
|
directive->space = token.number;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_directive_whb(struct parser *parser,
|
||||||
|
struct mips_directive *directive,
|
||||||
|
enum mips_directive_type type)
|
||||||
|
{
|
||||||
|
struct token token;
|
||||||
|
uint32_t size = 0;
|
||||||
|
uint32_t len = 0;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case MIPS_DIRECTIVE_WORD:
|
||||||
|
size = UINT32_MAX;
|
||||||
|
break;
|
||||||
|
case MIPS_DIRECTIVE_HALF:
|
||||||
|
size = UINT16_MAX;
|
||||||
|
break;
|
||||||
|
case MIPS_DIRECTIVE_BYTE:
|
||||||
|
size = UINT8_MAX;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
directive->type = type;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (assert_token(parser, TOK_NUMBER, &token))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (len >= MAX_ARG_LENGTH) {
|
||||||
|
ERROR_POS(token, "directives cannot be longer than "
|
||||||
|
"%d arguments", MAX_ARG_LENGTH);
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.number > size) {
|
||||||
|
ERROR_POS(token, "number cannot execede max size of: "
|
||||||
|
"%d", size);
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case MIPS_DIRECTIVE_WORD:
|
||||||
|
directive->words[len++] = token.number;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case MIPS_DIRECTIVE_HALF:
|
||||||
|
directive->halfs[len++] = token.number;
|
||||||
|
break;
|
||||||
|
case MIPS_DIRECTIVE_BYTE:
|
||||||
|
directive->bytes[len++] = token.number;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peek_token(parser, &token))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
if (token.type == TOK_COMMA) {
|
||||||
|
next_token(parser, NULL);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
directive->len = len;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_directive_extern(struct parser *parser,
|
||||||
|
struct mips_directive *directive)
|
||||||
|
{
|
||||||
|
struct token token;
|
||||||
|
if (assert_token(parser, TOK_IDENT, &token))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
directive->type = MIPS_DIRECTIVE_EXTERN;
|
||||||
|
strcpy(directive->name, token.text);
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_directive_globl(struct parser *parser,
|
||||||
|
struct mips_directive *directive)
|
||||||
|
{
|
||||||
|
struct token token;
|
||||||
|
if (assert_token(parser, TOK_IDENT, &token))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
directive->type = MIPS_DIRECTIVE_GLOBL;
|
||||||
|
strcpy(directive->name, token.text);
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_section(struct mips_directive *directive,
|
||||||
|
char name[MAX_LEX_LENGTH])
|
||||||
|
{
|
||||||
|
directive->type = MIPS_DIRECTIVE_SECTION;
|
||||||
|
strcpy(directive->name, name);
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_directive(struct parser *parser,
|
||||||
|
struct mips_directive *directive)
|
||||||
|
{
|
||||||
|
struct token token;
|
||||||
|
if (assert_token(parser, TOK_DIRECTIVE, &token))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
// .align n
|
||||||
|
if (strcmp(token.text, "align") == 0)
|
||||||
|
return parse_directive_align(parser, directive);
|
||||||
|
else if (strcmp(token.text, "space") == 0)
|
||||||
|
return parse_directive_space(parser, directive);
|
||||||
|
else if (strcmp(token.text, "word") == 0)
|
||||||
|
return parse_directive_whb(parser, directive,
|
||||||
|
MIPS_DIRECTIVE_WORD);
|
||||||
|
else if (strcmp(token.text, "half") == 0)
|
||||||
|
return parse_directive_whb(parser, directive,
|
||||||
|
MIPS_DIRECTIVE_HALF);
|
||||||
|
else if (strcmp(token.text, "byte") == 0)
|
||||||
|
return parse_directive_whb(parser, directive,
|
||||||
|
MIPS_DIRECTIVE_BYTE);
|
||||||
|
else if (strcmp(token.text, "extern") == 0)
|
||||||
|
return parse_directive_extern(parser, directive);
|
||||||
|
else if (strcmp(token.text, "globl") == 0)
|
||||||
|
return parse_directive_globl(parser, directive);
|
||||||
|
else
|
||||||
|
return parse_section(directive, token.text);
|
||||||
|
}
|
||||||
|
|
||||||
static int parse_constant(struct parser *parser, struct const_expr *expr,
|
static int parse_constant(struct parser *parser, struct const_expr *expr,
|
||||||
struct token ident)
|
struct token ident)
|
||||||
{
|
{
|
||||||
|
@ -96,7 +946,7 @@ static int parser_handle_ident(struct parser *parser, struct expr *expr)
|
||||||
return parse_constant(parser, &expr->constant, ident);
|
return parse_constant(parser, &expr->constant, ident);
|
||||||
} else {
|
} else {
|
||||||
expr->type = EXPR_INS;
|
expr->type = EXPR_INS;
|
||||||
return parser->parse_instruction(parser, &expr->ins, ident);
|
return parse_instruction(parser, &expr->ins, ident);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +958,7 @@ static int parse_label(struct parser *parser,
|
||||||
|
|
||||||
if (assert_token(parser, TOK_LABEL, &token))
|
if (assert_token(parser, TOK_LABEL, &token))
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
strcpy(expr->text, token.text);
|
strcpy(expr->label, token.text);
|
||||||
|
|
||||||
return M_SUCCESS;
|
return M_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -139,8 +989,7 @@ again:
|
||||||
|
|
||||||
case TOK_DIRECTIVE:
|
case TOK_DIRECTIVE:
|
||||||
expr->type = EXPR_DIRECTIVE;
|
expr->type = EXPR_DIRECTIVE;
|
||||||
res = parser->parse_directive(parser,
|
res = parse_directive(parser, &expr->directive);
|
||||||
&expr->directive);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_IDENT:
|
case TOK_IDENT:
|
||||||
|
@ -161,16 +1010,11 @@ int parser_init(struct lexer *lexer, struct parser *parser)
|
||||||
{
|
{
|
||||||
parser->lexer = lexer;
|
parser->lexer = lexer;
|
||||||
parser->peek.type = TOK_EOF;
|
parser->peek.type = TOK_EOF;
|
||||||
if (sectbl_init(&parser->sec_tbl))
|
|
||||||
return M_ERROR;
|
|
||||||
if (reftbl_init(&parser->ref_tbl))
|
|
||||||
return M_ERROR;
|
|
||||||
return M_SUCCESS;
|
return M_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void parser_free(struct parser *parser)
|
void parser_free(struct parser *parser)
|
||||||
{
|
{
|
||||||
sectbl_free(&parser->sec_tbl);
|
(void) parser;
|
||||||
reftbl_free(&parser->ref_tbl);
|
|
||||||
}
|
}
|
||||||
|
|
153
masm/parse.h
153
masm/parse.h
|
@ -9,135 +9,68 @@
|
||||||
#include <mips.h>
|
#include <mips.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
struct const_expr {
|
///
|
||||||
char name[MAX_LEX_LENGTH];
|
/// reference
|
||||||
uint32_t value;
|
///
|
||||||
};
|
|
||||||
|
|
||||||
enum expr_type {
|
|
||||||
EXPR_INS,
|
|
||||||
EXPR_DIRECTIVE,
|
|
||||||
EXPR_CONSTANT,
|
|
||||||
EXPR_LABEL,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct expr {
|
|
||||||
enum expr_type type;
|
|
||||||
union {
|
|
||||||
// instruction
|
|
||||||
union mips_instruction ins;
|
|
||||||
// directive
|
|
||||||
union mips_directive directive;
|
|
||||||
// constant
|
|
||||||
struct const_expr constant;
|
|
||||||
// segment or label
|
|
||||||
char text[MAX_LEX_LENGTH];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
enum section_entry_type {
|
|
||||||
ENT_INS,
|
|
||||||
ENT_WORD,
|
|
||||||
ENT_HALF,
|
|
||||||
ENT_BYTE,
|
|
||||||
ENT_NO_DATA,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct section_entry {
|
|
||||||
enum section_entry_type type;
|
|
||||||
size_t size;
|
|
||||||
|
|
||||||
union {
|
|
||||||
char data; // to get memory address
|
|
||||||
union mips_instruction ins;
|
|
||||||
int32_t word;
|
|
||||||
int16_t half;
|
|
||||||
int8_t byte;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct section {
|
|
||||||
uint32_t count;
|
|
||||||
uint32_t len;
|
|
||||||
uint32_t alignment;
|
|
||||||
uint32_t index; // what index is my section
|
|
||||||
char name[MAX_LEX_LENGTH];
|
|
||||||
bool read;
|
|
||||||
bool write;
|
|
||||||
bool execute;
|
|
||||||
struct section_entry *entries;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct section_table {
|
|
||||||
uint32_t count;
|
|
||||||
uint32_t len;
|
|
||||||
struct section *sections;
|
|
||||||
struct section *current;
|
|
||||||
char name[MAX_LEX_LENGTH];
|
|
||||||
};
|
|
||||||
|
|
||||||
int sectbl_init(struct section_table *sec_tbl);
|
|
||||||
void sectbl_free(struct section_table *sec_tbl);
|
|
||||||
|
|
||||||
int sectbl_alloc(struct section_table *sec_tbl, struct section **sec,
|
|
||||||
const char name[MAX_LEX_LENGTH]);
|
|
||||||
int sectbl_get(struct section_table *sec_tbl, struct section **sec,
|
|
||||||
const char name[MAX_LEX_LENGTH]);
|
|
||||||
int sec_push(struct section *section, struct section_entry entry);
|
|
||||||
size_t sec_size(struct section *section);
|
|
||||||
size_t sec_index(struct section *section, uint32_t index);
|
|
||||||
|
|
||||||
enum reference_type {
|
enum reference_type {
|
||||||
|
REF_NONE,
|
||||||
REF_OFFESET,
|
REF_OFFESET,
|
||||||
REF_TARGET,
|
REF_TARGET,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct reference {
|
struct reference {
|
||||||
enum reference_type type;
|
enum reference_type type;
|
||||||
struct section *section;
|
|
||||||
uint32_t index;
|
/// symbol name
|
||||||
char name[MAX_LEX_LENGTH];
|
char name[MAX_LEX_LENGTH];
|
||||||
|
|
||||||
|
/// integer addend
|
||||||
|
int64_t addend;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct reference_table {
|
struct const_expr {
|
||||||
uint32_t count;
|
char name[MAX_LEX_LENGTH];
|
||||||
uint32_t len;
|
uint32_t value;
|
||||||
struct reference *references;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int reftbl_init(struct reference_table *ref_tbl);
|
struct ins_expr {
|
||||||
void reftbl_free(struct reference_table *ref_tbl);
|
/// pesudo instructions can return
|
||||||
int reftbl_push(struct reference_table *ref_tbl, struct reference reference);
|
/// more than one instruction
|
||||||
|
size_t ins_len;
|
||||||
|
struct mips_instruction ins[2];
|
||||||
|
|
||||||
|
/// instructions can reference symbols.
|
||||||
|
/// instruction `n` will be paried with reference `n`
|
||||||
|
struct reference ref[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum expr_type {
|
||||||
|
EXPR_DIRECTIVE,
|
||||||
|
EXPR_CONSTANT,
|
||||||
|
EXPR_INS,
|
||||||
|
EXPR_LABEL,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct expr {
|
||||||
|
enum expr_type type;
|
||||||
|
union {
|
||||||
|
// directive
|
||||||
|
struct mips_directive directive;
|
||||||
|
// constant
|
||||||
|
struct const_expr constant;
|
||||||
|
// instruction
|
||||||
|
struct ins_expr ins;
|
||||||
|
// label
|
||||||
|
char label[MAX_LEX_LENGTH];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
struct parser {
|
struct parser {
|
||||||
struct lexer *lexer;
|
struct lexer *lexer;
|
||||||
struct token peek;
|
struct token peek;
|
||||||
|
|
||||||
// sections
|
|
||||||
struct section_table sec_tbl;
|
|
||||||
|
|
||||||
// references
|
|
||||||
struct reference_table ref_tbl;
|
|
||||||
|
|
||||||
int (*parse_instruction)(struct parser *, union mips_instruction *,
|
|
||||||
struct token);
|
|
||||||
int (*parse_directive)(struct parser *, union mips_directive *);
|
|
||||||
int (*is_instruction)(const char *ident);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* get the next token in the parser */
|
|
||||||
int next_token(struct parser *parser, struct token *tok);
|
|
||||||
|
|
||||||
/* peek the next token in the parser */
|
|
||||||
int peek_token(struct parser *parser, struct token *tok);
|
|
||||||
|
|
||||||
/* assert the next token is a specific type */
|
|
||||||
int assert_token(struct parser *parser, enum token_type type,
|
|
||||||
struct token *tok);
|
|
||||||
|
|
||||||
/* assert the next token is EOF or NL */
|
|
||||||
int assert_eol(struct parser *parser);
|
|
||||||
|
|
||||||
/* get the next expression in the parser */
|
/* get the next expression in the parser */
|
||||||
int parser_next(struct parser *parser, struct expr *expr);
|
int parser_next(struct parser *parser, struct expr *expr);
|
||||||
|
|
||||||
|
|
|
@ -1,872 +0,0 @@
|
||||||
#include <mips.h>
|
|
||||||
#include <mips32.h>
|
|
||||||
#include <merror.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <strings.h>
|
|
||||||
|
|
||||||
#include "parse_mips32.h"
|
|
||||||
#include "parse.h"
|
|
||||||
#include "mlimits.h"
|
|
||||||
#include "parse.h"
|
|
||||||
#include "lex.h"
|
|
||||||
|
|
||||||
/* each instruction has a given parse format
|
|
||||||
* internal to the parser */
|
|
||||||
enum mips32_parse_format {
|
|
||||||
// register type: rs, rt, td
|
|
||||||
MIPS32_PARSE_R,
|
|
||||||
// register type: rs, rt
|
|
||||||
MIPS32_PARSE_R2,
|
|
||||||
// register type: rd
|
|
||||||
MIPS32_PARSE_RD,
|
|
||||||
// register type: rs
|
|
||||||
MIPS32_PARSE_RS,
|
|
||||||
// imeediate type: rs, rt, immd
|
|
||||||
MIPS32_PARSE_I,
|
|
||||||
// jump type: offset
|
|
||||||
MIPS32_PARSE_J,
|
|
||||||
// jump type: register
|
|
||||||
MIPS32_PARSE_JR,
|
|
||||||
// offset 16b type: offset
|
|
||||||
MIPS32_PARSE_O16,
|
|
||||||
// offset 26b type: offset
|
|
||||||
MIPS32_PARSE_O26,
|
|
||||||
// breanch equal type: rs, rt, offset
|
|
||||||
MIPS32_PARSE_BE,
|
|
||||||
// branch zero type: rs, offset
|
|
||||||
MIPS32_PARSE_BZ,
|
|
||||||
// store and load: rt, offset(base)
|
|
||||||
MIPS32_PARSE_SL,
|
|
||||||
// store and load immediate: rt, immediate
|
|
||||||
MIPS32_PARSE_SLI,
|
|
||||||
// shift: rd, rt, sa
|
|
||||||
MIPS32_PARSE_S,
|
|
||||||
// shift variable: rd, rt, rs
|
|
||||||
MIPS32_PARSE_SV,
|
|
||||||
// none:
|
|
||||||
MIPS32_PARSE_NONE,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define FORMAT(ins, format) \
|
|
||||||
[MIPS32_INS_##ins] = MIPS32_PARSE_##format, \
|
|
||||||
|
|
||||||
const enum mips32_parse_format mips32_parse_formats[] = {
|
|
||||||
FORMAT(ADD, R)
|
|
||||||
FORMAT(ADDI, I)
|
|
||||||
FORMAT(ADDIU, I)
|
|
||||||
FORMAT(ADDU, R)
|
|
||||||
FORMAT(AND, R)
|
|
||||||
FORMAT(ANDI, I)
|
|
||||||
FORMAT(BAL, O16)
|
|
||||||
FORMAT(BALC, O26)
|
|
||||||
FORMAT(BC, O26)
|
|
||||||
FORMAT(BEQ, BE)
|
|
||||||
FORMAT(BEQL, BE)
|
|
||||||
FORMAT(BGEZ, BZ)
|
|
||||||
FORMAT(BGEZAL, BZ)
|
|
||||||
FORMAT(BGEZALL, BZ)
|
|
||||||
FORMAT(BGEZL, BZ)
|
|
||||||
FORMAT(BGTZ, BZ)
|
|
||||||
FORMAT(BGTZL, BZ)
|
|
||||||
FORMAT(BLEZ, BZ)
|
|
||||||
FORMAT(BLEZL, BZ)
|
|
||||||
FORMAT(BLTZ, BZ)
|
|
||||||
FORMAT(BLTZAL, BZ)
|
|
||||||
FORMAT(BLTZALL, BZ)
|
|
||||||
FORMAT(BLTZL, BZ)
|
|
||||||
FORMAT(BNE, BE)
|
|
||||||
FORMAT(BNEL, BE)
|
|
||||||
FORMAT(DDIV, R2)
|
|
||||||
FORMAT(DDIVU, R2)
|
|
||||||
FORMAT(DIV, R2)
|
|
||||||
FORMAT(DIVU, R2)
|
|
||||||
FORMAT(J, J)
|
|
||||||
FORMAT(JAL, J)
|
|
||||||
FORMAT(JALR, JR) // TODO: handle rd
|
|
||||||
FORMAT(JALX, J)
|
|
||||||
FORMAT(JR, JR)
|
|
||||||
FORMAT(LB, SL)
|
|
||||||
FORMAT(LBU, SL)
|
|
||||||
FORMAT(LH, SL)
|
|
||||||
FORMAT(LHU, SL)
|
|
||||||
FORMAT(LUI, SLI)
|
|
||||||
FORMAT(LW, SL)
|
|
||||||
FORMAT(LWL, SL)
|
|
||||||
FORMAT(LWR, SL)
|
|
||||||
FORMAT(MFHI, RD)
|
|
||||||
FORMAT(MFLO, RD)
|
|
||||||
FORMAT(MTHI, RS)
|
|
||||||
FORMAT(MTLO, RS)
|
|
||||||
FORMAT(MULT, R2)
|
|
||||||
FORMAT(MULTU, R2)
|
|
||||||
FORMAT(SB, SL)
|
|
||||||
FORMAT(SH, SL)
|
|
||||||
FORMAT(SW, SL)
|
|
||||||
FORMAT(SWL, SL)
|
|
||||||
FORMAT(SLL, S)
|
|
||||||
FORMAT(SLLV, SV)
|
|
||||||
FORMAT(SLT, R)
|
|
||||||
FORMAT(SLTI, I)
|
|
||||||
FORMAT(SLTIU, I)
|
|
||||||
FORMAT(SLTU, R)
|
|
||||||
FORMAT(SRA, S)
|
|
||||||
FORMAT(SRAV, SV)
|
|
||||||
FORMAT(SRL, S)
|
|
||||||
FORMAT(SRLV, SV)
|
|
||||||
FORMAT(SYSCALL, NONE)
|
|
||||||
FORMAT(OR, R)
|
|
||||||
FORMAT(ORI, I)
|
|
||||||
FORMAT(NOR, R)
|
|
||||||
FORMAT(SUB, R)
|
|
||||||
FORMAT(SUBU, R)
|
|
||||||
FORMAT(XOR, R)
|
|
||||||
FORMAT(XORI, I)
|
|
||||||
};
|
|
||||||
|
|
||||||
#undef FORMAT
|
|
||||||
|
|
||||||
#define MAX5 32
|
|
||||||
#define MAX16 65536
|
|
||||||
#define MAX26 67108864
|
|
||||||
|
|
||||||
static int get_reference(struct parser *parser, uint32_t *offset,
|
|
||||||
enum reference_type type)
|
|
||||||
{
|
|
||||||
struct token token;
|
|
||||||
|
|
||||||
if (next_token(parser, &token))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (token.type == TOK_NUMBER) {
|
|
||||||
*offset = token.number;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (token.type != TOK_IDENT) {
|
|
||||||
ERROR_POS(token, "unexpected token of type '%s'",
|
|
||||||
token_str(token.type));
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct reference reference = {
|
|
||||||
.section = parser->sec_tbl.current,
|
|
||||||
.index = parser->sec_tbl.current->count,
|
|
||||||
.type = type,
|
|
||||||
};
|
|
||||||
strcpy(reference.name, token.text);
|
|
||||||
|
|
||||||
if (reftbl_push(&parser->ref_tbl, reference))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
*offset = 0;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_offset(struct parser *parser, uint32_t *offset)
|
|
||||||
{
|
|
||||||
return get_reference(parser, offset, REF_OFFESET);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_target(struct parser *parser, uint32_t *offset)
|
|
||||||
{
|
|
||||||
return get_reference(parser, offset, REF_TARGET);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_instruction(const char *ident, struct mips32_instruction *res)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < __MIPS32_INS_LEN; i++) {
|
|
||||||
struct mips32_instruction ins =
|
|
||||||
mips32_instructions[i];
|
|
||||||
if (strcasecmp(ident, ins.name) == 0) {
|
|
||||||
if (res != NULL)
|
|
||||||
*res = ins;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int is_instruction(const char *ident)
|
|
||||||
{
|
|
||||||
return get_instruction(ident, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_register(struct parser *parser, enum mips32_register *reg)
|
|
||||||
{
|
|
||||||
struct token token;
|
|
||||||
if (assert_token(parser, TOK_REG, &token))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
int len = strlen(token.text);
|
|
||||||
int c0 = len > 0 ? token.text[0] : '\0',
|
|
||||||
c1 = len > 1 ? token.text[1] : '\0',
|
|
||||||
c2 = len > 2 ? token.text[2] : '\0',
|
|
||||||
c3 = len > 3 ? token.text[3] : '\0';
|
|
||||||
|
|
||||||
// $zero
|
|
||||||
if (c0 == 'z') {
|
|
||||||
if (c1 == 'e' && c2 == 'r' && c3 == 'o') {
|
|
||||||
*reg = MIPS32_REG_ZERO;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// $a0-a3 $at
|
|
||||||
else if (c0 == 'a') {
|
|
||||||
if (c1 == 't') {
|
|
||||||
*reg = MIPS32_REG_AT;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
if (c1 >= '0' && c1 <= '3') {
|
|
||||||
*reg = MIPS32_REG_A0;
|
|
||||||
*reg += c1 - '0';
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// $v0-v1
|
|
||||||
else if (c0 == 'v') {
|
|
||||||
if (c1 >= '0' && c1 <= '1') {
|
|
||||||
*reg = MIPS32_REG_V0;
|
|
||||||
*reg += c1 - '0';
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// $t0-t9
|
|
||||||
else if (c0 == 't') {
|
|
||||||
if (c1 >= '0' && c1 <= '7') {
|
|
||||||
*reg = MIPS32_REG_T0;
|
|
||||||
*reg += c1 - '0';
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
// reg T8-T9 are not in order with T0-T7
|
|
||||||
if (c1 >= '8' && c1 <= '9') {
|
|
||||||
*reg = MIPS32_REG_T8;
|
|
||||||
*reg += c1 - '8';
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// $s0-s7 $sp
|
|
||||||
else if (c0 == 's') {
|
|
||||||
if (c1 >= '0' && c1 <= '7') {
|
|
||||||
*reg = MIPS32_REG_S0;
|
|
||||||
*reg += c1 - '0';
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
if (c1 == 'p') {
|
|
||||||
*reg = MIPS32_REG_SP;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// $k0-k1
|
|
||||||
else if (c0 == 'k') {
|
|
||||||
if (c1 >= '0' && c1 <= '1') {
|
|
||||||
*reg = MIPS32_REG_K0;
|
|
||||||
*reg += c1 - '0';
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// $gp
|
|
||||||
else if (c0 == 'g') {
|
|
||||||
if (c1 == 'p') {
|
|
||||||
*reg = MIPS32_REG_GP;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// $fp
|
|
||||||
else if (c0 == 'f') {
|
|
||||||
if (c1 == 'p') {
|
|
||||||
*reg = MIPS32_REG_FP;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// $rp
|
|
||||||
else if (c0 == 'r') {
|
|
||||||
if (c1 == 'p') {
|
|
||||||
*reg = MIPS32_REG_RA;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// $0-31 (non aliased register names)
|
|
||||||
else if (c0 >= '0' && c0 <= '9') {
|
|
||||||
int i = c0 - '0';
|
|
||||||
if (c1 >= '0' && c1 <= '9') {
|
|
||||||
i *= 10;
|
|
||||||
i += c1 - '0';
|
|
||||||
}
|
|
||||||
if (i <= 31) {
|
|
||||||
*reg = i;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ERROR_POS(token, "unknown register $%s", token.text);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_instruction_r(struct parser *parser,
|
|
||||||
struct mips32_instruction *ins)
|
|
||||||
{
|
|
||||||
// format: rs, rt, rd
|
|
||||||
enum mips32_register reg;
|
|
||||||
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->R_data.rd = reg;
|
|
||||||
|
|
||||||
if (assert_token(parser, TOK_COMMA, NULL))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->R_data.rs = reg;
|
|
||||||
|
|
||||||
if (assert_token(parser, TOK_COMMA, NULL))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->R_data.rt = reg;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_instruction_r2(struct parser *parser,
|
|
||||||
struct mips32_instruction *ins)
|
|
||||||
{
|
|
||||||
// format: rs, rt
|
|
||||||
enum mips32_register reg;
|
|
||||||
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->R_data.rs = reg;
|
|
||||||
|
|
||||||
if (assert_token(parser, TOK_COMMA, NULL))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->R_data.rt = reg;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_instruction_rs(struct parser *parser,
|
|
||||||
struct mips32_instruction *ins)
|
|
||||||
{
|
|
||||||
// format: rs
|
|
||||||
enum mips32_register reg;
|
|
||||||
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->R_data.rs = reg;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_instruction_rd(struct parser *parser,
|
|
||||||
struct mips32_instruction *ins)
|
|
||||||
{
|
|
||||||
// format: rd
|
|
||||||
enum mips32_register reg;
|
|
||||||
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->R_data.rd = reg;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_instruction_i(struct parser *parser,
|
|
||||||
struct mips32_instruction *ins)
|
|
||||||
{
|
|
||||||
// format: rs, rt, immd
|
|
||||||
enum mips32_register reg;
|
|
||||||
struct token token;
|
|
||||||
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->I_data.rt = reg;
|
|
||||||
|
|
||||||
if (assert_token(parser, TOK_COMMA, NULL))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->I_data.rs = reg;
|
|
||||||
|
|
||||||
if (assert_token(parser, TOK_COMMA, NULL))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (assert_token(parser, TOK_NUMBER, &token))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (token.number >= MAX16)
|
|
||||||
return M_ERROR;
|
|
||||||
ins->I_data.immd = token.number;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_instruction_offset(struct parser *parser,
|
|
||||||
uint32_t max,
|
|
||||||
struct mips32_instruction *ins)
|
|
||||||
{
|
|
||||||
uint32_t n;
|
|
||||||
if (get_offset(parser, &n) || n > max)
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
switch (max) {
|
|
||||||
case MAX26:
|
|
||||||
ins->J_data.target = n;
|
|
||||||
break;
|
|
||||||
case MAX16:
|
|
||||||
ins->B_data.offset = n;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_instruction_j(struct parser *parser,
|
|
||||||
struct mips32_instruction *ins)
|
|
||||||
{
|
|
||||||
uint32_t n;
|
|
||||||
if (get_target(parser, &n) || n > MAX26)
|
|
||||||
return M_ERROR;
|
|
||||||
ins->J_data.target = n;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_instruction_jr(struct parser *parser,
|
|
||||||
struct mips32_instruction *ins)
|
|
||||||
{
|
|
||||||
uint32_t n;
|
|
||||||
if (get_target(parser, &n) || n > MAX26)
|
|
||||||
return M_ERROR;
|
|
||||||
ins->J_data.target = n;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_instruction_branch_equal(struct parser *parser,
|
|
||||||
struct mips32_instruction *ins)
|
|
||||||
{
|
|
||||||
enum mips32_register reg;
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->R_data.rs = reg;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_instruction_branch(struct parser *parser,
|
|
||||||
struct mips32_instruction *ins)
|
|
||||||
{
|
|
||||||
enum mips32_register reg;
|
|
||||||
uint32_t n;
|
|
||||||
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->B_data.rs = reg;
|
|
||||||
|
|
||||||
if (assert_token(parser, TOK_COMMA, NULL))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (get_offset(parser, &n) || n > MAX16)
|
|
||||||
return M_ERROR;
|
|
||||||
ins->B_data.offset = n;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_instruction_sl(struct parser *parser,
|
|
||||||
struct mips32_instruction *ins)
|
|
||||||
{
|
|
||||||
enum mips32_register reg;
|
|
||||||
uint32_t offset = 0;
|
|
||||||
struct token token;
|
|
||||||
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->I_data.rt = reg;
|
|
||||||
|
|
||||||
if (assert_token(parser, TOK_COMMA, NULL))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (peek_token(parser, &token))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (token.type != TOK_LPAREN)
|
|
||||||
if (get_offset(parser, &offset))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->I_data.immd = offset;
|
|
||||||
|
|
||||||
if (peek_token(parser, &token))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (token.type == TOK_NL) {
|
|
||||||
ins->I_data.rs = MIPS32_REG_ZERO;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (assert_token(parser, TOK_LPAREN, NULL))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->I_data.rs = reg;
|
|
||||||
|
|
||||||
if (assert_token(parser, TOK_RPAREN, NULL))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_instruction_sli(struct parser *parser,
|
|
||||||
struct mips32_instruction *ins)
|
|
||||||
{
|
|
||||||
enum mips32_register reg;
|
|
||||||
struct token token;
|
|
||||||
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->I_data.rt = reg;
|
|
||||||
|
|
||||||
if (assert_token(parser, TOK_COMMA, NULL))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (assert_token(parser, TOK_NUMBER, &token) || token.number > MAX16)
|
|
||||||
return M_ERROR;
|
|
||||||
ins->I_data.immd = token.number;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_instruction_s(struct parser *parser,
|
|
||||||
struct mips32_instruction *ins)
|
|
||||||
{
|
|
||||||
enum mips32_register reg;
|
|
||||||
struct token token;
|
|
||||||
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->R_data.rd = reg;
|
|
||||||
|
|
||||||
if (assert_token(parser, TOK_COMMA, NULL))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->R_data.rt = reg;
|
|
||||||
|
|
||||||
if (assert_token(parser, TOK_COMMA, NULL))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (assert_token(parser, TOK_NUMBER, &token) || token.number > MAX5)
|
|
||||||
return M_ERROR;
|
|
||||||
ins->R_data.shamt = token.number;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_instruction_sv(struct parser *parser,
|
|
||||||
struct mips32_instruction *ins)
|
|
||||||
{
|
|
||||||
enum mips32_register reg;
|
|
||||||
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->R_data.rd = reg;
|
|
||||||
|
|
||||||
if (assert_token(parser, TOK_COMMA, NULL))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->R_data.rt = reg;
|
|
||||||
|
|
||||||
if (assert_token(parser, TOK_COMMA, NULL))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (parse_register(parser, ®))
|
|
||||||
return M_ERROR;
|
|
||||||
ins->R_data.rs = reg;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_instruction(struct parser *parser,
|
|
||||||
union mips_instruction *ins,
|
|
||||||
struct token ident)
|
|
||||||
{
|
|
||||||
struct mips32_instruction instruction;
|
|
||||||
enum mips32_parse_format format;
|
|
||||||
int res = M_SUCCESS;
|
|
||||||
|
|
||||||
if (get_instruction(ident.text, &instruction)) {
|
|
||||||
ERROR_POS(ident, "unknown instruction '%s'", ident.text);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
ins->mips32 = instruction;
|
|
||||||
format = mips32_parse_formats[instruction.type];
|
|
||||||
|
|
||||||
switch (format) {
|
|
||||||
case MIPS32_PARSE_R:
|
|
||||||
res = parse_instruction_r(parser, &ins->mips32);
|
|
||||||
break;
|
|
||||||
case MIPS32_PARSE_R2:
|
|
||||||
res = parse_instruction_r2(parser, &ins->mips32);
|
|
||||||
break;
|
|
||||||
case MIPS32_PARSE_RS:
|
|
||||||
res = parse_instruction_rs(parser, &ins->mips32);
|
|
||||||
break;
|
|
||||||
case MIPS32_PARSE_RD:
|
|
||||||
res = parse_instruction_rd(parser, &ins->mips32);
|
|
||||||
break;
|
|
||||||
case MIPS32_PARSE_I:
|
|
||||||
res = parse_instruction_i(parser, &ins->mips32);
|
|
||||||
break;
|
|
||||||
case MIPS32_PARSE_J:
|
|
||||||
res = parse_instruction_j(parser, &ins->mips32);
|
|
||||||
break;
|
|
||||||
case MIPS32_PARSE_JR:
|
|
||||||
res = parse_instruction_jr(parser, &ins->mips32);
|
|
||||||
break;
|
|
||||||
case MIPS32_PARSE_O16:
|
|
||||||
res = parse_instruction_offset(parser, MAX16, &ins->mips32);
|
|
||||||
break;
|
|
||||||
case MIPS32_PARSE_O26:
|
|
||||||
res = parse_instruction_offset(parser, MAX26, &ins->mips32);
|
|
||||||
break;
|
|
||||||
case MIPS32_PARSE_BE:
|
|
||||||
res = parse_instruction_branch_equal(parser, &ins->mips32);
|
|
||||||
break;
|
|
||||||
case MIPS32_PARSE_BZ:
|
|
||||||
res = parse_instruction_branch(parser, &ins->mips32);
|
|
||||||
break;
|
|
||||||
case MIPS32_PARSE_SL:
|
|
||||||
res = parse_instruction_sl(parser, &ins->mips32);
|
|
||||||
break;
|
|
||||||
case MIPS32_PARSE_SLI:
|
|
||||||
res = parse_instruction_sli(parser, &ins->mips32);
|
|
||||||
break;
|
|
||||||
case MIPS32_PARSE_S:
|
|
||||||
res = parse_instruction_s(parser, &ins->mips32);
|
|
||||||
break;
|
|
||||||
case MIPS32_PARSE_SV:
|
|
||||||
res = parse_instruction_sv(parser, &ins->mips32);
|
|
||||||
break;
|
|
||||||
case MIPS32_PARSE_NONE:
|
|
||||||
res = M_SUCCESS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res == M_SUCCESS && assert_eol(parser))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int parse_directive_align(struct parser *parser,
|
|
||||||
struct mips32_directive *directive)
|
|
||||||
{
|
|
||||||
struct token token;
|
|
||||||
if (assert_token(parser, TOK_NUMBER, &token))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (token.number < 0) {
|
|
||||||
ERROR_POS(token, "cannot align negative");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (token.number > MAX16) {
|
|
||||||
ERROR_POS(token, "cannot align more than 65kb");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
directive->type = MIPS32_DIRECTIVE_ALIGN;
|
|
||||||
directive->align = token.number;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_directive_space(struct parser *parser,
|
|
||||||
struct mips32_directive *directive)
|
|
||||||
{
|
|
||||||
struct token token;
|
|
||||||
if (assert_token(parser, TOK_NUMBER, &token))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (token.number < 0) {
|
|
||||||
ERROR_POS(token, "cannot reserve negative");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (token.number > MAX16) {
|
|
||||||
ERROR_POS(token, "cannot reserve more than 65kb");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
directive->type = MIPS32_DIRECTIVE_SPACE;
|
|
||||||
directive->space = token.number;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_directive_whb(struct parser *parser,
|
|
||||||
struct mips32_directive *directive,
|
|
||||||
enum mips32_directive_type type)
|
|
||||||
{
|
|
||||||
struct token token;
|
|
||||||
uint32_t size = 0;
|
|
||||||
uint32_t len = 0;
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case MIPS32_DIRECTIVE_WORD:
|
|
||||||
size = UINT32_MAX;
|
|
||||||
break;
|
|
||||||
case MIPS32_DIRECTIVE_HALF:
|
|
||||||
size = UINT16_MAX;
|
|
||||||
break;
|
|
||||||
case MIPS32_DIRECTIVE_BYTE:
|
|
||||||
size = UINT8_MAX;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
directive->type = type;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
if (assert_token(parser, TOK_NUMBER, &token))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (len >= MAX_ARG_LENGTH) {
|
|
||||||
ERROR_POS(token, "directives cannot be longer than "
|
|
||||||
"%d arguments", MAX_ARG_LENGTH);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (token.number > size) {
|
|
||||||
ERROR_POS(token, "number cannot execede max size of: "
|
|
||||||
"%d", size);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case MIPS32_DIRECTIVE_WORD:
|
|
||||||
directive->words[len++] = token.number;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case MIPS32_DIRECTIVE_HALF:
|
|
||||||
directive->halfs[len++] = token.number;
|
|
||||||
break;
|
|
||||||
case MIPS32_DIRECTIVE_BYTE:
|
|
||||||
directive->bytes[len++] = token.number;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
if (peek_token(parser, &token))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
if (token.type == TOK_COMMA) {
|
|
||||||
next_token(parser, NULL);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
directive->len = len;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_directive_extern(struct parser *parser,
|
|
||||||
struct mips32_directive *directive)
|
|
||||||
{
|
|
||||||
struct token token;
|
|
||||||
if (assert_token(parser, TOK_IDENT, &token))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
directive->type = MIPS32_DIRECTIVE_EXTERN;
|
|
||||||
strcpy(directive->name, token.text);
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_directive_globl(struct parser *parser,
|
|
||||||
struct mips32_directive *directive)
|
|
||||||
{
|
|
||||||
struct token token;
|
|
||||||
if (assert_token(parser, TOK_IDENT, &token))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
directive->type = MIPS32_DIRECTIVE_GLOBL;
|
|
||||||
strcpy(directive->name, token.text);
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_section(struct mips32_directive *directive,
|
|
||||||
char name[MAX_LEX_LENGTH])
|
|
||||||
{
|
|
||||||
directive->type = MIPS32_DIRECTIVE_SECTION;
|
|
||||||
strcpy(directive->name, name);
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_directive(struct parser *parser,
|
|
||||||
union mips_directive *directive)
|
|
||||||
{
|
|
||||||
struct token token;
|
|
||||||
if (assert_token(parser, TOK_DIRECTIVE, &token))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
// .align n
|
|
||||||
if (strcmp(token.text, "align") == 0)
|
|
||||||
return parse_directive_align(parser, &directive->mips32);
|
|
||||||
else if (strcmp(token.text, "space") == 0)
|
|
||||||
return parse_directive_space(parser, &directive->mips32);
|
|
||||||
else if (strcmp(token.text, "word") == 0)
|
|
||||||
return parse_directive_whb(parser, &directive->mips32,
|
|
||||||
MIPS32_DIRECTIVE_WORD);
|
|
||||||
else if (strcmp(token.text, "half") == 0)
|
|
||||||
return parse_directive_whb(parser, &directive->mips32,
|
|
||||||
MIPS32_DIRECTIVE_HALF);
|
|
||||||
else if (strcmp(token.text, "byte") == 0)
|
|
||||||
return parse_directive_whb(parser, &directive->mips32,
|
|
||||||
MIPS32_DIRECTIVE_BYTE);
|
|
||||||
else if (strcmp(token.text, "extern") == 0)
|
|
||||||
return parse_directive_extern(parser, &directive->mips32);
|
|
||||||
else if (strcmp(token.text, "globl") == 0)
|
|
||||||
return parse_directive_globl(parser, &directive->mips32);
|
|
||||||
else
|
|
||||||
return parse_section(&directive->mips32, token.text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mips32_parser_init(struct parser *parser)
|
|
||||||
{
|
|
||||||
parser->parse_instruction = parse_instruction;
|
|
||||||
parser->is_instruction = is_instruction;
|
|
||||||
parser->parse_directive = parse_directive;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mips32_parser_free(struct parser *parser)
|
|
||||||
{
|
|
||||||
parser_free(parser);
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
/* Copyright (c) 2024 Freya Murphy */
|
|
||||||
|
|
||||||
#ifndef __PARSE_MIPS32_H__
|
|
||||||
#define __PARSE_MIPS32_H__
|
|
||||||
|
|
||||||
#include "parse.h"
|
|
||||||
|
|
||||||
/* initzlize a mips32 parser vtable */
|
|
||||||
void mips32_parser_init(struct parser *parser);
|
|
||||||
|
|
||||||
/* free the mips32 parser */
|
|
||||||
void mips32_parser_free(struct parser *parser);
|
|
||||||
|
|
||||||
#endif /* __PARSE_MIPS32_H__ */
|
|
|
@ -1,47 +0,0 @@
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <mips.h>
|
|
||||||
#include <merror.h>
|
|
||||||
#include <mlimits.h>
|
|
||||||
|
|
||||||
#include "parse.h"
|
|
||||||
|
|
||||||
#define RELTBL_INIT_LEN 8
|
|
||||||
|
|
||||||
int reftbl_init(struct reference_table *ref_tbl)
|
|
||||||
{
|
|
||||||
ref_tbl->len = RELTBL_INIT_LEN;
|
|
||||||
ref_tbl->count = 0;
|
|
||||||
ref_tbl->references = malloc(sizeof(struct reference) *
|
|
||||||
RELTBL_INIT_LEN);
|
|
||||||
|
|
||||||
if (ref_tbl->references == NULL) {
|
|
||||||
ERROR("cannot alloc");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reftbl_free(struct reference_table *ref_tbl)
|
|
||||||
{
|
|
||||||
free(ref_tbl->references);
|
|
||||||
}
|
|
||||||
|
|
||||||
int reftbl_push(struct reference_table *ref_tbl, struct reference reference)
|
|
||||||
{
|
|
||||||
if (ref_tbl->count >= ref_tbl->len) {
|
|
||||||
ref_tbl->len *= 2;
|
|
||||||
ref_tbl->references = realloc(ref_tbl->references,
|
|
||||||
sizeof(struct reference) * ref_tbl->len);
|
|
||||||
|
|
||||||
if (ref_tbl->references == NULL) {
|
|
||||||
ERROR("cannot realloc");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ref_tbl->references[ref_tbl->count++] = reference;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
43
masm/reltab.c
Normal file
43
masm/reltab.c
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#include <elf.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <merror.h>
|
||||||
|
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
|
#define RELTAB_INIT_LEN 8
|
||||||
|
|
||||||
|
int reltab_init(struct relocation_table *reltab)
|
||||||
|
{
|
||||||
|
reltab->size = RELTAB_INIT_LEN;
|
||||||
|
reltab->len = 0;
|
||||||
|
reltab->data = malloc(sizeof(Elf32_Rela) * RELTAB_INIT_LEN);
|
||||||
|
|
||||||
|
if (reltab->data == NULL) {
|
||||||
|
ERROR("cannot alloc");
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reltab_free(struct relocation_table *reltab)
|
||||||
|
{
|
||||||
|
free(reltab->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
int reltab_push(struct relocation_table *reltab, const Elf32_Rela rel)
|
||||||
|
{
|
||||||
|
if (reltab->len >= reltab->size) {
|
||||||
|
reltab->size *= 2;
|
||||||
|
reltab->data = realloc(reltab->data, sizeof(Elf32_Rela)
|
||||||
|
* reltab->size);
|
||||||
|
|
||||||
|
if (reltab->data == NULL) {
|
||||||
|
ERROR("cannot realloc");
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reltab->data[reltab->len++] = rel;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
166
masm/sectab.c
Normal file
166
masm/sectab.c
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <mips.h>
|
||||||
|
#include <merror.h>
|
||||||
|
#include <mlimits.h>
|
||||||
|
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
|
#define SECTBL_INIT_LEN 8
|
||||||
|
static const char inital_section[MAX_LEX_LENGTH] = "data";
|
||||||
|
|
||||||
|
int sectab_init(struct section_table *sectab)
|
||||||
|
{
|
||||||
|
sectab->size = SECTBL_INIT_LEN;
|
||||||
|
sectab->len = 0;
|
||||||
|
sectab->sections = malloc(sizeof(struct section) * SECTBL_INIT_LEN);
|
||||||
|
|
||||||
|
if (sectab->sections == NULL) {
|
||||||
|
ERROR("cannot alloc");
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sectab_alloc(sectab, §ab->current, inital_section))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sectab_free(struct section_table *sectab)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < sectab->len; i++) {
|
||||||
|
reltab_free(§ab->sections[i].reltab);
|
||||||
|
free(sectab->sections[i].entries);
|
||||||
|
}
|
||||||
|
free(sectab->sections);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct section_settings {
|
||||||
|
const char *name;
|
||||||
|
bool read;
|
||||||
|
bool write;
|
||||||
|
bool execute;
|
||||||
|
size_t align;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct section_settings default_section_settings[] = {
|
||||||
|
{"data", true, true, false, 1},
|
||||||
|
{"bss", true, true, false, 1},
|
||||||
|
{"rodata", true, false, false, 1},
|
||||||
|
{"text", true, false, true, 4},
|
||||||
|
};
|
||||||
|
|
||||||
|
int sectab_alloc(struct section_table *sectab, struct section **res,
|
||||||
|
const char name[MAX_LEX_LENGTH])
|
||||||
|
{
|
||||||
|
if (sectab->len >= sectab->size) {
|
||||||
|
sectab->size *= 2;
|
||||||
|
sectab->sections = realloc(sectab->sections,
|
||||||
|
sizeof(struct section) * sectab->size);
|
||||||
|
|
||||||
|
if (sectab->sections == NULL) {
|
||||||
|
ERROR("cannot realloc");
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set the sectio defaults */
|
||||||
|
struct section *sec;
|
||||||
|
sec = §ab->sections[sectab->len];
|
||||||
|
strcpy(sec->name,name);
|
||||||
|
sec->len = 0;
|
||||||
|
sec->size = SECTBL_INIT_LEN;
|
||||||
|
sec->alignment = 1;
|
||||||
|
sec->read = true;
|
||||||
|
sec->write = true;
|
||||||
|
sec->execute = false;
|
||||||
|
sec->index = sectab->len;
|
||||||
|
sec->entries = malloc(sizeof(struct section_entry) * SECTBL_INIT_LEN);
|
||||||
|
|
||||||
|
if (reltab_init(&sec->reltab))
|
||||||
|
return M_ERROR;
|
||||||
|
|
||||||
|
/* overwrite the default if the given name has their own
|
||||||
|
* defaults */
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
struct section_settings *set = &default_section_settings[i];
|
||||||
|
if (strcmp(set->name, name) == 0) {
|
||||||
|
sec->read = set->read;
|
||||||
|
sec->write = set->write;
|
||||||
|
sec->execute = set->execute;
|
||||||
|
sec->alignment = set->align;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sec->entries == NULL) {
|
||||||
|
ERROR("cannot alloc");
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
sectab->len++;
|
||||||
|
|
||||||
|
*res = sec;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sectab_get(struct section_table *sectab, struct section **sec,
|
||||||
|
const char name[MAX_LEX_LENGTH])
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < sectab->len; i++) {
|
||||||
|
struct section *temp = §ab->sections[i];
|
||||||
|
if (strcmp(name, temp->name) == 0) {
|
||||||
|
if (sec != NULL)
|
||||||
|
*sec = temp;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sec_push(struct section *section, struct section_entry entry)
|
||||||
|
{
|
||||||
|
if (section->len >= section->size) {
|
||||||
|
section->size *= 2;
|
||||||
|
void *new = realloc(section->entries,
|
||||||
|
sizeof(struct section_entry) * section->size);
|
||||||
|
|
||||||
|
if (new == NULL) {
|
||||||
|
ERROR("cannot realloc");
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
section->entries = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
section->entries[section->len++] = entry;
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sec_size(struct section *sec)
|
||||||
|
{
|
||||||
|
size_t n = 0;
|
||||||
|
for (size_t i = 0; i < sec->len; i++) {
|
||||||
|
size_t t = sec->entries[i].size;
|
||||||
|
size_t m = t % sec->alignment;
|
||||||
|
if (m)
|
||||||
|
t += sec->alignment - m;
|
||||||
|
n += t;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sec_index(struct section *sec, size_t idx)
|
||||||
|
{
|
||||||
|
size_t n = 0;
|
||||||
|
for (size_t i = 0; i < idx; i++) {
|
||||||
|
size_t t = sec->entries[i].size;
|
||||||
|
size_t m = t % sec->alignment;
|
||||||
|
if (m)
|
||||||
|
t += sec->alignment - m;
|
||||||
|
n += t;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
159
masm/sectbl.c
159
masm/sectbl.c
|
@ -1,159 +0,0 @@
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <mips.h>
|
|
||||||
#include <merror.h>
|
|
||||||
#include <mlimits.h>
|
|
||||||
|
|
||||||
#include "parse.h"
|
|
||||||
|
|
||||||
#define SECTBL_INIT_LEN 8
|
|
||||||
static const char inital_section[MAX_LEX_LENGTH] = "data";
|
|
||||||
|
|
||||||
int sectbl_init(struct section_table *sec_tbl)
|
|
||||||
{
|
|
||||||
sec_tbl->len = SECTBL_INIT_LEN;
|
|
||||||
sec_tbl->count = 0;
|
|
||||||
sec_tbl->sections = malloc(sizeof(struct section) * SECTBL_INIT_LEN);
|
|
||||||
|
|
||||||
if (sec_tbl->sections == NULL) {
|
|
||||||
ERROR("cannot alloc");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sectbl_alloc(sec_tbl, &sec_tbl->current, inital_section))
|
|
||||||
return M_ERROR;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sectbl_free(struct section_table *sec_tbl)
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < sec_tbl->count; i++) {
|
|
||||||
free(sec_tbl->sections[i].entries);
|
|
||||||
}
|
|
||||||
free(sec_tbl->sections);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct section_settings {
|
|
||||||
const char *name;
|
|
||||||
bool read;
|
|
||||||
bool write;
|
|
||||||
bool execute;
|
|
||||||
uint32_t align;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct section_settings default_section_settings[] = {
|
|
||||||
{"data", true, true, false, 1},
|
|
||||||
{"bss", true, true, false, 1},
|
|
||||||
{"rodata", true, false, false, 1},
|
|
||||||
{"text", true, false, true, 4},
|
|
||||||
};
|
|
||||||
|
|
||||||
int sectbl_alloc(struct section_table *sec_tbl, struct section **sec,
|
|
||||||
const char name[MAX_LEX_LENGTH])
|
|
||||||
{
|
|
||||||
if (sec_tbl->count >= sec_tbl->len) {
|
|
||||||
sec_tbl->len *= 2;
|
|
||||||
sec_tbl->sections = realloc(sec_tbl->sections,
|
|
||||||
sizeof(struct section) * sec_tbl->len);
|
|
||||||
|
|
||||||
if (sec_tbl->sections == NULL) {
|
|
||||||
ERROR("cannot realloc");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct section *temp;
|
|
||||||
temp = &sec_tbl->sections[sec_tbl->count];
|
|
||||||
strcpy(temp->name,name);
|
|
||||||
temp->count = 0;
|
|
||||||
temp->len = SECTBL_INIT_LEN;
|
|
||||||
temp->alignment = 1;
|
|
||||||
temp->read = true;
|
|
||||||
temp->write = true;
|
|
||||||
temp->execute = false;
|
|
||||||
temp->index = sec_tbl->count;
|
|
||||||
temp->entries = malloc(sizeof(struct section_entry) * SECTBL_INIT_LEN);
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
struct section_settings *set = &default_section_settings[i];
|
|
||||||
if (strcmp(set->name, name) == 0) {
|
|
||||||
temp->read = set->read;
|
|
||||||
temp->write = set->write;
|
|
||||||
temp->execute = set->execute;
|
|
||||||
temp->alignment = set->align;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (temp->entries == NULL) {
|
|
||||||
ERROR("cannot alloc");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
sec_tbl->count++;
|
|
||||||
|
|
||||||
*sec = temp;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sectbl_get(struct section_table *sec_tbl, struct section **sec,
|
|
||||||
const char name[MAX_LEX_LENGTH])
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < sec_tbl->count; i++) {
|
|
||||||
struct section *temp = &sec_tbl->sections[i];
|
|
||||||
if (strcmp(name, temp->name) == 0) {
|
|
||||||
if (sec != NULL)
|
|
||||||
*sec = temp;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sec_push(struct section *section, struct section_entry entry)
|
|
||||||
{
|
|
||||||
if (section->count >= section->len) {
|
|
||||||
section->len *= 2;
|
|
||||||
void *new = realloc(section->entries,
|
|
||||||
sizeof(struct section_entry) * section->len);
|
|
||||||
|
|
||||||
if (new == NULL) {
|
|
||||||
ERROR("cannot realloc");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
section->entries = new;
|
|
||||||
}
|
|
||||||
|
|
||||||
section->entries[section->count++] = entry;
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t sec_size(struct section *sec)
|
|
||||||
{
|
|
||||||
size_t n = 0;
|
|
||||||
for (uint32_t i = 0; i < sec->count; i++) {
|
|
||||||
size_t t = sec->entries[i].size;
|
|
||||||
size_t m = t % sec->alignment;
|
|
||||||
if (m)
|
|
||||||
t += sec->alignment - m;
|
|
||||||
n += t;
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t sec_index(struct section *sec, uint32_t idx)
|
|
||||||
{
|
|
||||||
size_t n = 0;
|
|
||||||
for (uint32_t i = 0; i < idx; i++) {
|
|
||||||
size_t t = sec->entries[i].size;
|
|
||||||
size_t m = t % sec->alignment;
|
|
||||||
if (m)
|
|
||||||
t += sec->alignment - m;
|
|
||||||
n += t;
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
54
masm/strtab.c
Normal file
54
masm/strtab.c
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#include <merror.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
|
int strtab_get_str(struct str_table *strtab, const char *str, size_t *res)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < strtab->size; i ++) {
|
||||||
|
if (strcmp(strtab->ptr + i, str) == 0) {
|
||||||
|
if (res != NULL)
|
||||||
|
*res = i;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
int strtab_write_str(struct str_table *strtab, const char *str, size_t *res)
|
||||||
|
{
|
||||||
|
if (strtab_get_str(strtab, str, res) == M_SUCCESS)
|
||||||
|
return M_SUCCESS;
|
||||||
|
|
||||||
|
size_t len = strlen(str);
|
||||||
|
char *new = realloc(strtab->ptr, strtab->size + len + 1);
|
||||||
|
if (new == NULL)
|
||||||
|
return M_ERROR;
|
||||||
|
strtab->ptr = new;
|
||||||
|
memcpy(strtab->ptr + strtab->size, str, len + 1);
|
||||||
|
|
||||||
|
if (res != NULL)
|
||||||
|
*res = strtab->size;
|
||||||
|
|
||||||
|
strtab->size += len + 1;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int strtab_init(struct str_table *strtab)
|
||||||
|
{
|
||||||
|
strtab->size = 1;
|
||||||
|
strtab->ptr = malloc(1);
|
||||||
|
if (strtab->ptr == NULL) {
|
||||||
|
ERROR("cannot alloc");
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
*strtab->ptr = '\0';
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void strtab_free(struct str_table *strtab)
|
||||||
|
{
|
||||||
|
free(strtab->ptr);
|
||||||
|
}
|
|
@ -1,54 +0,0 @@
|
||||||
#include <merror.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "asm.h"
|
|
||||||
|
|
||||||
int strtbl_get_str(struct str_table *str_tbl, const char *str, size_t *res)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < str_tbl->size; i ++) {
|
|
||||||
if (strcmp(str_tbl->ptr + i, str) == 0) {
|
|
||||||
if (res != NULL)
|
|
||||||
*res = i;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
int strtbl_write_str(struct str_table *str_tbl, const char *str, size_t *res)
|
|
||||||
{
|
|
||||||
if (strtbl_get_str(str_tbl, str, res) == M_SUCCESS)
|
|
||||||
return M_SUCCESS;
|
|
||||||
|
|
||||||
size_t len = strlen(str);
|
|
||||||
char *new = realloc(str_tbl->ptr, str_tbl->size + len + 1);
|
|
||||||
if (new == NULL)
|
|
||||||
return M_ERROR;
|
|
||||||
str_tbl->ptr = new;
|
|
||||||
memcpy(str_tbl->ptr + str_tbl->size, str, len + 1);
|
|
||||||
|
|
||||||
if (res != NULL)
|
|
||||||
*res = str_tbl->size;
|
|
||||||
|
|
||||||
str_tbl->size += len + 1;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int strtbl_init(struct str_table *str_tbl)
|
|
||||||
{
|
|
||||||
str_tbl->size = 1;
|
|
||||||
str_tbl->ptr = malloc(1);
|
|
||||||
if (str_tbl->ptr == NULL) {
|
|
||||||
ERROR("cannot alloc");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
*str_tbl->ptr = '\0';
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
void strtbl_free(struct str_table *str_tbl)
|
|
||||||
{
|
|
||||||
free(str_tbl->ptr);
|
|
||||||
}
|
|
70
masm/symtab.c
Normal file
70
masm/symtab.c
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#include <elf.h>
|
||||||
|
#include <merror.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "asm.h"
|
||||||
|
|
||||||
|
#define SYMTBL_INIT_LEN 24
|
||||||
|
|
||||||
|
int symtab_init(struct symbol_table *symtab)
|
||||||
|
{
|
||||||
|
symtab->size = SYMTBL_INIT_LEN;
|
||||||
|
symtab->len = 0;
|
||||||
|
symtab->symbols = malloc(sizeof(Elf32_Sym) * SYMTBL_INIT_LEN);
|
||||||
|
symtab->sections = malloc(sizeof(ssize_t) * SYMTBL_INIT_LEN);
|
||||||
|
|
||||||
|
if (symtab->symbols == NULL || symtab->sections == NULL) {
|
||||||
|
ERROR("cannot alloc");
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void symtab_free(struct symbol_table *symtab)
|
||||||
|
{
|
||||||
|
free(symtab->symbols);
|
||||||
|
free(symtab->sections);
|
||||||
|
}
|
||||||
|
|
||||||
|
int symtab_push(struct symbol_table *symtab, Elf32_Sym sym, ssize_t sec_idx)
|
||||||
|
{
|
||||||
|
if (symtab->len >= symtab->size) {
|
||||||
|
symtab->size *= 2;
|
||||||
|
symtab->symbols = realloc(symtab->symbols,
|
||||||
|
sizeof(Elf32_Sym) * symtab->size);
|
||||||
|
symtab->sections = realloc(symtab->sections,
|
||||||
|
sizeof(ssize_t) * symtab->size);
|
||||||
|
if (symtab->symbols == NULL || symtab->sections == NULL) {
|
||||||
|
ERROR("cannot realloc");
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
symtab->symbols[symtab->len] = sym;
|
||||||
|
symtab->sections[symtab->len++] = sec_idx;
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int symtab_find(struct symbol_table *symtab, Elf32_Sym **ptr,
|
||||||
|
size_t *idx, const char name[MAX_LEX_LENGTH])
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < symtab->len; i++) {
|
||||||
|
Elf32_Sym *sym = &symtab->symbols[i];
|
||||||
|
const char *str = &symtab->strtab->ptr[sym->st_name];
|
||||||
|
if (strcmp(str, name) == 0) {
|
||||||
|
if (ptr != NULL)
|
||||||
|
*ptr = sym;
|
||||||
|
|
||||||
|
ptrdiff_t diff = sym - symtab->symbols;
|
||||||
|
if (idx != NULL)
|
||||||
|
*idx = diff / sizeof(Elf32_Sym);
|
||||||
|
|
||||||
|
return M_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
|
@ -1,57 +0,0 @@
|
||||||
#include <merror.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "asm.h"
|
|
||||||
|
|
||||||
#define SYMTBL_INIT_LEN 24
|
|
||||||
|
|
||||||
int symtbl_init(struct symbol_table *sym_tbl)
|
|
||||||
{
|
|
||||||
sym_tbl->len = SYMTBL_INIT_LEN;
|
|
||||||
sym_tbl->count = 0;
|
|
||||||
sym_tbl->symbols = malloc(sizeof(struct symbol) * SYMTBL_INIT_LEN);
|
|
||||||
|
|
||||||
if (sym_tbl->symbols == NULL) {
|
|
||||||
ERROR("cannot alloc");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
void symtbl_free(struct symbol_table *sym_tbl)
|
|
||||||
{
|
|
||||||
free(sym_tbl->symbols);
|
|
||||||
}
|
|
||||||
|
|
||||||
int symtbl_push(struct symbol_table *sym_tbl, struct symbol sym)
|
|
||||||
{
|
|
||||||
if (sym_tbl->count >= sym_tbl->len) {
|
|
||||||
sym_tbl->len *= 2;
|
|
||||||
sym_tbl->symbols = realloc(sym_tbl->symbols,
|
|
||||||
sizeof(struct symbol) * sym_tbl->len);
|
|
||||||
if (sym_tbl->symbols == NULL) {
|
|
||||||
ERROR("cannot relloc");
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sym_tbl->symbols[sym_tbl->count++] = sym;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int symtbl_find(struct symbol_table *sym_tbl, struct symbol **ptr,
|
|
||||||
const char name[MAX_LEX_LENGTH])
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < sym_tbl->count; i++) {
|
|
||||||
struct symbol *sym = &sym_tbl->symbols[i];
|
|
||||||
if (strcmp(sym->name, name) == 0) {
|
|
||||||
if (ptr != NULL)
|
|
||||||
*ptr = sym;
|
|
||||||
return M_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
Loading…
Reference in a new issue