use std::borrow::Cow;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::fmt::Display;
use std::io::ErrorKind;
use std::marker::PhantomData;
use std::mem::size_of;
use bytemuck::{Pod, Zeroable};
use crate::fmt::{BinaryFile, Binfmt, FileType, SectionType};
use crate::howto::HowTo;
use crate::sym::{SymbolKind, SymbolType};
use crate::traits::private::Sealed;
use crate::traits::Numeric;
pub type ElfByte<E> = <E as ElfClass>::Byte;
pub type ElfHalf<E> = <E as ElfClass>::Half;
pub type ElfWord<E> = <E as ElfClass>::Word;
pub type ElfSword<E> = <E as ElfClass>::Sword;
pub type ElfXword<E> = <E as ElfClass>::Xword;
pub type ElfSxword<E> = <E as ElfClass>::Sxword;
pub type ElfAddr<E> = <E as ElfClass>::Addr;
pub type ElfOffset<E> = <E as ElfClass>::Offset;
pub type ElfSection<E> = <E as ElfClass>::Section;
pub type ElfVersym<E> = <E as ElfClass>::Versym;
pub type Symbol<E> = <E as ElfClass>::Symbol;
pub type ElfSize<E> = <E as ElfClass>::Size;
pub trait ElfSymbol: Sealed {
type Class: ElfClass;
fn name_idx(&self) -> ElfWord<Self::Class>;
fn value(&self) -> ElfAddr<Self::Class>;
fn size(&self) -> ElfSize<Self::Class>;
fn info(&self) -> ElfByte<Self::Class>;
fn other(&self) -> ElfByte<Self::Class>;
fn section(&self) -> ElfSection<Self::Class>;
}
pub trait ElfRelocation: Sealed {
type Class: ElfClass;
fn at_offset(&self) -> ElfAddr<Self::Class>;
fn rel_type(&self) -> ElfSize<Self::Class>;
fn symbol(&self) -> ElfSize<Self::Class>;
fn addend(&self) -> ElfOffset<Self::Class> {
Numeric::zero()
}
}
pub trait ElfProgramHeader: Sealed {
type Class: ElfClass;
fn pt_type(&self) -> consts::ProgramType;
fn offset(&self) -> ElfOffset<Self::Class>;
fn vaddr(&self) -> ElfAddr<Self::Class>;
fn paddr(&self) -> ElfAddr<Self::Class>;
fn memsize(&self) -> ElfSize<Self::Class>;
fn filesize(&self) -> ElfSize<Self::Class>;
fn align(&self) -> ElfSize<Self::Class>;
fn flags(&self) -> ElfWord<Self::Class>;
}
pub trait ElfClass: Sealed + Sized + Copy + 'static {
type Byte: Numeric;
const EI_CLASS: consts::EiClass;
type Half: Numeric;
type Word: Numeric;
type Sword: Numeric;
type Xword: Numeric;
type Sxword: Numeric;
type Addr: Numeric;
type Offset: Numeric;
type Section: Numeric;
type Versym: Numeric;
type Size: Numeric;
type Symbol: ElfSymbol<Class = Self> + Pod;
type Rel: ElfRelocation<Class = Self> + Pod;
type Rela: ElfRelocation<Class = Self> + Pod;
type ProgramHeader: ElfProgramHeader<Class = Self> + Pod;
fn new_sym(
st_name: Self::Word,
st_value: Self::Addr,
st_size: Self::Size,
st_info: u8,
st_other: u8,
st_shndx: Self::Half,
) -> Self::Symbol;
}
#[derive(Copy, Clone, Debug)]
pub enum Elf64 {}
#[derive(Copy, Clone, Debug)]
pub enum Elf32 {}
#[repr(C)]
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
pub struct Elf32Sym {
st_name: ElfWord<Elf32>,
st_value: ElfAddr<Elf32>,
st_size: ElfSize<Elf32>,
st_info: ElfByte<Elf32>,
st_other: ElfByte<Elf32>,
st_shndx: ElfSection<Elf32>,
}
impl Sealed for Elf32Sym {}
impl ElfSymbol for Elf32Sym {
type Class = Elf32;
fn name_idx(&self) -> u32 {
self.st_name
}
fn value(&self) -> <Self::Class as ElfClass>::Addr {
self.st_value
}
fn size(&self) -> ElfSize<Self::Class> {
self.st_size
}
fn info(&self) -> u8 {
self.st_info
}
fn other(&self) -> u8 {
self.st_other
}
fn section(&self) -> u16 {
self.st_shndx
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
pub struct Elf64Sym {
st_name: ElfWord<Elf64>,
st_info: ElfByte<Elf64>,
st_other: ElfByte<Elf64>,
st_shndx: ElfSection<Elf64>,
st_value: ElfAddr<Elf64>,
st_size: ElfSize<Elf64>,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct ElfRel<Class: ElfClass> {
r_offset: ElfAddr<Class>,
r_info: ElfSize<Class>,
}
unsafe impl<Class: ElfClass> Zeroable for ElfRel<Class> {}
unsafe impl<Class: ElfClass> Pod for ElfRel<Class> {}
mod private {
use super::*;
pub trait ElfRelocationExtractHelpers: ElfClass {
fn symbol(info: ElfSize<Self>) -> ElfSize<Self>;
fn rel_type(info: ElfSize<Self>) -> ElfSize<Self>;
}
}
use private::*;
use self::consts::ElfIdent;
impl<Class: ElfClass + ElfRelocationExtractHelpers> Sealed for ElfRel<Class> {}
impl<Class: ElfClass + ElfRelocationExtractHelpers> ElfRelocation for ElfRel<Class> {
type Class = Class;
fn at_offset(&self) -> <Self::Class as ElfClass>::Addr {
self.r_offset
}
fn rel_type(&self) -> <Self::Class as ElfClass>::Size {
Class::symbol(self.r_info)
}
fn symbol(&self) -> <Self::Class as ElfClass>::Size {
Class::rel_type(self.r_info)
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct ElfRela<Class: ElfClass> {
r_offset: ElfAddr<Class>,
r_info: ElfSize<Class>,
r_addend: ElfOffset<Class>,
}
unsafe impl<Class: ElfClass> Zeroable for ElfRela<Class> {}
unsafe impl<Class: ElfClass> Pod for ElfRela<Class> {}
impl<Class: ElfClass + ElfRelocationExtractHelpers> Sealed for ElfRela<Class> {}
impl<Class: ElfClass + ElfRelocationExtractHelpers> ElfRelocation for ElfRela<Class> {
type Class = Class;
fn at_offset(&self) -> <Self::Class as ElfClass>::Addr {
self.r_offset
}
fn rel_type(&self) -> <Self::Class as ElfClass>::Size {
Class::symbol(self.r_info)
}
fn symbol(&self) -> <Self::Class as ElfClass>::Size {
Class::rel_type(self.r_info)
}
fn addend(&self) -> <Self::Class as ElfClass>::Offset {
self.r_addend
}
}
impl Sealed for Elf64Sym {}
impl ElfSymbol for Elf64Sym {
type Class = Elf64;
fn name_idx(&self) -> u32 {
self.st_name
}
fn value(&self) -> <Self::Class as ElfClass>::Addr {
self.st_value
}
fn size(&self) -> ElfSize<Self::Class> {
self.st_size
}
fn info(&self) -> u8 {
self.st_info
}
fn other(&self) -> u8 {
self.st_other
}
fn section(&self) -> u16 {
self.st_shndx
}
}
impl Sealed for Elf64 {}
impl ElfClass for Elf64 {
const EI_CLASS: consts::EiClass = consts::ELFCLASS64;
type Addr = u64;
type Offset = i64;
type Size = u64;
type Symbol = Elf64Sym;
type Rel = ElfRel<Self>;
type Rela = ElfRela<Self>;
type Byte = u8;
type Half = u16;
type Word = u32;
type Sword = i32;
type Xword = u64;
type Sxword = u64;
type Section = u16;
type Versym = u16;
type ProgramHeader = Elf64Phdr;
fn new_sym(
st_name: Self::Word,
st_value: Self::Addr,
st_size: Self::Size,
st_info: u8,
st_other: u8,
st_shndx: Self::Half,
) -> Self::Symbol {
Elf64Sym {
st_name,
st_info,
st_other,
st_shndx,
st_value,
st_size,
}
}
}
impl ElfRelocationExtractHelpers for Elf64 {
fn symbol(info: Self::Size) -> Self::Size {
info >> 32
}
fn rel_type(info: Self::Size) -> Self::Size {
info & 0xffffffff
}
}
impl Sealed for Elf32 {}
impl ElfClass for Elf32 {
const EI_CLASS: consts::EiClass = consts::ELFCLASS32;
type Addr = u32;
type Offset = i32;
type Size = u32;
type Symbol = Elf32Sym;
type Rel = ElfRel<Self>;
type Rela = ElfRela<Self>;
type Byte = u8;
type Half = u16;
type Word = u32;
type Sword = i32;
type Xword = u64;
type Sxword = u64;
type Section = u16;
type Versym = u16;
type ProgramHeader = Elf32Phdr;
fn new_sym(
st_name: Self::Word,
st_value: Self::Addr,
st_size: Self::Size,
st_info: u8,
st_other: u8,
st_shndx: Self::Half,
) -> Self::Symbol {
Elf32Sym {
st_name,
st_value,
st_size,
st_info,
st_other,
st_shndx,
}
}
}
impl ElfRelocationExtractHelpers for Elf32 {
fn symbol(info: Self::Size) -> Self::Size {
info >> 8
}
fn rel_type(info: Self::Size) -> Self::Size {
info & 0xff
}
}
pub mod consts {
use bytemuck::{Pod, Zeroable};
pub const ELFMAG: [u8; 4] = *b"\x7fELF";
fake_enum::fake_enum! {
#[repr(pub u16)]
#[derive(Zeroable,Pod)]
pub enum ElfType{
ET_NONE = 0,
ET_REL = 1,
ET_EXEC = 2,
ET_DYN = 3,
ET_CORE = 4
}
}
fake_enum::fake_enum! {
#[repr(u16)]
#[derive(Zeroable,Pod)]
pub enum ElfMachine{
EM_NONE = 0, EM_M32 = 1, EM_SPARC = 2, EM_386 = 3, EM_68K = 4, EM_88K = 5, EM_IAMCU = 6, EM_860 = 7, EM_MIPS = 8, EM_S370 = 9, EM_MIPS_RS3_LE = 10, EM_PARISC = 15, EM_VPP500 = 17, EM_SPARC32PLUS = 18, EM_960 = 19, EM_PPC = 20, EM_PPC64 = 21, EM_S390 = 22, EM_SPU = 23, EM_V800 = 36, EM_FR20 = 37, EM_RH32 = 38, EM_RCE = 39, EM_ARM = 40, EM_ALPHA = 41, EM_SH = 42, EM_SPARCV9 = 43, EM_TRICORE = 44, EM_ARC = 45, EM_H8_300 = 46, EM_H8_300H = 47, EM_H8S = 48, EM_H8_500 = 49, EM_IA_64 = 50, EM_MIPS_X = 51, EM_COLDFIRE = 52, EM_68HC12 = 53, EM_MMA = 54, EM_PCP = 55, EM_NCPU = 56, EM_NDR1 = 57, EM_STARCORE = 58, EM_ME16 = 59, EM_ST100 = 60, EM_TINYJ = 61, EM_X86_64 = 62, EM_PDSP = 63, EM_PDP10 = 64, EM_PDP11 = 65, EM_FX66 = 66, EM_ST9PLUS = 67, EM_ST7 = 68, EM_68HC16 = 69, EM_68HC11 = 70, EM_68HC08 = 71, EM_68HC05 = 72, EM_SVX = 73, EM_ST19 = 74, EM_VAX = 75, EM_CRIS = 76, EM_JAVELIN = 77, EM_FIREPATH = 78, EM_ZSP = 79, EM_MMIX = 80, EM_HUANY = 81, EM_PRISM = 82, EM_AVR = 83, EM_FR30 = 84, EM_D10V = 85, EM_D30V = 86, EM_V850 = 87, EM_M32R = 88, EM_MN10300 = 89, EM_MN10200 = 90, EM_PJ = 91, EM_OPENRISC = 92, EM_ARC_COMPACT = 93, EM_XTENSA = 94, EM_VIDEOCORE = 95, EM_TMM_GPP = 96, EM_NS32K = 97, EM_TPC = 98, EM_SNP1K = 99, EM_ST200 = 100, EM_IP2K = 101, EM_MAX = 102, EM_CR = 103, EM_F2MC16 = 104, EM_MSP430 = 105, EM_BLACKFIN = 106, EM_SE_C33 = 107, EM_SEP = 108, EM_ARCA = 109, EM_UNICORE = 110, EM_EXCESS = 111, EM_DXP = 112, EM_ALTERA_NIOS2 = 113, EM_CRX = 114, EM_XGATE = 115, EM_C166 = 116, EM_M16C = 117, EM_DSPIC30F = 118, EM_CE = 119, EM_M32C = 120, EM_TSK3000 = 131, EM_RS08 = 132, EM_SHARC = 133, EM_ECOG2 = 134, EM_SCORE7 = 135, EM_DSP24 = 136, EM_VIDEOCORE3 = 137, EM_LATTICEMICO32 = 138, EM_SE_C17 = 139, EM_TI_C6000 = 140, EM_TI_C2000 = 141, EM_TI_C5500 = 142, EM_MMDSP_PLUS = 160, EM_CYPRESS_M8C = 161, EM_R32C = 162, EM_TRIMEDIA = 163, EM_HEXAGON = 164, EM_8051 = 165, EM_STXP7X = 166, EM_NDS32 = 167, EM_ECOG1 = 168, EM_ECOG1X = 168, EM_MAXQ30 = 169, EM_XIMO16 = 170, EM_MANIK = 171, EM_CRAYNV2 = 172, EM_RX = 173, EM_METAG = 174, EM_MCST_ELBRUS = 175, EM_ECOG16 = 176, EM_CR16 = 177, EM_ETPU = 178, EM_SLE9X = 179, EM_L10M = 180, EM_K10M = 181, EM_AARCH64 = 183, EM_AVR32 = 185, EM_STM8 = 186, EM_TILE64 = 187, EM_TILEPRO = 188, EM_CUDA = 190, EM_TILEGX = 191, EM_CLOUDSHIELD = 192, EM_COREA_1ST = 193, EM_COREA_2ND = 194, EM_ARC_COMPACT2 = 195, EM_OPEN8 = 196, EM_RL78 = 197, EM_VIDEOCORE5 = 198, EM_78KOR = 199, EM_56800EX = 200, EM_BA1 = 201, EM_BA2 = 202, EM_XCORE = 203, EM_MCHP_PIC = 204, EM_INTEL205 = 205, EM_INTEL206 = 206, EM_INTEL207 = 207, EM_INTEL208 = 208, EM_INTEL209 = 209, EM_KM32 = 210, EM_KMX32 = 211, EM_KMX16 = 212, EM_KMX8 = 213, EM_KVARC = 214, EM_CDP = 215, EM_COGE = 216, EM_COOL = 217, EM_NORC = 218, EM_CSR_KALIMBA = 219, EM_AMDGPU = 224, EM_RISCV = 243, EM_LANAI = 244, EM_BPF = 247, EM_VE = 251, EM_CSKY = 252, EM_WC65C816 = 257,
EM_CLEVER = 0x434C, }
}
fake_enum::fake_enum! {
#[repr(u8)]
#[derive(Zeroable,Pod)]
pub enum EiClass{
ELFCLASSNONE = 0,
ELFCLASS32 = 1,
ELFCLASS64 = 2
}
}
fake_enum::fake_enum! {
#[repr(u8)]
#[derive(Zeroable,Pod)]
pub enum EiData{
ELFDATANONE = 0,
ELFDATA2LSB = 1,
ELFDATA2MSB = 2
}
}
fake_enum::fake_enum! {
#[repr(u8)]
#[derive(Zeroable,Pod)]
pub enum EiVersion{
EV_NONE = 0,
EV_CURRENT = 1
}
}
fake_enum::fake_enum! {
#[repr(u8)]
#[derive(Zeroable,Pod)]
pub enum EiOsAbi{
ELFOSABI_NONE = 0, ELFOSABI_HPUX = 1, ELFOSABI_NETBSD = 2, ELFOSABI_GNU = 3, ELFOSABI_LINUX = 3, ELFOSABI_HURD = 4, ELFOSABI_SOLARIS = 6, ELFOSABI_AIX = 7, ELFOSABI_IRIX = 8, ELFOSABI_FREEBSD = 9, ELFOSABI_TRU64 = 10, ELFOSABI_MODESTO = 11, ELFOSABI_OPENBSD = 12, ELFOSABI_OPENVMS = 13, ELFOSABI_NSK = 14, ELFOSABI_AROS = 15, ELFOSABI_FENIXOS = 16, ELFOSABI_CLOUDABI = 17, ELFOSABI_FIRST_ARCH = 64, ELFOSABI_AMDGPU_HSA = 64, ELFOSABI_AMDGPU_PAL = 65, ELFOSABI_AMDGPU_MESA3D = 66, ELFOSABI_ARM = 97, ELFOSABI_C6000_ELFABI = 64, ELFOSABI_C6000_LINUX = 65, ELFOSABI_STANDALONE = 255, }
}
#[repr(C, packed)]
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
pub struct ElfIdent {
pub ei_mag: [u8; 4],
pub ei_class: EiClass,
pub ei_data: EiData,
pub ei_version: EiVersion,
pub ei_osabi: EiOsAbi,
pub ei_abiversion: u8,
pub ei_pad: [u8; 7],
}
static_assertions::const_assert_eq!(core::mem::size_of::<ElfIdent>(), 16);
static_assertions::const_assert_eq!(core::mem::align_of::<ElfIdent>(), 1);
fake_enum::fake_enum! {
#[repr(pub u32)]
#[derive(Zeroable,Pod)]
pub enum ProgramType{
PT_NULL = 0,
PT_LOAD = 1,
PT_DYNAMIC = 2,
PT_INTERP = 3,
PT_NOTE = 4,
PT_SHLIB = 5,
PT_PHDR = 6,
}
}
fake_enum::fake_enum! {
#[repr(pub u32)]
#[derive(Zeroable,Pod)]
pub enum SectionType{
SHT_NULL = 0,
SHT_PROGBITS = 1,
SHT_SYMTAB = 2,
SHT_STRTAB = 3,
SHT_RELA = 4,
SHT_HASH = 5,
SHT_DYNAMIC = 6,
SHT_NOTE = 7,
SHT_NOBITS = 8,
SHT_REL = 9,
SHT_SHLIB = 10,
SHT_DYNSYM = 11,
}
}
}
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct ElfHeader<E: ElfClass> {
pub e_ident: consts::ElfIdent,
pub e_type: consts::ElfType,
pub e_machine: consts::ElfMachine,
pub e_version: ElfWord<E>,
pub e_entry: ElfAddr<E>,
pub e_phoff: ElfOffset<E>,
pub e_shoff: ElfOffset<E>,
pub e_flags: ElfWord<E>,
pub e_ehsize: ElfHalf<E>,
pub e_phentsize: ElfHalf<E>,
pub e_phnum: ElfHalf<E>,
pub e_shentsize: ElfHalf<E>,
pub e_shnum: ElfHalf<E>,
pub e_shstrndx: ElfHalf<E>,
}
unsafe impl<E: ElfClass> Zeroable for ElfHeader<E> {}
unsafe impl<E: ElfClass + 'static> Pod for ElfHeader<E> {}
pub trait SectionHeader {}
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
#[repr(C)]
pub struct Elf32Phdr {
pub p_type: consts::ProgramType,
pub p_offset: ElfOffset<Elf32>,
pub p_vaddr: ElfAddr<Elf32>,
pub p_paddr: ElfAddr<Elf32>,
pub p_filesz: ElfSize<Elf32>,
pub p_memsz: ElfSize<Elf32>,
pub p_flags: ElfWord<Elf32>,
pub p_align: ElfSize<Elf32>,
}
impl Sealed for Elf32Phdr {}
impl ElfProgramHeader for Elf32Phdr {
type Class = Elf32;
fn pt_type(&self) -> consts::ProgramType {
self.p_type
}
fn offset(&self) -> ElfOffset<Self::Class> {
self.p_offset
}
fn vaddr(&self) -> ElfAddr<Self::Class> {
self.p_vaddr
}
fn paddr(&self) -> ElfAddr<Self::Class> {
self.p_paddr
}
fn memsize(&self) -> ElfSize<Self::Class> {
self.p_memsz
}
fn filesize(&self) -> ElfSize<Self::Class> {
self.p_filesz
}
fn align(&self) -> ElfSize<Self::Class> {
self.p_align
}
fn flags(&self) -> ElfWord<Self::Class> {
self.p_flags
}
}
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
#[repr(C)]
pub struct Elf64Phdr {
pub p_type: consts::ProgramType,
pub p_flags: ElfWord<Elf64>,
pub p_offset: ElfOffset<Elf64>,
pub p_vaddr: ElfAddr<Elf64>,
pub p_paddr: ElfAddr<Elf64>,
pub p_filesz: ElfSize<Elf64>,
pub p_memsz: ElfSize<Elf64>,
pub p_align: ElfSize<Elf64>,
}
impl Sealed for Elf64Phdr {}
impl ElfProgramHeader for Elf64Phdr {
type Class = Elf64;
fn pt_type(&self) -> consts::ProgramType {
self.p_type
}
fn offset(&self) -> ElfOffset<Self::Class> {
self.p_offset
}
fn vaddr(&self) -> ElfAddr<Self::Class> {
self.p_vaddr
}
fn paddr(&self) -> ElfAddr<Self::Class> {
self.p_paddr
}
fn memsize(&self) -> ElfSize<Self::Class> {
self.p_memsz
}
fn filesize(&self) -> ElfSize<Self::Class> {
self.p_filesz
}
fn align(&self) -> ElfSize<Self::Class> {
self.p_align
}
fn flags(&self) -> ElfWord<Self::Class> {
self.p_flags
}
}
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct ElfSectionHeader<Class: ElfClass> {
pub sh_name: ElfWord<Class>,
pub sh_type: consts::SectionType,
pub sh_flags: ElfOffset<Class>,
pub sh_addr: ElfAddr<Class>,
pub sh_offset: ElfOffset<Class>,
pub sh_size: ElfSize<Class>,
pub sh_link: ElfWord<Class>,
pub sh_info: ElfWord<Class>,
pub sh_addralign: ElfAddr<Class>,
pub sh_entsize: ElfSize<Class>,
}
unsafe impl<Class: ElfClass> Zeroable for ElfSectionHeader<Class> {}
unsafe impl<Class: ElfClass + 'static> Pod for ElfSectionHeader<Class> {}
#[derive(Copy, Clone, Debug)]
pub struct BadElfHeader;
impl Display for BadElfHeader {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
fmt.write_str("Invalid Elf Header")
}
}
impl std::error::Error for BadElfHeader {}
pub struct ElfFileData<Class: ElfClass> {
header: ElfHeader<Class>,
phdrs: Vec<Class::ProgramHeader>,
}
impl<Class: ElfClass> ElfFileData<Class> {
pub fn header(&self) -> &ElfHeader<Class> {
&self.header
}
pub fn flags_mut(&mut self) -> &mut ElfWord<Class> {
&mut self.header.e_flags
}
pub fn phdrs(&self) -> &[Class::ProgramHeader] {
&self.phdrs
}
pub fn phdrs_mut(&mut self) -> &mut Vec<Class::ProgramHeader> {
&mut self.phdrs
}
}
pub struct ElfFormat<Class: ElfClass, Howto> {
em: consts::ElfMachine,
data: consts::EiData,
create_header: Option<fn(&mut ElfHeader<Class>)>,
name: &'static str,
_cl: PhantomData<Class>,
_howto: PhantomData<fn() -> Howto>,
}
impl<Class: ElfClass, Howto> ElfFormat<Class, Howto> {
pub fn new(
em: consts::ElfMachine,
data: consts::EiData,
name: &'static str,
create_header: Option<fn(&mut ElfHeader<Class>)>,
) -> Self {
Self {
em,
data,
create_header,
name,
_cl: PhantomData,
_howto: PhantomData,
}
}
}
fn file_type_to_elf_type(ty: FileType) -> consts::ElfType {
match ty {
FileType::Exec => consts::ET_EXEC,
FileType::Relocatable => consts::ET_REL,
FileType::SharedObject => consts::ET_DYN,
FileType::FormatSpecific(val) => consts::ElfType(val as u16),
}
}
fn elf_type_to_file_type(ty: consts::ElfType) -> FileType {
match ty {
consts::ET_EXEC => FileType::Exec,
consts::ET_REL => FileType::Relocatable,
consts::ET_DYN => FileType::SharedObject,
consts::ElfType(x) => FileType::FormatSpecific(x as u32),
}
}
impl<Class: ElfClass + 'static, Howto: HowTo + 'static> Binfmt for ElfFormat<Class, Howto> {
fn relnum_to_howto(&self, relnum: u32) -> Option<&dyn HowTo> {
Howto::from_relnum(relnum).map(|x| x as &dyn HowTo)
}
fn code_to_howto(&self, code: crate::howto::RelocCode) -> Option<&dyn HowTo> {
Howto::from_reloc_code(code).map(|x| x as &dyn HowTo)
}
fn name(&self) -> &'static str {
self.name
}
fn create_file(&self, ty: FileType) -> crate::fmt::BinaryFile {
let mut header = ElfHeader {
e_ident: ElfIdent {
ei_mag: consts::ELFMAG,
ei_class: Class::EI_CLASS,
ei_data: self.data,
ei_version: consts::EV_CURRENT,
ei_osabi: consts::ELFOSABI_NONE,
ei_abiversion: 0,
..Zeroable::zeroed()
},
e_type: file_type_to_elf_type(ty),
e_machine: self.em,
e_version: Numeric::from_usize(bytemuck::cast::<_, u8>(consts::EV_CURRENT) as usize),
e_entry: Numeric::from_usize(0),
e_phoff: Numeric::from_usize(0),
e_shoff: Numeric::from_usize(0),
e_flags: Numeric::from_usize(0),
e_ehsize: Numeric::from_usize(0),
e_phentsize: Numeric::from_usize(size_of::<Class::ProgramHeader>()),
e_phnum: Numeric::from_usize(0),
e_shentsize: Numeric::from_usize(size_of::<ElfSectionHeader<Class>>()),
e_shnum: Numeric::from_usize(0),
e_shstrndx: Numeric::from_usize(0),
};
if let Some(f) = self.create_header {
(f)(&mut header);
}
let data = ElfFileData {
header,
phdrs: Vec::new(),
};
crate::fmt::BinaryFile::create(self, Box::new(data), ty)
}
fn read_file(
&self,
file: &mut (dyn std::io::Read + '_),
) -> std::io::Result<Option<crate::fmt::BinaryFile>> {
let mut header = ElfHeader::<Class>::zeroed();
file.read_exact(bytemuck::bytes_of_mut(&mut header.e_ident))?;
if header.e_ident.ei_mag != consts::ELFMAG {
return Ok(None);
}
if header.e_ident.ei_class != Class::EI_CLASS {
return Ok(None);
}
if header.e_ident.ei_data != self.data {
return Ok(None);
}
file.read_exact(&mut bytemuck::bytes_of_mut(&mut header)[16..])?;
if header.e_phentsize != Numeric::from_usize(size_of::<Class::ProgramHeader>())
&& header.e_phnum != Numeric::zero()
{
return Err(std::io::Error::new(
ErrorKind::InvalidData,
"Invalid Program Header Entry Size",
));
}
let mut phdrs = vec![Class::ProgramHeader::zeroed(); header.e_phnum.as_usize()];
file.read_exact(bytemuck::cast_slice_mut(&mut phdrs))?;
let data = ElfFileData { header, phdrs };
#[allow(unused_mut)]
let mut bfile =
BinaryFile::create(self, Box::new(data), elf_type_to_file_type(header.e_type));
if header.e_shentsize != Numeric::from_usize(size_of::<ElfSectionHeader<Class>>())
&& header.e_shnum != Numeric::zero()
{
return Err(std::io::Error::new(
ErrorKind::InvalidData,
"Invalid Section Header Entry Size",
));
}
let mut shdrs = vec![ElfSectionHeader::<Class>::zeroed(); header.e_shnum.as_usize()];
file.read_exact(bytemuck::cast_slice_mut(&mut shdrs))?;
for _shdr in &shdrs {}
Ok(Some(bfile))
}
fn write_file(
&self,
file: &mut (dyn std::io::Write + '_),
bfile: &crate::fmt::BinaryFile,
) -> std::io::Result<()> {
let mut shstrtab = (Vec::new(), HashMap::new());
fn add_to_strtab<'a>(
strtab: &mut (Vec<u8>, HashMap<Cow<'a, str>, usize>),
string: Cow<'a, str>,
) -> usize {
if let Entry::Vacant(e) = strtab.1.entry(string.clone()) {
let addr = strtab.0.len();
strtab.0.append(&mut Vec::from(string.as_bytes()));
strtab.0.push(0);
e.insert(addr);
addr
} else {
strtab.1[&string]
}
}
let mut shdrs = Vec::new();
let mut offset = size_of::<ElfHeader<Class>>()
+ size_of::<Class::ProgramHeader>()
* (bfile.data().downcast_ref::<ElfFileData<Class>>())
.unwrap()
.phdrs
.len();
shdrs.push(ElfSectionHeader::<Class> {
sh_name: Class::Word::from_usize(add_to_strtab(&mut shstrtab, "".into())),
sh_type: consts::SHT_NULL,
sh_flags: Class::Offset::from_usize(0),
sh_addr: Class::Addr::from_usize(0),
sh_offset: Class::Offset::from_usize(0),
sh_size: Class::Size::from_usize(0),
sh_link: Class::Word::from_usize(0),
sh_info: Class::Word::from_usize(0),
sh_addralign: Class::Addr::from_usize(0),
sh_entsize: Class::Size::from_usize(0),
});
for section in bfile.sections() {
#[allow(clippy::needless_borrow)]
shdrs.push(ElfSectionHeader::<Class> {
sh_name: Class::Word::from_usize(add_to_strtab(
&mut shstrtab,
(§ion.name).into(),
)),
sh_type: match section.ty {
SectionType::NoBits => consts::SHT_NOBITS,
SectionType::ProgBits => consts::SHT_PROGBITS,
SectionType::SymbolTable => consts::SHT_SYMTAB,
SectionType::StringTable => consts::SHT_STRTAB,
SectionType::Dynamic => consts::SHT_DYNAMIC,
SectionType::ProcedureLinkageTable => todo!(),
SectionType::GlobalOffsetTable => todo!(),
SectionType::FormatSpecific(_) => todo!(),
},
sh_flags: Class::Offset::from_usize(7),
sh_addr: Class::Addr::from_usize(0),
sh_offset: Class::Offset::from_usize(offset),
sh_size: Class::Size::from_usize(section.content.len()),
sh_link: Class::Word::from_usize(0),
sh_info: Class::Word::from_usize(0),
sh_addralign: Class::Addr::from_usize(section.align),
sh_entsize: Class::Size::from_usize(0),
});
offset += section.content.len();
}
let mut new_symbol_list: Vec<_> = bfile.symbols().cloned().collect();
new_symbol_list.sort_by_key(|s1| s1.kind());
let mut num_reloc_sections = 0;
for section in bfile.sections() {
if !section.relocs.is_empty() {
num_reloc_sections += 1;
for reloc in §ion.relocs {
if !new_symbol_list.iter().any(|x| x.name() == reloc.symbol) {
new_symbol_list.push(crate::sym::Symbol::new(
reloc.symbol.clone(),
None,
None,
SymbolType::Null,
SymbolKind::Global,
));
}
}
}
}
let mut symbols: Vec<Class::Symbol> = Vec::new();
let mut strtab = (Vec::new(), HashMap::new());
symbols.push(Class::new_sym(
Class::Word::from_usize(add_to_strtab(&mut strtab, "".into())),
Class::Addr::from_usize(0),
Class::Size::from_usize(0),
0,
0,
Class::Half::from_usize(0),
));
let mut local_syms = 1; for sym in &new_symbol_list {
symbols.push(Class::new_sym(
Class::Word::from_usize(add_to_strtab(
&mut strtab,
String::from(sym.name()).into(),
)),
Class::Addr::from_usize(sym.value().map_or(0, |x| x as usize)),
Class::Size::from_usize(0usize),
(match sym.kind() {
SymbolKind::Local => {
local_syms += 1;
0
}
SymbolKind::Global => 1,
SymbolKind::Weak => 2,
SymbolKind::FormatSpecific(x) => x as u8,
} << 4)
| match sym.symbol_type() {
SymbolType::Null => 0,
SymbolType::Object => 1,
SymbolType::Function => 2,
SymbolType::Section => 3,
SymbolType::File => 4,
SymbolType::Common => 5,
SymbolType::Tls => 6,
SymbolType::FormatSpecific(x) => x as u8,
},
0,
Class::Half::from_usize(sym.section().map_or(0, |x| x as usize + 1)),
));
}
let symbols_sec: Vec<u8> = Vec::from(bytemuck::cast_slice(&symbols));
let symbols_sec_id = shdrs.len();
shdrs.push(ElfSectionHeader::<Class> {
sh_name: Class::Word::from_usize(add_to_strtab(&mut shstrtab, ".symtab".into())),
sh_type: consts::SHT_SYMTAB,
sh_flags: Class::Offset::from_usize(0),
sh_addr: Class::Addr::from_usize(0),
sh_offset: Class::Offset::from_usize(offset),
sh_size: Class::Size::from_usize(symbols_sec.len()),
sh_link: Class::Word::from_usize(shdrs.len() + 1 + num_reloc_sections),
sh_info: Class::Word::from_usize(local_syms),
sh_addralign: Class::Addr::from_usize(8),
sh_entsize: Class::Size::from_usize(24),
});
offset += symbols_sec.len();
let mut all_relocs: Vec<u8> = Vec::new();
for (i, section) in bfile.sections().enumerate() {
if !section.relocs.is_empty() {
let mut relocs = Vec::new();
for reloc in §ion.relocs {
relocs.push(ElfRela::<Class> {
r_offset: Class::Addr::from_usize(reloc.offset as usize),
r_info: Class::Size::from_usize(
((new_symbol_list
.iter()
.position(|x| x.name() == reloc.symbol)
.unwrap()
+ 1)
<< 32)
+ Howto::from_reloc_code(reloc.code).unwrap().reloc_num() as usize,
),
r_addend: Class::Offset::from_usize(reloc.addend.map_or(0, |x| x as usize)),
});
}
let mut relocs = Vec::from(bytemuck::cast_slice(&relocs));
let target_section = i + 1;
shdrs.push(ElfSectionHeader::<Class> {
sh_name: Class::Word::from_usize(add_to_strtab(
&mut shstrtab,
(".rela".to_string() + §ion.name).into(),
)),
sh_type: consts::SHT_RELA,
sh_flags: Class::Offset::from_usize(7),
sh_addr: Class::Addr::from_usize(0),
sh_offset: Class::Offset::from_usize(offset),
sh_size: Class::Size::from_usize(relocs.len()),
sh_link: Class::Word::from_usize(symbols_sec_id),
sh_info: Class::Word::from_usize(target_section),
sh_addralign: Class::Addr::from_usize(8),
sh_entsize: Class::Size::from_usize(24),
});
offset += relocs.len();
all_relocs.append(&mut relocs);
}
}
shdrs.push(ElfSectionHeader::<Class> {
sh_name: Class::Word::from_usize(add_to_strtab(&mut shstrtab, ".strtab".into())),
sh_type: consts::SHT_STRTAB,
sh_flags: Class::Offset::from_usize(0),
sh_addr: Class::Addr::from_usize(0),
sh_offset: Class::Offset::from_usize(offset),
sh_size: Class::Size::from_usize(strtab.0.len()),
sh_link: Class::Word::from_usize(0),
sh_info: Class::Word::from_usize(0),
sh_addralign: Class::Addr::from_usize(1),
sh_entsize: Class::Size::from_usize(0),
});
offset += strtab.0.len();
shdrs.push(ElfSectionHeader::<Class> {
sh_name: Class::Word::from_usize(add_to_strtab(&mut shstrtab, ".shstrtab".into())),
sh_type: consts::SHT_STRTAB,
sh_flags: Class::Offset::from_usize(0),
sh_addr: Class::Addr::from_usize(0),
sh_offset: Class::Offset::from_usize(offset),
sh_size: Class::Size::from_usize(shstrtab.0.len()),
sh_link: Class::Word::from_usize(0),
sh_info: Class::Word::from_usize(0),
sh_addralign: Class::Addr::from_usize(1),
sh_entsize: Class::Size::from_usize(0),
});
offset += shstrtab.0.len();
let mut header = bfile
.data()
.downcast_ref::<ElfFileData<Class>>()
.unwrap()
.header;
header.e_shnum = Class::Half::from_usize(shdrs.len());
header.e_shoff = Class::Offset::from_usize(offset);
header.e_shstrndx = Class::Half::from_usize(shdrs.len() - 1);
file.write_all(bytemuck::bytes_of(&header))?;
for section in bfile.sections() {
file.write_all(§ion.content)?;
}
file.write_all(&symbols_sec)?;
file.write_all(&all_relocs)?;
file.write_all(&strtab.0)?;
file.write_all(&shstrtab.0)?;
file.write_all(bytemuck::cast_slice(&shdrs))?;
Ok(())
}
fn has_sections(&self) -> bool {
true
}
}