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