x64: handle -arch amd64/arm64 and -os for raw/linux/macos options (#9844)
parent
59e23dbb57
commit
b951d679ca
|
@ -7,10 +7,8 @@ import v.gen.x64
|
|||
import v.markused
|
||||
|
||||
pub fn (mut b Builder) build_x64(v_files []string, out_file string) {
|
||||
$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')
|
||||
$if !linux && !macos {
|
||||
eprintln('Warning: v -x64 can only generate macOS and Linux binaries for now')
|
||||
}
|
||||
util.timing_start('PARSE')
|
||||
b.parsed_files = parser.parse_files(v_files, b.table, b.pref, b.global_scope)
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
module x64
|
||||
|
||||
pub struct Amd64 {
|
||||
// arm64 specific stuff for code generation
|
||||
}
|
||||
|
||||
pub fn (mut x Amd64) allocate_var(mut g Gen, name string, size int, initial_val int) {
|
||||
// `a := 3` =>
|
||||
// `move DWORD [rbp-0x4],0x3`
|
||||
match size {
|
||||
1 {
|
||||
// BYTE
|
||||
g.write8(0xc6)
|
||||
g.write8(0x45)
|
||||
}
|
||||
4 {
|
||||
// DWORD
|
||||
g.write8(0xc7)
|
||||
g.write8(0x45)
|
||||
}
|
||||
8 {
|
||||
// QWORD
|
||||
g.write8(0x48)
|
||||
g.write8(0xc7)
|
||||
g.write8(0x45)
|
||||
}
|
||||
else {
|
||||
verror('allocate_var: bad size $size')
|
||||
}
|
||||
}
|
||||
// Generate N in `[rbp-N]`
|
||||
n := g.stack_var_pos + size
|
||||
g.write8(0xff - n + 1)
|
||||
g.stack_var_pos += size
|
||||
g.var_offset[name] = g.stack_var_pos
|
||||
// Generate the value assigned to the variable
|
||||
g.write32(initial_val)
|
||||
// println('allocate_var(size=$size, initial_val=$initial_val)')
|
||||
g.println('mov DWORD [rbp-$n.hex2()],$initial_val (Allocate var `$name`)')
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
module x64
|
||||
|
||||
pub struct Aarch64 {
|
||||
// arm64 specific stuff for code generation
|
||||
}
|
||||
|
||||
pub fn (mut x Aarch64) allocate_var(mut g Gen, name string, size int, initial_val int) {
|
||||
eprintln('TODO: allocating var on arm64 ($name) = $size = $initial_val')
|
||||
}
|
|
@ -22,7 +22,8 @@ const (
|
|||
et_rel = 1
|
||||
et_exec = 2
|
||||
et_dyn = 3
|
||||
e_machine = 0x3e
|
||||
e_machine_amd64 = 0x3e
|
||||
e_machine_aarch64 = 183
|
||||
shn_xindex = 0xffff
|
||||
sht_null = 0
|
||||
)
|
||||
|
@ -41,7 +42,11 @@ pub fn (mut g Gen) generate_elf_header() {
|
|||
g.buf << 1 // elf_osabi
|
||||
g.write64(0) // et_rel) // et_rel for .o
|
||||
g.write16(2) // e_type
|
||||
g.write16(x64.e_machine) //
|
||||
if g.pref.arch == .aarch64 {
|
||||
g.write16(x64.e_machine_aarch64)
|
||||
} else {
|
||||
g.write16(x64.e_machine_amd64)
|
||||
}
|
||||
g.write32(x64.ev_current) // e_version
|
||||
eh_size := 0x40
|
||||
phent_size := 0x38
|
||||
|
|
|
@ -11,10 +11,15 @@ import v.pref
|
|||
import term
|
||||
import strings
|
||||
|
||||
interface CodeGen {
|
||||
allocate_var(g &Gen, name string, size int, initial_val int)
|
||||
}
|
||||
|
||||
pub struct Gen {
|
||||
out_name string
|
||||
pref &pref.Preferences // Preferences shared from V struct
|
||||
mut:
|
||||
cgen CodeGen
|
||||
table &ast.Table
|
||||
buf []byte
|
||||
sect_header_name_pos int
|
||||
|
@ -82,24 +87,65 @@ enum Size {
|
|||
_64
|
||||
}
|
||||
|
||||
fn get_backend(pref &pref.Preferences) CodeGen {
|
||||
if pref.arch == .aarch64 {
|
||||
return Aarch64{}
|
||||
}
|
||||
return Amd64{}
|
||||
}
|
||||
|
||||
pub fn gen(files []ast.File, table &ast.Table, out_name string, pref &pref.Preferences) (int, int) {
|
||||
mut g := Gen{
|
||||
table: table
|
||||
sect_header_name_pos: 0
|
||||
out_name: out_name
|
||||
pref: pref
|
||||
cgen: get_backend(pref)
|
||||
}
|
||||
if !pref.is_verbose {
|
||||
println('use `v -x64 -v ...` to print resulting asembly/machine code')
|
||||
}
|
||||
g.generate_elf_header()
|
||||
g.generate_header()
|
||||
for file in files {
|
||||
if file.warnings.len > 0 {
|
||||
eprintln('Warning: ${file.warnings[0]}')
|
||||
}
|
||||
if file.errors.len > 0 {
|
||||
eprintln('Error ${file.errors[0]}')
|
||||
// verror('Error ${file.errors[0]}')
|
||||
}
|
||||
g.stmts(file.stmts)
|
||||
}
|
||||
g.generate_elf_footer()
|
||||
g.generate_footer()
|
||||
return g.nlines, g.buf.len
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) generate_header() {
|
||||
match g.pref.os {
|
||||
.macos {
|
||||
g.generate_macho_header()
|
||||
}
|
||||
.linux {
|
||||
g.generate_elf_header()
|
||||
}
|
||||
.raw {}
|
||||
else {
|
||||
verror('Error: only `raw`, `linux` and `macos` are supported for -os in -x64')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) generate_footer() {
|
||||
match g.pref.os {
|
||||
.macos {
|
||||
g.generate_macho_footer()
|
||||
}
|
||||
.linux {
|
||||
g.generate_elf_footer()
|
||||
}
|
||||
else {
|
||||
g.generate_macho_footer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) stmts(stmts []ast.Stmt) {
|
||||
for stmt in stmts {
|
||||
g.stmt(stmt)
|
||||
|
@ -174,6 +220,7 @@ fn (mut g Gen) write_string(s string) {
|
|||
for c in s {
|
||||
g.write8(int(c))
|
||||
}
|
||||
// g.write8(0) // null terminated strings
|
||||
}
|
||||
|
||||
fn (mut g Gen) write_string_with_padding(s string, max int) {
|
||||
|
@ -645,6 +692,27 @@ pub fn (mut g Gen) call_fn(node ast.CallExpr) {
|
|||
// println('call $name $addr')
|
||||
}
|
||||
|
||||
fn (mut g Gen) for_in_stmt(node ast.ForInStmt) {
|
||||
eprintln('for-in statement is not yet implemented')
|
||||
/*
|
||||
if node.is_range {
|
||||
// `for x in 1..10 {`
|
||||
// i := if node.val_var == '_' { g.new_tmp_var() } else { c_name(node.val_var) }
|
||||
// val_typ := g.table.mktyp(node.val_type)
|
||||
g.write32(0x3131) // 'for (${g.typ(val_typ)} $i = ')
|
||||
g.expr(node.cond)
|
||||
g.write32(0x3232) // ; $i < ')
|
||||
g.expr(node.high)
|
||||
g.write32(0x3333) // '; ++$i) {')
|
||||
} else if node.kind == .array {
|
||||
} else if node.kind == .array_fixed {
|
||||
} else if node.kind == .map {
|
||||
} else if node.kind == .string {
|
||||
} else if node.kind == .struct_ {
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
fn (mut g Gen) stmt(node ast.Stmt) {
|
||||
match node {
|
||||
ast.AssignStmt {
|
||||
|
@ -660,6 +728,9 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
ast.FnDecl {
|
||||
g.fn_decl(node)
|
||||
}
|
||||
ast.ForInStmt {
|
||||
g.for_in_stmt(node)
|
||||
}
|
||||
ast.ForStmt {
|
||||
g.for_stmt(node)
|
||||
}
|
||||
|
@ -690,7 +761,6 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
fn C.strtol(str &char, endptr &&char, base int) int
|
||||
|
||||
fn (mut g Gen) expr(node ast.Expr) {
|
||||
// println('cgen expr()')
|
||||
match node {
|
||||
ast.ArrayInit {}
|
||||
ast.BoolLiteral {}
|
||||
|
@ -721,38 +791,7 @@ fn (mut g Gen) expr(node ast.Expr) {
|
|||
}
|
||||
|
||||
fn (mut g Gen) allocate_var(name string, size int, initial_val int) {
|
||||
// `a := 3` =>
|
||||
// `move DWORD [rbp-0x4],0x3`
|
||||
match size {
|
||||
1 {
|
||||
// BYTE
|
||||
g.write8(0xc6)
|
||||
g.write8(0x45)
|
||||
}
|
||||
4 {
|
||||
// DWORD
|
||||
g.write8(0xc7)
|
||||
g.write8(0x45)
|
||||
}
|
||||
8 {
|
||||
// QWORD
|
||||
g.write8(0x48)
|
||||
g.write8(0xc7)
|
||||
g.write8(0x45)
|
||||
}
|
||||
else {
|
||||
verror('allocate_var: bad size $size')
|
||||
}
|
||||
}
|
||||
// Generate N in `[rbp-N]`
|
||||
n := g.stack_var_pos + size
|
||||
g.write8(0xff - n + 1)
|
||||
g.stack_var_pos += size
|
||||
g.var_offset[name] = g.stack_var_pos
|
||||
// Generate the value assigned to the variable
|
||||
g.write32(initial_val)
|
||||
// println('allocate_var(size=$size, initial_val=$initial_val)')
|
||||
g.println('mov DWORD [rbp-$n.hex2()],$initial_val (Allocate var `$name`)')
|
||||
g.cgen.allocate_var(g, name, size, initial_val)
|
||||
}
|
||||
|
||||
fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
||||
|
|
|
@ -37,9 +37,15 @@ struct Reloc {
|
|||
}
|
||||
|
||||
pub fn (mut g Gen) generate_macho_header() {
|
||||
if g.pref.arch == .aarch64 {
|
||||
g.write32(0xfeedfacf) // MH_MAGIC_64
|
||||
g.write32(0x0100000c) // CPU_TYPE_ARM64
|
||||
g.write32(0x00000000) // CPU_SUBTYPE_ARM64_ALL
|
||||
} else {
|
||||
g.write32(0xfeedfacf) // MH_MAGIC_64
|
||||
g.write32(0x01000007) // CPU_TYPE_X64
|
||||
g.write32(0x00000003) // CPU_SUBTYPE_X64
|
||||
}
|
||||
g.write32(0x00000001) // MH_OBJECT
|
||||
g.write32(0x00000004) // # of load commands
|
||||
g.write32(0x118) // size of load commands
|
||||
|
@ -76,7 +82,7 @@ pub fn (mut g Gen) generate_macho_header() {
|
|||
g.write32(0x18)
|
||||
|
||||
g.write32(0x01)
|
||||
g.write32(0x000b0000)
|
||||
g.write32(0x000a0000) // minOS 10.0
|
||||
g.write32(0)
|
||||
g.write32(0)
|
||||
// lc_symtab
|
||||
|
@ -93,6 +99,7 @@ pub fn (mut g Gen) generate_macho_header() {
|
|||
for _ in 0 .. 12 {
|
||||
g.write32(0)
|
||||
}
|
||||
// ADD THE CODE HERE THIS GOES INTO THE STMTS THING
|
||||
// g.write32(0x77777777)
|
||||
// assembly
|
||||
g.mov_arm(.x0, 1)
|
||||
|
@ -102,7 +109,7 @@ pub fn (mut g Gen) generate_macho_header() {
|
|||
g.mov_arm(.x16, 1)
|
||||
g.svc()
|
||||
//
|
||||
g.write_string('Hello WorlD!\n')
|
||||
g.write_string('Hello World!\n')
|
||||
g.write8(0) // padding?
|
||||
g.write8(0)
|
||||
g.write8(0)
|
||||
|
@ -113,9 +120,9 @@ pub fn (mut g Gen) generate_macho_header() {
|
|||
}
|
||||
|
||||
pub fn (mut g Gen) generate_macho_footer() {
|
||||
// Create the binary
|
||||
// Create the binary // should be .o ?
|
||||
mut f := os.create(g.out_name) or { panic(err) }
|
||||
os.chmod(g.out_name, 0o775) // make it an executable
|
||||
os.chmod(g.out_name, 0o775) // make it executable
|
||||
unsafe { f.write_ptr(g.buf.data, g.buf.len) }
|
||||
f.close()
|
||||
// println('\narm64 mach-o binary has been successfully generated')
|
||||
|
|
|
@ -17,6 +17,7 @@ pub enum OS {
|
|||
android
|
||||
solaris
|
||||
haiku
|
||||
raw
|
||||
all
|
||||
}
|
||||
|
||||
|
@ -35,6 +36,7 @@ pub fn os_from_string(os_str string) ?OS {
|
|||
'solaris' { return .solaris }
|
||||
'android' { return .android }
|
||||
'haiku' { return .haiku }
|
||||
'raw' { return .raw }
|
||||
'linux_or_macos', 'nix' { return .linux }
|
||||
'' { return ._auto }
|
||||
else { return error('bad OS $os_str') }
|
||||
|
@ -56,6 +58,7 @@ pub fn (o OS) str() string {
|
|||
.android { return 'Android' }
|
||||
.solaris { return 'Solaris' }
|
||||
.haiku { return 'Haiku' }
|
||||
.raw { return 'Raw' }
|
||||
.all { return 'all' }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue