nooc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/nooc
Log | Files | Refs | LICENSE

commit a19048e596632b05d785590daad0a04d4e4b0bc2
parent 16357fa6dce0888a80d9dcf0a2aad94042a6220c
Author: Nihal Jere <nihal@nihaljere.xyz>
Date:   Tue, 30 Nov 2021 13:38:37 -0600

expression evaluation at assignment

This required making the data segment RW, and adding an instruction to
move from a register to memory.

Diffstat:
Melf.c | 2+-
Mmain.c | 31++++++++++++++++++++++++-------
Mprog.nc | 4++--
Mx64.c | 20++++++++++++++++++++
Mx64.h | 1+
5 files changed, 48 insertions(+), 10 deletions(-)

diff --git a/elf.c b/elf.c @@ -48,7 +48,7 @@ elf(char *text, size_t len, char* data, size_t dlen, FILE *f) phdr_data.p_paddr = DATA_OFFSET; phdr_data.p_filesz = dlen; phdr_data.p_memsz = dlen; - phdr_data.p_flags = PF_R; + phdr_data.p_flags = PF_R | PF_W; phdr_data.p_align = 0x1000; fwrite(&ehdr, 1, sizeof(Elf64_Ehdr), f); diff --git a/main.c b/main.c @@ -505,15 +505,32 @@ main(int argc, char *argv[]) } } else if (item->kind == ITEM_DECL) { struct expr *expr = &exprs.data[decls.data[item->idx].val]; - if (expr->kind == EXPR_LIT) { - if (expr->class == C_INT) { + switch (expr->class) { + case C_INT: + // this is sort of an optimization, since we write at compile-time instead of evaluating and storing. should this happen here in the long term? + if (expr->kind == EXPR_LIT) { decls.data[item->idx].addr = data_pushint(expr->d.v.v.val); - } else if (expr->class == C_STR) { - size_t addr = data_push(expr->d.v.v.s.ptr, expr->d.v.v.s.len); - decls.data[item->idx].addr = data_pushint(addr); + } else { + decls.data[item->idx].addr = data_pushint(0); + enum reg reg = getreg(); + size_t exprlen = genexpr(NULL, decls.data[item->idx].val, reg); + size_t movlen = mov_m64_r64(NULL, decls.data[item->idx].addr, reg); + char *code = malloc(exprlen + movlen); + if (!code) + error("genexpr malloc failed"); + + genexpr(code, decls.data[item->idx].val, reg); + mov_m64_r64(code + exprlen, decls.data[item->idx].addr, reg); + array_push((&text), code, exprlen + movlen); + freereg(reg); } - } else { - error("cannot allocate memory for expression"); + break; + // FIXME: we assume that any string is a literal, may break if we add binary operands on strings in the future. + case C_STR: + decls.data[item->idx].addr = data_pushint(data_push(expr->d.v.v.s.ptr, expr->d.v.v.s.len)); + break; + default: + error("cannot generate code for unknown expression class"); } } else { error("cannot generate code for type"); diff --git a/prog.nc b/prog.nc @@ -4,7 +4,7 @@ exit i64 = 60 len1 i64 = 11 hello str = "hello " world str = "world" -len2 i64 = 6 -syscall(write, stdout, hello, 6) +len2 i64 = + 3 3 +syscall(write, stdout, hello, len2) syscall(write, stdout, world, 5) syscall(exit, 0) diff --git a/x64.c b/x64.c @@ -91,6 +91,26 @@ mov_r64_m64(char *buf, enum reg reg, uint64_t addr) } size_t +mov_m64_r64(char *buf, uint64_t addr, enum reg reg) +{ + uint8_t mov[] = {0x48, 0x89}; + uint8_t op1 = (MOD_INDIRECT << 6) | (reg << 3) | 4; + uint8_t sib = 0x25; + if (buf) { + memcpy(buf, mov, 2); + buf += 2; + *(buf++) = op1; + *(buf++) = sib; + *(buf++) = addr & 0xFF; + *(buf++) = (addr >> 8) & 0xFF; + *(buf++) = (addr >> 16) & 0xFF; + *(buf++) = (addr >> 24) & 0xFF; + } + + return 8; +} + +size_t add_r64_r64(char *buf, enum reg reg1, enum reg reg2) { uint8_t mov[] = {0x48, 0x03}; diff --git a/x64.h b/x64.h @@ -34,5 +34,6 @@ void freereg(enum reg reg); size_t add_r_imm(char *buf, enum reg reg, uint64_t imm); size_t mov_r_imm(char *buf, enum reg reg, uint64_t imm); size_t mov_r64_m64(char *buf, enum reg reg, uint64_t addr); +size_t mov_m64_r64(char *buf, uint64_t addr, enum reg reg); size_t add_r64_r64(char *buf, enum reg reg1, enum reg reg2); size_t sub_r64_r64(char *buf, enum reg reg1, enum reg reg2);