Skip to content

Commit

Permalink
Prepare to assemble more than x64: aarch64 and riscv64
Browse files Browse the repository at this point in the history
  • Loading branch information
tyfkda committed Apr 9, 2024
1 parent 099b502 commit d2af408
Show file tree
Hide file tree
Showing 23 changed files with 1,623 additions and 769 deletions.
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ ifeq ("$(ARCHTYPE)", "")
endif
ARCHTYPE_UPPER:=$(shell echo "$(ARCHTYPE)" | tr \'[a-z]\' \'[A-Z]\')

AS_ARCH_DIR:=$(AS_DIR)/arch/$(ARCHTYPE)
CC1_ARCH_DIR:=$(CC1_DIR)/arch/$(ARCHTYPE)
CC1_FE_DIR:=$(CC1_DIR)/frontend
CC1_BE_DIR:=$(CC1_DIR)/backend
Expand Down Expand Up @@ -85,10 +86,13 @@ cc1_SRCS:=$(wildcard $(CC1_FE_DIR)/*.c) $(wildcard $(CC1_BE_DIR)/*.c) $(wildcard
cpp_SRCS:=$(wildcard $(CPP_DIR)/*.c) \
$(CC1_DIR)/lexer.c $(UTIL_DIR)/util.c $(UTIL_DIR)/table.c
as_SRCS:=$(wildcard $(AS_DIR)/*.c) \
$(wildcard $(AS_ARCH_DIR)/*.c) \
$(UTIL_DIR)/gen_section.c $(UTIL_DIR)/util.c $(UTIL_DIR)/elfutil.c $(UTIL_DIR)/table.c
ld_SRCS:=$(wildcard $(LD_DIR)/*.c) $(UTIL_DIR)/archive.c \
$(UTIL_DIR)/gen_section.c $(UTIL_DIR)/util.c $(UTIL_DIR)/elfutil.c $(UTIL_DIR)/table.c

src_as_CFLAGS:=-I$(AS_DIR) -I$(AS_ARCH_DIR)
src_as_arch_$(ARCHTYPE)_CFLAGS:=-I$(AS_DIR) -I$(AS_ARCH_DIR)
src_cc_CFLAGS:=-I$(CC1_FE_DIR) -I$(CC1_BE_DIR) -I$(CC1_ARCH_DIR) # arch required for builtin.c
src_cc_frontend_CFLAGS:=-I$(CC1_FE_DIR)
src_cc_backend_CFLAGS:=-I$(CC1_FE_DIR) -I$(CC1_BE_DIR) -I$(CC1_ARCH_DIR)
Expand Down Expand Up @@ -123,7 +127,7 @@ $(OBJ_DIR)/%.o: $(1)/%.c $(PARENT_DEPS)
-c -o $$@ $$<
endef
XCC_SRC_DIRS:=$(XCC_DIR) $(CC1_FE_DIR) $(CC1_BE_DIR) $(CC1_DIR) $(CC1_ARCH_DIR) $(CPP_DIR) \
$(AS_DIR) $(LD_DIR) $(UTIL_DIR) $(DEBUG_DIR)
$(AS_DIR) $(AS_ARCH_DIR) $(LD_DIR) $(UTIL_DIR) $(DEBUG_DIR)
$(foreach D, $(XCC_SRC_DIRS), $(eval $(call DEFINE_OBJ_TARGET,$(D))))

.PHONY: test
Expand Down
10 changes: 10 additions & 0 deletions include/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ struct proghdr {
#define ET_REL (1) // Relocatable file
#define ET_EXEC (2) // Executable file

// Flags
// RISC-V
#define EF_RISCV_RVC (0x01)
#define EF_RISCV_FLOAT_ABI_SOFT (0x00)
#define EF_RISCV_FLOAT_ABI_SINGLE (0x02)
#define EF_RISCV_FLOAT_ABI_DOUBLE (0x04)
#define EF_RISCV_FLOAT_ABI_QUAD (0x06)
#define EF_RISCV_RVE (0x08)
#define EF_RISCV_TSO (0x10)

// Values for Proghdr type
#define PT_LOAD (1)

Expand Down
101 changes: 101 additions & 0 deletions src/as/arch/aarch64/asm_code.c
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");
}
58 changes: 58 additions & 0 deletions src/as/arch/aarch64/inst.h
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;
129 changes: 129 additions & 0 deletions src/as/arch/aarch64/ir_asm.c
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;
}
}
}
}
Loading

0 comments on commit d2af408

Please sign in to comment.