diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 3bc5f4745f..7d6ae8277f 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -458,11 +458,9 @@ pub fn (mut g Gen) gen_loop_end(to int, label int) { g.jl(label) } -pub fn (mut g Gen) allocate_string(s string, opsize int) int { - g.strings << s +pub fn (mut g Gen) allocate_string(s string, opsize int, typ RelocType) int { str_pos := g.buf.len + opsize - g.str_pos << str_pos - g.strs << String{s, str_pos} + g.strs << String{s, str_pos, typ} return str_pos } @@ -507,7 +505,7 @@ pub fn (mut g Gen) inline_strlen(r Register) { // TODO: strlen of string at runtime pub fn (mut g Gen) gen_print_reg(r Register, n int, fd int) { - mystrlen := true + mystrlen := true // if n < 0 maybe? g.mov_reg(.rsi, r) if mystrlen { g.inline_strlen(.rsi) @@ -550,24 +548,20 @@ pub fn (mut g Gen) gen_print(s string, fd int) { g.apicall('GetStdHandle') g.mov_reg(.rcx, .rax) // g.mov64(.rdx, g.allocate_string(s, 3)) - g.lea(.rdx, g.allocate_string(s, 3)) + g.lea(.rdx, g.allocate_string(s, 3, .abs64)) g.mov(.r8, s.len) // string length g.write([byte(0x4c), 0x8d, 0x4c, 0x24, 0x20]) // lea r9, [rsp+0x20] g.write([byte(0x48), 0xc7, 0x44, 0x24, 0x20]) g.write32(0) // mov qword[rsp+0x20], 0 // g.mov(.r9, rsp+0x20) g.apicall('WriteFile') - return + } else { + g.mov(.eax, g.nsyscall_write()) + g.mov(.edi, fd) + g.learel(.rsi, g.allocate_string(s, 3, .rel32)) // for rsi its 2 + g.mov(.edx, s.len) // len + g.syscall() } - // - // qq := s + '\n' - // - g.mov(.eax, g.nsyscall_write()) - g.mov(.edi, fd) - // segment_start + 0x9f) // str pos // placeholder - g.mov64(.rsi, g.allocate_string(s, 2)) // for rsi its 2 - g.mov(.edx, s.len) // len - g.syscall() } fn (mut g Gen) nsyscall_write() int { @@ -638,6 +632,24 @@ pub fn (mut g Gen) gen_amd64_exit(expr ast.Expr) { g.trap() // should never be reached, just in case } +fn (mut g Gen) learel(reg Register, val int) { + g.write8(0x48) + g.write8(0x8d) + match reg { + .rax { + g.write8(0x05) + } + .rsi { + g.write8(0x35) + } + else { + g.n_error('learel must use rsi or rax') + } + } + g.write32(val) + g.println('lea $reg, rip + $val') +} + fn (mut g Gen) lea(reg Register, val int) { g.write8(0x48) g.write8(0x8d) @@ -1109,7 +1121,7 @@ g.v_error('oops', node.pos) pos += 8 } ast.StringLiteral { - g.mov64(.rsi, g.allocate_string('$e.val', 2)) // for rsi its 2 + g.mov64(.rsi, g.allocate_string('$e.val', 2, .abs64)) // for rsi its 2 g.mov_reg_to_var(pos, .rsi) pos += 8 } @@ -1148,7 +1160,7 @@ g.v_error('oops', node.pos) ast.StringLiteral { dest := g.allocate_var(name, 4, 0) ie := node.right[i] as ast.StringLiteral - g.mov64(.rsi, g.allocate_string(ie.str(), 2)) // for rsi its 2 + g.mov64(.rsi, g.allocate_string(ie.str(), 2, .abs64)) // for rsi its 2 g.mov_reg_to_var(dest, .rsi) } ast.CallExpr { @@ -1254,6 +1266,10 @@ fn (mut g Gen) gen_asm_stmt_amd64(asm_node ast.AsmStmt) { line += a.val.str() imm = if a.val { 1 } else { 0 } } + ast.CharLiteral { + line += a.val.str() + imm = a.val.int() + } /* ast.AsmAddressing { } @@ -1261,8 +1277,6 @@ fn (mut g Gen) gen_asm_stmt_amd64(asm_node ast.AsmStmt) { } ast.AsmDisp { } - ast.CharLiteral { - } ast.FloatLiteral { } */ @@ -1489,7 +1503,6 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) { return } infix_expr := node.cond as ast.InfixExpr - // g.mov(.eax, 0x77777777) mut jump_addr := 0 // location of `jne *00 00 00 00*` start := g.pos() match mut infix_expr.left { diff --git a/vlib/v/gen/native/elf.v b/vlib/v/gen/native/elf.v index e1d3642c77..aa9a8a2bb5 100644 --- a/vlib/v/gen/native/elf.v +++ b/vlib/v/gen/native/elf.v @@ -4,58 +4,82 @@ module native const ( - mag0 = byte(0x7f) - mag1 = `E` - mag2 = `L` - mag3 = `F` - ei_class = 4 - elfclass64 = 2 - elfdata2lsb = 1 - ev_current = 1 -) + elf_class32 = 1 + elf_class64 = 2 -// ELF file types -const ( - elf_osabi = 0 - et_rel = 1 - et_exec = 2 - et_dyn = 3 - e_machine_amd64 = 0x3e - e_machine_arm64 = 0xb7 - shn_xindex = 0xffff - sht_null = 0 + elf_data_le = 1 + elf_data_be = 2 + + elf_version = 1 + elf_abiversion = 0 + + elf_type_rel = 1 + elf_type_exec = 2 + elf_type_dyn = 3 + + elf_amd64 = 0x3e + elf_arm64 = 0xb7 + + elf_osabi_none = 0 + elf_osabi_hpux = 1 + elf_osabi_netbsd = 2 + elf_osabi_linux = 3 + elf_osabi_freebsd = 9 + + elf_header_size = 0x40 + elf_phentry_size = 0x38 ) const ( segment_start = 0x400000 placeholder = 0 - sevens = 0x77777777 ) +/* +struct Header64 { + ident u8 // File identification. + @type u16 // File type. + machine u16 // Machine architecture. + version u32 // ELF format version. + entry u64 // Entry point. + phoff u64 // Program header file offset. + shoff u64 // Section header file offset. + flags u32 // Architecture-specific flags. + ehsize u16 // Size of ELF header in bytes. + phentsize u16 // Size of program header entry. + phnum u16 // Number of program header entries. + shentsize u16 // Size of section header entry. + shnum u16 // Number of section header entries. + shstrndx u16 // Section name strings section. +} +*/ + pub fn (mut g Gen) generate_elf_header() { - g.buf << [byte(native.mag0), native.mag1, native.mag2, native.mag3] - g.buf << native.elfclass64 // file class - g.buf << native.elfdata2lsb // data encoding - g.buf << native.ev_current // file version - g.buf << native.elf_osabi - g.write64(0) // et_rel) // et_rel for .o - g.write16(2) // e_type + elf_type := native.elf_type_dyn // PIE (use _exec for non-relocatable executables) + + g.buf << '\x7fELF'.bytes() + g.buf << native.elf_class64 + g.buf << native.elf_data_le + g.buf << native.elf_version + g.buf << native.elf_osabi_none + g.write64(0) // abiversion(1)+pad(6)+nident(1) + g.write16(elf_type) + if g.pref.arch == .arm64 { - g.write16(native.e_machine_arm64) + g.write16(native.elf_arm64) } else { - g.write16(native.e_machine_amd64) + g.write16(native.elf_amd64) } - g.write32(native.ev_current) // e_version - eh_size := 0x40 - phent_size := 0x38 - g.write64(native.segment_start + eh_size + phent_size) // e_entry - g.write64(0x40) // e_phoff + g.write32(native.elf_version) + g.write64(native.segment_start + native.elf_header_size + native.elf_phentry_size) // e_entry + g.write64(native.elf_header_size) // 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(native.elf_header_size) + g.write16(native.elf_phentry_size) g.write16(1) // e_phnum g.write16(0) // e_shentsize + // e_shnum := g.buf.len g.write16(0) // e_shnum (number of sections) g.write16(0) // e_shstrndx // Elf64_Phdr @@ -68,6 +92,16 @@ pub fn (mut g Gen) generate_elf_header() { g.write64(0) // p_filesz PLACEHOLDER, set to file_size later // addr: 060 g.write64(0) // p_memsz g.write64(0x1000) // p_align + // write sections + /* + sections := []string{} + g.write16_at(e_shnum, sections.len) // e_shnum (number of sections) + + for section in sections { + // write section data + println('section $section') + } + */ // user code starts here at // address: 00070 and a half if g.pref.is_verbose { @@ -79,24 +113,30 @@ pub fn (mut g Gen) generate_elf_header() { g.println('; call fn main') } -pub fn (mut g 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(native.segment_start + g.buf.len, int(g.str_pos[i])) - g.write_string(s) - g.write8(0) +fn (mut g Gen) elf_string_table() { + for _, s in g.strs { + match s.typ { + .abs64 { + // g.write64_at(native.segment_start + g.buf.len, int(g.str_pos[i])) + g.write64_at(s.pos, g.buf.len) + } + .rel32 { + g.write32_at(s.pos, g.buf.len - s.pos - 4) + } + else { + g.n_error('unsupported string reloc type') + } + } + g.write_string(s.str) } - // Now we know the file size, set it +} + +pub fn (mut g Gen) generate_elf_footer() { + g.elf_string_table() + // file_size holds the address at the end of the code and const strings table 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) + g.write64_at(g.file_size_pos, file_size) // set file size 64 bit value + g.write64_at(g.file_size_pos + 8, file_size) if g.pref.arch == .arm64 { bl_next := u32(0x94000001) g.write32_at(g.code_start_pos, int(bl_next)) diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index 61d2485086..1f4f7b65e7 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -31,9 +31,7 @@ mut: buf []byte sect_header_name_pos int offset i64 - str_pos []i64 stackframe_size int - strings []string // TODO use a map and don't duplicate strings file_size_pos i64 main_fn_addr i64 code_start_pos i64 // location of the start of the assembly instructions @@ -50,9 +48,18 @@ mut: strs []String } +enum RelocType { + rel8 + rel16 + rel32 + rel64 + abs64 +} + struct String { str string pos int + typ RelocType } struct CallPatch { @@ -168,7 +175,10 @@ pub fn (mut g Gen) generate_footer() { .raw { g.create_executable() } - else {} + else { + eprintln('Unsupported target file format') + exit(1) + } } } @@ -224,7 +234,7 @@ fn (mut g Gen) write64(n i64) { g.buf << byte(n >> 56) } -fn (mut g Gen) write64_at(n i64, at i64) { +fn (mut g Gen) write64_at(at i64, n i64) { // write 8 bytes g.buf[at] = byte(n) g.buf[at + 1] = byte(n >> 8) @@ -244,11 +254,17 @@ fn (mut g Gen) write32_at(at i64, n int) { g.buf[at + 3] = byte(n >> 24) } +fn (mut g Gen) write16_at(at i64, n int) { + // write 2 bytes + g.buf[at] = byte(n) + g.buf[at + 1] = byte(n >> 8) +} + fn (mut g Gen) write_string(s string) { for c in s { g.write8(int(c)) } - // g.write8(0) // null terminated strings + g.zeroes(1) } fn (mut g Gen) write_string_with_padding(s string, max int) { @@ -288,15 +304,16 @@ pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, name string) { g.gen_print_reg(.rax, 3, fd) } ast.IntegerLiteral { - g.mov64(.rax, g.allocate_string('$expr.val\n', 2)) + g.learel(.rax, g.allocate_string('$expr.val\n', 3, .rel32)) g.gen_print_reg(.rax, 3, fd) } ast.BoolLiteral { // register 'true' and 'false' strings // g.expr(expr) + // XXX mov64 shuoldnt be used for addressing if expr.val { - g.mov64(.rax, g.allocate_string('true', 2)) + g.learel(.rax, g.allocate_string('true', 3, .rel32)) } else { - g.mov64(.rax, g.allocate_string('false', 2)) + g.learel(.rax, g.allocate_string('false', 3, .rel32)) } g.gen_print_reg(.rax, 3, fd) } @@ -310,7 +327,7 @@ pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, name string) { mut off := 0 for f in s.fields { if f.name == field_name { - g.mov64(.rax, g.allocate_string('$off\n', 2)) + g.learel(.rax, g.allocate_string('$off\n', 3, .rel32)) g.gen_print_reg(.rax, 3, fd) break } @@ -591,7 +608,7 @@ fn (mut g Gen) stmt(node ast.Stmt) { ast.StringLiteral { s = e0.val.str() g.expr(node.exprs[0]) - g.mov64(.rax, g.allocate_string(s, 2)) + g.mov64(.rax, g.allocate_string(s, 2, .abs64)) } ast.Ident { g.expr(e0) @@ -643,7 +660,7 @@ fn (mut g Gen) gen_syscall(node ast.CallExpr) { match expr.expr { ast.StringLiteral { s := expr.expr.val.replace('\\n', '\n') - g.allocate_string(s, 2) + g.allocate_string(s, 2, .abs64) g.mov64(ra[i], 1) done = true } @@ -660,7 +677,7 @@ fn (mut g Gen) gen_syscall(node ast.CallExpr) { node.pos) } s := expr.val.replace('\\n', '\n') - g.allocate_string(s, 2) + g.allocate_string(s, 2, .abs64) g.mov64(ra[i], 1) } else { diff --git a/vlib/v/gen/native/macho.v b/vlib/v/gen/native/macho.v index d0bd9c6b1f..2b8d0961b7 100644 --- a/vlib/v/gen/native/macho.v +++ b/vlib/v/gen/native/macho.v @@ -395,16 +395,23 @@ fn (mut g Gen) write_symbol(s Symbol) { fn (mut g Gen) sym_string_table() int { begin := g.buf.len g.zeroes(1) - for i, s in g.strings { - pos := g.buf.len - int(g.str_pos[i]) - if g.pref.os == .windows { - g.write32_at(int(g.str_pos[i]), pos - 4) // 0x402028 + pos) - } else { - baddr := i64(0x100000000) - g.write64_at(g.buf.len + baddr, int(g.str_pos[i])) + for _, s in g.strs { + pos := g.buf.len - s.pos - 4 + match s.typ { + .rel32 { + g.write32_at(s.pos, pos) + } + else { + if g.pref.os == .windows { + // that should be .rel32, not windows-specific + g.write32_at(s.pos, pos) + } else { + baddr := i64(0x100000000) + g.write64_at(s.pos, g.buf.len + baddr) + } + } } - g.write_string(s) - g.write8(0) + g.write_string(s.str) } return g.buf.len - begin }