native: initial support for apple-m1 (#14795)
parent
8703e336e0
commit
1caff5b379
|
@ -151,7 +151,7 @@ jobs:
|
||||||
[ "$(stat -c %s leaks.txt)" = "0" ]
|
[ "$(stat -c %s leaks.txt)" = "0" ]
|
||||||
|
|
||||||
macos:
|
macos:
|
||||||
runs-on: macOS-latest
|
runs-on: macOS-12
|
||||||
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 121
|
timeout-minutes: 121
|
||||||
env:
|
env:
|
||||||
|
|
|
@ -39,6 +39,15 @@ pub fn build_native(mut b builder.Builder, v_files []string, out_file string) {
|
||||||
}
|
}
|
||||||
b.front_and_middle_stages(nvf) or { return }
|
b.front_and_middle_stages(nvf) or { return }
|
||||||
util.timing_start('Native GEN')
|
util.timing_start('Native GEN')
|
||||||
|
if b.pref.arch == ._auto {
|
||||||
|
$if amd64 {
|
||||||
|
b.pref.arch = .amd64
|
||||||
|
} $else $if arm64 {
|
||||||
|
b.pref.arch = .arm64
|
||||||
|
} $else {
|
||||||
|
eprintln('Error: Only arm64 and amd64 are supported by V')
|
||||||
|
}
|
||||||
|
}
|
||||||
b.stats_lines, b.stats_bytes = native.gen(b.parsed_files, b.table, out_file, b.pref)
|
b.stats_lines, b.stats_bytes = native.gen(b.parsed_files, b.table, out_file, b.pref)
|
||||||
util.timing_measure('Native GEN')
|
util.timing_measure('Native GEN')
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,9 @@ fn (mut g Gen) neg(reg Register) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) cmp(reg Register, size Size, val i64) {
|
fn (mut g Gen) cmp(reg Register, size Size, val i64) {
|
||||||
|
if g.pref.arch != .amd64 {
|
||||||
|
panic('cmp')
|
||||||
|
}
|
||||||
// Second byte depends on the size of the value
|
// Second byte depends on the size of the value
|
||||||
match size {
|
match size {
|
||||||
._8 {
|
._8 {
|
||||||
|
@ -349,6 +352,9 @@ fn (mut g Gen) movabs(reg Register, val i64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) mov_reg_to_var(var_offset int, reg Register) {
|
fn (mut g Gen) mov_reg_to_var(var_offset int, reg Register) {
|
||||||
|
if g.pref.arch != .amd64 {
|
||||||
|
panic('invalid arch for mov_reg_to_var')
|
||||||
|
}
|
||||||
// 89 7d fc mov DWORD PTR [rbp-0x4],edi
|
// 89 7d fc mov DWORD PTR [rbp-0x4],edi
|
||||||
match reg {
|
match reg {
|
||||||
.rax {
|
.rax {
|
||||||
|
@ -458,8 +464,14 @@ fn (mut g Gen) cdq() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut g Gen) ret() {
|
pub fn (mut g Gen) ret() {
|
||||||
|
if g.pref.arch == .amd64 {
|
||||||
g.write8(0xc3)
|
g.write8(0xc3)
|
||||||
g.println('ret')
|
g.println('ret')
|
||||||
|
} else if g.pref.arch == .arm64 {
|
||||||
|
g.write32(0xd65f03c0)
|
||||||
|
} else {
|
||||||
|
panic('invalid arch')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut g Gen) push(reg Register) {
|
pub fn (mut g Gen) push(reg Register) {
|
||||||
|
@ -1958,9 +1970,11 @@ fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
|
||||||
g.ret()
|
g.ret()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
pub fn (mut x Amd64) allocate_var(name string, size int, initial_val int) {
|
pub fn (mut x Amd64) allocate_var(name string, size int, initial_val int) {
|
||||||
// do nothing as interface call is crashing
|
// do nothing as interface call is crashing
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
pub fn (mut g Gen) allocate_array(name string, size int, items int) int {
|
pub fn (mut g Gen) allocate_array(name string, size int, items int) int {
|
||||||
pos := g.allocate_var(name, size, items)
|
pos := g.allocate_var(name, size, items)
|
||||||
|
@ -1969,6 +1983,10 @@ pub fn (mut g Gen) allocate_array(name string, size int, items int) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) int {
|
pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) int {
|
||||||
|
if g.pref.arch == .arm64 {
|
||||||
|
// TODO
|
||||||
|
return 0
|
||||||
|
}
|
||||||
// `a := 3` => `mov DWORD [rbp-0x4],0x3`
|
// `a := 3` => `mov DWORD [rbp-0x4],0x3`
|
||||||
match size {
|
match size {
|
||||||
1 {
|
1 {
|
||||||
|
|
|
@ -42,7 +42,7 @@ mut:
|
||||||
// arm64 specific stuff for code generation
|
// arm64 specific stuff for code generation
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut x Arm64) allocate_var(name string, size int, initial_val int) {
|
fn (mut x Arm64) allocate_var(name string, size int, initial_val int) {
|
||||||
eprintln('TODO: allocating var on arm64 ($name) = $size = $initial_val')
|
eprintln('TODO: allocating var on arm64 ($name) = $size = $initial_val')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,11 +54,8 @@ fn (mut g Gen) mov_arm(reg Arm64Register, val u64) {
|
||||||
// println(x & ~(m << 16))
|
// println(x & ~(m << 16))
|
||||||
// g.write32(0x777777)
|
// g.write32(0x777777)
|
||||||
r := int(reg)
|
r := int(reg)
|
||||||
if r == 0 && val == 1 {
|
if r >= 0 && r <= 16 {
|
||||||
g.write32(0xd2800020)
|
g.write32(int(u32(0xd2800000 + u32(r) + (u32(val) << 5))))
|
||||||
g.println('mov x0, 1')
|
|
||||||
} else if r >= 0 && r <= 16 {
|
|
||||||
g.write32(int(u32(0xd2800000 + int(r) + int(val)) << 5))
|
|
||||||
g.println('mov x$r, $val')
|
g.println('mov x$r, $val')
|
||||||
} else {
|
} else {
|
||||||
g.n_error('mov_arm unsupported values')
|
g.n_error('mov_arm unsupported values')
|
||||||
|
@ -82,17 +79,106 @@ fn (mut g Gen) neg_arm(r Arm64Register) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) neg_regs_arm(a Arm64Register, b Arm64Register) {
|
fn (mut g Gen) neg_regs_arm(a Arm64Register, b Arm64Register) {
|
||||||
if int(a) < 0x0f && int(b) < 0x0f {
|
if u32(a) < 0x0f && u32(b) < 0x0f {
|
||||||
g.write32(0xe2600000 | int(a) << 16 | int(b) << 12)
|
g.write32(int(0xe2600000 | (u32(a) << 16) | u32(b) << 12))
|
||||||
g.println('neg $a, $b')
|
g.println('neg $a, $b')
|
||||||
} else {
|
} else {
|
||||||
g.n_error('unhandled neg $a, $b')
|
g.n_error('unhandled neg $a, $b')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) sub_sp(v int) {
|
||||||
|
if g.pref.arch != .arm64 {
|
||||||
|
g.n_error('sub_sp is arm64-specifig')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// this is for 0x20 only
|
||||||
|
if v < 0 {
|
||||||
|
g.write32(i32(0x910083ff)) // add sp, X
|
||||||
|
} else {
|
||||||
|
g.write32(i32(0xd10083ff)) // sub sp, X
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (mut g Gen) fn_decl_arm64(node ast.FnDecl) {
|
pub fn (mut g Gen) fn_decl_arm64(node ast.FnDecl) {
|
||||||
g.gen_arm64_helloworld()
|
g.gen_arm64_helloworld()
|
||||||
// TODO
|
/*
|
||||||
|
0x100003f6c ff8300d1 sub sp, sp, 0x20 ; [00] -r-x section size 52 named 0.__TEXT.__text
|
||||||
|
0x100003f70 fd7b01a9 stp x29, x30, [sp, 0x10]
|
||||||
|
0x100003f74 fd430091 add x29, sp, 0x10
|
||||||
|
0x100003f78 bfc31fb8 stur wzr, [x29, -4]
|
||||||
|
0x100003f7c 68008052 mov w8, 3
|
||||||
|
0x100003f80 e80b00b9 str w8, [sp, 8]
|
||||||
|
0x100003f84 00000090 adrp x0, 0x100003000
|
||||||
|
0x100003f88 00b03e91 add x0, x0, 0xfac
|
||||||
|
0x100003f8c 05000094 bl sym.imp.puts ;[1]
|
||||||
|
0x100003f90 e00b40b9 ldr w0, [sp, 8] ; 5
|
||||||
|
0x100003f94 fd7b41a9 ldp x29, x30, [sp, 0x10]
|
||||||
|
0x100003f98 ff830091 add sp, sp, 0x20
|
||||||
|
0x100003f9c c0035fd6 ret
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
/*
|
||||||
|
g.push(.rbp)
|
||||||
|
g.mov_rbp_rsp()
|
||||||
|
*/
|
||||||
|
locals_count := node.scope.objects.len + node.params.len + node.defer_stmts.len
|
||||||
|
g.stackframe_size = (locals_count * 8) + 0x10
|
||||||
|
// g.sub8(.rsp, g.stackframe_size)
|
||||||
|
g.sub_sp(32)
|
||||||
|
|
||||||
|
// Copy values from registers to local vars (calling convention)
|
||||||
|
mut offset := 0
|
||||||
|
for i in 0 .. node.params.len {
|
||||||
|
name := node.params[i].name
|
||||||
|
// TODO optimize. Right now 2 mov's are used instead of 1.
|
||||||
|
g.allocate_var(name, 4, 0)
|
||||||
|
// `mov DWORD PTR [rbp-0x4],edi`
|
||||||
|
offset += 4
|
||||||
|
g.mov_reg_to_var(offset, native.fn_arg_registers[i])
|
||||||
|
}
|
||||||
|
// define defer vars
|
||||||
|
for i in 0 .. node.defer_stmts.len {
|
||||||
|
name := '_defer$i'
|
||||||
|
g.allocate_var(name, 8, 0)
|
||||||
|
}
|
||||||
|
//
|
||||||
|
g.stmts(node.stmts)
|
||||||
|
is_main := node.name == 'main.main'
|
||||||
|
if is_main {
|
||||||
|
// println('end of main: gen exit')
|
||||||
|
zero := ast.IntegerLiteral{}
|
||||||
|
g.gen_exit(zero)
|
||||||
|
g.ret()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// g.leave()
|
||||||
|
g.labels.addrs[0] = g.pos()
|
||||||
|
g.println('; label 0: return')
|
||||||
|
/*
|
||||||
|
if g.defer_stmts.len != 0 {
|
||||||
|
// save return value
|
||||||
|
g.push(.rax)
|
||||||
|
for defer_stmt in g.defer_stmts.reverse() {
|
||||||
|
defer_var := g.get_var_offset('_defer$defer_stmt.idx_in_fn')
|
||||||
|
g.mov_var_to_reg(.rax, defer_var)
|
||||||
|
g.cmp_zero(.rax)
|
||||||
|
label := g.labels.new_label()
|
||||||
|
jump_addr := g.cjmp(.je)
|
||||||
|
g.labels.patches << LabelPatch{
|
||||||
|
id: label
|
||||||
|
pos: jump_addr
|
||||||
|
}
|
||||||
|
g.stmts(defer_stmt.stmts)
|
||||||
|
g.labels.addrs[label] = g.pos()
|
||||||
|
}
|
||||||
|
//g.pop(.rax)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
g.sub_sp(-32)
|
||||||
|
g.ret()
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut g Gen) call_fn_arm64(node ast.CallExpr) {
|
pub fn (mut g Gen) call_fn_arm64(node ast.CallExpr) {
|
||||||
|
@ -143,6 +229,11 @@ fn (mut g Gen) gen_arm64_helloworld() {
|
||||||
g.mov_arm(.x8, 64) // write (linux-arm64)
|
g.mov_arm(.x8, 64) // write (linux-arm64)
|
||||||
g.svc()
|
g.svc()
|
||||||
} else {
|
} else {
|
||||||
|
g.mov_arm(.x0, 1)
|
||||||
|
g.adr(.x1, 0x10 + 4)
|
||||||
|
g.mov_arm(.x2, 13)
|
||||||
|
g.mov_arm(.x16, 4) // write
|
||||||
|
g.svc()
|
||||||
g.mov_arm(.x0, 0)
|
g.mov_arm(.x0, 0)
|
||||||
g.mov_arm(.x16, 1)
|
g.mov_arm(.x16, 1)
|
||||||
g.svc()
|
g.svc()
|
||||||
|
@ -167,8 +258,13 @@ fn (mut g Gen) bl() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) svc() {
|
fn (mut g Gen) svc() {
|
||||||
|
if g.pref.os == .linux {
|
||||||
g.write32(0xd4001001)
|
g.write32(0xd4001001)
|
||||||
g.println('svc 0x80')
|
g.println('svc 0x80')
|
||||||
|
} else {
|
||||||
|
g.write32(0xd4000001)
|
||||||
|
g.println('svc 0')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c Arm64) gen_exit(mut g Gen, expr ast.Expr) {
|
pub fn (mut c Arm64) gen_exit(mut g Gen, expr ast.Expr) {
|
||||||
|
|
|
@ -49,6 +49,9 @@ mut:
|
||||||
strs []String
|
strs []String
|
||||||
labels &LabelTable
|
labels &LabelTable
|
||||||
defer_stmts []ast.DeferStmt
|
defer_stmts []ast.DeferStmt
|
||||||
|
// macho specific
|
||||||
|
macho_ncmds int
|
||||||
|
macho_cmdsize int
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RelocType {
|
enum RelocType {
|
||||||
|
@ -114,6 +117,20 @@ fn get_backend(arch pref.Arch) ?CodeGen {
|
||||||
g: 0
|
g: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
._auto {
|
||||||
|
$if amd64 {
|
||||||
|
return Amd64{
|
||||||
|
g: 0
|
||||||
|
}
|
||||||
|
} $else $if arm64 {
|
||||||
|
return Arm64{
|
||||||
|
g: 0
|
||||||
|
}
|
||||||
|
} $else {
|
||||||
|
eprintln('-native only have amd64 and arm64 codegens')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
return error('unsupported architecture')
|
return error('unsupported architecture')
|
||||||
|
|
|
@ -4,21 +4,24 @@
|
||||||
module native
|
module native
|
||||||
|
|
||||||
const (
|
const (
|
||||||
s_attr_some_instructions = 0x00000400
|
s_attr_some_instructions = 0x0400
|
||||||
s_attr_pure_instructions = 0x80000000
|
s_attr_pure_instructions = 0x80000000
|
||||||
s_attr_ext_reloc = 0x00000200
|
s_attr_ext_reloc = 0x0200
|
||||||
s_attr_loc_reloc = 0x00000100
|
s_attr_loc_reloc = 0x0100
|
||||||
//
|
|
||||||
macho_symcmd_size = 0x18
|
macho_symcmd_size = 0x18
|
||||||
macho_d_size = 0x50
|
macho_d_size = 0x50
|
||||||
mh_object = 1
|
mh_object = 1
|
||||||
mh_execute = 2
|
mh_execute = 2
|
||||||
|
lc_dyld_chained_fixups = 0x80000034
|
||||||
|
lc_dyld_exports_trie = 0x80000033
|
||||||
|
lc_dyld_info_only = 0x80000022
|
||||||
lc_dysymtab = 0xb
|
lc_dysymtab = 0xb
|
||||||
lc_load_dylib = 0xc
|
lc_load_dylib = 0xc
|
||||||
lc_load_dylinker = 0xe
|
lc_load_dylinker = 0xe
|
||||||
lc_main = 0x80000028
|
lc_main = 0x80000028
|
||||||
lc_segment_64 = 0x19
|
lc_segment_64 = 0x19
|
||||||
lc_symtab = 0x2
|
lc_symtab = 0x2
|
||||||
|
base_addr = i64(0x1_0000_0000)
|
||||||
)
|
)
|
||||||
|
|
||||||
struct Symbol {
|
struct Symbol {
|
||||||
|
@ -41,31 +44,53 @@ struct Reloc {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) macho_segment64_pagezero() {
|
fn (mut g Gen) macho_segment64_pagezero() {
|
||||||
g.write32(native.lc_segment_64) // LC_SEGMENT_64
|
g.macho_add_loadcommand(native.lc_segment_64, 72)
|
||||||
g.write32(72) // cmdsize
|
|
||||||
g.write_string_with_padding('__PAGEZERO', 16) // section name
|
g.write_string_with_padding('__PAGEZERO', 16) // section name
|
||||||
g.write64(0) // vmaddr
|
g.write64(0) // vmaddr
|
||||||
g.write64(0x1000) // vmsize
|
// XXX g.write64(g.get_pagesize()) // vmsize
|
||||||
|
g.write64(native.base_addr) // vmsize
|
||||||
g.write64(0) // fileoff
|
g.write64(0) // fileoff
|
||||||
g.write64(0) // filesize
|
g.write64(0) // filesize
|
||||||
|
|
||||||
g.write32(0) // maxprot
|
g.write32(0) // maxprot
|
||||||
g.write32(0) // initprot
|
g.write32(0) // initprot
|
||||||
g.write32(0) // nsects
|
g.write32(0) // nsects
|
||||||
g.write32(0) // flags
|
g.write32(0) // flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) macho_add_loadcommand(typ u32, size int) {
|
||||||
|
g.macho_ncmds++
|
||||||
|
g.macho_cmdsize += size
|
||||||
|
g.write32(int(typ))
|
||||||
|
g.write32(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) macho_patch_header() {
|
||||||
|
g.write32_at(0x10, g.macho_ncmds)
|
||||||
|
g.write32_at(0x14, g.macho_cmdsize)
|
||||||
|
}
|
||||||
|
|
||||||
|
// probably unnecessary
|
||||||
|
fn (mut g Gen) macho_chained_fixups() {
|
||||||
|
g.macho_add_loadcommand(native.lc_dyld_chained_fixups, 16)
|
||||||
|
g.write32(0x4000) // dataoff
|
||||||
|
g.write32(56) // datasize
|
||||||
|
|
||||||
|
g.macho_add_loadcommand(native.lc_dyld_exports_trie, 16)
|
||||||
|
g.write32(0x4000) // dataoff
|
||||||
|
g.write32(56) // datasize
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g Gen) macho_segment64_linkedit() {
|
fn (mut g Gen) macho_segment64_linkedit() {
|
||||||
g.write32(native.lc_segment_64)
|
g.macho_add_loadcommand(native.lc_segment_64, 0x48)
|
||||||
g.write32(0x48) // cmdsize
|
|
||||||
g.write_string_with_padding('__LINKEDIT', 16)
|
g.write_string_with_padding('__LINKEDIT', 16)
|
||||||
|
|
||||||
g.write64(0x3000) // vmaddr
|
// g.size_pos << g.buf.len
|
||||||
g.write64(0x1000) // vmsize
|
g.write64(native.base_addr + g.get_pagesize()) // vmaddr
|
||||||
g.write64(0x1000) // fileoff
|
g.write64(g.get_pagesize()) // vmsize
|
||||||
|
g.write64(g.get_pagesize()) // fileoff
|
||||||
g.write64(0) // filesize
|
g.write64(0) // filesize
|
||||||
g.write32(7) // maxprot
|
g.write32(1) // maxprot
|
||||||
g.write32(3) // initprot
|
g.write32(1) // initprot
|
||||||
g.write32(0) // nsects
|
g.write32(0) // nsects
|
||||||
g.write32(0) // flags
|
g.write32(0) // flags
|
||||||
}
|
}
|
||||||
|
@ -85,40 +110,50 @@ fn (mut g Gen) macho_header(ncmds int, bintype int) int {
|
||||||
cmdsize_offset := g.buf.len
|
cmdsize_offset := g.buf.len
|
||||||
g.write32(0) // size of load commands
|
g.write32(0) // size of load commands
|
||||||
|
|
||||||
|
if g.pref.arch == .arm64 {
|
||||||
|
g.write32(0x00200085)
|
||||||
|
} else {
|
||||||
g.write32(0) // flags
|
g.write32(0) // flags
|
||||||
|
}
|
||||||
g.write32(0) // reserved
|
g.write32(0) // reserved
|
||||||
return cmdsize_offset
|
return cmdsize_offset
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) macho_segment64_text() []int {
|
fn (mut g Gen) macho_segment64_text() []int {
|
||||||
mut patch := []int{}
|
mut patch := []int{}
|
||||||
g.write32(native.lc_segment_64) // LC_SEGMENT_64
|
g.macho_add_loadcommand(native.lc_segment_64, 152)
|
||||||
g.write32(152) // 152
|
|
||||||
g.write_string_with_padding('__TEXT', 16) // section name
|
g.write_string_with_padding('__TEXT', 16) // section name
|
||||||
g.write64(0x100000000) // vmaddr
|
g.write64(native.base_addr) // vmaddr
|
||||||
patch << g.buf.len
|
|
||||||
g.write64(0x00001000) // + codesize) // vmsize
|
|
||||||
g.write64(0x00000000) // filesize
|
|
||||||
patch << g.buf.len
|
|
||||||
g.write64(0x00001000) // + codesize) // filesize
|
|
||||||
|
|
||||||
g.write32(7) // maxprot
|
g.write64(g.get_pagesize() * 2) // vmsize
|
||||||
|
g.write64(0) // fileoff
|
||||||
|
g.write64(g.get_pagesize() + 63) // filesize
|
||||||
|
|
||||||
|
g.write32(5) // maxprot
|
||||||
g.write32(5) // initprot
|
g.write32(5) // initprot
|
||||||
g.write32(1) // nsects
|
g.write32(1) // nsects
|
||||||
g.write32(0) // flags
|
g.write32(0) // flags
|
||||||
|
|
||||||
g.write_string_with_padding('__text', 16) // section name
|
g.write_string_with_padding('__text', 16) // section name
|
||||||
g.write_string_with_padding('__TEXT', 16) // segment name
|
g.write_string_with_padding('__TEXT', 16) // segment name
|
||||||
g.write64(0x0000000100001000) // vmaddr
|
g.write64(native.base_addr + g.get_pagesize()) // vmaddr
|
||||||
|
if g.pref.arch == .arm64 {
|
||||||
|
g.write64(0) // vmsize
|
||||||
|
} else {
|
||||||
patch << g.buf.len
|
patch << g.buf.len
|
||||||
g.write64(0) // vmsize
|
g.write64(0) // vmsize
|
||||||
g.write32(4096) // offset
|
}
|
||||||
g.write32(0) // align
|
g.write32(0) // offset
|
||||||
|
g.write32(4) // align
|
||||||
|
|
||||||
g.write32(0) // reloff
|
g.write32(0) // reloff
|
||||||
g.write32(0) // nreloc
|
g.write32(0) // nreloc
|
||||||
|
|
||||||
|
if g.pref.arch == .amd64 {
|
||||||
g.write32(0) // flags
|
g.write32(0) // flags
|
||||||
|
} else {
|
||||||
|
g.write32(0x80000400) // flags
|
||||||
|
}
|
||||||
g.write32(0)
|
g.write32(0)
|
||||||
|
|
||||||
g.write32(0) // reserved1
|
g.write32(0) // reserved1
|
||||||
|
@ -127,16 +162,25 @@ fn (mut g Gen) macho_segment64_text() []int {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) macho_symtab() {
|
fn (mut g Gen) macho_symtab() {
|
||||||
g.write32(native.lc_symtab)
|
g.macho_add_loadcommand(native.lc_dyld_info_only, 48)
|
||||||
g.write32(24)
|
g.write32(0) // rebase_off
|
||||||
g.write32(0x1000)
|
g.write32(0) // rebase_size
|
||||||
g.write32(0)
|
g.write32(0) // bind_off
|
||||||
g.write32(0x1000)
|
g.write32(0) // bind_size
|
||||||
g.write32(0)
|
g.write32(0) // weak_bind_off
|
||||||
|
g.write32(0) // weak_bind_size
|
||||||
|
g.write32(0) // lazy_bind_off
|
||||||
|
g.write32(0) // lazy_bind_size
|
||||||
|
g.write32(0x4000) // export_off
|
||||||
|
g.write32(56) // export_size
|
||||||
|
|
||||||
// lc_dysymtab
|
g.macho_add_loadcommand(native.lc_symtab, 24)
|
||||||
g.write32(native.lc_dysymtab)
|
g.write32(0x1000) // symoff
|
||||||
g.write32(0x50)
|
g.write32(0) // nsyms
|
||||||
|
g.write32(0x1000) // stroff
|
||||||
|
g.write32(0) // strsize
|
||||||
|
|
||||||
|
g.macho_add_loadcommand(native.lc_dysymtab, 0x50)
|
||||||
g.write32(0) // ilocalsym
|
g.write32(0) // ilocalsym
|
||||||
g.write32(0) // nlocalsym
|
g.write32(0) // nlocalsym
|
||||||
g.write32(0) // iextdefsym
|
g.write32(0) // iextdefsym
|
||||||
|
@ -158,47 +202,54 @@ fn (mut g Gen) macho_symtab() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) macho_dylibs() {
|
fn (mut g Gen) macho_dylibs() {
|
||||||
g.write32(native.lc_load_dylinker)
|
g.macho_add_loadcommand(native.lc_load_dylinker, 32)
|
||||||
g.write32(32) // cmdsize (must be aligned to int32)
|
|
||||||
g.write32(12) // offset
|
g.write32(12) // offset
|
||||||
g.write_string_with_padding('/usr/lib/dyld', 16)
|
g.write_string_with_padding('/usr/lib/dyld', 16)
|
||||||
g.write32(0) // padding // can be removed
|
g.write32(0) // padding // can be removed
|
||||||
|
|
||||||
g.write32(native.lc_load_dylib)
|
g.macho_add_loadcommand(native.lc_load_dylib, 56)
|
||||||
g.write32(56) // cmdsize
|
|
||||||
g.write32(24) // offset
|
g.write32(24) // offset
|
||||||
g.write32(0) // ts
|
g.write32(0) // ts
|
||||||
g.write32(1) // ver
|
g.write32(0x051f6403) // g.write32(1) // current version
|
||||||
g.write32(1) // compat
|
g.write32(0x10000) // compatibility version
|
||||||
g.write_string_with_padding('/usr/lib/libSystem.B.dylib', 32)
|
g.write_string_with_padding('/usr/lib/libSystem.B.dylib', 32)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) macho_main(addr int) {
|
fn (mut g Gen) macho_main(addr int) {
|
||||||
g.write32(int(native.lc_main)) // LC_MAIN
|
g.macho_add_loadcommand(native.lc_main, 24)
|
||||||
g.write32(24) // cmdsize
|
|
||||||
g.write32(addr) // entrypoint
|
g.write32(addr) // entrypoint
|
||||||
g.write32(0) // initial_stacksize
|
g.write32(0) // initial_stacksize
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut g Gen) generate_macho_header() {
|
pub fn (mut g Gen) generate_macho_header() {
|
||||||
g.code_start_pos = 0x1000
|
pagesize := g.get_pagesize()
|
||||||
g.debug_pos = 0x1000
|
g.code_start_pos = pagesize
|
||||||
cmdsize_offset := g.macho_header(8, native.mh_execute)
|
g.debug_pos = pagesize
|
||||||
|
ncmds := 0 // 9+ 2 -2 -3 -1
|
||||||
|
cmdsize_offset := g.macho_header(ncmds, native.mh_execute)
|
||||||
g.macho_segment64_pagezero()
|
g.macho_segment64_pagezero()
|
||||||
|
|
||||||
g.size_pos = g.macho_segment64_text()
|
g.size_pos = g.macho_segment64_text()
|
||||||
g.macho_segment64_linkedit()
|
// g.macho_segment64_linkedit()
|
||||||
|
// g.macho_chained_fixups()
|
||||||
g.macho_symtab()
|
g.macho_symtab()
|
||||||
g.macho_dylibs()
|
g.macho_dylibs()
|
||||||
g.macho_main(0x1000)
|
g.macho_main(pagesize)
|
||||||
|
|
||||||
g.write32_at(cmdsize_offset, g.buf.len - 24)
|
g.write32_at(cmdsize_offset, g.buf.len - 24)
|
||||||
g.write_nulls(0x1000 - g.buf.len)
|
g.write_nulls(pagesize - g.buf.len)
|
||||||
g.call(0)
|
g.call(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) get_pagesize() int {
|
||||||
|
if g.pref.arch == .arm64 {
|
||||||
|
return 0x4000 // 16KB
|
||||||
|
}
|
||||||
|
return 0x1000 // 4KB
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g Gen) write_nulls(len int) {
|
fn (mut g Gen) write_nulls(len int) {
|
||||||
pad := 0x1000 - g.buf.len
|
pad := g.get_pagesize() - g.buf.len
|
||||||
for _ in 0 .. pad {
|
for _ in 0 .. pad {
|
||||||
g.write8(0)
|
g.write8(0)
|
||||||
}
|
}
|
||||||
|
@ -208,11 +259,11 @@ pub fn (mut g Gen) generate_macho_object_header() {
|
||||||
if g.pref.arch == .arm64 {
|
if g.pref.arch == .arm64 {
|
||||||
g.write32(0xfeedfacf) // MH_MAGIC_64
|
g.write32(0xfeedfacf) // MH_MAGIC_64
|
||||||
g.write32(0x0100000c) // CPU_TYPE_ARM64
|
g.write32(0x0100000c) // CPU_TYPE_ARM64
|
||||||
g.write32(0x00000000) // CPU_SUBTYPE_ARM64_ALL
|
g.write32(0) // CPU_SUBTYPE_ARM64_ALL
|
||||||
} else {
|
} else {
|
||||||
g.write32(0xfeedfacf) // MH_MAGIC_64
|
g.write32(0xfeedfacf) // MH_MAGIC_64
|
||||||
g.write32(0x01000007) // CPU_TYPE_X64
|
g.write32(0x01000007) // CPU_TYPE_X64
|
||||||
g.write32(0x00000003) // CPU_SUBTYPE_X64
|
g.write32(3) // CPU_SUBTYPE_X64
|
||||||
}
|
}
|
||||||
g.write32(native.mh_object) // MH_OBJECT
|
g.write32(native.mh_object) // MH_OBJECT
|
||||||
text_offset := 0x138
|
text_offset := 0x138
|
||||||
|
@ -249,7 +300,6 @@ pub fn (mut g Gen) generate_macho_object_header() {
|
||||||
/// ???
|
/// ???
|
||||||
g.write32(0x32)
|
g.write32(0x32)
|
||||||
g.write32(0x18)
|
g.write32(0x18)
|
||||||
|
|
||||||
g.write32(0x01)
|
g.write32(0x01)
|
||||||
g.write32(0x000a0000) // minOS 10.0
|
g.write32(0x000a0000) // minOS 10.0
|
||||||
g.write32(0)
|
g.write32(0)
|
||||||
|
@ -257,8 +307,7 @@ pub fn (mut g Gen) generate_macho_object_header() {
|
||||||
// lc_symtab
|
// lc_symtab
|
||||||
g.sym_table_command()
|
g.sym_table_command()
|
||||||
//
|
//
|
||||||
g.write32(native.lc_dysymtab)
|
g.macho_add_loadcommand(native.lc_dysymtab, native.macho_d_size)
|
||||||
g.write32(native.macho_d_size)
|
|
||||||
g.write32(0)
|
g.write32(0)
|
||||||
g.write32(2)
|
g.write32(2)
|
||||||
g.write32(2)
|
g.write32(2)
|
||||||
|
@ -291,13 +340,26 @@ pub fn (mut g Gen) generate_macho_footer() {
|
||||||
g.write8(0)
|
g.write8(0)
|
||||||
for o in g.size_pos {
|
for o in g.size_pos {
|
||||||
n := g.read32_at(o)
|
n := g.read32_at(o)
|
||||||
|
// eprintln('$n + $delta')
|
||||||
g.write32_at(o, n + delta)
|
g.write32_at(o, n + delta)
|
||||||
}
|
}
|
||||||
g.write64(0)
|
g.write64(0)
|
||||||
// this is amd64-specific
|
g.macho_patch_header()
|
||||||
|
if g.pref.arch == .amd64 {
|
||||||
call_delta := int(g.main_fn_addr - g.code_start_pos) - 5
|
call_delta := int(g.main_fn_addr - g.code_start_pos) - 5
|
||||||
g.write32_at(g.code_start_pos + 1, call_delta)
|
g.write32_at(g.code_start_pos + 1, call_delta)
|
||||||
g.create_executable()
|
g.create_executable()
|
||||||
|
} else {
|
||||||
|
call_delta := int(g.main_fn_addr - g.code_start_pos)
|
||||||
|
if (call_delta % 4) != 0 || call_delta < 0 {
|
||||||
|
g.n_error('Invalid entrypoint->main delta ($call_delta)')
|
||||||
|
} else {
|
||||||
|
blop := (0x94 << 24) | (call_delta / 4)
|
||||||
|
g.write32_at(g.code_start_pos, int(blop))
|
||||||
|
g.write_nulls(g.get_pagesize() - g.buf.len)
|
||||||
|
g.create_executable()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) sym_table_command() {
|
fn (mut g Gen) sym_table_command() {
|
||||||
|
@ -338,8 +400,7 @@ fn (mut g Gen) sym_table_command() {
|
||||||
name: 'ltmp1'
|
name: 'ltmp1'
|
||||||
is_ext: false
|
is_ext: false
|
||||||
}
|
}
|
||||||
g.write32(native.lc_symtab)
|
g.macho_add_loadcommand(native.lc_symtab, native.macho_symcmd_size)
|
||||||
g.write32(native.macho_symcmd_size)
|
|
||||||
sym_table_offset := 0x168
|
sym_table_offset := 0x168
|
||||||
g.write32(sym_table_offset)
|
g.write32(sym_table_offset)
|
||||||
g_syms_len := 4
|
g_syms_len := 4
|
||||||
|
@ -406,8 +467,7 @@ fn (mut g Gen) sym_string_table() int {
|
||||||
// that should be .rel32, not windows-specific
|
// that should be .rel32, not windows-specific
|
||||||
g.write32_at(s.pos, pos)
|
g.write32_at(s.pos, pos)
|
||||||
} else {
|
} else {
|
||||||
baddr := i64(0x100000000)
|
g.write64_at(s.pos, g.buf.len + native.base_addr)
|
||||||
g.write64_at(s.pos, g.buf.len + baddr)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,9 @@ import v.ast
|
||||||
fn test_macho() {
|
fn test_macho() {
|
||||||
os.chdir(os.temp_dir()) or {}
|
os.chdir(os.temp_dir()) or {}
|
||||||
mut g := native.Gen{
|
mut g := native.Gen{
|
||||||
pref: &pref.Preferences{}
|
pref: &pref.Preferences{
|
||||||
|
arch: .amd64
|
||||||
|
}
|
||||||
out_name: 'test.bin'
|
out_name: 'test.bin'
|
||||||
table: ast.new_table()
|
table: ast.new_table()
|
||||||
code_gen: native.Amd64{
|
code_gen: native.Amd64{
|
||||||
|
|
Loading…
Reference in New Issue