1mod codegen;
2mod relocations;
3
4pub use codegen::*;
5pub use relocations::*;
6
7use crate::{ElfParser, StringTable, VariantStructBinarySerde};
8use binary_serde::{binary_serde_bitfield, BinarySerde, BitfieldBitOrder, Endianness};
9use elflib_macros::{define_raw_struct_by_variants, define_raw_struct_generic_bitlen};
10
11pub const ELF_MAGIC: &[u8] = &[0x7f, b'E', b'L', b'F'];
12pub const EI_NIDENT: usize = 16;
13pub const ELF_IDENT_PADDING_SIZE: usize = EI_NIDENT - ElfIdentHeader::SERIALIZED_SIZE;
14
15#[derive(Clone, Copy, PartialEq, Eq, Hash)]
16pub(crate) struct DebugIgnore<T>(pub(crate) T);
17impl<T> core::fmt::Debug for DebugIgnore<T> {
18    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
19        write!(f, "...")
20    }
21}
22impl<T> From<T> for DebugIgnore<T> {
23    fn from(value: T) -> Self {
24        Self(value)
25    }
26}
27impl<T> core::ops::Deref for DebugIgnore<T> {
28    type Target = T;
29
30    fn deref(&self) -> &Self::Target {
31        &self.0
32    }
33}
34impl<T> core::ops::DerefMut for DebugIgnore<T> {
35    fn deref_mut(&mut self) -> &mut Self::Target {
36        &mut self.0
37    }
38}
39
40#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
41pub struct ElfFileInfo {
42    pub endianness: Endianness,
43    pub bit_length: ArchBitLength,
44    pub os_abi: OsAbi,
45    pub arch: Architechture,
46}
47
48#[derive(Debug, PartialEq, Eq, Clone, Hash, BinarySerde)]
49pub struct ElfIdentHeader {
50    pub magic: [u8; ELF_MAGIC.len()],
51    pub bit_size: ArchBitLength,
52    pub endianness: ElfEndianness,
53    pub elf_version: ElfVersionInIdent,
54    pub os_abi: OsAbi,
55    pub abi_version: AbiVersion,
56}
57
58#[derive(Debug, PartialEq, Eq, Clone, Hash, BinarySerde)]
59pub struct ElfIdent {
60    pub header: ElfIdentHeader,
61    pub padding: [u8; ELF_IDENT_PADDING_SIZE],
62}
63
64define_raw_struct_by_variants! {
65    struct ProgramHeader32 {
66        ty: ProgramHeaderType,
67        offset: u32,
68        virt_addr: u32,
69        phys_addr: u32,
70        size_in_file: u32,
71        size_in_memory: u32,
72        flags: ProgramHeaderFlags,
73        alignment: u32,
74    }
75    struct ProgramHeader64 {
76        ty: ProgramHeaderType,
77        flags: ProgramHeaderFlags,
78        offset: u64,
79        virt_addr: u64,
80        phys_addr: u64,
81        size_in_file: u64,
82        size_in_memory: u64,
83        alignment: u64,
84    }
85    => ()
86}
87
88define_raw_struct_by_variants! {
89    struct SectionHeader64 {
90        name_offset: u32,
91        ty: SectionHeaderType,
92        flags: SectionHeaderFlags,
93        address: u64,
94        offset: u64,
95        size: u64,
96        link: u32,
97        info: u32,
98        address_alignemnt: u64,
99        entry_size: u64,
100    }
101    struct SectionHeader32 {
102        name_offset: u32,
103        ty: SectionHeaderType,
104        flags: SectionHeaderFlagsU32,
105        address: u32,
106        offset: u32,
107        size: u32,
108        link: u32,
109        info: u32,
110        address_alignemnt: u32,
111        entry_size: u32,
112    }
113    => ()
114}
115
116define_raw_struct_generic_bitlen! {
117    struct ElfHeader {
118        ident: ElfIdent,
119        ty: ElfFileType,
120        arch: Architechture,
121        version: ElfVersion,
122        entry: U,
123        program_headers_off: U,
124        section_headers_off: U,
125        flags: ElfFlags,
126        header_size: u16,
127        program_header_entry_size: u16,
128        program_headers_amount: u16,
129        section_header_entry_size: u16,
130        section_headers_amount: u16,
131        section_names_section_index: u16,
132    }
133    => ()
134}
135
136#[derive(Debug, PartialEq, Eq, Clone, Hash)]
137#[binary_serde_bitfield(order = BitfieldBitOrder::LsbFirst)]
138pub struct SymbolInfo {
139    #[bits(4)]
140    pub ty: SymbolType,
141
142    #[bits(4)]
143    pub binding: SymbolBinding,
144}
145
146#[derive(Debug, PartialEq, Eq, Clone, Hash)]
147#[binary_serde_bitfield(order = BitfieldBitOrder::LsbFirst)]
148pub struct SymbolOtherInfo {
149    #[bits(2)]
150    pub visibility: SymbolVisibility,
151
152    #[bits(6)]
153    pub padding: u8,
154}
155
156#[derive(Debug, Clone)]
157pub struct SymbolRefContext<'a> {
158    pub(crate) string_table: StringTable<'a>,
159}
160
161define_raw_struct_by_variants! {
162    struct Symbol32 {
163        name_index_in_string_table: u32,
164        value: u32,
165        size: u32,
166        info: SymbolInfo,
167        other_info: SymbolOtherInfo,
168        related_section_index: u16,
169    }
170    struct Symbol64 {
171        name_index_in_string_table: u32,
172        info: SymbolInfo,
173        other_info: SymbolOtherInfo,
174        related_section_index: u16,
175        value: u64,
176        size: u64,
177    }
178    => SymbolRefContext<'a>
179}
180
181#[derive(Debug, BinarySerde, Clone, Copy, PartialEq, Eq, Hash)]
182#[repr(u8)]
183pub enum AbiVersion {
184    Valid = 0,
185}
186
187#[derive(Debug, BinarySerde, Clone, Copy, PartialEq, Eq, Hash)]
188#[repr(u8)]
189pub enum ElfVersionInIdent {
190    Current = 1,
191}
192
193#[derive(Debug, BinarySerde, Clone, Copy, PartialEq, Eq, Hash)]
194#[repr(u32)]
195pub enum ElfVersion {
196    Current = 1,
197}
198
199#[derive(Debug, BinarySerde, Clone, Copy, PartialEq, Eq, Hash)]
200#[repr(u8)]
201pub enum ElfEndianness {
202    Little = 1,
203    Big = 2,
204}
205impl From<ElfEndianness> for binary_serde::Endianness {
206    fn from(value: ElfEndianness) -> Self {
207        match value {
208            ElfEndianness::Little => Endianness::Little,
209            ElfEndianness::Big => Endianness::Big,
210        }
211    }
212}
213impl From<binary_serde::Endianness> for ElfEndianness {
214    fn from(value: binary_serde::Endianness) -> Self {
215        match value {
216            Endianness::Little => ElfEndianness::Little,
217            Endianness::Big => ElfEndianness::Big,
218        }
219    }
220}
221
222#[derive(Debug, BinarySerde, Clone, Copy, PartialEq, Eq, Hash)]
223#[repr(u8)]
224pub enum ArchBitLength {
225    Arch32Bit = 1,
226    Arch64Bit = 2,
227}
228
229macro_rules! gen_enum_size_truncating_wrapper {
230    {$wrapper_name: ident, $inner_ty: ty, $truncated_uint: ty, $original_uint: ty, $convert_inner_to_bits_input_var_name: ident, $convert_inner_to_bits_body: block} => {
231        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
232        pub struct $wrapper_name($inner_ty);
233        impl BinarySerde for $wrapper_name {
234            const SERIALIZED_SIZE: usize = <$truncated_uint as BinarySerde>::SERIALIZED_SIZE;
235
236            type RecursiveArray = <$truncated_uint as BinarySerde>::RecursiveArray;
237
238            fn binary_serialize(&self, buf: &mut [u8], endianness: Endianness) {
239                let converted = {
240                    let $convert_inner_to_bits_input_var_name = &self.0;
241                    $convert_inner_to_bits_body
242                };
243                converted.binary_serialize(buf, endianness)
244            }
245
246            fn binary_deserialize(
247                buf: &[u8],
248                endianness: Endianness,
249            ) -> Result<Self, binary_serde::DeserializeError> {
250                let value = <$truncated_uint>::binary_deserialize(buf, endianness)?;
251                let bytes = (value as $original_uint).binary_serialize_to_array(endianness);
252                Ok(Self(<$inner_ty>::binary_deserialize(
253                    bytes.as_ref(),
254                    endianness,
255                )?))
256            }
257        }
258        impl TryFrom<$inner_ty> for $wrapper_name {
259            type Error = <$truncated_uint as TryFrom<$original_uint>>::Error;
260
261            fn try_from(value: $inner_ty) -> Result<Self, Self::Error> {
262                let converted = {
263                    let $convert_inner_to_bits_input_var_name = &value;
264                    $convert_inner_to_bits_body
265                };
266                let _ = <$truncated_uint>::try_from(converted)?;
267                Ok(Self(value))
268            }
269        }
270        impl From<$wrapper_name> for $inner_ty {
271            fn from(value: $wrapper_name) -> Self {
272                value.0
273            }
274        }
275    };
276}
277
278gen_enum_size_truncating_wrapper! {RelocationTypeU8, RelocationType, u8, u32, x, {*x as u32}}
279gen_enum_size_truncating_wrapper! {SectionHeaderFlagsU32, SectionHeaderFlags, u32, u64, x, {x.bits()}}