x64: basic mach-o and arm64 support
							parent
							
								
									818be80581
								
							
						
					
					
						commit
						845e8decce
					
				
							
								
								
									
										13
									
								
								vlib/gg/gg.v
								
								
								
								
							
							
						
						
									
										13
									
								
								vlib/gg/gg.v
								
								
								
								
							|  | @ -24,14 +24,13 @@ pub type FNMove = fn (x f32, y f32, z voidptr) | |||
| pub type FNChar = fn (c u32, x voidptr) | ||||
| 
 | ||||
| pub struct Event { | ||||
| pub: | ||||
| 	frame_count u64 | ||||
| 	typ         sapp.EventType | ||||
| 	key_code    KeyCode | ||||
| 	char_code   u32 | ||||
| 	key_repeat  bool | ||||
| 	modifiers   u32 | ||||
| pub mut: | ||||
| 	frame_count        u64 | ||||
| 	typ                sapp.EventType | ||||
| 	key_code           KeyCode | ||||
| 	char_code          u32 | ||||
| 	key_repeat         bool | ||||
| 	modifiers          u32 | ||||
| 	mouse_button       sapp.MouseButton | ||||
| 	mouse_x            f32 | ||||
| 	mouse_y            f32 | ||||
|  |  | |||
|  | @ -31,6 +31,8 @@ mut: | |||
| 	debug_pos            int | ||||
| 	errors               []errors.Error | ||||
| 	warnings             []errors.Warning | ||||
| 	syms                 []Symbol | ||||
| 	relocs               []Reloc | ||||
| } | ||||
| 
 | ||||
| // string_addr map[string]i64
 | ||||
|  | @ -173,6 +175,15 @@ fn (mut g Gen) write_string(s string) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) write_string_with_padding(s string, max int) { | ||||
| 	for c in s { | ||||
| 		g.write8(int(c)) | ||||
| 	} | ||||
| 	for _ in 0 .. max - s.len { | ||||
| 		g.write8(0) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) inc(reg Register) { | ||||
| 	g.write16(0xff49) | ||||
| 	match reg { | ||||
|  |  | |||
|  | @ -0,0 +1,27 @@ | |||
| // | ||||
| // Assembler program to print "Hello World!" | ||||
| // to stdout. | ||||
| // | ||||
| // X0-X2 - parameters to Unix system calls | ||||
| // X16 - Mach System Call function number | ||||
| // | ||||
| 
 | ||||
| .global _start			// Provide program starting address to linker | ||||
| .align 4			// Make sure everything is aligned properly | ||||
| 
 | ||||
| // Setup the parameters to print hello world | ||||
| // and then call the Kernel to do it. | ||||
| _start: mov	X0, #1		// 1 = StdOut | ||||
| 	adr	X0, helloworld 	// string to print | ||||
| 	//mov	X2, #13	    	// length of our string | ||||
| 	bl      _puts | ||||
| 	//mov	X16, #4		// Unix write system call | ||||
| 	//svc	#0x80		// Call kernel to output the string | ||||
| 
 | ||||
| // Setup the parameters to exit the program | ||||
| // and then call the kernel to do it. | ||||
| 	mov     X0, #0		// Use 0 return code | ||||
| 	mov     X16, #1		// System call number 1 terminates this program | ||||
| 	svc     #0x80		// Call kernel to terminate the program | ||||
| 
 | ||||
| helloworld:      .ascii  "Hello World!\n" | ||||
|  | @ -0,0 +1,281 @@ | |||
| // Copyright (c) 2019-2021 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 | ||||
| 
 | ||||
| import os | ||||
| 
 | ||||
| const ( | ||||
| 	S_ATTR_SOME_INSTRUCTIONS = 0x00000400 | ||||
| 	S_ATTR_PURE_INSTRUCTIONS = 0x80000000 | ||||
| 	S_ATTR_EXT_RELOC         = 0x00000200 | ||||
| 	S_ATTR_LOC_RELOC         = 0x00000100 | ||||
| 	//
 | ||||
| 	MACHO_SYMCMD_SIZE        = 0x18 | ||||
| 	MACHO_D_SIZE             = 0x50 | ||||
| 	LC_SYMTAB                = 0x2 | ||||
| 	LC_DYMSYMTAB             = 0xB | ||||
| ) | ||||
| 
 | ||||
| struct Symbol { | ||||
| 	str_entry  int | ||||
| 	symbol_typ int | ||||
| 	section    int | ||||
| 	desc       int | ||||
| 	val        i64 | ||||
| 	name       string | ||||
| 	is_ext     bool | ||||
| } | ||||
| 
 | ||||
| struct Reloc { | ||||
| 	addr  int | ||||
| 	pcrel int | ||||
| 	len   int | ||||
| 	ext   int | ||||
| 	typ   int | ||||
| 	snum  int // symbol index (if ext) or infile section number
 | ||||
| } | ||||
| 
 | ||||
| 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
 | ||||
| 	g.write32(0x00000001) // MH_OBJECT
 | ||||
| 	g.write32(0x00000004) // # of load commands
 | ||||
| 	g.write32(0x118) // size of load commands
 | ||||
| 	// g.write32(0x00002000) // MH_SUBSECTIONS_VIA_SYMBOLS
 | ||||
| 	g.write32(0) // MH_SUBSECTIONS_VIA_SYMBOLS
 | ||||
| 	g.write32(0) // reserved
 | ||||
| 	////
 | ||||
| 	g.write32(0x19) // LC_SEGMENT_64
 | ||||
| 	g.write32(0x98) // command size
 | ||||
| 	g.zeroes(16) // segment name
 | ||||
| 	g.write64(0) // VM address
 | ||||
| 	g.write64(0x25) // VM size
 | ||||
| 	g.write64(0x138) // file offset
 | ||||
| 	g.write64(0x25) // file size
 | ||||
| 	g.write32(0x7) // max vm protection
 | ||||
| 	g.write32(0x7) // initial vm protection
 | ||||
| 	g.write32(0x1) // # of sections
 | ||||
| 	g.write32(0) // flags
 | ||||
| 	////
 | ||||
| 	g.write_string_with_padding('__text', 16) // section name
 | ||||
| 	g.write_string_with_padding('__TEXT', 16) // segment name
 | ||||
| 	g.write64(0) // address
 | ||||
| 	g.write64(0x25) // size
 | ||||
| 	g.write32(0x138) // offset
 | ||||
| 	g.write32(0x4) // alignment
 | ||||
| 	g.write32(0x160) // relocation offset
 | ||||
| 	g.write32(0x1) // # of relocations
 | ||||
| 	g.write32(x64.S_ATTR_SOME_INSTRUCTIONS | x64.S_ATTR_PURE_INSTRUCTIONS) | ||||
| 	g.write32(0) | ||||
| 	g.write32(0) | ||||
| 	g.write32(0) | ||||
| 	/// ???
 | ||||
| 	g.write32(0x32) | ||||
| 	g.write32(0x18) | ||||
| 
 | ||||
| 	g.write32(0x01) | ||||
| 	g.write32(0x000b0000) | ||||
| 	g.write32(0) | ||||
| 	g.write32(0) | ||||
| 	// LC_SYMTAB
 | ||||
| 	g.sym_table_command() | ||||
| 	//
 | ||||
| 	g.write32(x64.LC_DYMSYMTAB) | ||||
| 	g.write32(x64.MACHO_D_SIZE) | ||||
| 	g.write32(0) | ||||
| 	g.write32(2) | ||||
| 	g.write32(2) | ||||
| 	g.write32(1) | ||||
| 	g.write32(3) | ||||
| 	g.write32(1) | ||||
| 	for _ in 0 .. 12 { | ||||
| 		g.write32(0) | ||||
| 	} | ||||
| 	// g.write32(0x77777777)
 | ||||
| 	// assembly
 | ||||
| 	g.mov_arm(.x0, 1) | ||||
| 	g.adr() | ||||
| 	g.bl() | ||||
| 	g.mov_arm(.x0, 0) | ||||
| 	g.mov_arm(.x16, 1) | ||||
| 	g.svc() | ||||
| 	//
 | ||||
| 	g.write_string('Hello WorlD!\n') | ||||
| 	g.write8(0) // padding?
 | ||||
| 	g.write8(0) | ||||
| 	g.write8(0) | ||||
| 	g.write_relocs() | ||||
| 	g.sym_table() | ||||
| 	g.sym_string_table() | ||||
| 	g.write8(0) | ||||
| } | ||||
| 
 | ||||
| pub fn (mut g Gen) generate_macho_footer() { | ||||
| 	// Create the binary
 | ||||
| 	mut f := os.create(g.out_name) or { panic(err) } | ||||
| 	os.chmod(g.out_name, 0o775) // make it an executable
 | ||||
| 	f.write_bytes(g.buf.data, g.buf.len) | ||||
| 	f.close() | ||||
| 	// println('\narm64 mach-o binary has been successfully generated')
 | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) sym_table_command() { | ||||
| 	g.syms << Symbol{ | ||||
| 		str_entry: 0x19 | ||||
| 		symbol_typ: 0xe | ||||
| 		section: 1 | ||||
| 		val: 0 | ||||
| 		name: '_start' | ||||
| 		is_ext: true | ||||
| 	} | ||||
| 	g.syms << Symbol{ | ||||
| 		str_entry: 0x0e | ||||
| 		symbol_typ: 0xe | ||||
| 		// symbol_typ: SYM_DEF
 | ||||
| 		section: 1 | ||||
| 		val: 0x18 | ||||
| 		name: '_puts' | ||||
| 		is_ext: false | ||||
| 	} | ||||
| 	g.syms << Symbol{ | ||||
| 		str_entry: 0x01 | ||||
| 		symbol_typ: 0xf | ||||
| 		// symbol_typ: SYM_DEF
 | ||||
| 		section: 1 | ||||
| 		// val: 0x27
 | ||||
| 		val: 0 | ||||
| 		name: 'helloworld' | ||||
| 		is_ext: false | ||||
| 	} | ||||
| 	g.syms << Symbol{ | ||||
| 		str_entry: 0x08 | ||||
| 		symbol_typ: 0x1 | ||||
| 		// symbol_typ: SYM_DEF
 | ||||
| 		section: 0 | ||||
| 		// val: 0x27
 | ||||
| 		val: 0 | ||||
| 		name: 'ltmp1' | ||||
| 		is_ext: false | ||||
| 	} | ||||
| 	g.write32(x64.LC_SYMTAB) | ||||
| 	g.write32(x64.MACHO_SYMCMD_SIZE) | ||||
| 	sym_table_offset := 0x168 | ||||
| 	g.write32(sym_table_offset) | ||||
| 	g_syms_len := 4 | ||||
| 	g.write32(g_syms_len) | ||||
| 	str_offset := 0x1a8 | ||||
| 	g.write32(str_offset) | ||||
| 	str_size := 0x20 | ||||
| 	g.write32(str_size) | ||||
| } | ||||
| 
 | ||||
| pub fn (mut g Gen) zeroes(n int) { | ||||
| 	for _ in 0 .. n { | ||||
| 		g.buf << 0 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| enum Register2 { | ||||
| 	x0 | ||||
| 	x1 | ||||
| 	x2 | ||||
| 	x3 | ||||
| 	x4 | ||||
| 	x5 | ||||
| 	x6 | ||||
| 	x7 | ||||
| 	x8 | ||||
| 	x9 | ||||
| 	x10 | ||||
| 	x11 | ||||
| 	x12 | ||||
| 	x13 | ||||
| 	x14 | ||||
| 	x15 | ||||
| 	x16 | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) mov_arm(reg Register2, val u64) { | ||||
| 	m := u64(0xffff) | ||||
| 	x := u64(val) | ||||
| 	// println('========')
 | ||||
| 	// println(x & ~m)
 | ||||
| 	// println(x & ~(m << 16))
 | ||||
| 	// g.write32(0x777777)
 | ||||
| 	r := int(reg) | ||||
| 	if r == 0 && val == 1 { | ||||
| 		g.write32(0xd2800020) | ||||
| 	} else if r == 0 { | ||||
| 		g.write32(0xd2800000) | ||||
| 	} else if r == 16 { | ||||
| 		g.write32(0xd2800030) | ||||
| 	} | ||||
| 	/* | ||||
| 	if 1 ^ (x & ~m) != 0 { | ||||
| 		// println('yep')
 | ||||
| 		g.write32(int(u64(0x52800000) | u64(r) | x << 5)) | ||||
| 		g.write32(0x88888888) | ||||
| 		g.write32(int(u64(0x52800000) | u64(r) | x >> 11)) | ||||
| 	} else if 1 ^ (x & ~(m << 16)) != 0 { | ||||
| 		// g.write32(int(u64(0x52800000) | u64(r) | x >> 11))
 | ||||
| 		// println('yep2')
 | ||||
| 		// g.write32(0x52a00000 | r | val >> 11)
 | ||||
| 	} | ||||
| 	*/ | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) adr() { | ||||
| 	g.write32(0x100000a0) | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) bl() { | ||||
| 	// g.write32(0xa9400000)
 | ||||
| 	g.write32(0x94000000) | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) svc() { | ||||
| 	g.write32(0xd4001001) | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) write_relocs() { | ||||
| 	g.write32(0x8) | ||||
| 	g.write32(0x2d000003) | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) sym_table() { | ||||
| 	// strings first
 | ||||
| 	for sym in g.syms { | ||||
| 		// if !sym.is_ext {
 | ||||
| 		g.write_symbol(sym) | ||||
| 		//}
 | ||||
| 	} | ||||
| 	// now fns  (external syms)
 | ||||
| 	/* | ||||
| 	for sym in g.syms { | ||||
| 		if sym.is_ext { | ||||
| 			g.write_symbol(sym) | ||||
| 		} | ||||
| 	} | ||||
| 	*/ | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) write_symbol(s Symbol) { | ||||
| 	// g.write8(0x77)
 | ||||
| 	g.write32(s.str_entry) | ||||
| 	g.write8(s.symbol_typ) | ||||
| 	g.write8(s.section) | ||||
| 	g.write8(0) | ||||
| 	g.write8(0) | ||||
| 	g.write64(s.val) | ||||
| 	// g.write16(s.desc)
 | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) sym_string_table() { | ||||
| 	g.zeroes(1) | ||||
| 	for sym in g.syms { | ||||
| 		g.write_string(sym.name) | ||||
| 		g.write8(0) | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,13 @@ | |||
| import v.gen.x64 | ||||
| import v.pref | ||||
| import v.table | ||||
| 
 | ||||
| fn test_macho() { | ||||
| 	mut g := x64.Gen{ | ||||
| 		pref: &pref.Preferences{} | ||||
| 		out_name: 'test.bin' | ||||
| 		table: &table.Table{} | ||||
| 	} | ||||
| 	g.generate_macho_header() | ||||
| 	g.generate_macho_footer() | ||||
| } | ||||
		Loading…
	
		Reference in New Issue