mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
native: add sections for string- and symbol-tables, reimplement elf program headers (#15305)
This commit is contained in:
parent
9561fb406e
commit
b4fd9b5f92
@ -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')
|
||||
|
@ -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
|
||||
})
|
||||
*/
|
||||
}
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user