From efff96d62207ac01dc6a9d8cc0ddf28eefa1ccae Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Mon, 20 Apr 2020 07:02:09 +0200 Subject: [PATCH] x64: make hello world run --- vlib/v/gen/x64/elf.v | 46 ++++++----- vlib/v/gen/x64/gen.v | 178 ++++++++++++++++++++----------------------- 2 files changed, 110 insertions(+), 114 deletions(-) diff --git a/vlib/v/gen/x64/elf.v b/vlib/v/gen/x64/elf.v index fdcdc83609..b9bdde1397 100644 --- a/vlib/v/gen/x64/elf.v +++ b/vlib/v/gen/x64/elf.v @@ -6,29 +6,33 @@ module x64 import os const ( - mag0 = 0x7f - mag1 = `E` - mag2 = `L` - mag3 = `F` - ei_class = 4 - elfclass64 = 2 + mag0 = byte(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 + ev_current = 1 +) + +// ELF file types +const ( + elf_osabi = 0 + et_rel = 1 + et_exec = 2 + et_dyn = 3 + e_machine = 0x3e shn_xindex = 0xffff - sht_null = 0 + sht_null = 0 ) const ( segment_start = 0x400000 + PLACEHOLDER = 0 ) -pub fn (g mut Gen) generate_elf_header() { +pub fn (var g Gen) generate_elf_header() { g.buf << [byte(mag0), mag1, mag2, mag3] g.buf << elfclass64 // file class g.buf << elfdata2lsb // data encoding @@ -63,14 +67,16 @@ pub fn (g mut Gen) generate_elf_header() { // 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 + g.call(PLACEHOLDER) // call main function, it's not guaranteed to be the first, we don't know its address yet } -pub fn (g mut Gen) generate_elf_footer() { +pub fn (var g 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 { @@ -84,12 +90,12 @@ pub fn (g mut Gen) generate_elf_footer() { 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 + // now 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) + g.write32_at(g.code_start_pos + 1, int(g.main_fn_addr - g.code_start_pos) - 5) // Create the binary - mut f := os.create(g.out_name) or { + var f := os.create(g.out_name) or { panic(err) } os.chmod(g.out_name, 0o775) // make it an executable diff --git a/vlib/v/gen/x64/gen.v b/vlib/v/gen/x64/gen.v index b6a89bf83c..53525ff788 100644 --- a/vlib/v/gen/x64/gen.v +++ b/vlib/v/gen/x64/gen.v @@ -3,11 +3,8 @@ // that can be found in the LICENSE file. module x64 -import ( - v.ast - v.util - // term -) +import v.ast +import v.util pub struct Gen { out_name string @@ -21,9 +18,9 @@ mut: main_fn_addr i64 code_start_pos i64 // location of the start of the assembly instructions fn_addr map[string]i64 - // string_addr map[string]i64 } +// string_addr map[string]i64 enum Register { eax edi @@ -43,10 +40,8 @@ enum Size { } pub fn gen(files []ast.File, out_name string) { - mut g := Gen{ + var g := Gen{ sect_header_name_pos: 0 - // buf: [] - out_name: out_name } g.generate_elf_header() @@ -68,104 +63,100 @@ pub fn new_gen(out_name string) &Gen { } } */ - - pub fn (g &Gen) pos() i64 { return g.buf.len } -fn (g mut Gen) write8(n int) { +fn (var g Gen) write8(n int) { // write 1 byte g.buf << byte(n) } -fn (g mut Gen) write16(n int) { +fn (var g Gen) write16(n int) { // write 2 bytes g.buf << byte(n) - g.buf << byte(n>>8) + g.buf << byte(n >> 8) } -fn (g mut Gen) write32(n int) { +fn (var g Gen) write32(n int) { // write 4 bytes g.buf << byte(n) - g.buf << byte(n>>8) - g.buf << byte(n>>16) - g.buf << byte(n>>24) + g.buf << byte(n >> 8) + g.buf << byte(n >> 16) + g.buf << byte(n >> 24) } -fn (g mut Gen) write64(n i64) { +fn (var g Gen) write64(n i64) { // write 8 bytes g.buf << byte(n) - g.buf << byte(n>>8) - g.buf << byte(n>>16) - g.buf << byte(n>>24) - g.buf << byte(n>>32) - g.buf << byte(n>>40) - g.buf << byte(n>>48) - g.buf << byte(n>>56) + g.buf << byte(n >> 8) + g.buf << byte(n >> 16) + g.buf << byte(n >> 24) + g.buf << byte(n >> 32) + g.buf << byte(n >> 40) + g.buf << byte(n >> 48) + g.buf << byte(n >> 56) } -fn (g mut Gen) write64_at(n i64, at i64) { +fn (var g Gen) write64_at(n, at i64) { // write 8 bytes g.buf[at] = byte(n) - g.buf[at + 1] = byte(n>>8) - g.buf[at + 2] = byte(n>>16) - g.buf[at + 3] = byte(n>>24) - g.buf[at + 4] = byte(n>>32) - g.buf[at + 5] = byte(n>>40) - g.buf[at + 6] = byte(n>>48) - g.buf[at + 7] = byte(n>>56) + g.buf[at + 1] = byte(n >> 8) + g.buf[at + 2] = byte(n >> 16) + g.buf[at + 3] = byte(n >> 24) + g.buf[at + 4] = byte(n >> 32) + g.buf[at + 5] = byte(n >> 40) + g.buf[at + 6] = byte(n >> 48) + g.buf[at + 7] = byte(n >> 56) } -fn (g mut Gen) write_string(s string) { +fn (var g Gen) write32_at(at i64, n int) { + // write 4 bytes + g.buf[at] = byte(n) + g.buf[at + 1] = byte(n >> 8) + g.buf[at + 2] = byte(n >> 16) + g.buf[at + 3] = byte(n >> 24) +} + +fn (var g Gen) write_string(s string) { for c in s { g.write8(int(c)) } } -fn (g mut Gen) inc(reg Register) { +fn (var g Gen) inc(reg Register) { g.write16(0xff49) match reg { - .r12 { - g.write8(0xc4) - } - else { - panic('unhandled inc $reg') - } + .r12 { g.write8(0xc4) } + else { panic('unhandled inc $reg') } } } -fn (g mut Gen) cmp(reg Register, size Size, val i64) { +fn (var g Gen) cmp(reg Register, size Size, val i64) { g.write8(0x49) // Second byte depends on the size of the value match size { - ._8 { - g.write8(0x83) - } - ._32 { - g.write8(0x81) - } - else { - panic('unhandled cmp') - } + ._8 { g.write8(0x83) } + ._32 { g.write8(0x81) } + else { panic('unhandled cmp') } } // Third byte depends on the register being compared to match reg { - .r12 { - g.write8(0xfc) - } - else { - panic('unhandled cmp') - } + .r12 { g.write8(0xfc) } + else { panic('unhandled cmp') } } g.write8(int(val)) } fn abs(a i64) i64 { - return if a < 0 { -a } else { a } + return if a < 0 { + -a + } else { + a + } } -fn (g mut Gen) jle(addr i64) { +fn (var g Gen) jle(addr i64) { // Calculate the relative offset to jump to // (`addr` is absolute address) offset := 0xff - int(abs(addr - g.buf.len)) - 1 @@ -173,7 +164,7 @@ fn (g mut Gen) jle(addr i64) { g.write8(offset) } -fn (g mut Gen) jl(addr i64) { +fn (var g Gen) jl(addr i64) { offset := 0xff - int(abs(addr - g.buf.len)) - 1 g.write8(0x7c) g.write8(offset) @@ -183,13 +174,13 @@ fn (g &Gen) abs_to_rel_addr(addr i64) int { return int(abs(addr - g.buf.len)) - 1 } -fn (g mut Gen) jmp(addr i64) { +fn (var g Gen) jmp(addr i64) { offset := 0xff - g.abs_to_rel_addr(addr) g.write8(0xe9) g.write8(offset) } -fn (g mut Gen) mov64(reg Register, val i64) { +fn (var g Gen) mov64(reg Register, val i64) { match reg { .rsi { g.write8(0x48) @@ -202,7 +193,7 @@ fn (g mut Gen) mov64(reg Register, val i64) { g.write64(val) } -fn (g mut Gen) call(addr int) { +fn (var g Gen) call(addr int) { // rel := g.abs_to_rel_addr(addr) // rel := 0xffffffff - int(abs(addr - g.buf.len))-1 println('call addr=$addr rel_addr=$addr pos=$g.buf.len') @@ -210,52 +201,49 @@ fn (g mut Gen) call(addr int) { g.write32(addr) } -fn (g mut Gen) syscall() { +fn (var g Gen) syscall() { // g.write(0x050f) g.write8(0x0f) g.write8(0x05) } -pub fn (g mut Gen) ret() { +pub fn (var g Gen) ret() { g.write8(0xc3) } // returns label's relative address -pub fn (g mut Gen) gen_loop_start(from int) int { +pub fn (var g Gen) gen_loop_start(from int) int { g.mov(.r12, from) label := g.buf.len g.inc(.r12) return label } -pub fn (g mut Gen) gen_loop_end(to int, label int) { +pub fn (var g Gen) gen_loop_end(to, label int) { g.cmp(.r12, ._8, to) g.jl(label) } -pub fn (g mut Gen) save_main_fn_addr() { +pub fn (var g Gen) save_main_fn_addr() { g.main_fn_addr = g.buf.len } -pub fn (g mut Gen) gen_print_from_expr(expr ast.Expr, newline bool) { +pub fn (var g Gen) gen_print_from_expr(expr ast.Expr, newline bool) { match expr { - ast.StringLiteral { - if newline { - g.gen_print(it.val+'\n') - } - else { + ast.StringLiteral { if newline { + g.gen_print(it.val + '\n') + } else { g.gen_print(it.val) - } - } + } } else {} } } -pub fn (g mut Gen) gen_print(s string) { +pub fn (var g Gen) gen_print(s string) { // // qq := s + '\n' // - g.strings << s + '\n' + g.strings << s // + '\n' // g.string_addr[s] = str_pos g.mov(.eax, 1) g.mov(.edi, 1) @@ -266,14 +254,14 @@ pub fn (g mut Gen) gen_print(s string) { g.syscall() } -pub fn (g mut Gen) gen_exit() { +pub fn (var g Gen) gen_exit() { // Return 0 g.mov(.edi, 0) // ret value g.mov(.eax, 60) g.syscall() } -fn (g mut Gen) mov(reg Register, val int) { +fn (var g Gen) mov(reg Register, val int) { match reg { .eax { g.write8(0xb8) @@ -299,17 +287,19 @@ fn (g mut Gen) mov(reg Register, val int) { g.write32(val) } -pub fn (g mut Gen) register_function_address(name string) { +pub fn (var g Gen) register_function_address(name string) { addr := g.pos() // println('reg fn addr $name $addr') g.fn_addr[name] = addr } -pub fn (g &Gen) write(s string) {} +pub fn (g &Gen) write(s string) { +} -pub fn (g &Gen) writeln(s string) {} +pub fn (g &Gen) writeln(s string) { +} -pub fn (g mut Gen) call_fn(name string) { +pub fn (var g Gen) call_fn(name string) { if !name.contains('__') { return } @@ -318,7 +308,7 @@ pub fn (g mut Gen) call_fn(name string) { println('call $name $addr') } -fn (g mut Gen) stmt(node ast.Stmt) { +fn (var g Gen) stmt(node ast.Stmt) { match node { ast.ConstDecl {} ast.FnDecl { @@ -326,15 +316,17 @@ fn (g mut Gen) stmt(node ast.Stmt) { if is_main { g.save_main_fn_addr() } - for arg in it.args {} + for arg in it.args { + } for stmt in it.stmts { g.stmt(stmt) } if is_main { println('end of main: gen exit') g.gen_exit() + // g.write32(0x88888888) } - g.ret() + // g.ret() } ast.Return {} ast.AssignStmt {} @@ -344,12 +336,12 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.expr(it.expr) } else { - verror('x64.stmt(): bad node') + println('x64.stmt(): bad node') } } } -fn (g mut Gen) expr(node ast.Expr) { +fn (var g Gen) expr(node ast.Expr) { // println('cgen expr()') match node { ast.AssignExpr {} @@ -359,8 +351,7 @@ fn (g mut Gen) expr(node ast.Expr) { ast.UnaryExpr { g.expr(it.left) } - */ - +*/ ast.StringLiteral {} ast.InfixExpr {} // `user := User{name: 'Bob'}` @@ -379,8 +370,7 @@ fn (g mut Gen) expr(node ast.Expr) { } } g.write(')') - */ - +*/ } ast.ArrayInit {} ast.Ident {}