x64: debug opcodes nicely

pull/4572/head
Alexander Medvednikov 2020-04-24 09:44:50 +02:00
parent 6bd34a069d
commit a3382a5319
4 changed files with 79 additions and 24 deletions

View File

@ -72,7 +72,9 @@ pub fn (mut g Gen) generate_elf_header() {
// address: 00070 and a half // address: 00070 and a half
println('code_start_pos = $g.buf.len.hex()') println('code_start_pos = $g.buf.len.hex()')
g.code_start_pos = g.buf.len g.code_start_pos = g.buf.len
g.debug_pos = g.buf.len
g.call(PLACEHOLDER) // call main function, it's not guaranteed to be the first, we don't know its address yet g.call(PLACEHOLDER) // call main function, it's not guaranteed to be the first, we don't know its address yet
g.println('call fn main')
} }
pub fn (mut g Gen) generate_elf_footer() { pub fn (mut g Gen) generate_elf_footer() {
@ -106,5 +108,5 @@ pub fn (mut g Gen) generate_elf_footer() {
os.chmod(g.out_name, 0o775) // make it an executable os.chmod(g.out_name, 0o775) // 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('\nx64 elf binary has been successfully generated')
} }

View File

@ -5,6 +5,8 @@ module x64
import v.ast import v.ast
import v.util import v.util
import term
import strings
pub struct Gen { pub struct Gen {
out_name string out_name string
@ -20,6 +22,7 @@ mut:
fn_addr map[string]i64 fn_addr map[string]i64
var_offset map[string]int // local var stack offset var_offset map[string]int // local var stack offset
stack_var_pos int stack_var_pos int
debug_pos int
} }
// string_addr map[string]i64 // string_addr map[string]i64
@ -197,6 +200,7 @@ fn (mut g Gen) cmp_var(var_name string, val int) {
offset := g.get_var_offset(var_name) offset := g.get_var_offset(var_name)
g.write8(0xff - offset + 1) g.write8(0xff - offset + 1)
g.write32(val) g.write32(val)
g.println('cmp var `$var_name` $val')
} }
// `add DWORD [rbp-0x4], 1` // `add DWORD [rbp-0x4], 1`
@ -205,6 +209,7 @@ fn (mut g Gen) inc_var(var_name string) {
offset := g.get_var_offset(var_name) offset := g.get_var_offset(var_name)
g.write8(0xff - offset + 1) g.write8(0xff - offset + 1)
g.write32(1) g.write32(1)
g.println('inc_var `$var_name`')
} }
// Returns the position of the address to jump to (set later). // Returns the position of the address to jump to (set later).
@ -212,6 +217,7 @@ fn (mut g Gen) jne() int {
g.write16(0x850f) g.write16(0x850f)
pos := g.pos() pos := g.pos()
g.write32(PLACEHOLDER) g.write32(PLACEHOLDER)
g.println('jne')
return pos return pos
} }
@ -219,12 +225,14 @@ fn (mut g Gen) jge() int {
g.write16(0x8d0f) g.write16(0x8d0f)
pos := g.pos() pos := g.pos()
g.write32(PLACEHOLDER) g.write32(PLACEHOLDER)
g.println('jne')
return pos return pos
} }
fn (mut g Gen) jmp(addr int) { fn (mut g Gen) jmp(addr int) {
g.write8(0xe9) g.write8(0xe9)
g.write32(addr) // 0xffffff g.write32(addr) // 0xffffff
g.println('jmp')
} }
fn abs(a i64) i64 { fn abs(a i64) i64 {
@ -241,12 +249,30 @@ fn (mut g Gen) jle(addr i64) {
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)
g.println('jle')
}
fn (mut g Gen) println(comment string) {
addr := g.debug_pos.hex()
// println('$g.debug_pos "$addr"')
print(term.red(strings.repeat(`0`, 6 - addr.len) + addr + ' '))
for i := g.debug_pos; i < g.buf.len; i++ {
s := g.buf[i].hex()
if s.len == 1 {
print(term.blue('0'))
}
print(term.blue(g.buf[i].hex()) + ' ')
}
g.debug_pos = g.buf.len
print(' ' + comment)
println('')
} }
fn (mut g Gen) jl(addr i64) { fn (mut g Gen) jl(addr i64) {
offset := 0xff - int(abs(addr - g.buf.len)) - 1 offset := 0xff - int(abs(addr - g.buf.len)) - 1
g.write8(0x7c) g.write8(0x7c)
g.write8(offset) g.write8(offset)
g.println('jl')
} }
fn (g &Gen) abs_to_rel_addr(addr i64) int { fn (g &Gen) abs_to_rel_addr(addr i64) int {
@ -271,6 +297,7 @@ fn (mut g Gen) mov64(reg Register, val i64) {
} }
} }
g.write64(val) g.write64(val)
g.println('mov64 $reg, $val')
} }
fn (mut g Gen) mov_from_reg(var_offset int, reg Register) { fn (mut g Gen) mov_from_reg(var_offset int, reg Register) {
@ -282,6 +309,7 @@ fn (mut g Gen) mov_from_reg(var_offset int, reg Register) {
else { verror('mov_from_reg $reg') } else { verror('mov_from_reg $reg') }
} }
g.write8(0xff - var_offset + 1) g.write8(0xff - var_offset + 1)
g.println('mov from reg')
} }
fn (mut g Gen) call(addr int) { fn (mut g Gen) call(addr int) {
@ -290,19 +318,22 @@ fn (mut g Gen) call(addr int) {
// +5 is to get the posistion "e8 xx xx xx xx" // +5 is to get the posistion "e8 xx xx xx xx"
// Not sure about the -1. // Not sure about the -1.
rel := 0xffffffff - (g.buf.len + 5 - addr - 1) rel := 0xffffffff - (g.buf.len + 5 - addr - 1)
println('call addr=$addr.hex() rel_addr=$rel.hex() pos=$g.buf.len') // println('call addr=$addr.hex() rel_addr=$rel.hex() pos=$g.buf.len')
g.write8(0xe8) g.write8(0xe8)
g.write32(rel) g.write32(rel)
// g.println('fn call')
} }
fn (mut g Gen) syscall() { fn (mut g Gen) syscall() {
// g.write(0x050f) // g.write(0x050f)
g.write8(0x0f) g.write8(0x0f)
g.write8(0x05) g.write8(0x05)
g.println('syscall')
} }
pub fn (mut g Gen) ret() { pub fn (mut g Gen) ret() {
g.write8(0xc3) g.write8(0xc3)
g.println('ret')
} }
pub fn (mut g Gen) push(reg Register) { pub fn (mut g Gen) push(reg Register) {
@ -318,11 +349,13 @@ pub fn (mut g Gen) push(reg Register) {
else {} else {}
} }
*/ */
g.println('push $reg')
} }
pub fn (mut g Gen) pop(reg Register) { pub fn (mut g Gen) pop(reg Register) {
g.write8(0x58 + reg) g.write8(0x58 + reg)
// TODO r8... // TODO r8...
g.println('pop $reg')
} }
pub fn (mut g Gen) sub32(reg Register, val int) { pub fn (mut g Gen) sub32(reg Register, val int) {
@ -330,6 +363,7 @@ pub fn (mut g Gen) sub32(reg Register, val int) {
g.write8(0x81) g.write8(0x81)
g.write8(0xe8 + reg) // TODO rax is different? g.write8(0xe8 + reg) // TODO rax is different?
g.write32(val) g.write32(val)
g.println('sub $reg,0x$val.hex()')
} }
pub fn (mut g Gen) add(reg Register, val int) { pub fn (mut g Gen) add(reg Register, val int) {
@ -337,10 +371,12 @@ pub fn (mut g Gen) add(reg Register, val int) {
g.write8(0x81) g.write8(0x81)
g.write8(0xe8 + reg) // TODO rax is different? g.write8(0xe8 + reg) // TODO rax is different?
g.write32(val) g.write32(val)
g.println('add $reg,0x$val.hex()')
} }
fn (mut g Gen) leave() { fn (mut g Gen) leave() {
g.write8(0xc9) g.write8(0xc9)
g.println('leave')
} }
// returns label's relative address // returns label's relative address
@ -419,6 +455,7 @@ fn (mut g Gen) mov(reg Register, val int) {
} }
} }
g.write32(val) g.write32(val)
g.println('mov $reg, $val')
} }
fn (mut g Gen) mov_reg(a, b Register) { fn (mut g Gen) mov_reg(a, b Register) {
@ -436,6 +473,7 @@ fn (mut g Gen) mov_rbp_rsp() {
g.write8(0x48) g.write8(0x48)
g.write8(0x89) g.write8(0x89)
g.write8(0xe5) g.write8(0xe5)
g.println('mov rbp,rsp')
} }
pub fn (mut g Gen) register_function_address(name string) { pub fn (mut g Gen) register_function_address(name string) {
@ -446,13 +484,13 @@ pub fn (mut g Gen) register_function_address(name string) {
pub fn (mut g Gen) call_fn(node ast.CallExpr) { pub fn (mut g Gen) call_fn(node ast.CallExpr) {
name := node.name name := node.name
println('call fn $name') // println('call fn $name')
addr := g.fn_addr[name] addr := g.fn_addr[name]
if addr == 0 { if addr == 0 {
verror('fn addr of `$name` = 0') verror('fn addr of `$name` = 0')
} }
// Copy values to registers (calling convention) // Copy values to registers (calling convention)
g.mov(.eax, 0) // g.mov(.eax, 0)
for i in 0 .. node.args.len { for i in 0 .. node.args.len {
expr := node.args[i].expr expr := node.args[i].expr
int_lit := expr as ast.IntegerLiteral int_lit := expr as ast.IntegerLiteral
@ -462,7 +500,8 @@ pub fn (mut g Gen) call_fn(node ast.CallExpr) {
verror('more than 6 args not allowed for now') verror('more than 6 args not allowed for now')
} }
g.call(int(addr)) g.call(int(addr))
println('call $name $addr') g.println('fn call `${name}()`')
// println('call $name $addr')
} }
fn (mut g Gen) stmt(node ast.Stmt) { fn (mut g Gen) stmt(node ast.Stmt) {
@ -480,6 +519,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
ast.ForStmt { ast.ForStmt {
g.for_stmt(it) g.for_stmt(it)
} }
ast.Module {}
ast.Return { ast.Return {
g.gen_exit() g.gen_exit()
g.ret() g.ret()
@ -548,22 +588,21 @@ fn (mut g Gen) allocate_var(name string, size, initial_val int) {
} }
} }
// Generate N in `[rbp-N]` // Generate N in `[rbp-N]`
g.write8(0xff - (g.stack_var_pos + size) + 1) n := g.stack_var_pos + size
g.write8(0xff - n + 1)
g.stack_var_pos += size g.stack_var_pos += size
g.var_offset[name] = g.stack_var_pos g.var_offset[name] = g.stack_var_pos
// Generate the value assigned to the variable // Generate the value assigned to the variable
g.write32(initial_val) g.write32(initial_val)
println('allocate_var(size=$size, initial_val=$initial_val)') // println('allocate_var(size=$size, initial_val=$initial_val)')
g.println('mov DWORD [rbp-0x$n],$initial_val (Aallocate var `$name`)')
} }
fn (mut g Gen) assign_stmt(node ast.AssignStmt) { fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
// `a := 1` | `a,b := 1,2` // `a := 1` | `a,b := 1,2`
for i, ident in node.left { for i, ident in node.left {
match node.right[0] { match node.right[0] {
ast.IntegerLiteral { ast.IntegerLiteral { g.allocate_var(ident.name, 4, it.val.int()) }
print(it.val)
g.allocate_var(ident.name, 4, it.val.int())
}
else {} else {}
} }
} }
@ -587,7 +626,7 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
// Now that we know where we need to jump if the condition is false, update the `jne` call. // Now that we know where we need to jump if the condition is false, update the `jne` call.
// The value is the relative address, difference between current position and the location // The value is the relative address, difference between current position and the location
// after `jne 00 00 00 00` // after `jne 00 00 00 00`
println('after if g.pos=$g.pos() jneaddr=$jne_addr') // println('after if g.pos=$g.pos() jneaddr=$jne_addr')
g.write32_at(jne_addr, g.pos() - jne_addr - 4) // 4 is for "00 00 00 00" g.write32_at(jne_addr, g.pos() - jne_addr - 4) // 4 is for "00 00 00 00"
} }
@ -612,18 +651,22 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) {
g.jmp(0xffffffff - (g.pos() + 5 - start) + 1) g.jmp(0xffffffff - (g.pos() + 5 - start) + 1)
// Update the jump addr to current pos // Update the jump addr to current pos
g.write32_at(jump_addr, g.pos() - jump_addr - 4) // 4 is for "00 00 00 00" g.write32_at(jump_addr, g.pos() - jump_addr - 4) // 4 is for "00 00 00 00"
g.println('jpm after for')
} }
fn (mut g Gen) fn_decl(node ast.FnDecl) { fn (mut g Gen) fn_decl(node ast.FnDecl) {
println(term.green('\n$node.name:'))
g.stack_var_pos = 0
is_main := node.name == 'main' is_main := node.name == 'main'
println('saving addr $node.name $g.buf.len.hex()') // println('saving addr $node.name $g.buf.len.hex()')
if is_main { if is_main {
g.save_main_fn_addr() g.save_main_fn_addr()
} else { } else {
g.register_function_address(node.name) g.register_function_address(node.name)
// g.write32(SEVENS) }
g.push(.rbp) g.push(.rbp)
g.mov_rbp_rsp() g.mov_rbp_rsp()
if !is_main {
g.sub32(.rsp, 0x20) g.sub32(.rsp, 0x20)
} }
if node.args.len > 0 { if node.args.len > 0 {
@ -642,7 +685,7 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
// //
g.stmts(node.stmts) g.stmts(node.stmts)
if is_main { if is_main {
println('end of main: gen exit') // println('end of main: gen exit')
g.gen_exit() g.gen_exit()
// return // return
} }

View File

@ -28,24 +28,27 @@ fn loop() {
} }
fn foo(a int) { fn foo(a int) {
println('foo') println('foo:')
if a == 1 { if a == 1 {
println('foo(1)') println('a == 1')
} }
a++ a++
if a == 1 { if a == 2 {
println('foo(2)') println('a == 2')
}
if a == 3 {
println('a == 3')
} }
} }
fn args() { fn args() {
println('===args===') println('===args===')
args(1) foo(1)
args(2) foo(2)
} }
fn main() { fn main() {
test() test()
loop() loop()
//args() args()
} }

View File

@ -6,3 +6,10 @@ hello
hello hello
hello hello
hello hello
===args===
foo:
a == 1
a == 2
foo:
a == 3