mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
native: support simple library calls (#15958)
This commit is contained in:
parent
9fc64de94b
commit
6ac9552d39
@ -866,6 +866,20 @@ fn (mut g Gen) call(addr int) i64 {
|
||||
return c_addr
|
||||
}
|
||||
|
||||
fn (mut g Gen) extern_call(addr int) {
|
||||
match g.pref.os {
|
||||
.linux {
|
||||
g.write8(0xff)
|
||||
g.write8(0x15)
|
||||
g.write32(0)
|
||||
g.println('call *@GOTPCREL(%rip)')
|
||||
}
|
||||
else {
|
||||
g.n_error('extern calls are not implemented for $g.pref.os')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) syscall() {
|
||||
// g.write(0x050f)
|
||||
g.write8(0x0f)
|
||||
@ -1725,7 +1739,10 @@ pub fn (mut g Gen) call_fn_amd64(node ast.CallExpr) {
|
||||
for i in 0 .. reg_size {
|
||||
g.pop(native.fn_arg_registers[i])
|
||||
}
|
||||
if addr == 0 {
|
||||
if node.name in g.extern_symbols {
|
||||
g.extern_fn_calls[g.pos()] = node.name
|
||||
g.extern_call(int(addr))
|
||||
} else if addr == 0 {
|
||||
g.delay_fn_call(n)
|
||||
g.call(int(0))
|
||||
} else {
|
||||
|
@ -87,7 +87,7 @@ const (
|
||||
elf_sh_symtab_entsize = elf_symtab_size
|
||||
elf_sh_symtab_align = 8
|
||||
|
||||
// elf symbol bining
|
||||
// elf symbol binding
|
||||
elf_stb_local = u8(0)
|
||||
elf_stb_global = u8(1)
|
||||
|
||||
@ -123,6 +123,7 @@ const (
|
||||
elf_r_amd64_gotpc32 = 26
|
||||
elf_r_amd64_size32 = 32
|
||||
elf_r_amd64_size64 = 33
|
||||
elf_r_amd64_gotpcrelx = 0x29
|
||||
)
|
||||
|
||||
const (
|
||||
@ -288,6 +289,8 @@ mut:
|
||||
info int // Extra section information.
|
||||
addralign i64 // Section Alignment (must be power of two).
|
||||
entsize i64 // Section entry size.
|
||||
|
||||
pos i64 // not part of the actual data
|
||||
}
|
||||
|
||||
struct SymbolTableSection {
|
||||
@ -301,13 +304,14 @@ mut:
|
||||
size i64 // Symbol size.
|
||||
}
|
||||
|
||||
fn (mut g Gen) create_symbol_table_section(str_name string, info u8, bind u8, other i8, value i64, size i64) SymbolTableSection {
|
||||
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{
|
||||
str_name: str_name
|
||||
info: i8(info | bind << 4)
|
||||
other: other
|
||||
value: value
|
||||
size: size
|
||||
shndx: shndx
|
||||
}
|
||||
}
|
||||
|
||||
@ -330,14 +334,16 @@ fn (mut g Gen) create_progbits_section(bytes []u8) ProgBitsSection {
|
||||
}
|
||||
|
||||
struct RelASection {
|
||||
name string // not in the actual data
|
||||
mut:
|
||||
offset i64 // Location at which to apply the relocation action.
|
||||
info i64 // Symbol table index and type of relocation to apply.
|
||||
addend i64 // Constant addent for computing the value of the relocation field.
|
||||
}
|
||||
|
||||
fn (mut g Gen) create_rela_section(offset i64, sym u32, typ u32, addend i64) RelASection {
|
||||
fn (mut g Gen) create_rela_section(name string, offset i64, sym int, typ u32, addend i64) RelASection {
|
||||
return RelASection{
|
||||
name: name
|
||||
offset: offset
|
||||
info: i64((u64(sym) << 32) + typ)
|
||||
addend: addend
|
||||
@ -426,11 +432,11 @@ type SectionData = DynSymSection
|
||||
| NoBitsSection
|
||||
| NoteSection
|
||||
| ProgBitsSection
|
||||
| RelASection
|
||||
| RelSection
|
||||
| ShLibSection
|
||||
| StringTableSection
|
||||
| []DynamicSection
|
||||
| []RelASection
|
||||
| []SymbolTableSection
|
||||
|
||||
struct Section {
|
||||
@ -476,15 +482,15 @@ fn (mut g Gen) create_shstrtab(mut sections []Section) {
|
||||
fn (mut g Gen) create_symtab(mut sections []Section, mut table []SymbolTableSection) {
|
||||
mut names := []string{len: table.len}
|
||||
mut offset := 1
|
||||
|
||||
text_section := g.find_section_header('.text', sections)
|
||||
mut local_symbols := 0
|
||||
|
||||
for i, mut entry in table {
|
||||
names[i] = entry.str_name
|
||||
|
||||
entry.name = offset
|
||||
if entry.name != 1 {
|
||||
entry.shndx = i16(text_section) // i16(sections.len + 1)
|
||||
|
||||
if (entry.info >> 4) == native.elf_stb_local {
|
||||
local_symbols++
|
||||
}
|
||||
|
||||
offset += entry.str_name.len + 1
|
||||
@ -493,10 +499,18 @@ fn (mut g Gen) create_symtab(mut sections []Section, mut table []SymbolTableSect
|
||||
sections << g.create_section('.strtab', native.elf_sht_strtab, 0, 0, 1, 0, g.create_string_table_section(names))
|
||||
|
||||
sections << // index of .strtab
|
||||
g.create_section('.symtab', native.elf_sht_symtab, sections.len - 1, table.len - 1,
|
||||
g.create_section('.symtab', native.elf_sht_symtab, sections.len - 1, local_symbols,
|
||||
native.elf_sh_symtab_align, native.elf_sh_symtab_entsize, table)
|
||||
}
|
||||
|
||||
fn (mut g Gen) create_relocation(name string, mut sections []Section, table []RelASection) Section {
|
||||
mut section := g.create_section(name, native.elf_sht_rela, g.find_section_header('.symtab',
|
||||
sections), 1, 8, 24, table)
|
||||
section.header.flags = i64(native.elf_shf_info_link)
|
||||
sections << section
|
||||
return section
|
||||
}
|
||||
|
||||
fn (mut g Gen) create_progbits(name string, flags u64, data []u8) Section {
|
||||
mut section := g.create_section(name, native.elf_sht_progbits, 0, 0, 1, data.len,
|
||||
ProgBitsSection{data})
|
||||
@ -514,7 +528,7 @@ fn (mut g Gen) find_section_header(name string, sections []Section) int {
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_section_header(mut sh SectionHeader) {
|
||||
sh_offset := g.pos()
|
||||
sh.pos = g.pos()
|
||||
|
||||
g.write32(sh.name) // sh_name
|
||||
g.println('; sh_name')
|
||||
@ -525,8 +539,8 @@ fn (mut g Gen) gen_section_header(mut sh SectionHeader) {
|
||||
g.write64(sh.addr) // sh_addr
|
||||
g.println('; sh_name')
|
||||
if sh.offset == 0 {
|
||||
g.write64(sh_offset)
|
||||
sh.offset = sh_offset
|
||||
g.write64(sh.pos)
|
||||
sh.offset = sh.pos
|
||||
} else {
|
||||
g.write64(sh.offset)
|
||||
} // sh_offset
|
||||
@ -566,7 +580,7 @@ fn (mut g Gen) gen_symtab_data(section Section, data []SymbolTableSection) {
|
||||
}
|
||||
|
||||
size := native.elf_symtab_size * data.len
|
||||
g.write64_at(section.header.offset + 32, i64(size))
|
||||
g.write64_at(section.header.pos + 32, i64(size))
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_section_data(sections []Section) {
|
||||
@ -574,7 +588,7 @@ fn (mut g Gen) gen_section_data(sections []Section) {
|
||||
data := section.data
|
||||
|
||||
// write the actual offset of the section data
|
||||
g.write64_at(section.header.offset + 24, i64(g.pos()))
|
||||
g.write64_at(section.header.pos + 24, i64(g.pos()))
|
||||
|
||||
match data {
|
||||
StringTableSection {
|
||||
@ -589,7 +603,7 @@ fn (mut g Gen) gen_section_data(sections []Section) {
|
||||
g.write8(0) // null-postfixed
|
||||
|
||||
size := g.pos() - start
|
||||
g.write64_at(section.header.offset + 32, i64(size))
|
||||
g.write64_at(section.header.pos + 32, i64(size))
|
||||
}
|
||||
[]SymbolTableSection {
|
||||
g.gen_symtab_data(section, data)
|
||||
@ -597,14 +611,21 @@ fn (mut g Gen) gen_section_data(sections []Section) {
|
||||
ProgBitsSection {
|
||||
// progbits have to be handled by the user.
|
||||
}
|
||||
RelASection {
|
||||
g.write64(data.offset)
|
||||
g.write64(data.info)
|
||||
g.write64(data.addend)
|
||||
g.println('; SHT_RELA ($data.offset, $data.info, $data.addend)')
|
||||
[]RelASection {
|
||||
if data.len == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
size := native.elf_rela_size
|
||||
g.write64_at(section.header.offset + 32, i64(size))
|
||||
for rela in data {
|
||||
g.write64(rela.offset)
|
||||
g.fn_addr[rela.name] = rela.offset
|
||||
g.write64(rela.info)
|
||||
g.write64(rela.addend)
|
||||
g.println('; SHT_RELA `$rela.name` ($rela.offset, $rela.info, $rela.addend)')
|
||||
}
|
||||
|
||||
size := native.elf_rela_size * data.len
|
||||
g.write64_at(section.header.pos + 32, i64(size))
|
||||
}
|
||||
HashSection {
|
||||
// TODO
|
||||
@ -618,7 +639,7 @@ fn (mut g Gen) gen_section_data(sections []Section) {
|
||||
}
|
||||
|
||||
size := native.elf_dynamic_size * data.len
|
||||
g.write64_at(section.header.offset + 32, i64(size))
|
||||
g.write64_at(section.header.pos + 32, i64(size))
|
||||
}
|
||||
NoteSection {
|
||||
start := g.pos()
|
||||
@ -636,7 +657,7 @@ fn (mut g Gen) gen_section_data(sections []Section) {
|
||||
g.write8(0)
|
||||
|
||||
size := g.pos() - start
|
||||
g.write64_at(section.header.offset + 32, i64(size))
|
||||
g.write64_at(section.header.pos + 32, i64(size))
|
||||
}
|
||||
NoBitsSection {
|
||||
// Nothing to do
|
||||
@ -647,13 +668,13 @@ fn (mut g Gen) gen_section_data(sections []Section) {
|
||||
g.println('; SHT_REL ($data.offset, $data.info)')
|
||||
|
||||
size := native.elf_rel_size
|
||||
g.write64_at(section.header.offset + 32, i64(size))
|
||||
g.write64_at(section.header.pos + 32, i64(size))
|
||||
}
|
||||
ShLibSection {
|
||||
g.write(data.data)
|
||||
|
||||
size := data.data.len
|
||||
g.write64_at(section.header.offset + 32, i64(size))
|
||||
g.write64_at(section.header.pos + 32, i64(size))
|
||||
}
|
||||
DynSymSection {
|
||||
g.gen_symtab_data(section, data.symbols)
|
||||
@ -662,6 +683,15 @@ fn (mut g Gen) gen_section_data(sections []Section) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) symtab_get_index(symbols []SymbolTableSection, name string) int {
|
||||
for i, sym in symbols {
|
||||
if sym.str_name == name {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) generate_linkable_elf_header() {
|
||||
elf_type := native.elf_type_rel // PIE (use _exec for non-relocatable executables)
|
||||
|
||||
@ -676,16 +706,20 @@ pub fn (mut g Gen) generate_linkable_elf_header() {
|
||||
g.create_progbits('.bss', native.elf_shf_write | native.elf_shf_alloc, []),
|
||||
]
|
||||
|
||||
mut symbols := [
|
||||
g.symbol_table = [
|
||||
SymbolTableSection{}, // first is null
|
||||
g.create_symbol_table_section('test.v', native.elf_stt_file, native.elf_stb_local,
|
||||
native.elf_stv_default, 0, 0), // source file TODO: replace test.v with actual source file name
|
||||
g.create_symbol_table_section('.text', native.elf_stt_section, native.elf_stb_local,
|
||||
native.elf_stv_default, 0, 0), // .text section
|
||||
g.create_symbol_table_section('main', native.elf_stt_func, native.elf_stb_global,
|
||||
native.elf_stv_default, 0, 0), // main label points to entry point address
|
||||
g.create_symbol_table_section('main', native.elf_stt_notype, native.elf_stb_global,
|
||||
native.elf_stv_default, 0, 0, i16(g.find_section_header('.text', sections))), // main label points to entry point address
|
||||
g.create_symbol_table_section('_GLOBAL_OFFSET_TABLE_', native.elf_stt_notype,
|
||||
native.elf_stb_global, native.elf_stv_default, 0, 0, 0),
|
||||
]
|
||||
g.create_symtab(mut sections, mut symbols) // create the .symtab section
|
||||
|
||||
for symbol in g.extern_symbols {
|
||||
g.symbol_table << g.create_symbol_table_section(symbol[2..], native.elf_stt_notype,
|
||||
native.elf_stb_global, native.elf_stv_default, 0, 0, 0)
|
||||
}
|
||||
g.create_symtab(mut sections, mut g.symbol_table) // create the .symtab section
|
||||
g.create_relocation('.rela.text', mut sections, [])
|
||||
g.create_shstrtab(mut sections) // create the .shstrtab section (this must be the last section!)
|
||||
|
||||
mut elf_header := g.default_elf_header()
|
||||
@ -709,6 +743,8 @@ pub fn (mut g Gen) generate_linkable_elf_header() {
|
||||
// write sections
|
||||
g.gen_section_data(sections)
|
||||
|
||||
g.elf_rela_section = sections[g.find_section_header('.rela.text', sections)]
|
||||
|
||||
// user code starts here
|
||||
if g.pref.is_verbose {
|
||||
eprintln('code_start_pos = $g.buf.len.hex()')
|
||||
@ -717,7 +753,7 @@ pub fn (mut g Gen) generate_linkable_elf_header() {
|
||||
g.code_start_pos = g.pos()
|
||||
g.debug_pos = int(g.pos())
|
||||
// if g.start_symbol_addr > 0 {
|
||||
// g.write64_at(g.start_symbol_addr + native.elf_symtab_size - 16, g.code_start_pos + native.segment_start)
|
||||
// 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)]
|
||||
@ -733,7 +769,6 @@ pub fn (mut g Gen) generate_linkable_elf_header() {
|
||||
g.ret()
|
||||
g.println('; return 0')
|
||||
|
||||
g.write64_at(g.start_symbol_addr + native.elf_symtab_size - 8, g.pos() - g.code_start_pos) // write 'main' function size
|
||||
g.debug_pos = g.buf.len
|
||||
}
|
||||
|
||||
@ -787,7 +822,7 @@ pub fn (mut g Gen) generate_simple_elf_header() {
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) elf_string_table() {
|
||||
pub fn (mut g Gen) elf_string_table() {
|
||||
for _, s in g.strs {
|
||||
match s.typ {
|
||||
.abs64 {
|
||||
@ -805,9 +840,29 @@ fn (mut g Gen) elf_string_table() {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) gen_rela_section() {
|
||||
mut relocations := []RelASection{}
|
||||
for call_pos, symbol in g.extern_fn_calls {
|
||||
relocations << g.create_rela_section(symbol, call_pos - g.code_start_pos + 2,
|
||||
g.symtab_get_index(g.symbol_table, symbol[2..]), native.elf_r_amd64_gotpcrelx,
|
||||
-4)
|
||||
}
|
||||
g.elf_rela_section.data = relocations
|
||||
g.gen_section_data([g.elf_rela_section])
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) generate_elf_footer() {
|
||||
g.elf_string_table()
|
||||
// file_size holds the address at the end of the code and const strings table
|
||||
|
||||
// write size of text section into section header
|
||||
if g.elf_text_header_addr != -1 {
|
||||
g.write64_at(g.elf_text_header_addr + 32, g.pos() - g.code_start_pos)
|
||||
}
|
||||
|
||||
if g.extern_symbols.len != 0 {
|
||||
g.gen_rela_section()
|
||||
}
|
||||
|
||||
file_size := g.buf.len
|
||||
g.write64_at(g.file_size_pos, file_size) // set file size 64 bit value
|
||||
g.write64_at(g.file_size_pos + 8, file_size)
|
||||
@ -824,11 +879,6 @@ pub fn (mut g Gen) generate_elf_footer() {
|
||||
g.write32_at(g.code_start_pos + 1, int(g.main_fn_addr - g.code_start_pos) - 5)
|
||||
}
|
||||
|
||||
// write size of text section into section header
|
||||
if g.elf_text_header_addr != -1 {
|
||||
g.write64_at(g.elf_text_header_addr + 32, g.pos() - g.code_start_pos)
|
||||
}
|
||||
|
||||
g.create_executable()
|
||||
}
|
||||
|
||||
|
@ -36,10 +36,14 @@ mut:
|
||||
offset i64
|
||||
file_size_pos i64
|
||||
elf_text_header_addr i64 = -1
|
||||
elf_rela_section Section
|
||||
main_fn_addr i64
|
||||
main_fn_size i64
|
||||
start_symbol_addr i64
|
||||
code_start_pos i64 // location of the start of the assembly instructions
|
||||
symbol_table []SymbolTableSection
|
||||
extern_symbols []string
|
||||
extern_fn_calls map[i64]string
|
||||
fn_addr map[string]i64
|
||||
var_offset map[string]int // local var stack offset
|
||||
var_alloc_size map[string]int // local var allocation size
|
||||
@ -259,27 +263,25 @@ pub fn (mut g Gen) typ(a int) &ast.TypeSymbol {
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) ast_has_external_functions() bool {
|
||||
mut has_external_fn := false
|
||||
|
||||
for file in g.files {
|
||||
walker.inspect(file, unsafe { &mut has_external_fn }, fn (node &ast.Node, data voidptr) bool {
|
||||
walker.inspect(file, unsafe { &mut g }, fn (node &ast.Node, data voidptr) bool {
|
||||
if node is ast.Expr && (node as ast.Expr) is ast.CallExpr
|
||||
&& ((node as ast.Expr) as ast.CallExpr).language != .v {
|
||||
call := node as ast.CallExpr
|
||||
unsafe {
|
||||
*&bool(data) = true // an external function was found
|
||||
mut g := &Gen(data)
|
||||
if call.name !in g.extern_symbols {
|
||||
g.extern_symbols << call.name
|
||||
}
|
||||
}
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
if has_external_fn {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return has_external_fn
|
||||
return g.extern_symbols.len != 0
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) generate_header() {
|
||||
@ -878,19 +880,15 @@ g.expr
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) extern_fn_decl(node ast.FnDecl) {
|
||||
// declarations like: fn C.malloc()
|
||||
// TODO: implement extern function calls here
|
||||
// Must store an address where the function label is located in the RelA elf section
|
||||
panic('C. functions are not implemented yet')
|
||||
}
|
||||
|
||||
fn (mut g Gen) fn_decl(node ast.FnDecl) {
|
||||
name := if node.is_method {
|
||||
'${g.table.get_type_name(node.receiver.typ)}.$node.name'
|
||||
} else {
|
||||
node.name
|
||||
}
|
||||
if node.no_body {
|
||||
return
|
||||
}
|
||||
if g.pref.is_verbose {
|
||||
println(term.green('\n$name:'))
|
||||
}
|
||||
@ -900,10 +898,6 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
|
||||
if node.is_builtin {
|
||||
g.warning('fn_decl: $name is builtin', node.pos)
|
||||
}
|
||||
if node.no_body {
|
||||
g.extern_fn_decl(node)
|
||||
return
|
||||
}
|
||||
|
||||
g.stack_var_pos = 0
|
||||
g.register_function_address(name)
|
||||
|
38
vlib/v/gen/native/tests/libc.vv
Normal file
38
vlib/v/gen/native/tests/libc.vv
Normal file
@ -0,0 +1,38 @@
|
||||
// because of an issue with checker, all C.* functions have to be declared first
|
||||
fn C.isalpha(c int) int
|
||||
fn C.isdigit(c int) int
|
||||
|
||||
fn main() {
|
||||
charutil()
|
||||
}
|
||||
|
||||
fn charutil() {
|
||||
$if linux {
|
||||
// ascii for `V`
|
||||
v_is_alpha := C.isalpha(86)
|
||||
if v_is_alpha != 0 {
|
||||
println('ok 1')
|
||||
} else {
|
||||
assert false
|
||||
}
|
||||
|
||||
null_is_alpha := C.isalpha(0)
|
||||
if null_is_alpha == 0 {
|
||||
println('ok 2')
|
||||
} else {
|
||||
assert false
|
||||
}
|
||||
|
||||
// ascii for `3`
|
||||
three_is_digit := C.isdigit(51)
|
||||
if three_is_digit != 0 {
|
||||
println('ok 3')
|
||||
} else {
|
||||
assert false
|
||||
}
|
||||
} $else {
|
||||
println('ok 1')
|
||||
println('ok 2')
|
||||
println('ok 3')
|
||||
}
|
||||
}
|
3
vlib/v/gen/native/tests/libc.vv.out
Normal file
3
vlib/v/gen/native/tests/libc.vv.out
Normal file
@ -0,0 +1,3 @@
|
||||
ok 1
|
||||
ok 2
|
||||
ok 3
|
Loading…
Reference in New Issue
Block a user