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
|
import v.markused
|
||||||
|
|
||||||
pub fn (mut b Builder) build_x64(v_files []string, out_file string) {
|
pub fn (mut b Builder) build_x64(v_files []string, out_file string) {
|
||||||
$if !linux {
|
$if !linux && !macos {
|
||||||
println('v -x64 can only generate Linux binaries for now')
|
eprintln('Warning: v -x64 can only generate macOS and Linux binaries for now')
|
||||||
println('You are not on a Linux system, so you will not ' +
|
|
||||||
'be able to run the resulting executable')
|
|
||||||
}
|
}
|
||||||
util.timing_start('PARSE')
|
util.timing_start('PARSE')
|
||||||
b.parsed_files = parser.parse_files(v_files, b.table, b.pref, b.global_scope)
|
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
|
// ELF file types
|
||||||
const (
|
const (
|
||||||
elf_osabi = 0
|
elf_osabi = 0
|
||||||
et_rel = 1
|
et_rel = 1
|
||||||
et_exec = 2
|
et_exec = 2
|
||||||
et_dyn = 3
|
et_dyn = 3
|
||||||
e_machine = 0x3e
|
e_machine_amd64 = 0x3e
|
||||||
shn_xindex = 0xffff
|
e_machine_aarch64 = 183
|
||||||
sht_null = 0
|
shn_xindex = 0xffff
|
||||||
|
sht_null = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -41,7 +42,11 @@ pub fn (mut g Gen) generate_elf_header() {
|
||||||
g.buf << 1 // elf_osabi
|
g.buf << 1 // elf_osabi
|
||||||
g.write64(0) // et_rel) // et_rel for .o
|
g.write64(0) // et_rel) // et_rel for .o
|
||||||
g.write16(2) // e_type
|
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
|
g.write32(x64.ev_current) // e_version
|
||||||
eh_size := 0x40
|
eh_size := 0x40
|
||||||
phent_size := 0x38
|
phent_size := 0x38
|
||||||
|
|
|
@ -11,10 +11,15 @@ import v.pref
|
||||||
import term
|
import term
|
||||||
import strings
|
import strings
|
||||||
|
|
||||||
|
interface CodeGen {
|
||||||
|
allocate_var(g &Gen, name string, size int, initial_val int)
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Gen {
|
pub struct Gen {
|
||||||
out_name string
|
out_name string
|
||||||
pref &pref.Preferences // Preferences shared from V struct
|
pref &pref.Preferences // Preferences shared from V struct
|
||||||
mut:
|
mut:
|
||||||
|
cgen CodeGen
|
||||||
table &ast.Table
|
table &ast.Table
|
||||||
buf []byte
|
buf []byte
|
||||||
sect_header_name_pos int
|
sect_header_name_pos int
|
||||||
|
@ -82,24 +87,65 @@ enum Size {
|
||||||
_64
|
_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) {
|
pub fn gen(files []ast.File, table &ast.Table, out_name string, pref &pref.Preferences) (int, int) {
|
||||||
mut g := Gen{
|
mut g := Gen{
|
||||||
table: table
|
table: table
|
||||||
sect_header_name_pos: 0
|
sect_header_name_pos: 0
|
||||||
out_name: out_name
|
out_name: out_name
|
||||||
pref: pref
|
pref: pref
|
||||||
|
cgen: get_backend(pref)
|
||||||
}
|
}
|
||||||
if !pref.is_verbose {
|
g.generate_header()
|
||||||
println('use `v -x64 -v ...` to print resulting asembly/machine code')
|
|
||||||
}
|
|
||||||
g.generate_elf_header()
|
|
||||||
for file in files {
|
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.stmts(file.stmts)
|
||||||
}
|
}
|
||||||
g.generate_elf_footer()
|
g.generate_footer()
|
||||||
return g.nlines, g.buf.len
|
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) {
|
pub fn (mut g Gen) stmts(stmts []ast.Stmt) {
|
||||||
for stmt in stmts {
|
for stmt in stmts {
|
||||||
g.stmt(stmt)
|
g.stmt(stmt)
|
||||||
|
@ -174,6 +220,7 @@ fn (mut g Gen) write_string(s string) {
|
||||||
for c in s {
|
for c in s {
|
||||||
g.write8(int(c))
|
g.write8(int(c))
|
||||||
}
|
}
|
||||||
|
// g.write8(0) // null terminated strings
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) write_string_with_padding(s string, max int) {
|
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')
|
// 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) {
|
fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
match node {
|
match node {
|
||||||
ast.AssignStmt {
|
ast.AssignStmt {
|
||||||
|
@ -660,6 +728,9 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
ast.FnDecl {
|
ast.FnDecl {
|
||||||
g.fn_decl(node)
|
g.fn_decl(node)
|
||||||
}
|
}
|
||||||
|
ast.ForInStmt {
|
||||||
|
g.for_in_stmt(node)
|
||||||
|
}
|
||||||
ast.ForStmt {
|
ast.ForStmt {
|
||||||
g.for_stmt(node)
|
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 C.strtol(str &char, endptr &&char, base int) int
|
||||||
|
|
||||||
fn (mut g Gen) expr(node ast.Expr) {
|
fn (mut g Gen) expr(node ast.Expr) {
|
||||||
// println('cgen expr()')
|
|
||||||
match node {
|
match node {
|
||||||
ast.ArrayInit {}
|
ast.ArrayInit {}
|
||||||
ast.BoolLiteral {}
|
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) {
|
fn (mut g Gen) allocate_var(name string, size int, initial_val int) {
|
||||||
// `a := 3` =>
|
g.cgen.allocate_var(g, name, size, initial_val)
|
||||||
// `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`)')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
||||||
|
|
|
@ -37,9 +37,15 @@ struct Reloc {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut g Gen) generate_macho_header() {
|
pub fn (mut g Gen) generate_macho_header() {
|
||||||
g.write32(0xfeedfacf) // MH_MAGIC_64
|
if g.pref.arch == .aarch64 {
|
||||||
g.write32(0x0100000c) // CPU_TYPE_ARM64
|
g.write32(0xfeedfacf) // MH_MAGIC_64
|
||||||
g.write32(0x00000000) // CPU_SUBTYPE_ARM64_ALL
|
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(0x00000001) // MH_OBJECT
|
||||||
g.write32(0x00000004) // # of load commands
|
g.write32(0x00000004) // # of load commands
|
||||||
g.write32(0x118) // size 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(0x18)
|
||||||
|
|
||||||
g.write32(0x01)
|
g.write32(0x01)
|
||||||
g.write32(0x000b0000)
|
g.write32(0x000a0000) // minOS 10.0
|
||||||
g.write32(0)
|
g.write32(0)
|
||||||
g.write32(0)
|
g.write32(0)
|
||||||
// lc_symtab
|
// lc_symtab
|
||||||
|
@ -93,6 +99,7 @@ pub fn (mut g Gen) generate_macho_header() {
|
||||||
for _ in 0 .. 12 {
|
for _ in 0 .. 12 {
|
||||||
g.write32(0)
|
g.write32(0)
|
||||||
}
|
}
|
||||||
|
// ADD THE CODE HERE THIS GOES INTO THE STMTS THING
|
||||||
// g.write32(0x77777777)
|
// g.write32(0x77777777)
|
||||||
// assembly
|
// assembly
|
||||||
g.mov_arm(.x0, 1)
|
g.mov_arm(.x0, 1)
|
||||||
|
@ -102,7 +109,7 @@ pub fn (mut g Gen) generate_macho_header() {
|
||||||
g.mov_arm(.x16, 1)
|
g.mov_arm(.x16, 1)
|
||||||
g.svc()
|
g.svc()
|
||||||
//
|
//
|
||||||
g.write_string('Hello WorlD!\n')
|
g.write_string('Hello World!\n')
|
||||||
g.write8(0) // padding?
|
g.write8(0) // padding?
|
||||||
g.write8(0)
|
g.write8(0)
|
||||||
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() {
|
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) }
|
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) }
|
unsafe { f.write_ptr(g.buf.data, g.buf.len) }
|
||||||
f.close()
|
f.close()
|
||||||
// println('\narm64 mach-o binary has been successfully generated')
|
// println('\narm64 mach-o binary has been successfully generated')
|
||||||
|
|
|
@ -17,6 +17,7 @@ pub enum OS {
|
||||||
android
|
android
|
||||||
solaris
|
solaris
|
||||||
haiku
|
haiku
|
||||||
|
raw
|
||||||
all
|
all
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +36,7 @@ pub fn os_from_string(os_str string) ?OS {
|
||||||
'solaris' { return .solaris }
|
'solaris' { return .solaris }
|
||||||
'android' { return .android }
|
'android' { return .android }
|
||||||
'haiku' { return .haiku }
|
'haiku' { return .haiku }
|
||||||
|
'raw' { return .raw }
|
||||||
'linux_or_macos', 'nix' { return .linux }
|
'linux_or_macos', 'nix' { return .linux }
|
||||||
'' { return ._auto }
|
'' { return ._auto }
|
||||||
else { return error('bad OS $os_str') }
|
else { return error('bad OS $os_str') }
|
||||||
|
@ -56,6 +58,7 @@ pub fn (o OS) str() string {
|
||||||
.android { return 'Android' }
|
.android { return 'Android' }
|
||||||
.solaris { return 'Solaris' }
|
.solaris { return 'Solaris' }
|
||||||
.haiku { return 'Haiku' }
|
.haiku { return 'Haiku' }
|
||||||
|
.raw { return 'Raw' }
|
||||||
.all { return 'all' }
|
.all { return 'all' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue