v/vlib/compiler/x64/gen.v

200 lines
3.4 KiB
V
Raw Normal View History

2019-11-19 07:53:52 +01:00
// 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)
}