sefault!!!

This commit is contained in:
nora 2023-02-13 21:59:19 +01:00
parent d6daaea999
commit e2ca10426e
7 changed files with 192 additions and 60 deletions

View file

@ -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"

View file

@ -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
// ------------------

View file

@ -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>,

View file

@ -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)
}
}