-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Prepare to assemble more than x64: aarch64 and riscv64
- Loading branch information
Showing
23 changed files
with
1,623 additions
and
769 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
#include "../../../config.h" | ||
#include "asm_code.h" | ||
|
||
#include <assert.h> | ||
#include <string.h> // memcpy | ||
|
||
#include "inst.h" | ||
#include "parse_asm.h" | ||
#include "util.h" | ||
|
||
#ifndef MAKE_CODE16 | ||
#define MAKE_CODE16(inst, code, ...) do { unsigned short buf[] = {__VA_ARGS__}; make_code16(inst, code, buf, sizeof(buf)); } while (0) | ||
#endif | ||
|
||
#ifndef MAKE_CODE32 | ||
#define MAKE_CODE32(inst, code, ...) do { unsigned int buf[] = {__VA_ARGS__}; make_code32(inst, code, buf, sizeof(buf)); } while (0) | ||
#endif | ||
|
||
void make_code16(Inst *inst, Code *code, unsigned short *buf, int len) { | ||
assert(len <= (int)sizeof(code->buf)); | ||
code->inst = inst; | ||
code->len = len; | ||
memcpy(code->buf, buf, len); | ||
} | ||
|
||
void make_code32(Inst *inst, Code *code, unsigned int *buf, int len) { | ||
assert(len <= (int)sizeof(code->buf)); | ||
code->inst = inst; | ||
code->len = len; | ||
memcpy(code->buf, buf, len); | ||
} | ||
|
||
inline bool assemble_error(const ParseInfo *info, const char *message) { | ||
parse_error(info, message); | ||
return false; | ||
} | ||
|
||
static unsigned char *asm_noop(Inst *inst, Code *code) { | ||
UNUSED(inst); | ||
unsigned char *p = code->buf; | ||
return p; | ||
} | ||
|
||
static unsigned char *asm_mov(Inst *inst, Code *code) { | ||
Operand *opr1 = &inst->opr1; | ||
Operand *opr2 = &inst->opr2; | ||
uint32_t x = 0x52800000U | (opr1->reg.size == REG64 ? (1U << 31) : 0U) | (opr2->immediate << 5) | opr1->reg.no; | ||
MAKE_CODE32(inst, code, x); | ||
return code->buf; | ||
} | ||
|
||
static unsigned char *asm_ret(Inst *inst, Code *code) { | ||
MAKE_CODE32(inst, code, 0xd65f03c0); | ||
return code->buf; | ||
} | ||
|
||
//////////////////////////////////////////////// | ||
|
||
typedef unsigned char *(*AsmInstFunc)(Inst *inst, Code *code); | ||
typedef struct { | ||
AsmInstFunc func; | ||
enum OperandType opr1_type; | ||
enum OperandType opr2_type; | ||
enum OperandType opr3_type; | ||
int flag; | ||
} AsmInstTable; | ||
|
||
static const AsmInstTable *table[] = { | ||
[NOOP] = (const AsmInstTable[]){ {asm_noop, NOOPERAND, NOOPERAND, NOOPERAND}, {NULL} }, | ||
[MOV] = (const AsmInstTable[]){ {asm_mov, REG, IMMEDIATE, NOOPERAND}, {NULL} }, | ||
[RET] = (const AsmInstTable[]){ {asm_ret, NOOPERAND, NOOPERAND, NOOPERAND}, {NULL} }, | ||
}; | ||
|
||
void assemble_inst(Inst *inst, const ParseInfo *info, Code *code) { | ||
code->flag = 0; | ||
code->len = 0; | ||
|
||
const AsmInstTable *pt = NULL; | ||
if (inst->op < (enum Opcode)ARRAY_SIZE(table) && table[inst->op] != NULL) { | ||
for (const AsmInstTable *p = table[inst->op]; p->func != NULL; ++p) { | ||
if (inst->opr1.type == p->opr1_type && inst->opr2.type == p->opr2_type && inst->opr3.type == p->opr3_type) { | ||
pt = p; | ||
break; | ||
} | ||
} | ||
} | ||
|
||
if (pt != NULL) { | ||
unsigned char *p = (*pt->func)(inst, code); | ||
if (p != NULL) { | ||
if (p > code->buf) { | ||
code->inst = inst; | ||
code->len = p - code->buf; | ||
assert((size_t)code->len <= sizeof(code->buf)); | ||
} | ||
return; | ||
} | ||
} | ||
|
||
assemble_error(info, "Illegal opeand"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// aarch64 Instruction | ||
|
||
#pragma once | ||
|
||
#include <stdint.h> // int64_t | ||
|
||
typedef struct Expr Expr; | ||
|
||
// Must match the order with kOpTable in parse_aarch64.c | ||
enum Opcode { | ||
NOOP, | ||
MOV, | ||
RET, | ||
}; | ||
|
||
enum RegType { | ||
NOREG, | ||
|
||
// 32bit | ||
W0, W1, W2, W3, W4, W5, W6, W7, W8, W9, W10, W11, W12, W13, W14, W15, | ||
W16, W17, W18, W19, W20, W21, W22, W23, W24, W25, W26, W27, W28, W29, W30, W31, | ||
|
||
// 64bit | ||
X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, | ||
X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, //X29, X30, X31, | ||
FP, LR, SP, | ||
}; | ||
|
||
enum RegSize { | ||
REG32, | ||
REG64, | ||
}; | ||
|
||
typedef struct { | ||
char size; // RegSize | ||
char no; // 0~31 | ||
} Reg; | ||
|
||
enum OperandType { | ||
NOOPERAND, | ||
REG, // reg | ||
IMMEDIATE, // 1234 | ||
}; | ||
|
||
typedef struct { | ||
enum OperandType type; | ||
union { | ||
Reg reg; | ||
int64_t immediate; | ||
}; | ||
} Operand; | ||
|
||
typedef struct Inst { | ||
enum Opcode op; | ||
Operand opr1; | ||
Operand opr2; | ||
Operand opr3; | ||
} Inst; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
#include "../../../config.h" | ||
#include "ir_asm.h" | ||
|
||
#include "gen_section.h" | ||
#include "table.h" | ||
#include "util.h" | ||
|
||
static LabelInfo *new_label(int section, uintptr_t address) { | ||
LabelInfo *info = malloc_or_die(sizeof(*info)); | ||
info->section = section; | ||
info->flag = 0; | ||
info->address = address; | ||
info->kind = LK_NONE; | ||
return info; | ||
} | ||
|
||
LabelInfo *add_label_table(Table *label_table, const Name *label, int section, bool define, bool global) { | ||
LabelInfo *info = table_get(label_table, label); | ||
if (info != NULL) { | ||
if (define) { | ||
if ((info->flag & LF_DEFINED) != 0) { | ||
fprintf(stderr, "`%.*s' already defined\n", NAMES(label)); | ||
return NULL; | ||
} | ||
info->address = 1; | ||
info->section = section; | ||
} | ||
} else { | ||
info = new_label(section, 0); | ||
table_put(label_table, label, info); | ||
} | ||
if (define) | ||
info->flag |= LF_DEFINED; | ||
if (global) | ||
info->flag |= LF_GLOBAL; | ||
return info; | ||
} | ||
|
||
IR *new_ir_label(const Name *label) { | ||
IR *ir = malloc_or_die(sizeof(*ir)); | ||
ir->kind = IR_LABEL; | ||
ir->label = label; | ||
return ir; | ||
} | ||
|
||
IR *new_ir_code(const Code *code) { | ||
IR *ir = malloc_or_die(sizeof(*ir)); | ||
ir->kind = IR_CODE; | ||
ir->code = *code; | ||
return ir; | ||
} | ||
|
||
IR *new_ir_data(const void *data, size_t size) { | ||
IR *ir = malloc_or_die(sizeof(*ir)); | ||
ir->kind = IR_DATA; | ||
ir->data.len = size; | ||
ir->data.buf = (unsigned char*)data; | ||
return ir; | ||
} | ||
|
||
IR *new_ir_bss(size_t size) { | ||
IR *ir = malloc_or_die(sizeof(*ir)); | ||
ir->kind = IR_BSS; | ||
ir->bss = size; | ||
return ir; | ||
} | ||
|
||
IR *new_ir_align(int align) { | ||
IR *ir = malloc_or_die(sizeof(*ir)); | ||
ir->kind = IR_ALIGN; | ||
ir->align = align; | ||
return ir; | ||
} | ||
|
||
IR *new_ir_expr(enum IrKind kind, const Expr *expr) { | ||
IR *ir = malloc_or_die(sizeof(*ir)); | ||
ir->kind = kind; | ||
ir->expr = expr; | ||
return ir; | ||
} | ||
|
||
bool calc_label_address(uintptr_t start_address, Vector **section_irs, Table *label_table) { | ||
UNUSED(start_address); | ||
UNUSED(section_irs); | ||
UNUSED(label_table); | ||
return true; | ||
} | ||
|
||
bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector *unresolved) { | ||
UNUSED(section_irs); | ||
UNUSED(label_table); | ||
UNUSED(unresolved); | ||
return true; | ||
} | ||
|
||
void emit_irs(Vector **section_irs) { | ||
for (int sec = 0; sec < SECTION_COUNT; ++sec) { | ||
Vector *irs = section_irs[sec]; | ||
for (int i = 0, len = irs->len; i < len; ++i) { | ||
IR *ir = irs->data[i]; | ||
switch (ir->kind) { | ||
case IR_LABEL: | ||
break; | ||
case IR_CODE: | ||
add_code(ir->code.buf, ir->code.len); | ||
break; | ||
case IR_DATA: | ||
add_section_data(sec, ir->data.buf, ir->data.len); | ||
break; | ||
case IR_BSS: | ||
add_bss(ir->bss); | ||
break; | ||
case IR_ALIGN: | ||
align_section_size(sec, ir->align); | ||
break; | ||
case IR_EXPR_BYTE: | ||
case IR_EXPR_SHORT: | ||
case IR_EXPR_LONG: | ||
case IR_EXPR_QUAD: | ||
{ | ||
int64_t zero = 0; | ||
int size = 1 << (ir->kind - IR_EXPR_BYTE); | ||
add_section_data(sec, &zero, size); // TODO: Target endian | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.