native: initial support for linux-arm64 (hello world only for now) (#10176)
parent
4b11e59bb0
commit
efa07cbcbf
|
@ -154,6 +154,8 @@ NB: the build flags are shared with the run command too:
|
|||
and will become an error, after vlib modules are cleaned up.
|
||||
|
||||
For C-specific build flags, use `v help build-c`.
|
||||
For JS-specific build flags, use `v help build-js`.
|
||||
For Native-specific build flags, use `v help build-native`.
|
||||
|
||||
For Native-specific build flags, use `v help build-native`.
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ V supports the following commands:
|
|||
Use `tracev yourfile.v` when the compiler panics.
|
||||
NB: `tracev` is much slower and more verbose than ordinary `v`
|
||||
|
||||
Use "v help <command>" for more information about a command, example: `v help build`, `v help build-c`
|
||||
Use "v help <command>" for more information about a command, example: `v help build`, `v help build-c`, `v help build-native`
|
||||
Use "v help other" to see less frequently used commands.
|
||||
|
||||
Note: Help is required to write more help topics.
|
||||
|
|
|
@ -192,6 +192,10 @@ fn (mut g Gen) mov_var_to_reg(reg Register, var_offset int) {
|
|||
}
|
||||
|
||||
fn (mut g Gen) call(addr int) {
|
||||
if g.pref.arch == .arm64 {
|
||||
g.bl()
|
||||
return
|
||||
}
|
||||
// Need to calculate the difference between current position (position after the e8 call)
|
||||
// and the function to call.
|
||||
// +5 is to get the posistion "e8 xx xx xx xx"
|
||||
|
@ -472,6 +476,10 @@ fn (mut g Gen) mov_rbp_rsp() {
|
|||
}
|
||||
|
||||
pub fn (mut g Gen) call_fn(node ast.CallExpr) {
|
||||
if g.pref.arch == .arm64 {
|
||||
g.call_fn_arm64(node)
|
||||
return
|
||||
}
|
||||
name := node.name
|
||||
// println('call fn $name')
|
||||
addr := g.fn_addr[name]
|
||||
|
|
|
@ -43,12 +43,9 @@ fn (mut g Gen) mov_arm(reg Arm64Register, val u64) {
|
|||
if r == 0 && val == 1 {
|
||||
g.write32(0xd2800020)
|
||||
g.println('mov x0, 1')
|
||||
} else if r == 0 {
|
||||
g.write32(0xd2800000)
|
||||
g.println('mov x0, 0')
|
||||
} else if r == 16 {
|
||||
g.write32(0xd2800030)
|
||||
g.println('mov x16, 1')
|
||||
} else if r >= 0 && r <= 16 {
|
||||
g.write32(0xd2800000 + int(r) + (int(val) << 5))
|
||||
g.println('mov x$r, $val')
|
||||
} else {
|
||||
verror('mov_arm unsupported values')
|
||||
}
|
||||
|
@ -67,33 +64,73 @@ fn (mut g Gen) mov_arm(reg Arm64Register, val u64) {
|
|||
}
|
||||
|
||||
pub fn (mut g Gen) fn_decl_arm64(node ast.FnDecl) {
|
||||
g.gen_arm64_helloworld()
|
||||
// TODO
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_arm64_helloworld() {
|
||||
// g.write32(0x77777777)
|
||||
// assembly
|
||||
g.mov_arm(.x0, 1)
|
||||
g.adr()
|
||||
g.bl()
|
||||
pub fn (mut g Gen) call_fn_arm64(node ast.CallExpr) {
|
||||
name := node.name
|
||||
// println('call fn $name')
|
||||
addr := g.fn_addr[name]
|
||||
if addr == 0 {
|
||||
verror('fn addr of `$name` = 0')
|
||||
}
|
||||
// Copy values to registers (calling convention)
|
||||
// g.mov_arm(.eax, 0)
|
||||
for i in 0 .. node.args.len {
|
||||
expr := node.args[i].expr
|
||||
match expr {
|
||||
ast.IntegerLiteral {
|
||||
// `foo(2)` => `mov edi,0x2`
|
||||
// g.mov_arm(native.fn_arg_registers[i], expr.val.int())
|
||||
}
|
||||
/*
|
||||
ast.Ident {
|
||||
// `foo(x)` => `mov edi,DWORD PTR [rbp-0x8]`
|
||||
var_offset := g.get_var_offset(expr.name)
|
||||
if g.pref.is_verbose {
|
||||
println('i=$i fn name= $name offset=$var_offset')
|
||||
println(int(native.fn_arg_registers[i]))
|
||||
}
|
||||
g.mov_var_to_reg(native.fn_arg_registers[i], var_offset)
|
||||
}
|
||||
*/
|
||||
else {
|
||||
verror('unhandled call_fn (name=$name) node: ' + expr.type_name())
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.args.len > 6 {
|
||||
verror('more than 6 args not allowed for now')
|
||||
}
|
||||
g.call(int(addr))
|
||||
g.println('fn call `${name}()`')
|
||||
// println('call $name $addr')
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_arm64_helloworld() {
|
||||
if g.pref.os == .linux {
|
||||
g.mov_arm(.x0, 1)
|
||||
g.adr(.x1, 0x10)
|
||||
g.mov_arm(.x2, 13)
|
||||
g.mov_arm(.x8, 64) // write (linux-arm64)
|
||||
g.svc()
|
||||
} else {
|
||||
g.mov_arm(.x0, 0)
|
||||
g.mov_arm(.x16, 1)
|
||||
g.svc()
|
||||
}
|
||||
zero := ast.IntegerLiteral{}
|
||||
g.gen_exit(zero)
|
||||
/*
|
||||
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)
|
||||
}
|
||||
|
||||
fn (mut g Gen) adr() {
|
||||
g.write32(0x100000a0)
|
||||
g.println('adr x0, 0x14')
|
||||
fn (mut g Gen) adr(r Arm64Register, delta int) {
|
||||
g.write32(0x10000000 | int(r) | (delta << 4))
|
||||
g.println('adr $r, $delta')
|
||||
}
|
||||
|
||||
fn (mut g Gen) bl() {
|
||||
|
@ -124,6 +161,7 @@ pub fn (mut c Arm64) gen_exit(mut g Gen, expr ast.Expr) {
|
|||
}
|
||||
.linux {
|
||||
c.g.mov_arm(.x16, return_code)
|
||||
c.g.mov_arm(.x8, 93)
|
||||
c.g.mov_arm(.x0, 0)
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -37,7 +37,7 @@ pub fn (mut g Gen) generate_elf_header() {
|
|||
g.buf << native.elfclass64 // file class
|
||||
g.buf << native.elfdata2lsb // data encoding
|
||||
g.buf << native.ev_current // file version
|
||||
g.buf << 1 // elf_osabi
|
||||
g.buf << native.elf_osabi
|
||||
g.write64(0) // et_rel) // et_rel for .o
|
||||
g.write16(2) // e_type
|
||||
if g.pref.arch == .arm64 {
|
||||
|
@ -97,11 +97,17 @@ pub fn (mut g Gen) generate_elf_footer() {
|
|||
file_size := g.buf.len
|
||||
g.write64_at(file_size, g.file_size_pos) // set file size 64 bit value
|
||||
g.write64_at(file_size, g.file_size_pos + 8)
|
||||
// call main function, it's not guaranteed to be the first
|
||||
// we generated call(0) ("e8 0")
|
||||
// now need to replace "0" with a relative address of the main function
|
||||
// +1 is for "e8"
|
||||
// -5 is for "e8 00 00 00 00"
|
||||
g.write32_at(g.code_start_pos + 1, int(g.main_fn_addr - g.code_start_pos) - 5)
|
||||
if g.pref.arch == .arm64 {
|
||||
bl_next := u32(0x94000001)
|
||||
g.write32_at(g.code_start_pos, int(bl_next))
|
||||
} else {
|
||||
// amd64
|
||||
// call main function, it's not guaranteed to be the first
|
||||
// we generated call(0) ("e8 0")
|
||||
// now need to replace "0" with a relative address of the main function
|
||||
// +1 is for "e8"
|
||||
// -5 is for "e8 00 00 00 00"
|
||||
g.write32_at(g.code_start_pos + 1, int(g.main_fn_addr - g.code_start_pos) - 5)
|
||||
}
|
||||
g.create_executable()
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ pub fn gen(files []&ast.File, table &ast.Table, out_name string, pref &pref.Pref
|
|||
pref: pref
|
||||
}
|
||||
g.cgen = g.get_backend() or {
|
||||
eprintln('No available backend for this configuration')
|
||||
eprintln('No available backend for this configuration. Use `-a arm64` or `-a amd64`.')
|
||||
exit(1)
|
||||
}
|
||||
g.generate_header()
|
||||
|
|
Loading…
Reference in New Issue