diff --git a/vlib/v/gen/native/elf.v b/vlib/v/gen/native/elf.v index aa9a8a2bb5..6ab5d8fce9 100644 --- a/vlib/v/gen/native/elf.v +++ b/vlib/v/gen/native/elf.v @@ -4,30 +4,55 @@ module native const ( - elf_class32 = 1 - elf_class64 = 2 + elf_class32 = 1 + elf_class64 = 2 - elf_data_le = 1 - elf_data_be = 2 + elf_data_le = 1 + elf_data_be = 2 - elf_version = 1 - elf_abiversion = 0 + elf_version = 1 + elf_abiversion = 0 - elf_type_rel = 1 - elf_type_exec = 2 - elf_type_dyn = 3 + elf_type_rel = 1 + elf_type_exec = 2 + elf_type_dyn = 3 - elf_amd64 = 0x3e - elf_arm64 = 0xb7 + elf_amd64 = 0x3e + elf_arm64 = 0xb7 - elf_osabi_none = 0 - elf_osabi_hpux = 1 - elf_osabi_netbsd = 2 - elf_osabi_linux = 3 - elf_osabi_freebsd = 9 + elf_osabi_none = 0 + elf_osabi_hpux = 1 + elf_osabi_netbsd = 2 + elf_osabi_linux = 3 + elf_osabi_freebsd = 9 - elf_header_size = 0x40 - elf_phentry_size = 0x38 + elf_header_size = 0x40 + elf_phentry_size = 0x38 + elf_shentry_size = 0x40 + elf_symtab_size = 0x18 + + elf_sh_symtab_entsize = 0x18 + elf_sh_symtab_info = 1 + elf_sh_symtab_align = 8 + + elf_sht_strtab = 3 + elf_sht_symtab = 2 + + elf_pt_load = 1 + elf_p_align = 0x1000 + + // elf symbol bining + elf_stb_local = u8(0) + elf_stb_global = u8(1) + + // elf symbol types + elf_stt_notype = u8(0) + elf_stt_object = u8(1) + elf_stt_func = u8(2) + elf_stt_section = u8(3) + + // elf symbol visibility + elf_stv_default = i8(0) ) const ( @@ -35,29 +60,304 @@ const ( placeholder = 0 ) +struct ProgramHeader { +mut: + typ int // Program header type. + flags int // Segment-independent flags. + offset i64 // Offset of the segment in the file image. + vaddr i64 // Virtual segment address. + paddr i64 // Physical segment address. + filesz i64 // Segment size in the file. + memsz i64 // Segment size in memory. + align i64 // Segment alignment. +} + +fn (mut g Gen) create_program_header(typ int, flags int, align i64) ProgramHeader { + return ProgramHeader{ + typ: typ + flags: flags + align: align + } +} + +fn (mut p ProgramHeader) set_addr(addr i64) { + p.vaddr = addr + p.paddr = addr +} + +fn (mut g Gen) gen_program_header64(p ProgramHeader) { + g.write32(p.typ) // p_type + g.println('; p_type') + g.write32(p.flags) // p_flags + g.println('; p_flags') + g.write64(p.offset) // p_offset + g.println('; p_offset') + g.write64(if p.vaddr == 0 { + native.segment_start + } else { + p.vaddr + }) // p_vaddr + g.println('; p_vaddr') + g.write64(if p.paddr == 0 { + native.segment_start + } else { + p.paddr + }) // p_paddr + g.println('; p_paddr') + if p.filesz == 0 { + g.file_size_pos = g.pos() + } + g.write64(p.filesz) // p_filesz + g.println('; p_filesz') + g.write64(p.memsz) // p_memsz + g.println('; p_memsz') + g.write64(p.align) // p_align + g.println('; p_align') + g.println('; ^^^ program header (64)') +} + +struct SectionHeader { +mut: + name int // Offset to name string in .shstrtab. + typ int // Section type. + flags i64 // Section attributes. + addr i64 // Section address. + offset i64 // Section address offset. + size i64 // Section size. + link int // Section index for associated section types. + info int // Extra section information. + addralign i64 // Section Alignment (must be power of two). + entsize i64 // Section entry size. +} + +struct SymbolTable { + str_name string // string name (not generated) +mut: + name int // Index to name in .strtab. + info i8 // symbol type and binding attribute. + other i8 // Symbol visibility. + shndx i16 // Related section header table index. + value i64 // value of the associated symbol + size i64 // Symbol size +} + +fn (mut g Gen) create_symbol_table(str_name string, info u8, bind u8, other i8, value i64, size i64) SymbolTable { + return SymbolTable{ + str_name: str_name + info: i8(info | bind << 4) + other: other + value: value + size: size + } +} + +struct StringTable { +mut: + strings []string +} + +fn (mut g Gen) create_string_table(strings []string) StringTable { + return StringTable{strings} +} + +type SectionData = StringTable | []SymbolTable + +struct Section { + name string +mut: + header SectionHeader + data SectionData +} + +fn (mut g Gen) create_section(name string, typ int, link int, info int, addralign i64, entsize i64, data SectionData) Section { + return Section{ + name: name + header: SectionHeader{ + typ: typ + link: link + info: info + addralign: addralign + entsize: entsize + } + data: data + } +} + +fn (mut g Gen) create_shstrtab(mut sections []Section) { + mut names := []string{len: sections.len + 1} + mut offset := 1 + + for i, mut section in sections { + names[i] = section.name + section.header.name = offset + offset += section.name.len + 1 + } + + names[sections.len] = '.shstrtab' + + mut shstrtab := g.create_section(names[sections.len], native.elf_sht_strtab, 0, 0, + 1, 0, g.create_string_table(names)) + shstrtab.header.name = offset + + sections << shstrtab +} + +fn (mut g Gen) create_symtab(mut sections []Section, mut table []SymbolTable) { + mut names := []string{len: table.len} + mut offset := 1 + + for i, mut entry in table { + names[i] = entry.str_name + + entry.name = offset + entry.shndx = i16(sections.len + 1) + + offset += entry.str_name.len + 1 + } + + sections << g.create_section('.strtab', native.elf_sht_strtab, 0, 0, 1, 0, g.create_string_table(names)) + + sections << // index of .strtab + g.create_section('.symtab', native.elf_sht_symtab, sections.len - 1, native.elf_sh_symtab_info, + native.elf_sh_symtab_align, native.elf_sh_symtab_entsize, table) +} + +fn (mut g Gen) find_section_header(name string, sections []Section) int { + for i, section in sections { + if name == section.name { + return i + } + } + return 0 +} + +fn (mut g Gen) gen_section_header64(mut sh SectionHeader) { + sh_offset := g.pos() + + g.write32(sh.name) // sh_name + g.println('; sh_name') + g.write32(sh.typ) // sh_type + g.println('; sh_type') + g.write64(sh.flags) // sh_flags + g.println('; sh_addr') + g.write64(sh.addr) // sh_addr + g.println('; sh_name') + if sh.offset == 0 { + g.write64(sh_offset) + sh.offset = sh_offset + } else { + g.write64(sh.offset) + } // sh_offset + g.println('; sh_offset') + g.write64(sh.size) // sh_size + g.println('; sh_size') + g.write32(sh.link) // sh_link + g.println('; sh_link') + g.write32(sh.info) // sh_info + g.println('; sh_info') + g.write64(sh.addralign) // sh_addralign + g.println('; sh_addralign') + g.write64(sh.entsize) // sh_entsize + g.println('; sh_entsize') +} + +fn (mut g Gen) gen_sections(mut sections []Section) { + for mut section in sections { + g.gen_section_header64(mut section.header) + g.println('; ^^^ section header (64) "$section.name"') + } +} + +fn (mut g Gen) gen_section_data(sections []Section) { + for section in sections { + data := section.data + + // write the actual offset of the section data + g.write64_at(section.header.offset + 24, i64(g.pos())) + + match data { + StringTable { + start := g.pos() + + g.write8(0) // null-prefixed + for str in data.strings { + g.write(str.bytes()) + g.write8(0) // null-terminate string + g.println('; "$str"') + } + g.write8(0) // null-postfixed + + size := g.pos() - start + g.write64_at(section.header.offset + 32, i64(size)) + } + []SymbolTable { + for symbol in data { + if symbol.str_name == '_start' { + g.start_symbol_addr = g.pos() + } + + g.write32(symbol.name) + g.write8(symbol.info) + g.write8(symbol.other) + g.write16(symbol.shndx) + g.write64(symbol.value) + g.write64(symbol.size) + g.println('; $symbol') + } + + size := native.elf_symtab_size * data.len + g.write64_at(section.header.offset + 32, i64(size)) + } + } + } +} + /* -struct Header64 { - ident u8 // File identification. - @type u16 // File type. - machine u16 // Machine architecture. - version u32 // ELF format version. - entry u64 // Entry point. - phoff u64 // Program header file offset. - shoff u64 // Section header file offset. - flags u32 // Architecture-specific flags. - ehsize u16 // Size of ELF header in bytes. - phentsize u16 // Size of program header entry. - phnum u16 // Number of program header entries. - shentsize u16 // Size of section header entry. - shnum u16 // Number of section header entries. - shstrndx u16 // Section name strings section. +draft for formatting the ELF header in the future + +struct HeaderData { +mut: + ident i16 // File identification. + typ i16 // File type. + machine i16 // Machine architecture. + version int // ELF format version. + entry i64 // Entry point. + phoff i64 // Program header file offset. + shoff i64 // Section header file offset. + flags int // Architecture-specific flags. + ehsize i16 // Size of ELF header in bytes. + phentsize i16 // Size of program header entry. + phnum i16 // Number of program header entries. + shentsize i16 // Size of section header entry. + shnum i16 // Number of section header entries. + shstrndx i16 // Section name strings section. +} + +struct ElfHeader { +mut: + data: HeaderData, + shdrs: map[string]Section } */ pub fn (mut g Gen) generate_elf_header() { - elf_type := native.elf_type_dyn // PIE (use _exec for non-relocatable executables) + elf_type := native.elf_type_exec // PIE (use _exec for non-relocatable executables) + + mut sections := [ + Section{}, // null section as first section + ] + + mut symbols := [ + SymbolTable{}, // first is null + g.create_symbol_table('_start', native.elf_stt_notype, native.elf_stb_global, + native.elf_stv_default, 0, 0), + ] + + g.create_symtab(mut sections, mut symbols) + g.create_shstrtab(mut sections) // create the .shstrtab section (this must be the last section!) g.buf << '\x7fELF'.bytes() + g.println('; elf header (magic)') g.buf << native.elf_class64 g.buf << native.elf_data_le g.buf << native.elf_version @@ -70,44 +370,45 @@ pub fn (mut g Gen) generate_elf_header() { } else { g.write16(native.elf_amd64) } + g.write32(native.elf_version) - g.write64(native.segment_start + native.elf_header_size + native.elf_phentry_size) // e_entry + e_entry_addr := g.pos() + g.write64(0) // e_entry (temp value) g.write64(native.elf_header_size) // e_phoff - g.write64(0) // e_shoff + g.write64(native.elf_header_size + native.elf_phentry_size) // e_shoff g.write32(0) // e_flags g.write16(native.elf_header_size) g.write16(native.elf_phentry_size) g.write16(1) // e_phnum - g.write16(0) // e_shentsize + g.write16(native.elf_shentry_size) // e_shentsize // e_shnum := g.buf.len - g.write16(0) // e_shnum (number of sections) - g.write16(0) // e_shstrndx - // Elf64_Phdr - g.write32(1) // p_type - g.write32(5) // p_flags - g.write64(0) // p_offset - g.write64(native.segment_start) // p_vaddr addr:050 - g.write64(native.segment_start) // - g.file_size_pos = i64(g.buf.len) - g.write64(0) // p_filesz PLACEHOLDER, set to file_size later // addr: 060 - g.write64(0) // p_memsz - g.write64(0x1000) // p_align - // write sections - /* - sections := []string{} - g.write16_at(e_shnum, sections.len) // e_shnum (number of sections) + g.write16(sections.len) // e_shnum (number of sections) + g.write16(g.find_section_header('.shstrtab', sections)) // e_shstrndx - for section in sections { - // write section data - println('section $section') - } - */ - // user code starts here at - // address: 00070 and a half + // Elf64_Phdr + // Main program header + phdr := g.create_program_header(native.elf_pt_load, 5, native.elf_p_align) + g.gen_program_header64(phdr) + + // write section headers + g.gen_sections(mut sections) + + // write sections + g.gen_section_data(sections) + + // user code starts here if g.pref.is_verbose { eprintln('code_start_pos = $g.buf.len.hex()') } - g.code_start_pos = i64(g.buf.len) + + g.code_start_pos = g.pos() + g.debug_pos = int(g.pos()) + g.write64_at(e_entry_addr, g.code_start_pos + native.segment_start) + 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.debug_pos = g.buf.len g.call(native.placeholder) // call main function, it's not guaranteed to be the first, we don't know its address yet g.println('; call fn main') diff --git a/vlib/v/gen/native/elf_obj.v b/vlib/v/gen/native/elf_obj.v deleted file mode 100644 index 047bf213ad..0000000000 --- a/vlib/v/gen/native/elf_obj.v +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) 2019-2022 Alexander Medvednikov. All rights reserved. -// Use of this source code is governed by an MIT license -// that can be found in the LICENSE file. -module native - -/* -This file is unused right now, since binaries without sections -are generated. - -But it will be necessary once we have dynamic linking. -*/ -enum SectionType { - null = 0 - progbits = 1 - symtab = 2 - strtab = 3 - rela = 4 -} - -struct SectionConfig { - name string - typ SectionType - flags i64 - data voidptr - is_saa bool - datalen i64 - link int - info int - align i64 - entsize i64 -} - -fn (mut g Gen) section_header(c SectionConfig) { - g.write32(g.sect_header_name_pos) - g.sect_header_name_pos += c.name.len + 1 - g.write32(int(c.typ)) - g.write64(c.flags) - g.write64(0) // sh_addr - g.write64(g.offset) // offset - g.offset += c.datalen + 1 - g.write64(c.datalen) - g.write32(c.link) - g.write32(c.info) - g.write64(c.align) - g.write64(c.entsize) -} - -fn genobj() { - /* - // SHN_UNDEF - mut g := Gen{} - nr_sections := 7 - g.section_header(SectionConfig{ - name: '' - typ: .null - flags:0 - data: 0 - is_saa: false - link: 0 - info:0 - align:0 - entsize: 0 - }) - - /* - for sect in sections { - g.section_header(SectionConfig{ - name:0 - typ: sect.typ - flags: sect.flags - data: sect.data - is_saa: true - datalen: sect.len - link: 0 - info: 0 - align: sect.align - entsize: sect.entsize - }) - - } - */ - - g.section_header(SectionConfig{ - name: '.DATA' - typ: .progbits - flags: 0x2 - //data: sect.data - is_saa: true - datalen: 0xd - link: 0 - info: 0 - align: 1 - entsize: 0 - }) - - g.section_header(SectionConfig{ - name: '.TEXT' - typ: .progbits - flags: 0x2 - //data: sect.data - is_saa: true - datalen: 0xd - link: 0 - info: 0 - align: 1 - entsize: 0 - }) - g.section_header(SectionConfig{ - name: '.shstrtab' - typ: .strtab - flags: 0x2 - //data: sect.data - is_saa: true - datalen: 0x22 - link: 0 - info: 0 - align: 1 - entsize: 0 - }) - g.section_header(SectionConfig{ - name: '.symtab' - typ: .symtab - flags: 0x2 - //data: sect.data - is_saa: true - datalen: 0xd - link: 0 - info: 0 - align: 1 - entsize: 0 - }) - g.section_header(SectionConfig{ - name: '.strtab' - typ: .symtab - flags: 0x2 - //data: sect.data - is_saa: true - datalen: 0xd - link: 0 - info: 0 - align: 1 - entsize: 0 - }) - g.section_header(SectionConfig{ - name: '.rela.TEXT' - typ: .rela - flags: 0x0 - //data: sect.data - is_saa: true - datalen: 0x18 - link: 4 - info: 2 - align: 8 - entsize: 0x18 - }) - */ -} diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index f57097757f..e5f9ec20ef 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -32,6 +32,7 @@ mut: offset i64 file_size_pos i64 main_fn_addr i64 + start_symbol_addr i64 code_start_pos i64 // location of the start of the assembly instructions fn_addr map[string]i64 var_offset map[string]int // local var stack offset