mirror of
https://github.com/Noratrieb/elven-forest.git
synced 2026-01-14 10:45:03 +01:00
sefault!!!
This commit is contained in:
parent
d6daaea999
commit
e2ca10426e
7 changed files with 192 additions and 60 deletions
|
|
@ -6,7 +6,9 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.3.2"
|
||||
bstr = "1.2.0"
|
||||
bytemuck = { version = "1.13.0", features = ["derive", "min_const_generics"] }
|
||||
memmap2 = "0.5.8"
|
||||
memoffset = "0.8.0"
|
||||
thiserror = "1.0.38"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
#![allow(non_upper_case_globals)]
|
||||
#![allow(clippy::unreadable_literal)]
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
use bitflags::bitflags;
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
|
||||
macro_rules! const_group_with_fmt {
|
||||
(
|
||||
pub struct $struct_name:ident($ty:ty): $group_name:literal
|
||||
|
|
@ -63,6 +68,19 @@ macro_rules! const_group_with_fmt {
|
|||
self.partial_cmp(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$ty> for $struct_name {
|
||||
fn from(ty: $ty) -> $struct_name {
|
||||
$struct_name(ty)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl From<$struct_name> for $ty {
|
||||
fn from(wrap: $struct_name) -> $ty {
|
||||
wrap.0
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -238,6 +256,22 @@ pub const PT_HIOS: u32 = 0x6fffffff; /* End of OS-specific */
|
|||
pub const PT_LOPROC: u32 = 0x70000000; /* Start of processor-specific */
|
||||
pub const PT_HIPROC: u32 = 0x7fffffff; /* End of processor-specific */
|
||||
|
||||
bitflags! {
|
||||
#[derive(Zeroable, Pod)]
|
||||
#[repr(transparent)]
|
||||
pub struct PhFlags: u32 {
|
||||
const PF_X = (1 << 0); /* Segment is executable */
|
||||
const PF_W = (1 << 1); /* Segment is writable */
|
||||
const PF_R = (1 << 2); /* Segment is readable */
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for PhFlags {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------
|
||||
// Symbols
|
||||
// ------------------
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ pub struct ElfHeader {
|
|||
pub shstrndex: c::SectionIdx,
|
||||
}
|
||||
|
||||
pub(crate) const HEADER_ENTRY_OFFSET: usize = 24;
|
||||
pub const HEADER_ENTRY_OFFSET: usize = 24;
|
||||
|
||||
#[test]
|
||||
fn elf_header_entry_offset() {
|
||||
|
|
@ -135,7 +135,7 @@ const _: [u8; c::EI_NIDENT] = [0; mem::size_of::<ElfIdent>()];
|
|||
#[repr(C)]
|
||||
pub struct Phdr {
|
||||
pub r#type: c::PhType,
|
||||
pub flags: u32,
|
||||
pub flags: c::PhFlags,
|
||||
pub offset: Offset,
|
||||
pub vaddr: Addr,
|
||||
pub paddr: Addr,
|
||||
|
|
@ -489,7 +489,7 @@ fn load_ref<'a, T: Pod>(data: &'a [u8], kind: impl Into<String>) -> Result<&'a T
|
|||
load_slice(data, 1, kind).map(|slice| &slice[0])
|
||||
}
|
||||
|
||||
fn load_slice<'a, T: Pod>(
|
||||
pub(crate) fn load_slice<'a, T: Pod>(
|
||||
data: &'a [u8],
|
||||
amount_of_elems: usize,
|
||||
kind: impl Into<String>,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::consts::{Machine, SectionIdx, ShType, Type, SHT_NULL, SHT_STRTAB};
|
||||
use crate::consts::{Machine, PhFlags, PhType, SectionIdx, ShType, Type, SHT_NULL, SHT_STRTAB};
|
||||
use crate::read::{self, Addr, ElfIdent, Offset, ShStringIdx};
|
||||
use std::io;
|
||||
use std::mem::size_of;
|
||||
|
|
@ -17,8 +17,7 @@ pub type Result<T> = std::result::Result<T, WriteElfError>;
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct ElfWriter {
|
||||
header: read::ElfHeader,
|
||||
entry: SectionRelativeAbsoluteAddr,
|
||||
sections_headers: Vec<Section>,
|
||||
sections: Vec<Section>,
|
||||
programs_headers: Vec<ProgramHeader>,
|
||||
}
|
||||
|
||||
|
|
@ -29,7 +28,7 @@ pub struct Header {
|
|||
pub machine: Machine,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct SectionRelativeAbsoluteAddr {
|
||||
pub section: SectionIdx,
|
||||
pub rel_offset: Offset,
|
||||
|
|
@ -45,7 +44,16 @@ pub struct Section {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ProgramHeader {}
|
||||
pub struct ProgramHeader {
|
||||
pub r#type: PhType,
|
||||
pub flags: PhFlags,
|
||||
pub offset: SectionRelativeAbsoluteAddr,
|
||||
pub vaddr: Addr,
|
||||
pub paddr: Addr,
|
||||
pub filesz: u64,
|
||||
pub memsz: u64,
|
||||
pub align: u64,
|
||||
}
|
||||
|
||||
const SH_STRTAB: usize = 1;
|
||||
|
||||
|
|
@ -90,39 +98,45 @@ impl ElfWriter {
|
|||
|
||||
Self {
|
||||
header,
|
||||
entry: SectionRelativeAbsoluteAddr {
|
||||
section: SectionIdx(0),
|
||||
rel_offset: Offset(0),
|
||||
},
|
||||
sections_headers: vec![null_section, shstrtab],
|
||||
sections: vec![null_section, shstrtab],
|
||||
programs_headers: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_entry(&mut self, entry: SectionRelativeAbsoluteAddr) {
|
||||
self.entry = entry;
|
||||
pub fn set_entry(&mut self, entry: Addr) {
|
||||
self.header.entry = entry;
|
||||
}
|
||||
|
||||
pub fn add_sh_string(&mut self, content: &[u8]) -> ShStringIdx {
|
||||
let shstrtab = &mut self.sections_headers[SH_STRTAB];
|
||||
let shstrtab = &mut self.sections[SH_STRTAB];
|
||||
let idx = shstrtab.content.len();
|
||||
shstrtab.content.extend(content);
|
||||
shstrtab.content.push(0);
|
||||
ShStringIdx(idx as u32)
|
||||
}
|
||||
|
||||
pub fn add_section(&mut self, section: Section) {
|
||||
self.sections_headers.push(section);
|
||||
pub fn add_section(&mut self, section: Section) -> Result<SectionIdx> {
|
||||
let len = self.sections.len();
|
||||
self.sections.push(section);
|
||||
Ok(SectionIdx(
|
||||
len.try_into()
|
||||
.map_err(|_| WriteElfError::TooMany("sections"))?,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn add_program_header(&mut self, ph: ProgramHeader) {
|
||||
self.programs_headers.push(ph);
|
||||
}
|
||||
}
|
||||
|
||||
mod writing {
|
||||
use bytemuck::Pod;
|
||||
|
||||
use crate::read::{Addr, ElfHeader, Offset, Shdr, HEADER_ENTRY_OFFSET};
|
||||
use super::{ElfWriter, Result, WriteElfError};
|
||||
use crate::read::{Addr, ElfHeader, Offset, Phdr, Shdr};
|
||||
use std::{io::Write, mem::size_of, num::NonZeroU64};
|
||||
|
||||
use super::{ElfWriter, Result, WriteElfError};
|
||||
const SH_OFFSET_OFFSET: usize = memoffset::offset_of!(Shdr, offset);
|
||||
|
||||
impl ElfWriter {
|
||||
pub fn write(&self) -> Result<Vec<u8>> {
|
||||
|
|
@ -133,7 +147,7 @@ mod writing {
|
|||
let mut header = self.header;
|
||||
|
||||
header.shnum = self
|
||||
.sections_headers
|
||||
.sections
|
||||
.len()
|
||||
.try_into()
|
||||
.map_err(|_| WriteElfError::TooMany("sections"))?;
|
||||
|
|
@ -147,25 +161,32 @@ mod writing {
|
|||
// We know the size of the header.
|
||||
current_known_position += size_of::<ElfHeader>() as u64;
|
||||
|
||||
// We put the section headers directly after the header.
|
||||
if !self.sections_headers.is_empty() {
|
||||
header.shoff = Offset(current_known_position);
|
||||
}
|
||||
// ld orderes it ph/sh apparently so we will do the same
|
||||
|
||||
// There will be all the section headers right after the header.
|
||||
current_known_position += (header.shentsize * header.shnum) as u64;
|
||||
|
||||
// We put the program headers directly after the section headers.
|
||||
if !self.programs_headers.is_empty() {
|
||||
header.phoff = Offset(current_known_position);
|
||||
}
|
||||
|
||||
// There will be all the program headers right after the section headers.
|
||||
current_known_position += (header.phentsize * header.phnum) as u64;
|
||||
// There will be all the program headers right after the header.
|
||||
let program_headers_start = current_known_position;
|
||||
let all_ph_size = (header.phentsize as u64) * (header.phnum as u64);
|
||||
current_known_position += all_ph_size;
|
||||
|
||||
if !self.sections.is_empty() {
|
||||
header.shoff = Offset(current_known_position);
|
||||
}
|
||||
|
||||
// There will be all the section headers right after the program headers.
|
||||
let section_headers_start = current_known_position;
|
||||
let section_headers_size = header.shentsize as u64 * header.shnum as u64;
|
||||
current_known_position += section_headers_size;
|
||||
|
||||
write_pod(&header, &mut output);
|
||||
|
||||
for (sh_idx, section) in self.sections_headers.iter().enumerate() {
|
||||
// Reserve some space for the program headers
|
||||
output.extend(std::iter::repeat(0).take(all_ph_size as usize));
|
||||
|
||||
for section in &self.sections {
|
||||
let header = Shdr {
|
||||
name: section.name,
|
||||
r#type: section.r#type,
|
||||
|
|
@ -179,14 +200,6 @@ mod writing {
|
|||
entsize: section.fixed_entsize.map(NonZeroU64::get).unwrap_or(0),
|
||||
};
|
||||
|
||||
if sh_idx == self.entry.section.0 as usize {
|
||||
let base = current_known_position;
|
||||
let entry = base + self.entry.rel_offset.0;
|
||||
let entry_pos = &mut output[HEADER_ENTRY_OFFSET..][..size_of::<u64>()];
|
||||
let entry_ref = bytemuck::cast_slice_mut::<u8, u64>(entry_pos);
|
||||
entry_ref[0] = entry;
|
||||
}
|
||||
|
||||
// We will write the content for this section at that offset and also make sure to align the next one.
|
||||
// FIXME: Align to the alignment of the next section.
|
||||
current_known_position += align_up(section.content.len() as u64, 8);
|
||||
|
|
@ -194,9 +207,7 @@ mod writing {
|
|||
write_pod(&header, &mut output);
|
||||
}
|
||||
|
||||
assert_eq!(self.programs_headers.len(), 0); // FIXME: yeah
|
||||
|
||||
for section in &self.sections_headers {
|
||||
for section in &self.sections {
|
||||
let section_size = section.content.len() as u64;
|
||||
let aligned_size = align_up(section_size, 8);
|
||||
let padding = aligned_size - section_size;
|
||||
|
|
@ -207,6 +218,42 @@ mod writing {
|
|||
}
|
||||
}
|
||||
|
||||
// We know have a few clues about section offsets, so write the program headers.
|
||||
for (i, program_header) in self.programs_headers.iter().enumerate() {
|
||||
let rel_offset = program_header.offset;
|
||||
let section_base_offset = section_headers_start as usize
|
||||
+ header.shentsize as usize * rel_offset.section.0 as usize;
|
||||
|
||||
let section_offset_offset = section_base_offset + SH_OFFSET_OFFSET;
|
||||
let section_content_offset_bytes = output[section_offset_offset..]
|
||||
[..size_of::<u64>()]
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let section_content_offset = u64::from_ne_bytes(section_content_offset_bytes);
|
||||
|
||||
let offset = Offset(section_content_offset + rel_offset.rel_offset.0);
|
||||
|
||||
let ph = Phdr {
|
||||
r#type: program_header.r#type,
|
||||
flags: program_header.flags,
|
||||
offset,
|
||||
vaddr: program_header.vaddr,
|
||||
paddr: program_header.paddr,
|
||||
filesz: program_header.filesz,
|
||||
memsz: program_header.memsz,
|
||||
align: program_header.align,
|
||||
};
|
||||
|
||||
let program_header_start =
|
||||
program_headers_start as usize + header.phentsize as usize * i as usize;
|
||||
let space = &mut output[program_header_start..][..header.phentsize as usize];
|
||||
let ph_bytes = bytemuck::cast_slice::<Phdr, u8>(std::slice::from_ref(&ph));
|
||||
|
||||
space.copy_from_slice(ph_bytes);
|
||||
|
||||
write_pod(&ph, &mut output);
|
||||
}
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue