x64: basic mach-o and arm64 support

pull/9134/head
Alexander Medvednikov 2021-03-05 17:52:34 +03:00
parent 818be80581
commit 845e8decce
5 changed files with 338 additions and 7 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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"

View File

@ -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)
}
}

View File

@ -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()
}