refactor masm to add codegen step

This commit is contained in:
Freya Murphy 2024-10-04 19:41:10 -04:00
parent b2ca1c9e98
commit 1c11a13ff3
Signed by: freya
GPG key ID: 744AB800E383AE52
23 changed files with 2793 additions and 2679 deletions

View file

@ -32,7 +32,7 @@ static const Elf32_Ehdr MIPS_ELF_EHDR =
.e_machine = B16(EM_MIPS),
.e_version = B32(EV_CURRENT),
.e_entry = 0x00,
.e_flags = B32(EF_MIPS_ARCH_32R6),
.e_flags = 0x00, // B32(EF_MIPS_ARCH_32R6),
.e_ehsize = B16(sizeof(Elf32_Ehdr)),
.e_phentsize = B16(sizeof(Elf32_Phdr)),
.e_shentsize = B16(sizeof(Elf32_Shdr)),

View file

@ -8,8 +8,8 @@
/* Error codes
*/
#define M_SUCCESS 0
#define M_EOF 1
#define M_ERROR -1
#define M_ERROR 1
#define M_EOF 2
#define __DEBUG 1
#define __WARNING 2

View file

@ -1,467 +0,0 @@
/* Copyright (c) 2024 Freya Murphy */
#ifndef __MIPS_H__
#define __MIPS_H__
#include <mlimits.h>
#include <stdint.h>
/* all mips registers $0-$31 */
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,
};
/* mips instructions */
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_DIV,
MIPS_INS_MOD,
MIPS_INS_DIVU,
MIPS_INS_MODU,
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_MFHI,
MIPS_INS_MFLO,
MIPS_INS_MTHI,
MIPS_INS_MTLO,
MIPS_INS_MUL,
MIPS_INS_MUH,
MIPS_INS_MULU,
MIPS_INS_MUHU,
MIPS_INS_SB,
MIPS_INS_SH,
MIPS_INS_SW,
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,
};
union mips_instruction_data {
/* raw ins */
uint32_t raw : 32;
/* register type */
struct {
uint32_t funct : 6;
uint32_t shamt : 5;
uint32_t rd : 5;
uint32_t rt : 5;
uint32_t rs : 5;
uint32_t op : 6;
};
/* immediate type */
struct {
uint32_t immd : 16;
uint32_t : 16;
};
/* jump type */
struct {
uint32_t target : 26;
uint32_t : 6;
};
/* branch compact */
struct {
int32_t offs26 : 26;
uint32_t : 6;
};
/* branch */
struct {
int32_t offset : 16;
uint32_t bfunct : 5;
uint32_t : 11;
};
} __attribute__((packed));
/* mips instruction information */
struct mips_instruction {
// metadata
enum mips_instruction_type type;
const char *name;
// data
union mips_instruction_data data;
};
#define MIPS_INS(ins, ...) \
[MIPS_INS_ ##ins] = { \
MIPS_INS_ ##ins, \
#ins, \
.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, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_ADD)
/* ADDI - add immediate */
#define MIPS_OP_ADDI 0b001000
MIPS_INS(ADDI, .op = MIPS_OP_ADDI)
/* ADDIU - add immediate unsigned */
#define MIPS_OP_ADDIU 0b001001
MIPS_INS(ADDIU, .op = MIPS_OP_ADDIU)
/* ADDU - add unsigned */
#define MIPS_FUNCT_ADDU 0b100001
MIPS_INS(ADDU, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_ADDU)
/* AND - and */
#define MIPS_FUNCT_AND 0b100100
MIPS_INS(AND, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_AND)
/* ANDI - and immediate */
#define MIPS_OP_ANDI 0b001100
MIPS_INS(ANDI, .op = MIPS_OP_ANDI)
/* BAL - branch and link */
#define MIPS_OP_REGIMM 0b000001
#define MIPS_FUNCT_BAL 0b10001
MIPS_INS(BAL, .op = MIPS_OP_REGIMM, .bfunct = MIPS_FUNCT_BAL)
/* BALC - branch and link, compact */
#define MIPS_OP_BALC 0b111010
MIPS_INS(BALC, .op = MIPS_OP_BALC)
/* BC - branch, compact */
#define MIPS_OP_BC 0b110010
MIPS_INS(BC, .op = MIPS_OP_BC)
/* BEQ - branch on equal */
#define MIPS_OP_BEQ 0b000100
MIPS_INS(BEQ, .op = MIPS_OP_BEQ)
/* BEQL - branch on equal likely */
#define MIPS_OP_BEQL 0b010100
MIPS_INS(BEQL, .op = MIPS_OP_BEQL)
/* BGEZ - branch on greater than or equal to zero */
#define MIPS_FUNCT_BGEZ 0b00001
MIPS_INS(BGEZ, .op = MIPS_OP_REGIMM, .bfunct = MIPS_FUNCT_BGEZ)
/* BGEZAL - branch on greater than or equal to zero and link */
#define MIPS_FUNCT_BGEZAL 0b10001
MIPS_INS(BGEZAL, .op = MIPS_OP_REGIMM, .bfunct = MIPS_FUNCT_BGEZAL)
/* BGEZAL - branch on greater than or equal to zero and link likely */
#define MIPS_FUNCT_BGEZALL 0b10011
MIPS_INS(BGEZALL, .op = MIPS_OP_REGIMM, .bfunct = MIPS_FUNCT_BGEZALL)
/* BGEZL - branch on greater than or equal to zero likely */
#define MIPS_FUNCT_BGEZL 0b00011
MIPS_INS(BGEZL, .op = MIPS_OP_REGIMM, .bfunct = MIPS_FUNCT_BGEZL)
/* BGTZ - branch on greater than zero */
#define MIPS_OP_BGTZ 0b000111
MIPS_INS(BGTZ, .op = MIPS_OP_BGTZ)
/* BGTZL - branch on greater than zero likely */
#define MIPS_OP_BGTZL 0b010111
MIPS_INS(BGTZL, .op = MIPS_OP_BGTZL)
/* BLEZ - branch on less than or equal to zero */
#define MIPS_OP_BLEZ 0b000110
MIPS_INS(BLEZ, .op = MIPS_OP_BLEZ)
/* BLEZL - branch on less than or equal to zero likely */
#define MIPS_OP_BLEZL 0b010110
MIPS_INS(BLEZL, .op = MIPS_OP_BLEZL)
/* BLTZ - branch on less than zero */
#define MIPS_FUNCT_BLTZ 0b00000
MIPS_INS(BLTZ, .op = MIPS_OP_REGIMM, .bfunct = MIPS_FUNCT_BLTZ)
/* BLTZAL - branch on less than zero and link */
#define MIPS_FUNCT_BLTZAL 0b10000
MIPS_INS(BLTZAL, .op = MIPS_OP_REGIMM, .bfunct = MIPS_FUNCT_BLTZAL)
/* BLTZALL - branch on less than zero and link likely */
#define MIPS_FUNCT_BLTZALL 0b10010
MIPS_INS(BLTZALL, .op = MIPS_OP_REGIMM, .bfunct = MIPS_FUNCT_BLTZALL)
/* BLTZL - branch on less than zero likely */
#define MIPS_FUNCT_BLTZL 0b00010
MIPS_INS(BLTZL, .op = MIPS_OP_REGIMM, .bfunct = MIPS_FUNCT_BLTZL)
/* BNE - branch on not equal */
#define MIPS_OP_BNE 0b000101
MIPS_INS(BNE, .op = MIPS_OP_BNE)
/* BNEL - branch on not equal likely */
#define MIPS_OP_BNEL 0b010101
MIPS_INS(BNEL, .op = MIPS_OP_BNEL)
/* DIV - divide */
#define MIPS_FUNCT_SOP32 0b011010
#define MIPS_SOP32_DIV 0b00010
MIPS_INS(DIV, .op = MIPS_OP_SPECIAL, .shamt = MIPS_SOP32_DIV,
.funct = MIPS_FUNCT_SOP32)
/* MOD - modulo */
#define MIPS_SOP32_MOD 0b00011
MIPS_INS(MOD, .op = MIPS_OP_SPECIAL, .shamt = MIPS_SOP32_MOD,
.funct = MIPS_FUNCT_SOP32)
/* DIVU - divide unsigned */
#define MIPS_FUNCT_SOP33 0b011011
#define MIPS_SOP33_DIVU 0b00010
MIPS_INS(DIVU, .op = MIPS_OP_SPECIAL, .shamt = MIPS_SOP33_DIVU,
.funct = MIPS_FUNCT_SOP33)
/* MODU - modulo unsigned */
#define MIPS_SOP33_MODU 0b00011
MIPS_INS(MODU, .op = MIPS_OP_SPECIAL, .shamt = MIPS_SOP33_MODU,
.funct = MIPS_FUNCT_SOP33)
/* J - jump */
#define MIPS_OP_J 0b000010
MIPS_INS(J, .op = MIPS_OP_J)
/* JAL - jump and link */
#define MIPS_OP_JAL 0b000011
MIPS_INS(JAL, .op = MIPS_OP_JAL)
/* JALR - jump and link register */
#define MIPS_FUNCT_JALR 0b001001
MIPS_INS(JALR, .rd = MIPS_REG_RA, .op = MIPS_OP_SPECIAL,
.funct = MIPS_FUNCT_JALR)
/* JALX - jump and link exchange */
#define MIPS_OP_JALX 0b011101
MIPS_INS(JALX, .op = MIPS_OP_JALX)
/* JR - jump register */
#define MIPS_FUNCT_JR 0b001000
MIPS_INS(JR, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_JR)
/* LB - load byte */
#define MIPS_OP_LB 0b100000
MIPS_INS(LB, .op = MIPS_OP_LB)
/* LBU - load byte unsigned */
#define MIPS_OP_LBU 0b100100
MIPS_INS(LBU, .op = MIPS_OP_LBU)
/* LH - load half */
#define MIPS_OP_LH 0b100001
MIPS_INS(LH, .op = MIPS_OP_LH)
/* LHU - load half unsigned */
#define MIPS_OP_LHU 0b100101
MIPS_INS(LHU, .op = MIPS_OP_LHU)
/* LUI - load upper immediate */
#define MIPS_OP_LUI 0b001111
MIPS_INS(LUI, .op = MIPS_OP_LUI)
/* LW - load word */
#define MIPS_OP_LW 0b100011
MIPS_INS(LW, .op = MIPS_OP_LW)
/* MFHI - move from hi */
#define MIPS_FUNCT_MFHI 0b010000
MIPS_INS(MFHI, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_MFHI)
/* MFLO - move from hi */
#define MIPS_FUNCT_MFLO 0b010010
MIPS_INS(MFLO, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_MFLO)
/* MTHI - move from hi */
#define MIPS_FUNCT_MTHI 0b010001
MIPS_INS(MTHI, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_MTHI)
/* MTLO - move from hi */
#define MIPS_FUNCT_MTLO 0b010011
MIPS_INS(MTLO, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_MTLO)
/* MUL - multiply low word */
#define MIPS_FUNCT_SOP30 0b011000
#define MIPS_SOP30_MUL 0b00010
MIPS_INS(MUL, .op = MIPS_OP_SPECIAL, .shamt = MIPS_SOP30_MUL,
.funct = MIPS_FUNCT_SOP30)
/* MUH - multiply high word */
#define MIPS_SOP30_MUH 0b00011
MIPS_INS(MUH, .op = MIPS_OP_SPECIAL, .shamt = MIPS_SOP30_MUH,
.funct = MIPS_FUNCT_SOP30)
/* MULU - multiply low word unsigned */
#define MIPS_FUNCT_SOP31 0b011001
#define MIPS_SOP31_MULU 0b00010
MIPS_INS(MULU, .op = MIPS_OP_SPECIAL, .shamt = MIPS_SOP31_MULU,
.funct = MIPS_FUNCT_SOP31)
/* MUHU - multiply high word unsgined */
#define MIPS_SOP31_MUHU 0b00011
MIPS_INS(MUHU, .op = MIPS_OP_SPECIAL, .shamt = MIPS_SOP31_MUHU,
.funct = MIPS_FUNCT_SOP31)
/* SB - store byte */
#define MIPS_OP_SB 0b101000
MIPS_INS(SB, .op = MIPS_OP_SB)
/* SH - store half */
#define MIPS_OP_SH 0b101001
MIPS_INS(SH, .op = MIPS_OP_SH)
/* SW - store word */
#define MIPS_OP_SW 0b101011
MIPS_INS(SW, .op = MIPS_OP_SW)
/* SLL - shift left logical */
#define MIPS_FUNCT_SLL 0b000000
MIPS_INS(SLL, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SLL)
/* SLLV - shift left logical variable */
#define MIPS_FUNCT_SLLV 0b000100
MIPS_INS(SLLV, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SLLV)
/* SLT - set less then */
#define MIPS_FUNCT_SLT 0b101010
MIPS_INS(SLT, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SLT)
/* SLTI - set less then immediate */
#define MIPS_OP_SLTI 0b001010
MIPS_INS(SLTI, .op = MIPS_OP_SLTI)
/* SLTIU - set less then imemdiate unsigned */
#define MIPS_OP_SLTIU 0b001011
MIPS_INS(SLTIU, .op = MIPS_OP_SLTIU)
/* SLTU - set less than unsigned */
#define MIPS_FUNCT_SLTU 0b101011
MIPS_INS(SLTU, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SLTU)
/* SRA - shift right arithmetic */
#define MIPS_FUNCT_SRA 0b000011
MIPS_INS(SRA, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SRA)
/* SRAV - shift right arithmetic variable */
#define MIPS_FUNCT_SRAV 0b000111
MIPS_INS(SRAV, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SRAV)
/* SRL - shift right logical */
#define MIPS_FUNCT_SRL 0b000010
MIPS_INS(SRL, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SRL)
/* SRLV - shift right logical variable */
#define MIPS_FUNCT_SRLV 0b000110
MIPS_INS(SRLV, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SRLV)
/* SUB - subtract */
#define MIPS_FUNCT_SUB 0b100010
MIPS_INS(SUB, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SUB)
/* SUBU - subtract unsigned */
#define MIPS_FUNCT_SUBU 0b100011
MIPS_INS(SUBU, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SUBU)
/* SYSCALL - syscall */
#define MIPS_FUNCT_SYSCALL 0b001100
MIPS_INS(SYSCALL, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_SYSCALL)
/* OR - or */
#define MIPS_FUNCT_OR 0b100101
MIPS_INS(OR, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_OR)
/* ORI - or imemdiate */
#define MIPS_OP_ORI 0b001101
MIPS_INS(ORI, .op = MIPS_OP_ORI)
/* NOR - not or */
#define MIPS_FUNCT_NOR 0b100111
MIPS_INS(NOR, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_NOR)
/* XOR - exclusive or */
#define MIPS_FUNCT_XOR 0b100110
MIPS_INS(XOR, .op = MIPS_OP_SPECIAL, .funct = MIPS_FUNCT_XOR)
/* XORI - exclusive or immediate */
#define MIPS_OP_XORI 0b001110
MIPS_INS(XORI, .op = MIPS_OP_XORI)
};
#undef MIPS_INS
#endif /* __MIPS_H__ */

142
include/mips32.h Normal file
View file

@ -0,0 +1,142 @@
/* Copyright (c) 2024 Freya Murphy */
#ifndef __MIPS32_H__
#define __MIPS32_H__
#include <stddef.h>
#include <stdint.h>
#include <mlimits.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 */
union mips32_instruction {
/* raw ins */
uint32_t raw : 32;
/* register type */
struct {
uint32_t funct : 6;
uint32_t shamt : 5;
uint32_t rd : 5;
uint32_t rt : 5;
uint32_t rs : 5;
uint32_t op : 6;
};
/* immediate type */
struct {
uint32_t immd : 16;
uint32_t : 16;
};
/* jump type */
struct {
uint32_t target : 26;
uint32_t : 6;
};
/* branch compact */
struct {
int32_t offs26 : 26;
uint32_t : 6;
};
/* branch */
struct {
int32_t offset : 16;
uint32_t bfunct : 5;
uint32_t : 11;
};
} __attribute__((packed));
/// grammer syntax:
///
/// ... the grammer takes entries parsed from the instruction,
/// and updates the instructions with values based on the type
/// of entry. i.e. immd would require a immd in the next argument,
/// and update the low 16bits of the instruction.
///
/// GRAMMER -> ENTRIES
/// GRAMMER -> ε
/// ENTRIES -> ENTRIES, ENTRY
/// ENTRY -> rd // i.e. $at
/// ENTRY -> rs
/// ENTRY -> rt
/// ENTRY -> immd // i.e. 0x80
/// ENTRY -> offset // i.e. main (16bits)
/// ENTRY -> offest(base) // i.e. 4($sp)
/// ENTRY -> target // i.e. main (28bits shifted)
///
/// // grammer entries are always defined onto themselves... meaning the
/// // name of their type directly corresponds to the mips field in the
/// // instruction
///
/// pseudo grammer syntax:
///
/// ... psuedo entries represents what values should be placed where
/// in each of the pseudo instructions. psuedo grammer is extended such
/// that hardcoded values can be returned. i.e. setting rt=$at
///
/// GRAMMER -> ENTRIES
/// GRAMMER -> ε
/// ENTREIS -> ENTRIES, ENTRYSET
/// ENTRYSET -> ENTRY | SET
/// SET -> ENTRY = <REGISTER>
/// ENTRY -> <GRAMMER: ENTRY> // i.e. any valid entry from grammer synax
/// ENTRY -> hi // high 16bits of <target> into <immd>
/// ENTRY -> lo // low 16bits of <target> into <immd>
/* mips grammer */
struct mips32_grammer {
// the name of the ins
char *name;
// the grammer of the ins
char *grammer;
// the index of the ins (if real)
int enum_index;
// for pseudo instructions only
int pseudo_len;
struct mips32__pseudo_grammer {
// what instruction is this
// part in the pseudo instruction
int enum_index;
// what parts of the instruction
// to update with values from
// grammer
char *update;
} pseudo_grammer[MAX_ARG_LENGTH];
};
#endif /* __MIPS32_H__ */

158
include/mips32r6.h Normal file
View file

@ -0,0 +1,158 @@
/* Copyright (c) 2024 Freya Murphy */
#ifndef __MIPS32R6_H__
#define __MIPS32R6_H__
#include <mlimits.h>
#include <stdint.h>
#include <mips32.h>
/* mips instructions */
enum mips32r6_instruction_type {
MIPS32R6_INS_ADD,
MIPS32R6_INS_ADDI,
MIPS32R6_INS_ADDIU,
MIPS32R6_INS_ADDU,
MIPS32R6_INS_AND,
MIPS32R6_INS_ANDI,
MIPS32R6_INS_BAL,
MIPS32R6_INS_BALC,
MIPS32R6_INS_BC,
MIPS32R6_INS_BEQ,
MIPS32R6_INS_BGEZ,
MIPS32R6_INS_BGEZAL,
MIPS32R6_INS_BGTZ,
MIPS32R6_INS_BLEZ,
MIPS32R6_INS_BLTZ,
MIPS32R6_INS_BLTZAL,
MIPS32R6_INS_BNE,
MIPS32R6_INS_DIV,
MIPS32R6_INS_MOD,
MIPS32R6_INS_DIVU,
MIPS32R6_INS_MODU,
MIPS32R6_INS_J,
MIPS32R6_INS_JAL,
MIPS32R6_INS_JALR,
MIPS32R6_INS_JALX,
MIPS32R6_INS_JR,
MIPS32R6_INS_LB,
MIPS32R6_INS_LBU,
MIPS32R6_INS_LH,
MIPS32R6_INS_LHU,
MIPS32R6_INS_LUI,
MIPS32R6_INS_LW,
MIPS32R6_INS_MUL,
MIPS32R6_INS_MUH,
MIPS32R6_INS_MULU,
MIPS32R6_INS_MUHU,
MIPS32R6_INS_SB,
MIPS32R6_INS_SH,
MIPS32R6_INS_SW,
MIPS32R6_INS_SLL,
MIPS32R6_INS_SLLV,
MIPS32R6_INS_SLT,
MIPS32R6_INS_SLTI,
MIPS32R6_INS_SLTIU,
MIPS32R6_INS_SLTU,
MIPS32R6_INS_SRA,
MIPS32R6_INS_SRAV,
MIPS32R6_INS_SRL,
MIPS32R6_INS_SRLV,
MIPS32R6_INS_SUB,
MIPS32R6_INS_SUBU,
MIPS32R6_INS_SYSCALL,
MIPS32R6_INS_OR,
MIPS32R6_INS_ORI,
MIPS32R6_INS_NOR,
MIPS32R6_INS_XOR,
MIPS32R6_INS_XORI,
__MIPS32R6_INS_NULL,
};
#define MIPS32R6_OP_SPECIAL 0b000000
#define MIPS32R6_OP_ADDI 0b001000
#define MIPS32R6_OP_ADDIU 0b001001
#define MIPS32R6_OP_ANDI 0b001100
#define MIPS32R6_OP_REGIMM 0b000001
#define MIPS32R6_OP_BALC 0b111010
#define MIPS32R6_OP_BC 0b110010
#define MIPS32R6_OP_BEQ 0b000100
#define MIPS32R6_OP_BEQL 0b010100
#define MIPS32R6_OP_BGTZ 0b000111
#define MIPS32R6_OP_BGTZL 0b010111
#define MIPS32R6_OP_BLEZ 0b000110
#define MIPS32R6_OP_BLEZL 0b010110
#define MIPS32R6_OP_BNE 0b000101
#define MIPS32R6_OP_BNEL 0b010101
#define MIPS32R6_OP_J 0b000010
#define MIPS32R6_OP_JAL 0b000011
#define MIPS32R6_OP_JALX 0b011101
#define MIPS32R6_OP_LB 0b100000
#define MIPS32R6_OP_LBU 0b100100
#define MIPS32R6_OP_LH 0b100001
#define MIPS32R6_OP_LHU 0b100101
#define MIPS32R6_OP_LUI 0b001111
#define MIPS32R6_OP_LW 0b100011
#define MIPS32R6_OP_SB 0b101000
#define MIPS32R6_OP_SH 0b101001
#define MIPS32R6_OP_SW 0b101011
#define MIPS32R6_OP_SLTI 0b001010
#define MIPS32R6_OP_SLTIU 0b001011
#define MIPS32R6_OP_ORI 0b001101
#define MIPS32R6_OP_XORI 0b001110
#define MIPS32R6_FUNCT_ADD 0b100000
#define MIPS32R6_FUNCT_ADDU 0b100001
#define MIPS32R6_FUNCT_AND 0b100100
#define MIPS32R6_FUNCT_SOP32 0b011010
#define MIPS32R6_FUNCT_SOP33 0b011011
#define MIPS32R6_FUNCT_JALR 0b001001
#define MIPS32R6_FUNCT_JR 0b001000
#define MIPS32R6_FUNCT_MFHI 0b010000
#define MIPS32R6_FUNCT_MFLO 0b010010
#define MIPS32R6_FUNCT_MTHI 0b010001
#define MIPS32R6_FUNCT_MTLO 0b010011
#define MIPS32R6_FUNCT_SOP30 0b011000
#define MIPS32R6_FUNCT_SOP31 0b011001
#define MIPS32R6_FUNCT_SLL 0b000000
#define MIPS32R6_FUNCT_SLLV 0b000100
#define MIPS32R6_FUNCT_SLT 0b101010
#define MIPS32R6_FUNCT_SLTU 0b101011
#define MIPS32R6_FUNCT_SRA 0b000011
#define MIPS32R6_FUNCT_SRAV 0b000111
#define MIPS32R6_FUNCT_SRL 0b000010
#define MIPS32R6_FUNCT_SRLV 0b000110
#define MIPS32R6_FUNCT_SUB 0b100010
#define MIPS32R6_FUNCT_SUBU 0b100011
#define MIPS32R6_FUNCT_SYSCALL 0b001100
#define MIPS32R6_FUNCT_OR 0b100101
#define MIPS32R6_FUNCT_NOR 0b100111
#define MIPS32R6_FUNCT_XOR 0b100110
#define MIPS32R6_FUNCT_BAL 0b10001
#define MIPS32R6_FUNCT_BGEZ 0b00001
#define MIPS32R6_FUNCT_BGEZAL 0b10001
#define MIPS32R6_FUNCT_BGEZALL 0b10011
#define MIPS32R6_FUNCT_BGEZL 0b00011
#define MIPS32R6_FUNCT_BLTZ 0b00000
#define MIPS32R6_FUNCT_BLTZAL 0b10000
#define MIPS32R6_FUNCT_BLTZALL 0b10010
#define MIPS32R6_FUNCT_BLTZL 0b00010
#define MIPS32R6_SOP30_MUL 0b00010
#define MIPS32R6_SOP30_MUH 0b00011
#define MIPS32R6_SOP31_MULU 0b00010
#define MIPS32R6_SOP31_MUHU 0b00011
#define MIPS32R6_SOP32_DIV 0b00010
#define MIPS32R6_SOP32_MOD 0b00011
#define MIPS32R6_SOP33_DIVU 0b00010
#define MIPS32R6_SOP33_MODU 0b00011
#define __MIPS32R6_INS_LEN (__MIPS32R6_INS_NULL)
#define __MIPS32R6_PSEUDO_LEN (4)
#define __MIPS32R6_GRAMMER_LEN (__MIPS32R6_INS_LEN + __MIPS32R6_PSEUDO_LEN)
extern struct mips32_grammer mips32r6_grammers[__MIPS32R6_GRAMMER_LEN];
extern union mips32_instruction mips32r6_instructions[__MIPS32R6_INS_LEN];
#endif /* __MIPS32R6_H__ */

286
lib/mips32r6.c Normal file
View file

@ -0,0 +1,286 @@
#include <mips32r6.h>
#define RTYPE "rd,rs,rt"
#define ITYPE "rt,rs,immd"
#define JTYPE "target"
#define LOAD "rt,offset(base)"
#define SHIFT "rd,rt,sa"
#define SHIFTV "rd,rt,rs"
#define BRANCH "rs,rt,offset"
#define BRANCHZ "rs,offset"
#define INS(name, grammer) {#name, grammer, MIPS32R6_INS_ ##name, \
/* pseudo stub */ 0, {{0, ""}}}
#define PSEUDO(name, grammer, ...) {name, grammer, __MIPS32R6_INS_NULL, \
__VA_ARGS__ }
struct mips32_grammer mips32r6_grammers[__MIPS32R6_GRAMMER_LEN] = {
// real instructions
INS(ADD, RTYPE),
INS(ADDI, ITYPE),
INS(ADDIU, ITYPE),
INS(ADDU, RTYPE),
INS(AND, RTYPE),
INS(ADDI, ITYPE),
INS(ANDI, ITYPE),
INS(BAL, "offset"),
INS(BALC, "target"),
INS(BC, "target"),
INS(BEQ, BRANCH),
INS(BGEZ, BRANCHZ),
INS(BGEZAL, BRANCHZ),
INS(BGTZ, BRANCHZ),
INS(BLEZ, BRANCHZ),
INS(BLTZ, BRANCHZ),
INS(BLTZAL, BRANCHZ),
INS(BNE, BRANCH),
INS(DIV, RTYPE),
INS(MOD, RTYPE),
INS(DIVU, RTYPE),
INS(MODU, RTYPE),
INS(J, JTYPE),
INS(JAL, JTYPE),
INS(JALR, "rs"),
INS(JR, "rs"),
INS(LB, LOAD),
INS(LBU, LOAD),
INS(LH, LOAD),
INS(LHU, LOAD),
INS(LUI, "rt,immd"),
INS(LW, LOAD),
INS(MUL, RTYPE),
INS(MUH, RTYPE),
INS(MULU, RTYPE),
INS(MUHU, RTYPE),
INS(SB, LOAD),
INS(SH, LOAD),
INS(SW, LOAD),
INS(SLL, SHIFT),
INS(SLLV, SHIFTV),
INS(SLT, RTYPE),
INS(SLTI, ITYPE),
INS(SLTIU, ITYPE),
INS(SLTU, RTYPE),
INS(SRA, SHIFT),
INS(SRAV, SHIFTV),
INS(SRL, SHIFT),
INS(SRLV, SHIFT),
INS(SUB, RTYPE),
INS(SUBU, RTYPE),
INS(SYSCALL, ""),
INS(OR, RTYPE),
INS(ORI, ITYPE),
INS(NOR, RTYPE),
INS(XOR, RTYPE),
INS(XORI, ITYPE),
// pseudo instructions
PSEUDO("li", "rt,immd", 1, {
{MIPS32R6_INS_ADDI, "rt,immd"}
}),
PSEUDO("la", "rt,target", 2, {
{MIPS32R6_INS_LUI, "rt=$at,hi"},
{MIPS32R6_INS_ORI, "rt,rs=$at,lo"},
}),
PSEUDO("move", "rd,rs", 1, {
{MIPS32R6_INS_OR, "rd,rs"}
}),
PSEUDO("nop", "", 1, {
{MIPS32R6_INS_SLL, ""},
}),
};
#define MIPS_INS(ins, ...) \
[MIPS32R6_INS_ ##ins] = { __VA_ARGS__ },
union mips32_instruction mips32r6_instructions[__MIPS32R6_INS_LEN] = {
/* ADD - add */
MIPS_INS(ADD, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_ADD)
/* ADDI - add immediate */
MIPS_INS(ADDI, .op = MIPS32R6_OP_ADDI)
/* ADDIU - add immediate unsigned */
MIPS_INS(ADDIU, .op = MIPS32R6_OP_ADDIU)
/* ADDU - add unsigned */
MIPS_INS(ADDU, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_ADDU)
/* AND - and */
MIPS_INS(AND, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_AND)
/* ANDI - and immediate */
MIPS_INS(ANDI, .op = MIPS32R6_OP_ANDI)
/* BAL - branch and link */
MIPS_INS(BAL, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_BAL)
/* BALC - branch and link, compact */
MIPS_INS(BALC, .op = MIPS32R6_OP_BALC)
/* BC - branch, compact */
MIPS_INS(BC, .op = MIPS32R6_OP_BC)
/* BEQ - branch on equal */
MIPS_INS(BEQ, .op = MIPS32R6_OP_BEQ)
/* BGEZ - branch on greater than or equal to zero */
MIPS_INS(BGEZ, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_BGEZ)
/* BGEZAL - branch on greater than or equal to zero and link */
MIPS_INS(BGEZAL, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_BGEZAL)
/* BGTZ - branch on greater than zero */
MIPS_INS(BGTZ, .op = MIPS32R6_OP_BGTZ)
/* BLEZ - branch on less than or equal to zero */
MIPS_INS(BLEZ, .op = MIPS32R6_OP_BLEZ)
/* BLTZ - branch on less than zero */
MIPS_INS(BLTZ, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_BLTZ)
/* BLTZAL - branch on less than zero and link */
MIPS_INS(BLTZAL, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_BLTZAL)
/* BNE - branch on not equal */
MIPS_INS(BNE, .op = MIPS32R6_OP_BNE)
/* DIV - divide */
MIPS_INS(DIV, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP32_DIV,
.funct = MIPS32R6_FUNCT_SOP32)
/* MOD - modulo */
MIPS_INS(MOD, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP32_MOD,
.funct = MIPS32R6_FUNCT_SOP32)
/* DIVU - divide unsigned */
MIPS_INS(DIVU, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP33_DIVU,
.funct = MIPS32R6_FUNCT_SOP33)
/* MODU - modulo unsigned */
MIPS_INS(MODU, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP33_MODU,
.funct = MIPS32R6_FUNCT_SOP33)
/* J - jump */
MIPS_INS(J, .op = MIPS32R6_OP_J)
/* JAL - jump and link */
MIPS_INS(JAL, .op = MIPS32R6_OP_JAL)
/* JALR - jump and link register */
MIPS_INS(JALR, .rd = MIPS32_REG_RA, .op = MIPS32R6_OP_SPECIAL,
.funct = MIPS32R6_FUNCT_JALR)
/* JALX - jump and link exchange */
MIPS_INS(JALX, .op = MIPS32R6_OP_JALX)
/* JR - jump register */
MIPS_INS(JR, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_JR)
/* LB - load byte */
MIPS_INS(LB, .op = MIPS32R6_OP_LB)
/* LBU - load byte unsigned */
MIPS_INS(LBU, .op = MIPS32R6_OP_LBU)
/* LH - load half */
MIPS_INS(LH, .op = MIPS32R6_OP_LH)
/* LHU - load half unsigned */
MIPS_INS(LHU, .op = MIPS32R6_OP_LHU)
/* LUI - load upper immediate */
MIPS_INS(LUI, .op = MIPS32R6_OP_LUI)
/* LW - load word */
MIPS_INS(LW, .op = MIPS32R6_OP_LW)
/* MUL - multiply low word */
MIPS_INS(MUL, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP30_MUL,
.funct = MIPS32R6_FUNCT_SOP30)
/* MUH - multiply high word */
MIPS_INS(MUH, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP30_MUH,
.funct = MIPS32R6_FUNCT_SOP30)
/* MULU - multiply low word unsigned */
MIPS_INS(MULU, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP31_MULU,
.funct = MIPS32R6_FUNCT_SOP31)
/* MUHU - multiply high word unsgined */
MIPS_INS(MUHU, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP31_MUHU,
.funct = MIPS32R6_FUNCT_SOP31)
/* SB - store byte */
MIPS_INS(SB, .op = MIPS32R6_OP_SB)
/* SH - store half */
MIPS_INS(SH, .op = MIPS32R6_OP_SH)
/* SW - store word */
MIPS_INS(SW, .op = MIPS32R6_OP_SW)
/* SLL - shift left logical */
MIPS_INS(SLL, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_SLL)
/* SLLV - shift left logical variable */
MIPS_INS(SLLV, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_SLLV)
/* SLT - set less then */
MIPS_INS(SLT, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_SLT)
/* SLTI - set less then immediate */
MIPS_INS(SLTI, .op = MIPS32R6_OP_SLTI)
/* SLTIU - set less then imemdiate unsigned */
MIPS_INS(SLTIU, .op = MIPS32R6_OP_SLTIU)
/* SLTU - set less than unsigned */
MIPS_INS(SLTU, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_SLTU)
/* SRA - shift right arithmetic */
MIPS_INS(SRA, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_SRA)
/* SRAV - shift right arithmetic variable */
MIPS_INS(SRAV, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_SRAV)
/* SRL - shift right logical */
MIPS_INS(SRL, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_SRL)
/* SRLV - shift right logical variable */
MIPS_INS(SRLV, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_SRLV)
/* SUB - subtract */
MIPS_INS(SUB, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_SUB)
/* SUBU - subtract unsigned */
MIPS_INS(SUBU, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_SUBU)
/* SYSCALL - syscall */
MIPS_INS(SYSCALL, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_SYSCALL)
/* OR - or */
MIPS_INS(OR, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_OR)
/* ORI - or imemdiate */
MIPS_INS(ORI, .op = MIPS32R6_OP_ORI)
/* NOR - not or */
MIPS_INS(NOR, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_NOR)
/* XOR - exclusive or */
MIPS_INS(XOR, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_XOR)
/* XORI - exclusive or immediate */
MIPS_INS(XORI, .op = MIPS32R6_OP_XORI)
};
#undef MIPS_INS

View file

@ -3,7 +3,7 @@
CFLAGS += -std=gnu2x
# add include directory
CFLAGS += -isystem ../include
CFLAGS += -isystem ../include -DPREFIX=$(PREFIX)
INCLUDE += ../include
# add lib directory
@ -13,7 +13,7 @@ H_SRC = $(shell find $(SRC) $(INCLUDE) -type f -name "*.h")
C_SRC = $(shell find $(SRC) -type f -name "*.c")
C_OBJ = $(patsubst %.c,$(BIN)/%.o,$(C_SRC))
.PHONY: clean build run test
.PHONY: clean build run fuzz
build: $(BIN)/$(OUT)
@ -24,8 +24,8 @@ clean:
run: build
$(BIN)/$(OUT)
test:
make -C ../test $(OUT)
fuzz: clean
make -C . build CC=afl-cc LD=afl-cc
mkdir -p ../fuzz
rm -fr ../fuzz/$(OUT)
afl-fuzz -i ../test/$(OUT) -o ../fuzz -M $(OUT) -- $(BIN)/$(OUT) @@

View file

@ -1,5 +1,4 @@
#include <merror.h>
#include <mips.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
@ -9,8 +8,9 @@
#include <melf.h>
#include "asm.h"
#include "gen.h"
#include "mlimits.h"
#include "parse.h"
#include "tab.h"
extern char *current_file;
@ -19,325 +19,158 @@ extern char *current_file;
#define SEC_ALIGN 0x1000
static int create_symbol(struct assembler *assembler,
const char name[MAX_LEX_LENGTH],
ssize_t section_idx,
size_t section_offset,
unsigned char bind)
static int elf_rel_type(enum reference_type ty) {
switch (ty) {
case REF_NONE:
return R_MIPS_NONE;
case REF_MIPS_16:
return R_MIPS_16;
case REF_MIPS_26:
return R_MIPS_26;
case REF_MIPS_PC16:
return R_MIPS_PC16;
case REF_MIPS_LO16:
return R_MIPS_LO16;
case REF_MIPS_HI16:
return R_MIPS_HI16;
}
return R_MIPS_NONE;
}
static int elf_section_init_reltab(struct section *sec,
struct elf_section *elf_sec)
{
size_t str_off;
if (strtab_write_str(&assembler->strtab, name, &str_off))
Elf32_Rel *reltab = malloc(sizeof(Elf32_Rel) *
sec->reftab.len);
if (reltab == NULL) {
PERROR("cannot alloc");
return M_ERROR;
}
for (uint32_t i = 0; i < sec->reftab.len; i++) {
Elf32_Rel *rel = &reltab[i];
struct reference *ref = &sec->reftab.references[i];
rel->r_offset = B32(ref->offset);
int sym = ref->symbol->tabidx + 1;
int type = elf_rel_type(ref->type);
rel->r_info = B32(ELF32_R_INFO(sym, type));
}
Elf32_Sym symbol = {
.st_name = B32(str_off),
.st_value = B32(section_offset),
.st_size = 0,
.st_info = ELF32_ST_INFO(bind, STT_NOTYPE),
.st_other = ELF32_ST_VISIBILITY(STV_DEFAULT),
.st_shndx = B16(section_idx),
};
elf_sec->reltab_len = sec->reftab.len;
elf_sec->reltab = reltab;
// dont put magic flag values inside symbol, only real indexes
if (section_idx < 0)
symbol.st_shndx = 0;
return M_SUCCESS;
}
if (symtab_push(&assembler->symtab, symbol, section_idx))
static int elf_section_init(struct section *sec, struct elf_section *elf_sec)
{
elf_sec->data = sec;
elf_sec->shdr_idx = 0; // dont know yet
elf_sec->reltab_shidx = 0; // dont know yet
elf_sec->reltab_len = sec->reftab.len;
elf_sec->reltab = NULL;
if (sec->reftab.len && elf_section_init_reltab(sec, elf_sec))
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)
/* free an elf section */
static void elf_section_free(struct elf_section *sec)
{
if (symtab_find(&assembler->symtab, res, res2, name) == M_SUCCESS)
return M_SUCCESS;
if (sec->reltab != NULL)
free(sec->reltab);
}
if (create_symbol(assembler, name, SYMSEC_STUB, 0, STB_LOCAL))
static int asm_init_sections(struct assembler *assembler)
{
struct section *sections = assembler->gen.sections;
uint32_t len = assembler->gen.sections_len;
struct elf_section *elftab = malloc(sizeof(struct elf_section) * len);
if (elftab == NULL) {
PERROR("cannot alloc");
return M_ERROR;
}
size_t idx = assembler->symtab.len - 1;
if (res != NULL)
*res = &assembler->symtab.symbols[idx];
if (res2 != NULL)
*res2 = idx;
for (uint32_t i = 0; i < len; i++) {
struct elf_section *elfsec = &elftab[i];
elfsec->data = &sections[i];
if (elf_section_init(&sections[i], elfsec)) {
free(elftab);
return M_ERROR;
}
}
assembler->sections = elftab;
assembler->section_len = len;
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;
static int elf_sym_bind(enum symbol_type ty) {
switch (ty) {
case SYM_LOCAL:
return STB_LOCAL;
case SYM_GLOBAL:
return STB_GLOBAL;
case SYM_EXTERN:
return STB_GLOBAL;
}
case MIPS_DIRECTIVE_ALIGN: {
assembler->sectab.current->alignment =
1 << directive->align;
if (assembler->sectab.current->alignment == 0) {
ERROR("cannot align to zero");
return M_ERROR;
}
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];
entry.size = sizeof(uint32_t);
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];
entry.size = sizeof(uint16_t);
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];
entry.size = sizeof(uint8_t);
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;
}
case MIPS_DIRECTIVE_ASCII: {
struct section_entry entry;
entry.type = ENT_STR;
entry.size = strlen(directive->name);
memcpy(entry.str, directive->name, entry.size);
if (sec_push(assembler->sectab.current, entry))
return M_ERROR;
break;
}
case MIPS_DIRECTIVE_ASCIIZ: {
struct section_entry entry;
entry.type = ENT_STR;
entry.size = strlen(directive->name) + 1;
memcpy(entry.str, directive->name, entry.size);
if (sec_push(assembler->sectab.current, entry))
return M_ERROR;
break;
}
}
return M_SUCCESS;
return STB_GLOBAL;
}
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 = B32(sec_size(cur));
return M_SUCCESS;
}
ERROR("redefined symbol '%s'", name);
return M_ERROR;
static int asm_init_symtab(struct assembler *assembler) {
struct symbol_table *symtab = &assembler->gen.symtab;
size_t len = symtab->len + 1;
Elf32_Sym *elftab = malloc(sizeof(Elf32_Sym) * len);
if (elftab == NULL) {
PERROR("cannot alloc");
}
if (create_symbol(assembler, name, cur->index, sec_size(cur),
STB_LOCAL))
return M_ERROR;
// add null entry
elftab[0] = (Elf32_Sym) {0};
return M_SUCCESS;
}
// add rest of the entries
for (uint32_t i = 0; i < symtab->len; i++) {
struct symbol *sym = &symtab->symbols[i];
int bind = elf_sym_bind(sym->type);
int type = STT_NOTYPE;
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++) {
union mips_instruction_data *ins =
&expr->ins[i].data;
struct reference *ref =
&expr->ref[i];
struct section_entry entry;
entry.type = ENT_INS;
entry.size = sizeof(union mips_instruction_data);
entry.ins = B32(ins->raw);
if (sec_push(sec, entry))
// get name
size_t str_off;
if (strtab_write_str(&assembler->strtab, sym->name.str,
&str_off)) {
free(elftab);
return M_ERROR;
}
if (ref->type == R_MIPS_NONE)
continue;
size_t symidx;
if (find_symbol_or_stub(assembler, ref->name, NULL, &symidx))
return M_ERROR;
Elf32_Rela rel = {
.r_info = B32(ELF32_R_INFO(symidx, ref->type)),
.r_addend = B32(ref->addend),
.r_offset = B32(sec_index(sec, secidx + i)),
elftab[i+1] = (Elf32_Sym) {
.st_name = B32(str_off),
.st_info = ELF32_ST_INFO(bind, type),
.st_size = 0,
.st_other = 0,
.st_value = B32(sym->offset),
.st_shndx = 0,
};
if (reltab_push(&sec->reltab, rel))
return M_ERROR;
}
assembler->symbols = elftab;
assembler->symtab_len = len;
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) {
PERROR("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 = B32(PT_LOAD);
hdr->p_flags = B32(
(sec->execute << 0) |
(sec->write << 1) |
(sec->read <&l