x64 fixes
parent
807c16dd1b
commit
b1d6021875
|
@ -1,14 +1,21 @@
|
||||||
fn test_fn() {
|
fn println(s string) { }
|
||||||
println('test fn')
|
|
||||||
}
|
//fn test_fn() {
|
||||||
|
//println('test fn')
|
||||||
|
//}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println('x64 test')
|
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!')
|
println('Hello world from V x64 machine code generator!')
|
||||||
|
//i++
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
println('Hello again!')
|
println('Hello again!')
|
||||||
//test_fn()
|
//test_fn()
|
||||||
println('done')
|
println('done')
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -420,7 +420,7 @@ pub fn (v mut V) compile_x64() {
|
||||||
println('v -x64 can only generate Linux binaries for now')
|
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')
|
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
|
v.files << v.dir
|
||||||
|
|
||||||
table := &table.Table{}
|
table := &table.Table{}
|
||||||
|
|
|
@ -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')
|
|
||||||
}
|
|
||||||
|
|
|
@ -168,6 +168,7 @@ pub struct ForStmt {
|
||||||
pub:
|
pub:
|
||||||
cond Expr
|
cond Expr
|
||||||
stmts []Stmt
|
stmts []Stmt
|
||||||
|
is_in bool
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ReturnStmt {
|
pub struct ReturnStmt {
|
||||||
|
|
|
@ -72,7 +72,11 @@ fn (g mut Gen) stmt(node ast.Stmt) {
|
||||||
}
|
}
|
||||||
ast.ForStmt {
|
ast.ForStmt {
|
||||||
g.write('while (')
|
g.write('while (')
|
||||||
|
if !it.is_in {
|
||||||
|
// `for in` loops don't have a condition
|
||||||
|
println('it cond')
|
||||||
g.expr(it.cond)
|
g.expr(it.cond)
|
||||||
|
}
|
||||||
g.writeln(') {')
|
g.writeln(') {')
|
||||||
for stmt in it.stmts {
|
for stmt in it.stmts {
|
||||||
g.stmt(stmt)
|
g.stmt(stmt)
|
||||||
|
@ -116,7 +120,8 @@ fn (g mut Gen) expr(node ast.Expr) {
|
||||||
if it.op in [.inc, .dec] {
|
if it.op in [.inc, .dec] {
|
||||||
g.expr(it.left)
|
g.expr(it.left)
|
||||||
g.write(it.op.str())
|
g.write(it.op.str())
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
g.write(it.op.str())
|
g.write(it.op.str())
|
||||||
g.expr(it.left)
|
g.expr(it.left)
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,12 +89,11 @@ pub fn (g mut Gen) generate_elf_footer() {
|
||||||
// -5 is for "e8 00 00 00 00"
|
// -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.write64_at(int(g.main_fn_addr - g.code_start_pos) - 5, g.code_start_pos + 1)
|
||||||
// Create the binary
|
// Create the binary
|
||||||
mut f := os.create(g.out_name)or{
|
mut f := os.create(g.out_name) or {
|
||||||
panic(err)
|
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.write_bytes(g.buf.data, g.buf.len)
|
||||||
f.close()
|
f.close()
|
||||||
println('x64 elf binary has been successfully generated')
|
println('x64 elf binary has been successfully generated')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,6 @@ enum Size {
|
||||||
|
|
||||||
pub fn gen(files []ast.File, out_name string) {
|
pub fn gen(files []ast.File, out_name string) {
|
||||||
mut g := Gen{
|
mut g := Gen{
|
||||||
// out: strings.new_builder(100)
|
|
||||||
sect_header_name_pos: 0
|
sect_header_name_pos: 0
|
||||||
buf: []
|
buf: []
|
||||||
out_name: out_name
|
out_name: out_name
|
||||||
|
@ -58,6 +57,7 @@ pub fn gen(files []ast.File, out_name string) {
|
||||||
g.generate_elf_footer()
|
g.generate_elf_footer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
pub fn new_gen(out_name string) &Gen {
|
pub fn new_gen(out_name string) &Gen {
|
||||||
return &Gen{
|
return &Gen{
|
||||||
sect_header_name_pos: 0
|
sect_header_name_pos: 0
|
||||||
|
@ -65,6 +65,8 @@ pub fn new_gen(out_name string) &Gen {
|
||||||
out_name: out_name
|
out_name: out_name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
pub fn (g &Gen) pos() i64 {
|
pub fn (g &Gen) pos() i64 {
|
||||||
return g.buf.len
|
return g.buf.len
|
||||||
|
@ -233,6 +235,15 @@ pub fn (g mut Gen) save_main_fn_addr() {
|
||||||
g.main_fn_addr = g.buf.len
|
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) {
|
pub fn (g mut Gen) gen_print(s string) {
|
||||||
g.strings << s + '\n'
|
g.strings << s + '\n'
|
||||||
// g.string_addr[s] = str_pos
|
// g.string_addr[s] = str_pos
|
||||||
|
@ -306,23 +317,19 @@ fn (g mut Gen) stmt(node ast.Stmt) {
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
}
|
}
|
||||||
ast.FnDecl {
|
ast.FnDecl {
|
||||||
if it.name == 'main' {
|
is_main := it.name == 'main'
|
||||||
g.write('int ${it.name}(')
|
if is_main {
|
||||||
|
g.save_main_fn_addr()
|
||||||
}
|
}
|
||||||
else {
|
for arg in it.args {}
|
||||||
g.write('$it.typ.name ${it.name}(')
|
|
||||||
}
|
|
||||||
for arg in it.args {
|
|
||||||
g.write(arg.typ.name + ' ' + arg.name)
|
|
||||||
}
|
|
||||||
g.writeln(') { ')
|
|
||||||
for stmt in it.stmts {
|
for stmt in it.stmts {
|
||||||
g.stmt(stmt)
|
g.stmt(stmt)
|
||||||
}
|
}
|
||||||
if it.name == 'main' {
|
if is_main {
|
||||||
g.writeln('return 0;')
|
println('end of main: gen exit')
|
||||||
|
g.gen_exit()
|
||||||
}
|
}
|
||||||
g.writeln('}')
|
g.ret()
|
||||||
}
|
}
|
||||||
ast.Return {
|
ast.Return {
|
||||||
g.write('return ')
|
g.write('return ')
|
||||||
|
@ -335,6 +342,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
}
|
}
|
||||||
ast.ForStmt {
|
ast.ForStmt {
|
||||||
|
if it.is_in {}
|
||||||
g.write('while (')
|
g.write('while (')
|
||||||
g.expr(it.cond)
|
g.expr(it.cond)
|
||||||
g.writeln(') {')
|
g.writeln(') {')
|
||||||
|
@ -401,6 +409,11 @@ fn (g mut Gen) expr(node ast.Expr) {
|
||||||
g.write('}')
|
g.write('}')
|
||||||
}
|
}
|
||||||
ast.CallExpr {
|
ast.CallExpr {
|
||||||
|
if it.name == 'println' || it.name == 'print' {
|
||||||
|
expr := it.args[0]
|
||||||
|
g.gen_print_from_expr(expr)
|
||||||
|
}
|
||||||
|
/*
|
||||||
g.write('${it.name}(')
|
g.write('${it.name}(')
|
||||||
for i, expr in it.args {
|
for i, expr in it.args {
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
|
@ -409,6 +422,8 @@ fn (g mut Gen) expr(node ast.Expr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.write(')')
|
g.write(')')
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
ast.ArrayInit {
|
ast.ArrayInit {
|
||||||
g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.typ.name), {\t')
|
g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.typ.name), {\t')
|
||||||
|
|
|
@ -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 {
|
pub fn parse_files(paths []string, table &table.Table) []ast.File {
|
||||||
mut files := []ast.File
|
mut files := []ast.File
|
||||||
for path in paths {
|
for path in paths {
|
||||||
|
println('parse file "$path"')
|
||||||
mut stmts := []ast.Stmt
|
mut stmts := []ast.Stmt
|
||||||
text := os.read_file(path) or {
|
text := os.read_file(path) or {
|
||||||
panic(err)
|
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 {
|
fn (p mut Parser) for_statement() ast.ForStmt {
|
||||||
p.check(.key_for)
|
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)
|
cond,typ := p.expr(0)
|
||||||
if !types.check(types.bool_type, typ) {
|
if !types.check(types.bool_type, typ) {
|
||||||
p.error('non-bool used as for condition')
|
p.error('non-bool used as for condition')
|
||||||
|
|
Loading…
Reference in New Issue