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') | ||||
| } | ||||
|  | @ -18,13 +18,14 @@ const ( | |||
| 
 | ||||
| // ELF file types
 | ||||
| const ( | ||||
| 	elf_osabi  = 0 | ||||
| 	et_rel     = 1 | ||||
| 	et_exec    = 2 | ||||
| 	et_dyn     = 3 | ||||
| 	e_machine  = 0x3e | ||||
| 	shn_xindex = 0xffff | ||||
| 	sht_null   = 0 | ||||
| 	elf_osabi         = 0 | ||||
| 	et_rel            = 1 | ||||
| 	et_exec           = 2 | ||||
| 	et_dyn            = 3 | ||||
| 	e_machine_amd64   = 0x3e | ||||
| 	e_machine_aarch64 = 183 | ||||
| 	shn_xindex        = 0xffff | ||||
| 	sht_null          = 0 | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
|  | @ -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() { | ||||
| 	g.write32(0xfeedfacf) // MH_MAGIC_64
 | ||||
| 	g.write32(0x0100000c) // CPU_TYPE_ARM64
 | ||||
| 	g.write32(0x00000000) // CPU_SUBTYPE_ARM64_ALL
 | ||||
| 	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