From b1d6021875f1a558b15fa86b48dfbff5d9b83b4e Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 1 Jan 2020 22:34:46 +0100 Subject: [PATCH] x64 fixes --- examples/x64/hello_world.v | 15 ++++-- vlib/compiler/main.v | 2 +- vlib/compiler/x64/elf.v | 100 ------------------------------------- vlib/v/ast/ast.v | 11 ++-- vlib/v/gen/cgen.v | 9 +++- vlib/v/gen/x64/elf.v | 5 +- vlib/v/gen/x64/gen.v | 41 ++++++++++----- vlib/v/parser/parser.v | 19 +++++++ 8 files changed, 74 insertions(+), 128 deletions(-) delete mode 100644 vlib/compiler/x64/elf.v diff --git a/examples/x64/hello_world.v b/examples/x64/hello_world.v index 6ebcf145e6..8c538cf58b 100644 --- a/examples/x64/hello_world.v +++ b/examples/x64/hello_world.v @@ -1,14 +1,21 @@ -fn test_fn() { - println('test fn') -} +fn println(s string) { } + +//fn test_fn() { + //println('test fn') +//} fn main() { println('x64 test') - for _ in 0..5 { + //i := 0 + //for i < 5 { + for _ in 1..5 { println('Hello world from V x64 machine code generator!') + //i++ } + /* println('Hello again!') //test_fn() println('done') + */ } diff --git a/vlib/compiler/main.v b/vlib/compiler/main.v index c6fc52dfaf..eeb6af078b 100644 --- a/vlib/compiler/main.v +++ b/vlib/compiler/main.v @@ -420,7 +420,7 @@ pub fn (v mut V) compile_x64() { println('v -x64 can only generate Linux binaries for now') println('You are not on a Linux system, so you will not ' + 'be able to run the resulting executable') } - v.files << v.v_files_from_dir(filepath.join(v.pref.vlib_path,'builtin','bare')) + //v.files << v.v_files_from_dir(filepath.join(v.pref.vlib_path,'builtin','bare')) v.files << v.dir table := &table.Table{} diff --git a/vlib/compiler/x64/elf.v b/vlib/compiler/x64/elf.v deleted file mode 100644 index ff018cb784..0000000000 --- a/vlib/compiler/x64/elf.v +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. -// Use of this source code is governed by an MIT license -// that can be found in the LICENSE file. -module x64 - -import os - -const ( - mag0 = 0x7f - mag1 = `E` - mag2 = `L` - mag3 = `F` - ei_class = 4 - elfclass64 = 2 - elfdata2lsb = 1 - ev_current = 1 - elf_osabi = 0 - // ELF file types - et_rel = 1 - et_exec = 2 - et_dyn = 3 - e_machine = 0x3e - shn_xindex = 0xffff - sht_null = 0 -) - -const ( - segment_start = 0x400000 -) - -pub fn (g mut Gen) generate_elf_header() { - g.buf << [byte(mag0), mag1, mag2, mag3] - g.buf << elfclass64 // file class - g.buf << elfdata2lsb // data encoding - g.buf << ev_current // file version - g.buf << 1 // elf_osabi - g.write64(0) // et_rel) // et_rel for .o - g.write16(2) // e_type - g.write16(e_machine) // - g.write32(ev_current) // e_version - eh_size := 0x40 - phent_size := 0x38 - g.write64(segment_start + eh_size + phent_size) // e_entry - g.write64(0x40) // e_phoff - g.write64(0) // e_shoff - g.write32(0) // e_flags - g.write16(eh_size) // e_ehsize - g.write16(phent_size) // e_phentsize - g.write16(1) // e_phnum - g.write16(0) // e_shentsize - g.write16(0) // e_shnum (number of sections) - g.write16(0) // e_shstrndx - // Elf64_Phdr - g.write32(1) // p_type - g.write32(5) // p_flags - g.write64(0) // p_offset - g.write64(segment_start) // p_vaddr addr:050 - g.write64(segment_start) // - g.file_size_pos = g.buf.len - g.write64(0) // p_filesz PLACEHOLDER, set to file_size later // addr: 060 - g.write64(0) // p_memsz - g.write64(0x1000) // p_align - // user code starts here at - // address: 00070 and a half - g.code_start_pos = g.buf.len - g.call(0) // call main function, it's not guaranteed to be the first -} - -pub fn (g mut Gen) generate_elf_footer() { - // Return 0 - g.mov(.edi, 0) // ret value - g.mov(.eax, 60) - g.syscall() - // Strings table - // Loop thru all strings and set the right addresses - for i, s in g.strings { - g.write64_at(segment_start + g.buf.len, int(g.str_pos[i])) - g.write_string(s) - g.write8(6) - } - // Now we know the file size, set it - file_size := g.buf.len - g.write64_at(file_size, g.file_size_pos) // set file size 64 bit value - g.write64_at(file_size, g.file_size_pos + 8) - // call main function, it's not guaranteed to be the first - // we generated call(0) ("e8 0") - // no need to replace "0" with a relative address of the main function - // +1 is for "e8" - // -5 is for "e8 00 00 00 00" - g.write64_at(int(g.main_fn_addr - g.code_start_pos) - 5, g.code_start_pos + 1) - // Create the binary - mut f := os.create(g.out_name)or{ - panic(err) - } - os.chmod(g.out_name, 0775) - f.write_bytes(g.buf.data, g.buf.len) - f.close() - println('x64 elf binary has been successfully generated') -} - diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index c71065c82b..87a4b0cc9d 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -8,10 +8,10 @@ import ( v.types ) -pub type Expr = BinaryExpr | UnaryExpr | IfExpr | StringLiteral | IntegerLiteral | +pub type Expr = BinaryExpr | UnaryExpr | IfExpr | StringLiteral | IntegerLiteral | FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit -pub type Stmt = VarDecl | FnDecl | Return | Module | Import | ExprStmt | AssignStmt | +pub type Stmt = VarDecl | FnDecl | Return | Module | Import | ExprStmt | AssignStmt | ForStmt | StructDecl // Stand-alone expression in a statement list. pub struct ExprStmt { @@ -158,9 +158,9 @@ pub: pub struct IfExpr { pub: - tok_kind token.Kind - cond Expr - stmts []Stmt + tok_kind token.Kind + cond Expr + stmts []Stmt else_stmts []Stmt } @@ -168,6 +168,7 @@ pub struct ForStmt { pub: cond Expr stmts []Stmt + is_in bool } pub struct ReturnStmt { diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 5a8964d078..aa91deed2d 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -72,7 +72,11 @@ fn (g mut Gen) stmt(node ast.Stmt) { } ast.ForStmt { g.write('while (') - g.expr(it.cond) + if !it.is_in { + // `for in` loops don't have a condition + println('it cond') + g.expr(it.cond) + } g.writeln(') {') for stmt in it.stmts { g.stmt(stmt) @@ -116,7 +120,8 @@ fn (g mut Gen) expr(node ast.Expr) { if it.op in [.inc, .dec] { g.expr(it.left) g.write(it.op.str()) - } else { + } + else { g.write(it.op.str()) g.expr(it.left) } diff --git a/vlib/v/gen/x64/elf.v b/vlib/v/gen/x64/elf.v index ff018cb784..1fc4be2752 100644 --- a/vlib/v/gen/x64/elf.v +++ b/vlib/v/gen/x64/elf.v @@ -89,12 +89,11 @@ pub fn (g mut Gen) generate_elf_footer() { // -5 is for "e8 00 00 00 00" g.write64_at(int(g.main_fn_addr - g.code_start_pos) - 5, g.code_start_pos + 1) // Create the binary - mut f := os.create(g.out_name)or{ + mut f := os.create(g.out_name) or { panic(err) } - os.chmod(g.out_name, 0775) + os.chmod(g.out_name, 0775) // make it an executable f.write_bytes(g.buf.data, g.buf.len) f.close() println('x64 elf binary has been successfully generated') } - diff --git a/vlib/v/gen/x64/gen.v b/vlib/v/gen/x64/gen.v index 0ccf602e38..fa4280c29e 100644 --- a/vlib/v/gen/x64/gen.v +++ b/vlib/v/gen/x64/gen.v @@ -43,7 +43,6 @@ enum Size { pub fn gen(files []ast.File, out_name string) { mut g := Gen{ - // out: strings.new_builder(100) sect_header_name_pos: 0 buf: [] out_name: out_name @@ -58,6 +57,7 @@ pub fn gen(files []ast.File, out_name string) { g.generate_elf_footer() } +/* pub fn new_gen(out_name string) &Gen { return &Gen{ sect_header_name_pos: 0 @@ -65,6 +65,8 @@ pub fn new_gen(out_name string) &Gen { out_name: out_name } } +*/ + pub fn (g &Gen) pos() i64 { return g.buf.len @@ -233,6 +235,15 @@ pub fn (g mut Gen) save_main_fn_addr() { g.main_fn_addr = g.buf.len } +pub fn (g mut Gen) gen_print_from_expr(expr ast.Expr) { + match expr { + ast.StringLiteral { + g.gen_print(it.val) + } + else {} + } +} + pub fn (g mut Gen) gen_print(s string) { g.strings << s + '\n' // g.string_addr[s] = str_pos @@ -306,23 +317,19 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.writeln(';') } ast.FnDecl { - if it.name == 'main' { - g.write('int ${it.name}(') + is_main := it.name == 'main' + if is_main { + g.save_main_fn_addr() } - else { - g.write('$it.typ.name ${it.name}(') - } - for arg in it.args { - g.write(arg.typ.name + ' ' + arg.name) - } - g.writeln(') { ') + for arg in it.args {} for stmt in it.stmts { g.stmt(stmt) } - if it.name == 'main' { - g.writeln('return 0;') + if is_main { + println('end of main: gen exit') + g.gen_exit() } - g.writeln('}') + g.ret() } ast.Return { g.write('return ') @@ -335,6 +342,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.writeln(';') } ast.ForStmt { + if it.is_in {} g.write('while (') g.expr(it.cond) g.writeln(') {') @@ -401,6 +409,11 @@ fn (g mut Gen) expr(node ast.Expr) { g.write('}') } ast.CallExpr { + if it.name == 'println' || it.name == 'print' { + expr := it.args[0] + g.gen_print_from_expr(expr) + } + /* g.write('${it.name}(') for i, expr in it.args { g.expr(expr) @@ -409,6 +422,8 @@ fn (g mut Gen) expr(node ast.Expr) { } } g.write(')') + */ + } ast.ArrayInit { g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.typ.name), {\t') diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 9a429c1419..297916406a 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -93,6 +93,7 @@ pub fn parse_file(path string, table &table.Table) ast.File { pub fn parse_files(paths []string, table &table.Table) []ast.File { mut files := []ast.File for path in paths { + println('parse file "$path"') mut stmts := []ast.Stmt text := os.read_file(path) or { panic(err) @@ -437,6 +438,24 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { fn (p mut Parser) for_statement() ast.ForStmt { p.check(.key_for) + // `for i in start .. end` + if p.peek_tok.kind == .key_in { + var := p.check_name() + p.check(.key_in) + start := p.tok.lit.int() + p.check(.number) + p.check(.dotdot) + end := p.tok.lit.int() + // println('for start=$start $end') + p.check(.number) + stmts := p.parse_block() + // println('nr stmts=$stmts.len') + return ast.ForStmt{ + stmts: stmts + is_in: true + } + } + // `for cond {` cond,typ := p.expr(0) if !types.check(types.bool_type, typ) { p.error('non-bool used as for condition')