x64 machine code generation (ELF)
parent
ab91733a28
commit
9712213f50
|
@ -0,0 +1,6 @@
|
||||||
|
fn main() {
|
||||||
|
for _ in 0..5 {
|
||||||
|
println('Hello world from V x64 machine code generator!')
|
||||||
|
}
|
||||||
|
println('Hello again!')
|
||||||
|
}
|
11
v.v
11
v.v
|
@ -95,31 +95,30 @@ fn main() {
|
||||||
//println('unknown command/argument\n')
|
//println('unknown command/argument\n')
|
||||||
//println(compiler.help_text)
|
//println(compiler.help_text)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct the V object from command line arguments
|
// Construct the V object from command line arguments
|
||||||
mut v := compiler.new_v(args)
|
mut v := compiler.new_v(args)
|
||||||
if v.pref.is_verbose {
|
if v.pref.is_verbose {
|
||||||
println(args)
|
println(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
if 'run' in args {
|
if 'run' in args {
|
||||||
// always recompile for now, too error prone to skip recompilation otherwise
|
// always recompile for now, too error prone to skip recompilation otherwise
|
||||||
// for example for -repl usage, especially when piping lines to v
|
// for example for -repl usage, especially when piping lines to v
|
||||||
v.compile()
|
v.compile()
|
||||||
v.run_compiled_executable_and_exit()
|
v.run_compiled_executable_and_exit()
|
||||||
}
|
}
|
||||||
|
|
||||||
mut tmark := benchmark.new_benchmark()
|
mut tmark := benchmark.new_benchmark()
|
||||||
v.compile()
|
if v.pref.x64 {
|
||||||
|
v.compile_x64()
|
||||||
|
} else {
|
||||||
|
v.compile()
|
||||||
|
}
|
||||||
if v.pref.is_stats {
|
if v.pref.is_stats {
|
||||||
tmark.stop()
|
tmark.stop()
|
||||||
println( 'compilation took: ' + tmark.total_duration().str() + 'ms')
|
println( 'compilation took: ' + tmark.total_duration().str() + 'ms')
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.pref.is_test {
|
if v.pref.is_test {
|
||||||
v.run_compiled_executable_and_exit()
|
v.run_compiled_executable_and_exit()
|
||||||
}
|
}
|
||||||
|
|
||||||
v.finalize_compilation()
|
v.finalize_compilation()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,10 @@ pub fn tos3(s *C.char) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn println(s string) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
pub fn (a string) clone() string {
|
pub fn (a string) clone() string {
|
||||||
mut b := string {
|
mut b := string {
|
||||||
|
|
|
@ -283,9 +283,10 @@ fn (p mut Parser) fn_decl() {
|
||||||
// C function header def? (fn C.NSMakeRect(int,int,int,int))
|
// C function header def? (fn C.NSMakeRect(int,int,int,int))
|
||||||
is_c := f.name == 'C' && p.tok == .dot
|
is_c := f.name == 'C' && p.tok == .dot
|
||||||
// Just fn signature? only builtin.v + default build mode
|
// Just fn signature? only builtin.v + default build mode
|
||||||
if p.is_vh {
|
//if p.is_vh {
|
||||||
//println('\n\nfn_decl() name=$f.name receiver_typ=$receiver_typ nogen=$p.cgen.nogen')
|
//if f.name == 'main' {
|
||||||
}
|
//println('\n\nfn_decl() name=$f.name pass=$p.pass $p.file_name receiver_typ=$receiver_typ nogen=$p.cgen.nogen')
|
||||||
|
//}
|
||||||
if is_c {
|
if is_c {
|
||||||
p.check(.dot)
|
p.check(.dot)
|
||||||
f.name = p.check_name()
|
f.name = p.check_name()
|
||||||
|
@ -989,6 +990,12 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
|
||||||
if clone {
|
if clone {
|
||||||
p.gen('/*YY f=$f.name arg=$arg.name is_moved=$arg.is_moved*/string_clone(')
|
p.gen('/*YY f=$f.name arg=$arg.name is_moved=$arg.is_moved*/string_clone(')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// x64 println gen
|
||||||
|
if p.pref.x64 && i == 0 && f.name == 'println' && p.tok == .str && p.peek() == .rpar {
|
||||||
|
p.x64.gen_print(p.lit)
|
||||||
|
}
|
||||||
|
|
||||||
mut typ := p.bool_expression()
|
mut typ := p.bool_expression()
|
||||||
// Register an interface type usage:
|
// Register an interface type usage:
|
||||||
// fn run(r Animal) { ... }
|
// fn run(r Animal) { ... }
|
||||||
|
@ -1008,6 +1015,8 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
|
||||||
if clone {
|
if clone {
|
||||||
p.gen(')')
|
p.gen(')')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Optimize `println`: replace it with `printf` to avoid extra allocations and
|
// Optimize `println`: replace it with `printf` to avoid extra allocations and
|
||||||
// function calls.
|
// function calls.
|
||||||
// `println(777)` => `printf("%d\n", 777)`
|
// `println(777)` => `printf("%d\n", 777)`
|
||||||
|
@ -1021,6 +1030,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
|
||||||
if i == 0 && (f.name == 'println' || f.name == 'print') &&
|
if i == 0 && (f.name == 'println' || f.name == 'print') &&
|
||||||
!(typ in ['string', 'ustring', 'void' ])
|
!(typ in ['string', 'ustring', 'void' ])
|
||||||
{
|
{
|
||||||
|
//
|
||||||
T := p.table.find_type(typ)
|
T := p.table.find_type(typ)
|
||||||
$if !windows {
|
$if !windows {
|
||||||
$if !js {
|
$if !js {
|
||||||
|
|
|
@ -11,6 +11,8 @@ fn (p mut Parser) for_st() {
|
||||||
next_tok := p.peek()
|
next_tok := p.peek()
|
||||||
//debug := p.scanner.file_path.contains('r_draw')
|
//debug := p.scanner.file_path.contains('r_draw')
|
||||||
p.open_scope()
|
p.open_scope()
|
||||||
|
mut label := 0
|
||||||
|
mut to := 0
|
||||||
if p.tok == .lcbr {
|
if p.tok == .lcbr {
|
||||||
// Infinite loop
|
// Infinite loop
|
||||||
p.gen('while (1) {')
|
p.gen('while (1) {')
|
||||||
|
@ -130,9 +132,17 @@ fn (p mut Parser) for_st() {
|
||||||
if is_range {
|
if is_range {
|
||||||
p.check_types(typ, 'int')
|
p.check_types(typ, 'int')
|
||||||
p.check_space(.dotdot)
|
p.check_space(.dotdot)
|
||||||
|
if p.pref.x64 {
|
||||||
|
to = p.lit.int()
|
||||||
|
}
|
||||||
range_typ, range_expr := p.tmp_expr()
|
range_typ, range_expr := p.tmp_expr()
|
||||||
p.check_types(range_typ, 'int')
|
p.check_types(range_typ, 'int')
|
||||||
range_end = range_expr
|
range_end = range_expr
|
||||||
|
if p.pref.x64 {
|
||||||
|
label = p.x64.gen_loop_start(expr.int())
|
||||||
|
//to = range_expr.int() // TODO why empty?
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
is_arr := typ.contains('array')
|
is_arr := typ.contains('array')
|
||||||
is_str := typ == 'string'
|
is_str := typ == 'string'
|
||||||
|
@ -189,5 +199,8 @@ fn (p mut Parser) for_st() {
|
||||||
p.close_scope()
|
p.close_scope()
|
||||||
p.for_expr_cnt--
|
p.for_expr_cnt--
|
||||||
p.returns = false // TODO handle loops that are guaranteed to return
|
p.returns = false // TODO handle loops that are guaranteed to return
|
||||||
|
if label > 0 {
|
||||||
|
p.x64.gen_loop_end(to, label)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
module compiler
|
||||||
|
|
||||||
|
import filepath
|
||||||
|
|
||||||
|
//import compiler.x64
|
||||||
|
|
||||||
|
pub fn (v mut V) compile_x64() {
|
||||||
|
$if !linux {
|
||||||
|
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.dir
|
||||||
|
v.x64.generate_elf_header()
|
||||||
|
for f in v.files {
|
||||||
|
v.parse(f, .decl)
|
||||||
|
}
|
||||||
|
for f in v.files {
|
||||||
|
v.parse(f, .main)
|
||||||
|
}
|
||||||
|
v.x64.generate_elf_footer()
|
||||||
|
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import (
|
||||||
os
|
os
|
||||||
strings
|
strings
|
||||||
filepath
|
filepath
|
||||||
|
compiler.x64
|
||||||
)
|
)
|
||||||
|
|
||||||
pub const (
|
pub const (
|
||||||
|
@ -63,6 +64,7 @@ pub mut:
|
||||||
dir string // directory (or file) being compiled (TODO rename to path?)
|
dir string // directory (or file) being compiled (TODO rename to path?)
|
||||||
table &Table // table with types, vars, functions etc
|
table &Table // table with types, vars, functions etc
|
||||||
cgen &CGen // C code generator
|
cgen &CGen // C code generator
|
||||||
|
x64 &x64.Gen
|
||||||
pref &Preferences // all the preferences and settings extracted to a struct for reusability
|
pref &Preferences // all the preferences and settings extracted to a struct for reusability
|
||||||
lang_dir string // "~/code/v"
|
lang_dir string // "~/code/v"
|
||||||
out_name string // "program.exe"
|
out_name string // "program.exe"
|
||||||
|
@ -123,6 +125,7 @@ pub mut:
|
||||||
|
|
||||||
vlib_path string
|
vlib_path string
|
||||||
vpath string
|
vpath string
|
||||||
|
x64 bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should be called by main at the end of the compilation process, to cleanup
|
// Should be called by main at the end of the compilation process, to cleanup
|
||||||
|
@ -968,10 +971,13 @@ pub fn new_v(args[]string) &V {
|
||||||
mut out_name_c := get_vtmp_filename(out_name, '.tmp.c')
|
mut out_name_c := get_vtmp_filename(out_name, '.tmp.c')
|
||||||
|
|
||||||
cflags := get_cmdline_cflags(args)
|
cflags := get_cmdline_cflags(args)
|
||||||
|
|
||||||
rdir := os.realpath(dir)
|
rdir := os.realpath(dir)
|
||||||
rdir_name := os.filename(rdir)
|
rdir_name := os.filename(rdir)
|
||||||
|
|
||||||
|
if '-bare' in args {
|
||||||
|
verror('use -freestanding instead of -bare')
|
||||||
|
}
|
||||||
|
|
||||||
obfuscate := '-obf' in args
|
obfuscate := '-obf' in args
|
||||||
is_repl := '-repl' in args
|
is_repl := '-repl' in args
|
||||||
pref := &Preferences {
|
pref := &Preferences {
|
||||||
|
@ -998,7 +1004,8 @@ pub fn new_v(args[]string) &V {
|
||||||
compress: '-compress' in args
|
compress: '-compress' in args
|
||||||
enable_globals: '--enable-globals' in args
|
enable_globals: '--enable-globals' in args
|
||||||
fast: '-fast' in args
|
fast: '-fast' in args
|
||||||
is_bare: '-bare' in args
|
is_bare: '-freestanding' in args
|
||||||
|
x64: '-x64' in args
|
||||||
is_repl: is_repl
|
is_repl: is_repl
|
||||||
build_mode: build_mode
|
build_mode: build_mode
|
||||||
cflags: cflags
|
cflags: cflags
|
||||||
|
@ -1028,6 +1035,7 @@ pub fn new_v(args[]string) &V {
|
||||||
table: new_table(obfuscate)
|
table: new_table(obfuscate)
|
||||||
out_name_c: out_name_c
|
out_name_c: out_name_c
|
||||||
cgen: new_cgen(out_name_c)
|
cgen: new_cgen(out_name_c)
|
||||||
|
x64: x64.new_gen(out_name)
|
||||||
vroot: vroot
|
vroot: vroot
|
||||||
pref: pref
|
pref: pref
|
||||||
mod: mod
|
mod: mod
|
||||||
|
|
|
@ -7,6 +7,7 @@ module compiler
|
||||||
import (
|
import (
|
||||||
os
|
os
|
||||||
strings
|
strings
|
||||||
|
compiler.x64
|
||||||
)
|
)
|
||||||
|
|
||||||
struct Parser {
|
struct Parser {
|
||||||
|
@ -28,6 +29,7 @@ mut:
|
||||||
prev_tok2 TokenKind // TODO remove these once the tokens are cached
|
prev_tok2 TokenKind // TODO remove these once the tokens are cached
|
||||||
lit string
|
lit string
|
||||||
cgen &CGen
|
cgen &CGen
|
||||||
|
x64 &x64.Gen
|
||||||
table &Table
|
table &Table
|
||||||
import_table ImportTable // Holds imports for just the file being parsed
|
import_table ImportTable // Holds imports for just the file being parsed
|
||||||
pass Pass
|
pass Pass
|
||||||
|
@ -161,6 +163,7 @@ fn (v mut V) new_parser(scanner &Scanner) Parser {
|
||||||
table: v.table
|
table: v.table
|
||||||
cur_fn: EmptyFn
|
cur_fn: EmptyFn
|
||||||
cgen: v.cgen
|
cgen: v.cgen
|
||||||
|
x64: v.x64
|
||||||
pref: v.pref
|
pref: v.pref
|
||||||
os: v.os
|
os: v.os
|
||||||
vroot: v.vroot
|
vroot: v.vroot
|
||||||
|
@ -2967,3 +2970,7 @@ fn (p mut Parser) is_expr_fn_call(start_tok_idx int) (bool, string) {
|
||||||
}
|
}
|
||||||
return is_fn_call, expr
|
return is_fn_call, expr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn todo_remove() {
|
||||||
|
x64.new_gen('f')
|
||||||
|
}
|
||||||
|
|
|
@ -299,8 +299,8 @@ fn (p mut Parser) struct_init(typ string) string {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
field_typ := field.typ
|
field_typ := field.typ
|
||||||
if !p.builtin_mod && field_typ.ends_with('*') && field_typ.contains('Cfg') {
|
if !p.builtin_mod && field_typ.ends_with('*') && p.mod != 'os' { //&&
|
||||||
p.error('pointer field `${typ}.${field.name}` must be initialized')
|
p.warn('pointer field `${typ}.${field.name}` must be initialized')
|
||||||
}
|
}
|
||||||
// init map fields
|
// init map fields
|
||||||
if field_typ.starts_with('map_') {
|
if field_typ.starts_with('map_') {
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
// Create the binary
|
||||||
|
f := os.create('out.bin') or { panic(err) }
|
||||||
|
f.write_bytes(g.buf.data, g.buf.len)
|
||||||
|
f.close()
|
||||||
|
println('x64 elf binary has been successfully generated')
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is unused right now, since binaries without sections
|
||||||
|
are generated.
|
||||||
|
|
||||||
|
But it will be necessary once we have dynamic linking.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum SectionType {
|
||||||
|
null = 0
|
||||||
|
progbits = 1
|
||||||
|
symtab = 2
|
||||||
|
strtab = 3
|
||||||
|
rela = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SectionConfig {
|
||||||
|
name string
|
||||||
|
typ SectionType
|
||||||
|
flags i64
|
||||||
|
data voidptr
|
||||||
|
is_saa bool
|
||||||
|
datalen i64
|
||||||
|
link int
|
||||||
|
info int
|
||||||
|
align i64
|
||||||
|
entsize i64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (g mut Gen) section_header(c SectionConfig) {
|
||||||
|
g.write32(g.sect_header_name_pos)
|
||||||
|
g.sect_header_name_pos += c.name.len + 1
|
||||||
|
g.write32(int(c.typ))
|
||||||
|
g.write64(c.flags)
|
||||||
|
g.write64(0) // sh_addr
|
||||||
|
g.write64(g.offset)// offset
|
||||||
|
g.offset += c.datalen+1
|
||||||
|
g.write64(c.datalen)
|
||||||
|
g.write32(c.link)
|
||||||
|
g.write32(c.info)
|
||||||
|
g.write64(c.align)
|
||||||
|
g.write64(c.entsize)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn genobj() {
|
||||||
|
/*
|
||||||
|
// SHN_UNDEF
|
||||||
|
mut g := Gen{}
|
||||||
|
nr_sections := 7
|
||||||
|
g.section_header(SectionConfig{
|
||||||
|
name: ''
|
||||||
|
typ: .null
|
||||||
|
flags:0
|
||||||
|
data: 0
|
||||||
|
is_saa: false
|
||||||
|
link: 0
|
||||||
|
info:0
|
||||||
|
align:0
|
||||||
|
entsize: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
for sect in sections {
|
||||||
|
g.section_header(SectionConfig{
|
||||||
|
name:0
|
||||||
|
typ: sect.typ
|
||||||
|
flags: sect.flags
|
||||||
|
data: sect.data
|
||||||
|
is_saa: true
|
||||||
|
datalen: sect.len
|
||||||
|
link: 0
|
||||||
|
info: 0
|
||||||
|
align: sect.align
|
||||||
|
entsize: sect.entsize
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
g.section_header(SectionConfig{
|
||||||
|
name: '.DATA'
|
||||||
|
typ: .progbits
|
||||||
|
flags: 0x2
|
||||||
|
//data: sect.data
|
||||||
|
is_saa: true
|
||||||
|
datalen: 0xd
|
||||||
|
link: 0
|
||||||
|
info: 0
|
||||||
|
align: 1
|
||||||
|
entsize: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
g.section_header(SectionConfig{
|
||||||
|
name: '.TEXT'
|
||||||
|
typ: .progbits
|
||||||
|
flags: 0x2
|
||||||
|
//data: sect.data
|
||||||
|
is_saa: true
|
||||||
|
datalen: 0xd
|
||||||
|
link: 0
|
||||||
|
info: 0
|
||||||
|
align: 1
|
||||||
|
entsize: 0
|
||||||
|
})
|
||||||
|
g.section_header(SectionConfig{
|
||||||
|
name: '.shstrtab'
|
||||||
|
typ: .strtab
|
||||||
|
flags: 0x2
|
||||||
|
//data: sect.data
|
||||||
|
is_saa: true
|
||||||
|
datalen: 0x22
|
||||||
|
link: 0
|
||||||
|
info: 0
|
||||||
|
align: 1
|
||||||
|
entsize: 0
|
||||||
|
})
|
||||||
|
g.section_header(SectionConfig{
|
||||||
|
name: '.symtab'
|
||||||
|
typ: .symtab
|
||||||
|
flags: 0x2
|
||||||
|
//data: sect.data
|
||||||
|
is_saa: true
|
||||||
|
datalen: 0xd
|
||||||
|
link: 0
|
||||||
|
info: 0
|
||||||
|
align: 1
|
||||||
|
entsize: 0
|
||||||
|
})
|
||||||
|
g.section_header(SectionConfig{
|
||||||
|
name: '.strtab'
|
||||||
|
typ: .symtab
|
||||||
|
flags: 0x2
|
||||||
|
//data: sect.data
|
||||||
|
is_saa: true
|
||||||
|
datalen: 0xd
|
||||||
|
link: 0
|
||||||
|
info: 0
|
||||||
|
align: 1
|
||||||
|
entsize: 0
|
||||||
|
})
|
||||||
|
g.section_header(SectionConfig{
|
||||||
|
name: '.rela.TEXT'
|
||||||
|
typ: .rela
|
||||||
|
flags: 0x0
|
||||||
|
//data: sect.data
|
||||||
|
is_saa: true
|
||||||
|
datalen: 0x18
|
||||||
|
link: 4
|
||||||
|
info: 2
|
||||||
|
align: 8
|
||||||
|
entsize: 0x18
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,199 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
pub struct Gen {
|
||||||
|
out_name string
|
||||||
|
mut:
|
||||||
|
buf []byte
|
||||||
|
sect_header_name_pos int
|
||||||
|
offset i64
|
||||||
|
str_pos []i64
|
||||||
|
strings []string // TODO use a map and don't duplicate strings
|
||||||
|
//str string
|
||||||
|
file_size_pos i64
|
||||||
|
//string_addr map[string]i64
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Register {
|
||||||
|
eax
|
||||||
|
edi
|
||||||
|
rax
|
||||||
|
rdi
|
||||||
|
rsi
|
||||||
|
edx
|
||||||
|
rdx
|
||||||
|
r12
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Size {
|
||||||
|
_8
|
||||||
|
_16
|
||||||
|
_32
|
||||||
|
_64
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_gen(out_name string) &Gen {
|
||||||
|
return &Gen{
|
||||||
|
sect_header_name_pos : 0
|
||||||
|
buf: []
|
||||||
|
out_name: out_name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn (g mut Gen) write8(n int) {
|
||||||
|
// write 1 byte
|
||||||
|
g.buf << byte(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (g mut Gen) write16(n int) {
|
||||||
|
// write 2 bytes
|
||||||
|
g.buf << byte(n)
|
||||||
|
g.buf << byte(n >> 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (g mut 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (g mut 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (g mut Gen) write64_at(n i64, 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (g mut Gen) write_string(s string) {
|
||||||
|
for c in s {
|
||||||
|
g.write8(int(c))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (g mut Gen) inc(reg Register) {
|
||||||
|
g.write16(0xff49)
|
||||||
|
match reg {
|
||||||
|
.r12 { g.write8(0xc4) }
|
||||||
|
else { panic('unhandled inc $reg') }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (g mut 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') }
|
||||||
|
}
|
||||||
|
// Third byte depends on the register being compared to
|
||||||
|
match reg {
|
||||||
|
.r12 { g.write8(0xfc) }
|
||||||
|
else { panic('unhandled cmp') }
|
||||||
|
}
|
||||||
|
g.write8(int(val))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn abs(a i64) i64 { return if a < 0 { -a } else { a } }
|
||||||
|
|
||||||
|
fn (g mut Gen) jle(addr i64) {
|
||||||
|
offset := 0xff - int(abs(addr - g.buf.len))-1
|
||||||
|
g.write8(0x7e)
|
||||||
|
g.write8(offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (g mut Gen) mov64(reg Register, val i64) {
|
||||||
|
match reg {
|
||||||
|
.rsi {
|
||||||
|
g.write8(0x48)
|
||||||
|
g.write8(0xbe)
|
||||||
|
}
|
||||||
|
else { println('unhandled mov $reg') }
|
||||||
|
}
|
||||||
|
g.write64(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (g mut Gen) call(val int) {
|
||||||
|
g.write8(0xe8)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (g mut Gen) syscall() {
|
||||||
|
// g.write(0x050f)
|
||||||
|
g.write8(0x0f)
|
||||||
|
g.write8(0x05)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (g mut Gen) ret() {
|
||||||
|
g.write8(0xc3)
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns label's relative address
|
||||||
|
pub fn (g mut 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) {
|
||||||
|
g.cmp(.r12, ._8, to)
|
||||||
|
g.jle(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (g mut Gen) gen_print(s string) {
|
||||||
|
g.strings << s + '\n'
|
||||||
|
//g.string_addr[s] = str_pos
|
||||||
|
g.mov(.eax, 1)
|
||||||
|
g.mov(.edi, 1)
|
||||||
|
str_pos := g.buf.len + 2
|
||||||
|
g.str_pos << str_pos
|
||||||
|
g.mov64(.rsi, 0) //segment_start + 0x9f) // str pos // PLACEHOLDER
|
||||||
|
g.mov(.edx, s.len+1) // len
|
||||||
|
g.syscall()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (g mut Gen) mov(reg Register, val int) {
|
||||||
|
match reg {
|
||||||
|
.eax { g.write8(0xb8) }
|
||||||
|
.edi { g.write8(0xbf) }
|
||||||
|
.edx { g.write8(0xba) }
|
||||||
|
.rsi {
|
||||||
|
g.write8(0x48)
|
||||||
|
g.write8(0xbe)
|
||||||
|
}
|
||||||
|
.r12 {
|
||||||
|
g.write8(0x41)
|
||||||
|
g.write8(0xbc) // r11 is 0xbb etc
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
panic('unhandled mov $reg')
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
g.write32(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
21
vlib/os/os.v
21
vlib/os/os.v
|
@ -87,6 +87,27 @@ pub fn (f File) read_bytes_at(size, pos int) []byte {
|
||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_bytes(path string) ?[]byte {
|
||||||
|
mut fp := vfopen(path, 'rb')
|
||||||
|
if isnil(fp) {
|
||||||
|
return error('failed to open file "$path"')
|
||||||
|
}
|
||||||
|
C.fseek(fp, 0, C.SEEK_END)
|
||||||
|
fsize := C.ftell(fp)
|
||||||
|
C.rewind(fp)
|
||||||
|
println('fsize=$fsize')
|
||||||
|
mut data := malloc(fsize)
|
||||||
|
C.fread(data, fsize, 1, fp)
|
||||||
|
mut res := [`0`].repeat(fsize)
|
||||||
|
for i in 0..fsize {
|
||||||
|
res[i] = data[i]
|
||||||
|
}
|
||||||
|
C.fclose(fp)
|
||||||
|
//res := []byte(data, 10) // TODO can't `return []byte(data)`
|
||||||
|
//println('res0 = ' + res[0].str())
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
// read_file reads the file in `path` and returns the contents.
|
// read_file reads the file in `path` and returns the contents.
|
||||||
pub fn read_file(path string) ?string {
|
pub fn read_file(path string) ?string {
|
||||||
mode := 'rb'
|
mode := 'rb'
|
||||||
|
|
Loading…
Reference in New Issue