x64: function calls; http: download_file()
parent
208f67132d
commit
52d25336db
|
@ -1,6 +1,11 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
|
println('x64 test')
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
println('Hello world from V x64 machine code generator!')
|
println('Hello world from V x64 machine code generator!')
|
||||||
}
|
}
|
||||||
println('Hello again!')
|
println('Hello again!')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_fn() {
|
||||||
|
println('test fn')
|
||||||
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ mut:
|
||||||
fn_name_token_idx int // used by error reporting
|
fn_name_token_idx int // used by error reporting
|
||||||
comptime_define string
|
comptime_define string
|
||||||
is_used bool // so that we can skip unused fns in resulting C code
|
is_used bool // so that we can skip unused fns in resulting C code
|
||||||
|
//x64_addr i64 // address in the generated x64 binary
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TypeInst {
|
struct TypeInst {
|
||||||
|
@ -397,6 +398,9 @@ fn (p mut Parser) fn_decl() {
|
||||||
str_args := f.str_args(p.table)
|
str_args := f.str_args(p.table)
|
||||||
// Special case for main() args
|
// Special case for main() args
|
||||||
if f.name == 'main__main' && !has_receiver {
|
if f.name == 'main__main' && !has_receiver {
|
||||||
|
if p.pref.x64 && !p.first_pass() {
|
||||||
|
p.x64.save_main_fn_addr()
|
||||||
|
}
|
||||||
if str_args != '' || typ != 'void' {
|
if str_args != '' || typ != 'void' {
|
||||||
p.error_with_token_index('fn main must have no arguments and no return values', f.fn_name_token_idx)
|
p.error_with_token_index('fn main must have no arguments and no return values', f.fn_name_token_idx)
|
||||||
}
|
}
|
||||||
|
@ -525,6 +529,12 @@ fn (p mut Parser) fn_decl() {
|
||||||
//p.genln('// live_function body end')
|
//p.genln('// live_function body end')
|
||||||
p.genln('pthread_mutex_unlock(&live_fn_mutex);')
|
p.genln('pthread_mutex_unlock(&live_fn_mutex);')
|
||||||
}
|
}
|
||||||
|
if p.pref.x64 && f.name == 'main__main' && !p.first_pass() {
|
||||||
|
p.x64.gen_exit()
|
||||||
|
}
|
||||||
|
if p.pref.x64 && !p.first_pass() {
|
||||||
|
p.x64.ret()
|
||||||
|
}
|
||||||
// {} closed correctly? scope_level should be 0
|
// {} closed correctly? scope_level should be 0
|
||||||
if p.mod == 'main' {
|
if p.mod == 'main' {
|
||||||
// println(p.cur_fn.scope_level)
|
// println(p.cur_fn.scope_level)
|
||||||
|
@ -541,6 +551,7 @@ fn (p mut Parser) fn_decl() {
|
||||||
p.check_unused_variables()
|
p.check_unused_variables()
|
||||||
p.set_current_fn( EmptyFn )
|
p.set_current_fn( EmptyFn )
|
||||||
p.returns = false
|
p.returns = false
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
|
|
|
@ -367,7 +367,6 @@ pub fn (v mut V) compile_x64() {
|
||||||
v.parse(f, .main)
|
v.parse(f, .main)
|
||||||
}
|
}
|
||||||
v.x64.generate_elf_footer()
|
v.x64.generate_elf_footer()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (v mut V) generate_init() {
|
fn (v mut V) generate_init() {
|
||||||
|
|
|
@ -167,7 +167,7 @@ fn (p mut Parser) match_statement(is_expr bool) string {
|
||||||
p.gen(')')
|
p.gen(')')
|
||||||
|
|
||||||
if p.tok == .arrow {
|
if p.tok == .arrow {
|
||||||
p.warn(warn_match_arrow)
|
p.error(warn_match_arrow)
|
||||||
p.check(.arrow)
|
p.check(.arrow)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,8 @@ pub fn (g mut Gen) generate_elf_header() {
|
||||||
g.write64(0x1000) // p_align
|
g.write64(0x1000) // p_align
|
||||||
// user code starts here at
|
// user code starts here at
|
||||||
// address: 00070 and a half
|
// 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() {
|
pub fn (g mut Gen) generate_elf_footer() {
|
||||||
|
@ -87,6 +89,12 @@ pub fn (g mut Gen) generate_elf_footer() {
|
||||||
file_size := g.buf.len
|
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) // set file size 64 bit value
|
||||||
g.write64_at(file_size, g.file_size_pos+8)
|
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
|
// Create the binary
|
||||||
f := os.create(g.out_name) or { panic(err) }
|
f := os.create(g.out_name) or { panic(err) }
|
||||||
os.chmod(g.out_name, 0775)
|
os.chmod(g.out_name, 0775)
|
||||||
|
|
|
@ -12,8 +12,9 @@ mut:
|
||||||
offset i64
|
offset i64
|
||||||
str_pos []i64
|
str_pos []i64
|
||||||
strings []string // TODO use a map and don't duplicate strings
|
strings []string // TODO use a map and don't duplicate strings
|
||||||
//str string
|
|
||||||
file_size_pos i64
|
file_size_pos i64
|
||||||
|
main_fn_addr i64
|
||||||
|
code_start_pos i64 // location of the start of the assembly instructions
|
||||||
//string_addr map[string]i64
|
//string_addr map[string]i64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,11 +121,29 @@ fn (g mut Gen) cmp(reg Register, size Size, val i64) {
|
||||||
fn abs(a i64) i64 { return if a < 0 { -a } else { a } }
|
fn abs(a i64) i64 { return if a < 0 { -a } else { a } }
|
||||||
|
|
||||||
fn (g mut Gen) jle(addr i64) {
|
fn (g mut Gen) jle(addr i64) {
|
||||||
|
// Calculate the relative offset to jump to
|
||||||
|
// (`addr` is absolute address)
|
||||||
offset := 0xff - int(abs(addr - g.buf.len))-1
|
offset := 0xff - int(abs(addr - g.buf.len))-1
|
||||||
g.write8(0x7e)
|
g.write8(0x7e)
|
||||||
g.write8(offset)
|
g.write8(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (g mut Gen) jl(addr i64) {
|
||||||
|
offset := 0xff - int(abs(addr - g.buf.len))-1
|
||||||
|
g.write8(0x7c)
|
||||||
|
g.write8(offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
offset := 0xff - g.abs_to_rel_addr(addr)
|
||||||
|
g.write8(0xe9)
|
||||||
|
g.write8(offset)
|
||||||
|
}
|
||||||
|
|
||||||
fn (g mut Gen) mov64(reg Register, val i64) {
|
fn (g mut Gen) mov64(reg Register, val i64) {
|
||||||
match reg {
|
match reg {
|
||||||
.rsi {
|
.rsi {
|
||||||
|
@ -137,7 +156,9 @@ fn (g mut Gen) mov64(reg Register, val i64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut Gen) call(val int) {
|
fn (g mut Gen) call(val int) {
|
||||||
|
//println('call val=$val')
|
||||||
g.write8(0xe8)
|
g.write8(0xe8)
|
||||||
|
g.write32(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut Gen) syscall() {
|
fn (g mut Gen) syscall() {
|
||||||
|
@ -146,7 +167,7 @@ fn (g mut Gen) syscall() {
|
||||||
g.write8(0x05)
|
g.write8(0x05)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut Gen) ret() {
|
pub fn (g mut Gen) ret() {
|
||||||
g.write8(0xc3)
|
g.write8(0xc3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,6 +184,10 @@ pub fn (g mut Gen) gen_loop_end(to int, label int) {
|
||||||
g.jle(label)
|
g.jle(label)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (g mut Gen) save_main_fn_addr() {
|
||||||
|
g.main_fn_addr = g.buf.len
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
|
@ -175,6 +200,13 @@ pub fn (g mut Gen) gen_print(s string) {
|
||||||
g.syscall()
|
g.syscall()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (g mut 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 (g mut Gen) mov(reg Register, val int) {
|
||||||
match reg {
|
match reg {
|
||||||
.eax { g.write8(0xb8) }
|
.eax { g.write8(0xb8) }
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
// 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 http
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
fn download_file(url, out string) bool {
|
||||||
|
s := http.get(url) or { return false }
|
||||||
|
os.write_file(out, s.text)
|
||||||
|
return true
|
||||||
|
//download_file_with_progress(url, out, empty, empty)
|
||||||
|
}
|
|
@ -5,57 +5,53 @@
|
||||||
module http
|
module http
|
||||||
|
|
||||||
type downloadfn fn (written int)
|
type downloadfn fn (written int)
|
||||||
type download_finished_fn fn ()
|
type download_finished_fn fn ()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
struct DownloadStruct {
|
struct DownloadStruct {
|
||||||
mut:
|
mut:
|
||||||
stream voidptr
|
stream voidptr
|
||||||
written int
|
written int
|
||||||
cb downloadfn
|
cb downloadfn
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn download_cb(ptr voidptr, size, nmemb size_t, userp voidptr) {
|
fn download_cb(ptr voidptr, size, nmemb size_t, userp voidptr) {
|
||||||
/*
|
/*
|
||||||
mut data := &DownloadStruct(userp)
|
mut data := &DownloadStruct(userp)
|
||||||
written := C.fwrite(ptr, size, nmemb, data.stream)
|
written := C.fwrite(ptr, size, nmemb, data.stream)
|
||||||
data.written += written
|
data.written += written
|
||||||
data.cb(data.written)
|
data.cb(data.written)
|
||||||
//#data->cb(data->written); // TODO
|
//#data->cb(data->written); // TODO
|
||||||
return written
|
return written
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
fn download_file_with_progress(url, out string, cb downloadfn, cb_finished fn()) {
|
fn download_file_with_progress(url, out string, cb downloadfn, cb_finished fn()) {
|
||||||
/*
|
/*
|
||||||
curl := C.curl_easy_init()
|
curl := C.curl_easy_init()
|
||||||
if isnil(curl) {
|
if isnil(curl) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cout := out.str
|
cout := out.str
|
||||||
fp := C.fopen(cout, 'wb')
|
fp := C.fopen(cout, 'wb')
|
||||||
C.curl_easy_setopt(curl, CURLOPT_URL, url.str)
|
C.curl_easy_setopt(curl, CURLOPT_URL, url.str)
|
||||||
C.curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, download_cb)
|
C.curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, download_cb)
|
||||||
data := &DownloadStruct {
|
data := &DownloadStruct {
|
||||||
stream:fp
|
stream:fp
|
||||||
cb: cb
|
cb: cb
|
||||||
}
|
}
|
||||||
C.curl_easy_setopt(curl, CURLOPT_WRITEDATA, data)
|
C.curl_easy_setopt(curl, CURLOPT_WRITEDATA, data)
|
||||||
mut d := 0.0
|
mut d := 0.0
|
||||||
C.curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)
|
C.curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)
|
||||||
C.curl_easy_perform(curl)
|
C.curl_easy_perform(curl)
|
||||||
C.curl_easy_cleanup(curl)
|
C.curl_easy_cleanup(curl)
|
||||||
C.fclose(fp)
|
C.fclose(fp)
|
||||||
cb_finished()
|
cb_finished()
|
||||||
*/
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
fn download_file(url, out string) {
|
|
||||||
//download_file_with_progress(url, out, empty, empty)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn empty() {
|
fn empty() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ module http
|
||||||
fn download_file_with_progress(url, out string, cb, cb_finished voidptr) {
|
fn download_file_with_progress(url, out string, cb, cb_finished voidptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
pub fn download_file(url, out string) {
|
pub fn download_file(url, out string) {
|
||||||
C.URLDownloadToFile(0, url.to_wide(), out.to_wide(), 0, 0)
|
C.URLDownloadToFile(0, url.to_wide(), out.to_wide(), 0, 0)
|
||||||
/*
|
/*
|
||||||
|
@ -25,3 +26,4 @@ pub fn download_file(url, out string) {
|
||||||
# }
|
# }
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
Loading…
Reference in New Issue