mirror of
https://github.com/vlang/v.git
synced 2025-08-03 09:47:15 -04:00
native: add support for (elf) globals (#25016)
This commit is contained in:
parent
5ec3cc17e1
commit
c49b9da04e
@ -334,7 +334,7 @@ fn (mut c Amd64) cmp_var_reg(var Var, reg Register, config VarConfig) {
|
||||
c.g.println('cmp var `${var.name}`, ${reg}')
|
||||
}
|
||||
GlobalVar {
|
||||
// TODO
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
}
|
||||
ExternVar {
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
@ -383,7 +383,7 @@ fn (mut c Amd64) cmp_var(var Var, val i32, config VarConfig) {
|
||||
c.g.println('cmp var `${var.name}` ${val}')
|
||||
}
|
||||
GlobalVar {
|
||||
// TODO
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
}
|
||||
ExternVar {
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
@ -433,7 +433,7 @@ fn (mut c Amd64) dec_var(var Var, config VarConfig) {
|
||||
c.g.println('dec_var `${var.name}`')
|
||||
}
|
||||
GlobalVar {
|
||||
// TODO
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
}
|
||||
ExternVar {
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
@ -507,8 +507,7 @@ fn (mut c Amd64) inc_var(var Var, config VarConfig) {
|
||||
c.g.println('inc_var ${size_str} `${var.name}`')
|
||||
}
|
||||
GlobalVar {
|
||||
c.g.n_error('${@LOCATION} Global variables incrementation is not supported yet')
|
||||
// TODO
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
}
|
||||
ExternVar {
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
@ -794,8 +793,24 @@ fn (mut c Amd64) mov_reg_to_var(var Var, r Register, config VarConfig) {
|
||||
c.g.println('mov ${size_str} PTR [rbp-${int(offset).hex2()}],${reg} ; `${var.name}`')
|
||||
}
|
||||
GlobalVar {
|
||||
// TODO
|
||||
c.g.n_error('${@LOCATION} Unsupported GlobalVar')
|
||||
size := match c.g.get_type_size(var.typ) {
|
||||
1 { Size._8 }
|
||||
2 { Size._16 }
|
||||
4 { Size._32 }
|
||||
8 { Size._64 }
|
||||
else { c.g.n_error('${@LOCATION} unsupported size of global var') }
|
||||
}
|
||||
mut addr_reg := Amd64Register.rdx
|
||||
if reg == .rdx || reg == .edx {
|
||||
addr_reg = .rax
|
||||
}
|
||||
c.push(addr_reg)
|
||||
c.g.global_vars[c.g.pos() + 2] = var.name // +2 for the mov64 instruction
|
||||
c.mov64(addr_reg, i64(0))
|
||||
c.g.println('; will get patched by relocs')
|
||||
c.mov_store(addr_reg, reg, size)
|
||||
c.pop(addr_reg)
|
||||
c.g.println('; mov global:`${var.name}` ${reg}')
|
||||
}
|
||||
ExternVar {
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
@ -886,7 +901,7 @@ fn (mut c Amd64) mov_int_to_var(var Var, integer i32, config VarConfig) {
|
||||
}
|
||||
}
|
||||
GlobalVar {
|
||||
// TODO
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
}
|
||||
ExternVar {
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
@ -1009,7 +1024,20 @@ fn (mut c Amd64) mov_var_to_reg(reg Register, var Var, config VarConfig) {
|
||||
c.g.println('${instruction} ${reg}, ${size_str} PTR [rbp-${int(offset).hex2()}] ; `${var.name}`')
|
||||
}
|
||||
GlobalVar {
|
||||
c.g.n_error('${@LOCATION} Unsupported GlobalVar')
|
||||
if c.g.get_type_size(var.typ) > 8 {
|
||||
c.g.n_error('${@LOCATION} unsupported size of global var')
|
||||
}
|
||||
mut addr_reg := Amd64Register.rdx
|
||||
if reg as Amd64Register == .rdx || reg as Amd64Register == .edx {
|
||||
addr_reg = .rax
|
||||
}
|
||||
c.push(addr_reg)
|
||||
c.g.global_vars[c.g.pos() + 2] = var.name // +2 for the mov64 instruction
|
||||
c.mov64(addr_reg, i64(0))
|
||||
c.g.println('; will get patched by relocs')
|
||||
c.mov_deref(reg, addr_reg, var.typ)
|
||||
c.pop(addr_reg)
|
||||
c.g.println('; mov ${reg} global:`${var.name}`')
|
||||
}
|
||||
ExternVar {
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
@ -3859,7 +3887,7 @@ fn (mut c Amd64) init_struct(var Var, init ast.StructInit) {
|
||||
}
|
||||
}
|
||||
GlobalVar {
|
||||
c.g.n_error('${@LOCATION} GlobalVar not implemented for ast.StructInit')
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
}
|
||||
ExternVar {
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
@ -3932,7 +3960,7 @@ fn (mut c Amd64) init_array(var Var, node ast.ArrayInit) {
|
||||
}
|
||||
}
|
||||
GlobalVar {
|
||||
c.g.n_error('${@LOCATION} GlobalVar not implemented for ast.ArrayInit')
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
}
|
||||
ExternVar {
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
@ -4265,7 +4293,7 @@ fn (mut c Amd64) mov_ssereg_to_var(var Var, reg Amd64SSERegister, config VarConf
|
||||
c.g.println('${inst} [rbp-${int(offset).hex2()}], ${reg}')
|
||||
}
|
||||
GlobalVar {
|
||||
// TODO
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
}
|
||||
ExternVar {
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
@ -4321,7 +4349,7 @@ fn (mut c Amd64) mov_var_to_ssereg(reg Amd64SSERegister, var Var, config VarConf
|
||||
c.g.println('${inst} ${reg}, [rbp-${int(offset).hex2()}]')
|
||||
}
|
||||
GlobalVar {
|
||||
// TODO
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
}
|
||||
ExternVar {
|
||||
c.g.n_error('${@LOCATION} unsupported var type ${var}')
|
||||
|
@ -55,6 +55,13 @@ const blacklist = {
|
||||
'string.last_index': true
|
||||
'string.last_index_u8': false
|
||||
'string.contains_u8': false
|
||||
'malloc_noscan': true
|
||||
'vmemcpy': false
|
||||
'eprint': false
|
||||
'eprintln': false
|
||||
'_write_buf_to_fd': false
|
||||
'_writeln_to_fd': false
|
||||
'_memory_panic': true
|
||||
}
|
||||
|
||||
const windows_blacklist = {
|
||||
|
@ -4,6 +4,7 @@
|
||||
module native
|
||||
|
||||
import os
|
||||
import ast
|
||||
|
||||
const elf_class32 = 1
|
||||
const elf_class64 = 2
|
||||
@ -300,6 +301,8 @@ mut:
|
||||
size i64 // Symbol size.
|
||||
}
|
||||
|
||||
// see for more details: https://gist.github.com/x0nu11byt3/bcb35c3de461e5fb66173071a2379779
|
||||
// https://www.etherington.xyz/elfguide#symtab-section-entries
|
||||
fn (mut g Gen) create_symbol_table_section(str_name string, info u8, bind u8, other i8, value i64, size i64,
|
||||
shndx i16) SymbolTableSection {
|
||||
return SymbolTableSection{
|
||||
@ -615,7 +618,6 @@ fn (mut g Gen) gen_section_data(sections []Section) {
|
||||
for rela in data {
|
||||
g.write64(rela.offset)
|
||||
g.fn_addr[rela.name] = rela.offset // that's wierd it's the call offset, not the fn
|
||||
g.fn_names << rela.name
|
||||
g.write64(rela.info)
|
||||
g.write64(rela.addend)
|
||||
g.println('; SHT_RELA `${rela.name}` (${rela.offset}, ${rela.info}, ${rela.addend})')
|
||||
@ -711,6 +713,23 @@ pub fn (mut g Gen) generate_linkable_elf_header() {
|
||||
elf_stv_default, 0, 0, 0),
|
||||
]
|
||||
|
||||
mut sym_data_offset := 0 // offset from the beggining of the data section
|
||||
for f in g.files {
|
||||
for s in f.stmts {
|
||||
if s is ast.GlobalDecl {
|
||||
for fi in s.fields {
|
||||
size := g.get_type_size(fi.typ)
|
||||
if size > 0 {
|
||||
g.symbol_table << g.create_symbol_table_section(fi.name, elf_stt_object,
|
||||
elf_stb_global, elf_stv_default, sym_data_offset, size, i16(g.find_section_header('.data',
|
||||
sections)))
|
||||
}
|
||||
sym_data_offset += size
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for symbol in g.extern_symbols {
|
||||
g.symbol_table << g.create_symbol_table_section(symbol[2..], elf_stt_notype, elf_stb_global,
|
||||
elf_stv_default, 0, 0, 0)
|
||||
@ -742,6 +761,37 @@ pub fn (mut g Gen) generate_linkable_elf_header() {
|
||||
|
||||
g.elf_rela_section = sections[g.find_section_header('.rela.text', sections)]
|
||||
|
||||
// Init data section
|
||||
// TODO: use .bss for uninitialized data or generate the data
|
||||
data_section := sections[g.find_section_header('.data', sections)]
|
||||
g.elf_data_header_addr = data_section.header.offset
|
||||
|
||||
data_pos := g.pos()
|
||||
g.println('\ndata_start_pos = ${data_pos.hex()}')
|
||||
g.write64_at(g.elf_data_header_addr + 24, data_pos)
|
||||
for f in g.files {
|
||||
for s in f.stmts {
|
||||
if s is ast.GlobalDecl {
|
||||
for fi in s.fields {
|
||||
size := g.get_type_size(fi.typ)
|
||||
match size {
|
||||
1 { g.write8(0xF) }
|
||||
2 { g.write16(0xF) }
|
||||
4 { g.write32(0xF) }
|
||||
8 { g.write64(i64(0xF)) }
|
||||
else { println('${@LOCATION} unsupported size ${size} for global ${fi}') }
|
||||
}
|
||||
g.println('; global ${fi.name}, size: ${size}')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g.write64_at(g.elf_data_header_addr + 32, g.pos() - data_pos)
|
||||
// TODO: pre-calculate .data instead of genetating it at runtime
|
||||
|
||||
// It is wierd, the init section has something in it but I did not find
|
||||
// where does it come from
|
||||
|
||||
// user code starts here
|
||||
if g.pref.is_verbose {
|
||||
eprintln('code_start_pos = ${g.buf.len.hex()}')
|
||||
@ -752,11 +802,29 @@ pub fn (mut g Gen) generate_linkable_elf_header() {
|
||||
// if g.start_symbol_addr > 0 {
|
||||
// g.write64_at(g.start_symbol_addr + native.elf_symtab_size - 16, g.code_start_pos)
|
||||
//}
|
||||
|
||||
text_section := sections[g.find_section_header('.text', sections)]
|
||||
g.elf_text_header_addr = text_section.header.offset
|
||||
g.write64_at(g.elf_text_header_addr + 24, g.pos()) // write the code start pos to the text section
|
||||
|
||||
g.println('; fill .data')
|
||||
for f in g.files {
|
||||
for s in f.stmts {
|
||||
if s is ast.GlobalDecl {
|
||||
for fi in s.fields {
|
||||
size := g.get_type_size(fi.typ)
|
||||
if size > 8 || size <= 0 {
|
||||
println('${@LOCATION} unsupported size ${size} for global ${fi}')
|
||||
} else if fi.expr !is ast.EmptyExpr {
|
||||
g.expr(fi.expr)
|
||||
g.code_gen.mov_reg_to_var(GlobalVar{fi.name, fi.typ}, g.code_gen.main_reg())
|
||||
g.println('; global ${fi.name}, size: ${size}')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g.elf_main_call_pos = g.pos()
|
||||
g.code_gen.call(placeholder)
|
||||
g.println('; call main.main')
|
||||
g.code_gen.mov64(g.code_gen.main_reg(), i64(0))
|
||||
@ -848,9 +916,13 @@ pub fn (mut g Gen) gen_rela_section() {
|
||||
g.symtab_get_index(g.symbol_table, symbol[2..]), elf_r_amd64_gotpcrelx, -4)
|
||||
}
|
||||
for var_pos, symbol in g.extern_vars {
|
||||
relocations << g.create_rela_section(symbol, var_pos - g.code_start_pos + 2, g.symtab_get_index(g.symbol_table,
|
||||
relocations << g.create_rela_section(symbol, var_pos - g.code_start_pos, g.symtab_get_index(g.symbol_table,
|
||||
symbol[2..]), elf_r_amd64_64, 0)
|
||||
}
|
||||
for var_pos, symbol in g.global_vars {
|
||||
relocations << g.create_rela_section(symbol, var_pos - g.code_start_pos, g.symtab_get_index(g.symbol_table,
|
||||
symbol), elf_r_amd64_64, 0)
|
||||
}
|
||||
g.elf_rela_section.data = relocations
|
||||
g.gen_section_data([g.elf_rela_section])
|
||||
}
|
||||
@ -872,7 +944,7 @@ pub fn (mut g Gen) generate_elf_footer() {
|
||||
g.write64_at(g.file_size_pos + 8, file_size)
|
||||
if g.pref.arch == .arm64 {
|
||||
bl_next := u32(0x94000001)
|
||||
g.write32_at(g.code_start_pos, i32(bl_next))
|
||||
g.write32_at(g.elf_main_call_pos, i32(bl_next))
|
||||
} else {
|
||||
// amd64
|
||||
// call main function, it's not guaranteed to be the first
|
||||
@ -880,7 +952,7 @@ pub fn (mut g Gen) generate_elf_footer() {
|
||||
// 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, i32(g.main_fn_addr - g.code_start_pos) - 5)
|
||||
g.write32_at(g.elf_main_call_pos + 1, i32(g.main_fn_addr - g.elf_main_call_pos) - 5)
|
||||
}
|
||||
g.create_executable()
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ fn (mut g Gen) local_var_ident(ident ast.Ident, var LocalVar) {
|
||||
fn (mut g Gen) extern_var_ident(var ExternVar) {
|
||||
if g.pref.os == .linux {
|
||||
main_reg := g.code_gen.main_reg()
|
||||
g.extern_vars[g.pos()] = var.name
|
||||
g.extern_vars[g.pos() + 2] = var.name // + 2 for the mov64 instruction
|
||||
g.code_gen.mov64(main_reg, Number(i64(0)))
|
||||
g.code_gen.mov_deref(main_reg, main_reg, ast.u64_type_idx)
|
||||
} else if g.pref.os == .macos {
|
||||
|
@ -39,8 +39,9 @@ mut:
|
||||
extern_symbols []string
|
||||
linker_include_paths []string
|
||||
linker_libs []string
|
||||
extern_vars map[i64]string
|
||||
extern_fn_calls map[i64]string
|
||||
global_vars map[i64]string // used to patch
|
||||
extern_vars map[i64]string // used to patch
|
||||
extern_fn_calls map[i64]string // used to patch
|
||||
fn_addr map[string]i64
|
||||
fn_names []string
|
||||
var_offset map[string]i32 // local var stack offset
|
||||
@ -65,7 +66,9 @@ mut:
|
||||
return_type ast.Type
|
||||
comptime_omitted_branches []ast.IfBranch
|
||||
// elf specific
|
||||
elf_main_call_pos i64
|
||||
elf_text_header_addr i64 = -1
|
||||
elf_data_header_addr i64 = -1
|
||||
elf_rela_section Section
|
||||
// macho specific
|
||||
macho_ncmds i32
|
||||
@ -253,7 +256,10 @@ struct PreprocVar {
|
||||
val i64
|
||||
}
|
||||
|
||||
struct GlobalVar {}
|
||||
struct GlobalVar {
|
||||
name string
|
||||
typ ast.Type
|
||||
}
|
||||
|
||||
@[params]
|
||||
struct VarConfig {
|
||||
@ -300,7 +306,9 @@ fn (mut g Gen) get_var_from_ident(ident ast.Ident) IdentVar {
|
||||
return PreprocVar{ident.info.typ, ident.name, preprocessed_val}
|
||||
}
|
||||
mut obj := ident.obj
|
||||
if obj !in [ast.Var, ast.ConstField, ast.GlobalField, ast.AsmRegister] {
|
||||
if obj is ast.GlobalField {
|
||||
return GlobalVar{obj.name, obj.typ}
|
||||
} else if obj !in [ast.Var, ast.ConstField, ast.AsmRegister] {
|
||||
obj = ident.scope.find(ident.name) or {
|
||||
g.n_error('${@LOCATION} unknown variable ${ident.name}')
|
||||
}
|
||||
@ -389,6 +397,7 @@ pub fn gen(files []&ast.File, mut table ast.Table, out_name string, pref_ &pref.
|
||||
g.init_builtins()
|
||||
g.calculate_all_size_align()
|
||||
g.calculate_enum_fields()
|
||||
g.fn_names = g.table.fns.keys()
|
||||
for file in g.files {
|
||||
/*
|
||||
if file.warnings.len > 0 {
|
||||
@ -1175,7 +1184,6 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
|
||||
g.stack_var_pos = 0
|
||||
g.stack_depth = 0
|
||||
g.register_function_address(name)
|
||||
g.fn_names << name
|
||||
g.labels = &LabelTable{}
|
||||
g.defer_stmts.clear()
|
||||
g.return_type = node.return_type
|
||||
@ -1225,6 +1233,7 @@ fn (mut g Gen) println(comment string) {
|
||||
@[noreturn]
|
||||
pub fn (mut g Gen) n_error(s string) {
|
||||
print_backtrace()
|
||||
flush_stdout()
|
||||
util.verror('native error', s)
|
||||
}
|
||||
|
||||
|
@ -106,8 +106,10 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||
g.gen_assert(node)
|
||||
}
|
||||
ast.GlobalDecl {
|
||||
if !g.is_builtin_mod && !g.pref.experimental {
|
||||
g.warning('globals are not supported yet', node.pos)
|
||||
if g.pref.os == .linux {
|
||||
// handled in elf generator
|
||||
} else if !g.is_builtin_mod && !g.pref.experimental {
|
||||
g.warning('global variables are not supported', node.pos)
|
||||
}
|
||||
}
|
||||
ast.Import {} // do nothing here
|
||||
|
@ -20,10 +20,23 @@ fn test_c_extern_vars() {
|
||||
C.fprintf(C.stdout, s.str, 3)
|
||||
}
|
||||
|
||||
fn test_prints() {
|
||||
print_character(`a`)
|
||||
}
|
||||
|
||||
__global foo = 3
|
||||
|
||||
fn test_globals() {
|
||||
assert foo == 3
|
||||
foo = 5
|
||||
assert foo == 5
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_for_c_in_string()
|
||||
test_c_extern_vars()
|
||||
test_prints()
|
||||
test_globals()
|
||||
flush_stderr()
|
||||
flush_stdout()
|
||||
print_character(`a`)
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ fn test_native() {
|
||||
work_test_path := os.join_path(wrkdir, test_file_name)
|
||||
exe_test_path := os.join_path(wrkdir, test_file_name + '.exe')
|
||||
tmperrfile := os.join_path(dir, test + '.tmperr')
|
||||
cmd := '${os.quoted_path(vexe)} -o ${os.quoted_path(exe_test_path)} -b native ${os.quoted_path(full_test_path)} -d no_backtrace -d custom_define 2> ${os.quoted_path(tmperrfile)}'
|
||||
cmd := '${os.quoted_path(vexe)} -enable-globals -o ${os.quoted_path(exe_test_path)} -b native ${os.quoted_path(full_test_path)} -d no_backtrace -d custom_define 2> ${os.quoted_path(tmperrfile)}'
|
||||
if is_verbose {
|
||||
println(cmd)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user