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