1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

native: implement elf section types (#15316)

This commit is contained in:
Spydr 2022-08-01 22:04:59 +02:00 committed by GitHub
parent a35356758c
commit dab8159b56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -13,9 +13,12 @@ const (
elf_version = 1
elf_abiversion = 0
// elf type
elf_type_none = 0
elf_type_rel = 1
elf_type_exec = 2
elf_type_dyn = 3
elf_type_core = 4
elf_amd64 = 0x3e
elf_arm64 = 0xb7
@ -28,19 +31,46 @@ const (
elf_header_size = 0x40
elf_phentry_size = 0x38
elf_shentry_size = 0x40
elf_symtab_size = 0x18
elf_sh_symtab_entsize = 0x18
// elf program header type
elf_pt_null = 0
elf_pt_load = 1
elf_pt_dynamic = 2
elf_pt_interp = 3
elf_pt_note = 4
elf_pt_shlib = 5
elf_pt_phdr = 6
elf_pt_tls = 7
// alignment of program headers
elf_p_align = 0x1000
// elf section header size
elf_shentry_size = 0x40
// elf section type
elf_sht_null = 0x00
elf_sht_progbits = 0x01
elf_sht_symtab = 0x02
elf_sht_strtab = 0x03
elf_sht_rela = 0x04
elf_sht_hash = 0x05
elf_sht_dynamic = 0x06
elf_sht_note = 0x07
elf_sht_nobits = 0x08
elf_sht_rel = 0x09
elf_sht_shlib = 0x0a
elf_sht_dynsym = 0x0b
// elf symbol tables
elf_symtab_size = 0x18
elf_dynamic_size = 0x10
elf_rela_size = 0x18
elf_rel_size = 0x10
elf_sh_symtab_entsize = elf_symtab_size
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)
@ -53,6 +83,29 @@ const (
// elf symbol visibility
elf_stv_default = i8(0)
// elf relocation types
elf_r_amd64_none = 0
elf_r_amd64_64 = 1
elf_r_amd64_pc32 = 2
elf_r_amd64_got32 = 3
elf_r_amd64_plt32 = 4
elf_r_amd64_copy = 5
elf_r_amd64_glob_dat = 6
elf_r_amd64_jump_slot = 7
elf_r_amd64_relative = 8
elf_r_amd64_gotpcrel = 9
elf_r_amd64_32 = 10
elf_r_amd64_32s = 11
elf_r_amd64_16 = 12
elf_r_amd64_pc16 = 13
elf_r_amd64_8 = 14
elf_r_amd64_pc8 = 15
elf_r_amd64_pc64 = 24
elf_r_amd64_gotoff64 = 25
elf_r_amd64_gotpc32 = 26
elf_r_amd64_size32 = 32
elf_r_amd64_size64 = 33
)
const (
@ -85,7 +138,7 @@ fn (mut p ProgramHeader) set_addr(addr i64) {
p.paddr = addr
}
fn (mut g Gen) gen_program_header64(p ProgramHeader) {
fn (mut g Gen) gen_program_header(p ProgramHeader) {
g.write32(p.typ) // p_type
g.println('; p_type')
g.write32(p.flags) // p_flags
@ -130,19 +183,19 @@ mut:
entsize i64 // Section entry size.
}
struct SymbolTable {
struct SymbolTableSection {
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
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{
fn (mut g Gen) create_symbol_table_section(str_name string, info u8, bind u8, other i8, value i64, size i64) SymbolTableSection {
return SymbolTableSection{
str_name: str_name
info: i8(info | bind << 4)
other: other
@ -151,16 +204,127 @@ fn (mut g Gen) create_symbol_table(str_name string, info u8, bind u8, other i8,
}
}
struct StringTable {
struct StringTableSection {
mut:
strings []string
}
fn (mut g Gen) create_string_table(strings []string) StringTable {
return StringTable{strings}
fn (mut g Gen) create_string_table_section(strings []string) StringTableSection {
return StringTableSection{strings}
}
type SectionData = StringTable | []SymbolTable
struct ProgBitsSection {
mut:
bytes []u8 // Bytes of information defined by the program.
}
fn (mut g Gen) create_progbits_section(bytes []u8) ProgBitsSection {
return ProgBitsSection{bytes}
}
struct RelASection {
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 {
return RelASection{
offset: offset
info: i64((u64(sym) << 32) + typ)
addend: addend
}
}
struct HashSection {
// TODO
}
fn (mut g Gen) create_hash_section() HashSection {
return HashSection{}
}
struct DynamicSection {
mut:
tag i64 // Type of the dynamic Section.
un i64 // Consists of d_val and d_ptr, represents program virtual addresses.
}
fn (mut g Gen) create_dynamic_section(tag i64, val i64) DynamicSection {
return DynamicSection{tag, val}
}
struct NoteSection {
mut:
namesz int // Length of the name field in bytes.
descsz int // Length of the descriptor field in bytes.
typ int // Type of the node
name []u8 // Name string of the note.
desc []u8 // Descripition string of the node, must be aligned by 4 bytes
}
fn (mut g Gen) create_note_section(typ int, name string, desc string) NoteSection {
return NoteSection{
namesz: name.len
descsz: desc.len
typ: typ
name: name.bytes()
desc: desc.bytes()
}
}
struct NoBitsSection {
// The NoBits section does not occupy any bytes in the file
}
fn (mut g Gen) chreate_nobits_section() NoBitsSection {
return NoBitsSection{}
}
struct RelSection {
mut:
offset i64 // Location at which to apply the relocation action.
info i64 // Symbol table index and type of relocation to apply.
}
fn (mut g Gen) create_rel_section(offset i64, sym u32, typ u32) RelSection {
return RelSection{
offset: offset
info: i64((u64(sym) << 32) + typ)
}
}
struct ShLibSection {
mut:
data []u8 // Reserved bytes with unspecified semantics
}
fn (mut g Gen) create_shlib_section(data []u8) ShLibSection {
return ShLibSection{data}
}
struct DynSymSection {
mut:
symbols []SymbolTableSection
}
fn (mut g Gen) create_dynsym_section(symbols []SymbolTableSection) DynSymSection {
return DynSymSection{symbols}
}
type SectionData = DynSymSection
| HashSection
| NoBitsSection
| NoteSection
| ProgBitsSection
| RelASection
| RelSection
| ShLibSection
| StringTableSection
| []DynamicSection
| []SymbolTableSection
struct Section {
name string
@ -196,13 +360,13 @@ fn (mut g Gen) create_shstrtab(mut sections []Section) {
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))
1, 0, g.create_string_table_section(names))
shstrtab.header.name = offset
sections << shstrtab
}
fn (mut g Gen) create_symtab(mut sections []Section, mut table []SymbolTable) {
fn (mut g Gen) create_symtab(mut sections []Section, mut table []SymbolTableSection) {
mut names := []string{len: table.len}
mut offset := 1
@ -215,7 +379,7 @@ fn (mut g Gen) create_symtab(mut sections []Section, mut table []SymbolTable) {
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 << 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, native.elf_sh_symtab_info,
@ -231,7 +395,7 @@ fn (mut g Gen) find_section_header(name string, sections []Section) int {
return 0
}
fn (mut g Gen) gen_section_header64(mut sh SectionHeader) {
fn (mut g Gen) gen_section_header(mut sh SectionHeader) {
sh_offset := g.pos()
g.write32(sh.name) // sh_name
@ -263,11 +427,30 @@ fn (mut g Gen) gen_section_header64(mut sh SectionHeader) {
fn (mut g Gen) gen_sections(mut sections []Section) {
for mut section in sections {
g.gen_section_header64(mut section.header)
g.gen_section_header(mut section.header)
g.println('; ^^^ section header (64) "$section.name"')
}
}
fn (mut g Gen) gen_symtab_data(section Section, data []SymbolTableSection) {
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('; SHT_SYMTAB $symbol.str_name')
}
size := native.elf_symtab_size * data.len
g.write64_at(section.header.offset + 32, i64(size))
}
fn (mut g Gen) gen_section_data(sections []Section) {
for section in sections {
data := section.data
@ -276,7 +459,7 @@ fn (mut g Gen) gen_section_data(sections []Section) {
g.write64_at(section.header.offset + 24, i64(g.pos()))
match data {
StringTable {
StringTableSection {
start := g.pos()
g.write8(0) // null-prefixed
@ -290,24 +473,79 @@ fn (mut g Gen) gen_section_data(sections []Section) {
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()
[]SymbolTableSection {
g.gen_symtab_data(section, data)
}
ProgBitsSection {
start := 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')
}
g.write(data.bytes)
g.println('; SHT_PROGBITS Section')
size := native.elf_symtab_size * data.len
size := g.pos() - start
g.write64_at(section.header.offset + 32, i64(size))
}
RelASection {
g.write64(data.offset)
g.write64(data.info)
g.write64(data.addend)
g.println('; SHT_RELA ($data.offset, $data.info, $data.addend)')
size := native.elf_rela_size
g.write64_at(section.header.offset + 32, i64(size))
}
HashSection {
// TODO
g.n_error('ELF Section `SHT_HASH` not implemented yet')
}
[]DynamicSection {
for dyn in data {
g.write64(dyn.tag)
g.write64(dyn.un)
g.println('; SHT_DYNAMIC ($dyn.tag, $dyn.un)')
}
size := native.elf_dynamic_size * data.len
g.write64_at(section.header.offset + 32, i64(size))
}
NoteSection {
start := g.pos()
g.write32(data.namesz)
g.write32(data.descsz)
g.write32(data.typ)
g.write(data.name)
for _ in 0 .. ((g.pos() % 4) + 1) {
g.write8(0) // align by 4 bytes + null terminator
}
g.write(data.desc)
g.write8(0)
size := g.pos() - start
g.write64_at(section.header.offset + 32, i64(size))
}
NoBitsSection {
// Nothing to do
}
RelSection {
g.write64(data.offset)
g.write64(data.info)
g.println('; SHT_REL ($data.offset, $data.info)')
size := native.elf_rel_size
g.write64_at(section.header.offset + 32, i64(size))
}
ShLibSection {
g.write(data.data)
size := data.data.len
g.write64_at(section.header.offset + 32, i64(size))
}
DynSymSection {
g.gen_symtab_data(section, data.symbols)
}
}
}
}
@ -343,21 +581,26 @@ mut:
pub fn (mut g Gen) generate_elf_header() {
elf_type := native.elf_type_exec // PIE (use _exec for non-relocatable executables)
// generate program headers
mut program_headers := []ProgramHeader{}
program_headers << g.create_program_header(native.elf_pt_load, 5, native.elf_p_align)
// generate sections
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),
SymbolTableSection{}, // first is null
g.create_symbol_table_section('_start', native.elf_stt_notype, native.elf_stb_global,
native.elf_stv_default, 0, 0), // _start label points to entry point address
]
g.create_symtab(mut sections, mut symbols)
g.create_symtab(mut sections, mut symbols) // create the .symtab section
g.create_shstrtab(mut sections) // create the .shstrtab section (this must be the last section!)
// write elf header
g.buf << '\x7fELF'.bytes()
g.println('; elf header (magic)')
g.println('; \\x7fELF')
g.buf << native.elf_class64
g.buf << native.elf_data_le
g.buf << native.elf_version
@ -375,20 +618,20 @@ pub fn (mut g Gen) generate_elf_header() {
e_entry_addr := g.pos()
g.write64(0) // e_entry (temp value)
g.write64(native.elf_header_size) // e_phoff
g.write64(native.elf_header_size + native.elf_phentry_size) // e_shoff
g.write64(native.elf_header_size + native.elf_phentry_size * program_headers.len) // 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(program_headers.len) // e_phnum
g.write16(native.elf_shentry_size) // e_shentsize
// e_shnum := g.buf.len
g.write16(sections.len) // e_shnum (number of sections)
g.write16(g.find_section_header('.shstrtab', sections)) // e_shstrndx
// 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 program headers
for header in program_headers {
g.gen_program_header(header)
}
// write section headers
g.gen_sections(mut sections)
@ -403,7 +646,9 @@ pub fn (mut g Gen) generate_elf_header() {
g.code_start_pos = g.pos()
g.debug_pos = int(g.pos())
if elf_type == native.elf_type_exec {
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)