goblin_experimental/elf/
header.rs

1include!("constants_header.rs");
2
3macro_rules! elf_header {
4    ($size:ident) => {
5        use core::fmt;
6
7        #[repr(C)]
8        #[derive(Clone, Copy, Default, PartialEq)]
9        pub struct Header {
10            /// Magic number and other info
11            pub e_ident: [u8; SIZEOF_IDENT],
12            /// Object file type
13            pub e_type: u16,
14            /// Architecture
15            pub e_machine: u16,
16            /// Object file version
17            pub e_version: u32,
18            /// Entry point virtual address
19            pub e_entry: $size,
20            /// Program header table file offset
21            pub e_phoff: $size,
22            /// Section header table file offset
23            pub e_shoff: $size,
24            /// Processor-specific flags
25            pub e_flags: u32,
26            /// ELF header size in bytes
27            pub e_ehsize: u16,
28            /// Program header table entry size
29            pub e_phentsize: u16,
30            /// Program header table entry count
31            pub e_phnum: u16,
32            /// Section header table entry size
33            pub e_shentsize: u16,
34            /// Section header table entry count
35            pub e_shnum: u16,
36            /// Section header string table index
37            pub e_shstrndx: u16,
38        }
39
40        use plain;
41        // Declare that this is a plain type.
42        unsafe impl plain::Plain for Header {}
43
44        impl Header {
45            /// Returns the corresponding ELF header from the given byte array.
46            pub fn from_bytes(bytes: &[u8; SIZEOF_EHDR]) -> &Header {
47                // FIXME: Length is ensured correct because it's encoded in the type,
48                // but it can still panic due to invalid alignment.
49                plain::from_bytes(bytes).unwrap()
50            }
51        }
52        impl fmt::Debug for Header {
53            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
54                f.debug_struct("Header")
55                    .field("e_ident", &format_args!("{:?}", self.e_ident))
56                    .field("e_type", &et_to_str(self.e_type))
57                    .field("e_machine", &format_args!("0x{:x}", self.e_machine))
58                    .field("e_version", &format_args!("0x{:x}", self.e_version))
59                    .field("e_entry", &format_args!("0x{:x}", self.e_entry))
60                    .field("e_phoff", &format_args!("0x{:x}", self.e_phoff))
61                    .field("e_shoff", &format_args!("0x{:x}", self.e_shoff))
62                    .field("e_flags", &format_args!("{:x}", self.e_flags))
63                    .field("e_ehsize", &self.e_ehsize)
64                    .field("e_phentsize", &self.e_phentsize)
65                    .field("e_phnum", &self.e_phnum)
66                    .field("e_shentsize", &self.e_shentsize)
67                    .field("e_shnum", &self.e_shnum)
68                    .field("e_shstrndx", &self.e_shstrndx)
69                    .finish()
70            }
71        }
72    };
73}
74
75/// No file type.
76pub const ET_NONE: u16 = 0;
77/// Relocatable file.
78pub const ET_REL: u16 = 1;
79/// Executable file.
80pub const ET_EXEC: u16 = 2;
81/// Shared object file.
82pub const ET_DYN: u16 = 3;
83/// Core file.
84pub const ET_CORE: u16 = 4;
85/// Number of defined types.
86pub const ET_NUM: u16 = 5;
87/// OS-specific range start
88pub const ET_LOOS: u16 = 0xfe00;
89/// OS-specific range end
90pub const ET_HIOS: u16 = 0xfeff;
91/// Processor-specific range start
92pub const ET_LOPROC: u16 = 0xff00;
93/// Processor-specific range end
94pub const ET_HIPROC: u16 = 0xffff;
95
96/// The ELF magic number.
97pub const ELFMAG: &[u8; 4] = b"\x7FELF";
98/// Sizeof ELF magic number.
99pub const SELFMAG: usize = 4;
100
101/// File class byte index.
102pub const EI_CLASS: usize = 4;
103/// Invalid class.
104pub const ELFCLASSNONE: u8 = 0;
105/// 32-bit objects.
106pub const ELFCLASS32: u8 = 1;
107/// 64-bit objects.
108pub const ELFCLASS64: u8 = 2;
109/// ELF class number.
110pub const ELFCLASSNUM: u8 = 3;
111
112/// Data encoding byte index.
113pub const EI_DATA: usize = 5;
114/// Invalid data encoding.
115pub const ELFDATANONE: u8 = 0;
116/// 2's complement, little endian.
117pub const ELFDATA2LSB: u8 = 1;
118/// 2's complement, big endian.
119pub const ELFDATA2MSB: u8 = 2;
120
121/// File version byte index.
122pub const EI_VERSION: usize = 6;
123/// Current ELF version.
124pub const EV_CURRENT: u8 = 1;
125
126/// OS ABI byte index.
127pub const EI_OSABI: usize = 7;
128/// UNIX System V ABI.
129pub const ELFOSABI_NONE: u8 = 0;
130/// UNIX System V ABI.
131///
132/// Alias.
133pub const ELFOSABI_SYSV: u8 = ELFOSABI_NONE;
134/// HP-UX.
135pub const ELFOSABI_HPUX: u8 = 1;
136/// NetBSD.
137pub const ELFOSABI_NETBSD: u8 = 2;
138/// Object uses GNU ELF extensions.
139pub const ELFOSABI_GNU: u8 = 3;
140/// Object uses GNU ELF extensions.
141///
142/// Alias.
143pub const ELFOSABI_LINUX: u8 = ELFOSABI_GNU;
144/// Sun Solaris.
145pub const ELFOSABI_SOLARIS: u8 = 6;
146/// IBM AIX.
147pub const ELFOSABI_AIX: u8 = 7;
148/// SGI Irix.
149pub const ELFOSABI_IRIX: u8 = 8;
150/// FreeBSD
151pub const ELFOSABI_FREEBSD: u8 = 9;
152/// Compaq TRU64 UNIX.
153pub const ELFOSABI_TRU64: u8 = 10;
154/// Novell Modesto.
155pub const ELFOSABI_MODESTO: u8 = 11;
156/// OpenBSD.
157pub const ELFOSABI_OPENBSD: u8 = 12;
158/// ARM EABI.
159pub const ELFOSABI_ARM_AEABI: u8 = 64;
160/// ARM.
161pub const ELFOSABI_ARM: u8 = 97;
162/// Standalone (embedded) application.
163pub const ELFOSABI_STANDALONE: u8 = 255;
164
165/// ABI version byte index.
166pub const EI_ABIVERSION: usize = 8;
167
168/// Number of bytes in an identifier.
169pub const SIZEOF_IDENT: usize = 16;
170
171/// Convert a ELF class byte to the associated string.
172#[inline]
173pub fn class_to_str(et: u8) -> &'static str {
174    match et {
175        ELFCLASSNONE => "NONE",
176        ELFCLASS32 => "ELF32",
177        ELFCLASS64 => "ELF64",
178        _ => "UNKNOWN_CLASS",
179    }
180}
181
182/// Convert an ET value to their associated string.
183#[inline]
184pub fn et_to_str(et: u16) -> &'static str {
185    match et {
186        ET_NONE => "NONE",
187        ET_REL => "REL",
188        ET_EXEC => "EXEC",
189        ET_DYN => "DYN",
190        ET_CORE => "CORE",
191        ET_NUM => "NUM",
192        _ => "UNKNOWN_ET",
193    }
194}
195
196if_alloc! {
197    use crate::error;
198    use scroll::{ctx, Endian};
199    use core::fmt;
200    use crate::container::{Ctx, Container};
201    use alloc::string::ToString;
202
203    #[derive(Copy, Clone, PartialEq)]
204    /// An ELF header
205    pub struct Header {
206        pub e_ident           : [u8; SIZEOF_IDENT],
207        pub e_type            : u16,
208        pub e_machine         : u16,
209        pub e_version         : u32,
210        pub e_entry           : u64,
211        pub e_phoff           : u64,
212        pub e_shoff           : u64,
213        pub e_flags           : u32,
214        pub e_ehsize          : u16,
215        pub e_phentsize       : u16,
216        pub e_phnum           : u16,
217        pub e_shentsize       : u16,
218        pub e_shnum           : u16,
219        pub e_shstrndx        : u16,
220    }
221
222    impl Header {
223        /// Return the size of the underlying program header, given a `container`
224        #[inline]
225        pub fn size(ctx: Ctx) -> usize {
226            use scroll::ctx::SizeWith;
227            Self::size_with(&ctx)
228        }
229        /// Returns the container type this header specifies
230        pub fn container(&self) -> error::Result<Container> {
231            use crate::error::Error;
232            match self.e_ident[EI_CLASS] {
233                ELFCLASS32 => { Ok(Container::Little) },
234                ELFCLASS64 => { Ok(Container::Big) },
235                class => Err(Error::Malformed(format!("Invalid class in Header: {}", class)))
236            }
237        }
238        /// Returns the byte order this header specifies
239        pub fn endianness(&self) -> error::Result<scroll::Endian> {
240            use crate::error::Error;
241            match self.e_ident[EI_DATA] {
242                ELFDATA2LSB => { Ok(scroll::LE) },
243                ELFDATA2MSB => { Ok(scroll::BE) },
244                class => Err(Error::Malformed(format!("Invalid endianness in Header: {}", class)))
245            }
246        }
247        pub fn new(ctx: Ctx) -> Self {
248            use crate::elf32;
249            use crate::elf64;
250            let (typ, ehsize, phentsize, shentsize) = match ctx.container {
251                Container::Little => {
252                    (ELFCLASS32, header32::SIZEOF_EHDR,
253                     elf32::program_header::SIZEOF_PHDR,
254                     elf32::section_header::SIZEOF_SHDR)
255                },
256                Container::Big => {
257                    (ELFCLASS64, header64::SIZEOF_EHDR,
258                     elf64::program_header::SIZEOF_PHDR,
259                     elf64::section_header::SIZEOF_SHDR)
260                }
261            };
262            let byteorder = match ctx.le { Endian::Little => ELFDATA2LSB, Endian::Big => ELFDATA2MSB };
263            Header {
264                e_ident: [
265                    127,
266                    69,
267                    76,
268                    70,
269                    typ,
270                    byteorder,
271                    EV_CURRENT,
272                    ELFOSABI_NONE,
273                    0,
274                    0,
275                    0,
276                    0,
277                    0,
278                    0,
279                    0,
280                    0
281                ],
282                e_type: ET_DYN,
283                e_machine: EM_NONE,
284                e_version: 1,
285                e_entry: 0x0,
286                e_phoff: 0x0,
287                e_shoff: 0x0,
288                e_flags: 0,
289                e_ehsize: ehsize as u16,
290                e_phentsize: phentsize as u16,
291                e_phnum: 0,
292                e_shentsize: shentsize as u16,
293                e_shnum: 0,
294                e_shstrndx: 0,
295            }
296        }
297    }
298
299    impl fmt::Debug for Header {
300        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
301            f.debug_struct("Header")
302               .field("e_ident", &format_args!("{:?}", self.e_ident))
303               .field("e_type", &et_to_str(self.e_type))
304               .field("e_machine", &format_args!("0x{:x}", self.e_machine))
305               .field("e_version", &format_args!("0x{:x}", self.e_version))
306               .field("e_entry", &format_args!("0x{:x}", self.e_entry))
307               .field("e_phoff", &format_args!("0x{:x}", self.e_phoff))
308               .field("e_shoff", &format_args!("0x{:x}", self.e_shoff))
309               .field("e_flags", &format_args!("{:x}", self.e_flags))
310               .field("e_ehsize", &self.e_ehsize)
311               .field("e_phentsize", &self.e_phentsize)
312               .field("e_phnum", &self.e_phnum)
313               .field("e_shentsize", &self.e_shentsize)
314               .field("e_shnum", &self.e_shnum)
315               .field("e_shstrndx", &self.e_shstrndx)
316               .finish()
317        }
318    }
319
320    impl ctx::SizeWith<crate::container::Ctx> for Header {
321        fn size_with(ctx: &crate::container::Ctx) -> usize {
322            match ctx.container {
323                Container::Little => {
324                    header32::SIZEOF_EHDR
325                },
326                Container::Big => {
327                    header64::SIZEOF_EHDR
328                },
329            }
330        }
331    }
332
333    impl<'a> ctx::TryFromCtx<'a, scroll::Endian> for Header {
334        type Error = crate::error::Error;
335        fn try_from_ctx(bytes: &'a [u8], _ctx: scroll::Endian) -> error::Result<(Self, usize)> {
336            use scroll::Pread;
337            if bytes.len() < SIZEOF_IDENT {
338                return Err(error::Error::Malformed("Too small".to_string()));
339            }
340            let ident: &[u8] = &bytes[..SIZEOF_IDENT];
341            if &ident[0..SELFMAG] != ELFMAG {
342                let magic: u64 = ident.pread_with(0, scroll::LE)?;
343                return Err(error::Error::BadMagic(magic));
344            }
345            let class = ident[EI_CLASS];
346            match class {
347                ELFCLASS32 => {
348                    Ok((Header::from(bytes.pread::<header32::Header>(0)?), header32::SIZEOF_EHDR))
349                },
350                ELFCLASS64 => {
351                    Ok((Header::from(bytes.pread::<header64::Header>(0)?), header64::SIZEOF_EHDR))
352                },
353                _ => {
354                    Err(error::Error::Malformed(format!("invalid ELF class {:x}", class)))
355                }
356            }
357        }
358    }
359
360    impl ctx::TryIntoCtx<scroll::Endian> for Header {
361        type Error = crate::error::Error;
362        fn try_into_ctx(self, bytes: &mut [u8], _ctx: scroll::Endian) -> Result<usize, Self::Error> {
363            use scroll::Pwrite;
364            match self.container()? {
365                Container::Little => {
366                    bytes.pwrite(header32::Header::from(self), 0)
367                },
368                Container::Big => {
369                    bytes.pwrite(header64::Header::from(self), 0)
370                }
371            }
372        }
373    }
374    impl ctx::IntoCtx<crate::container::Ctx> for Header {
375        fn into_ctx(self, bytes: &mut [u8], ctx: crate::container::Ctx) {
376            use scroll::Pwrite;
377            match ctx.container {
378                Container::Little => {
379                    bytes.pwrite_with(header32::Header::from(self), 0, ctx.le).unwrap()
380                },
381                Container::Big => {
382                    bytes.pwrite_with(header64::Header::from(self), 0, ctx.le).unwrap()
383                }
384            };
385        }
386    }
387} // end if_alloc
388
389macro_rules! elf_header_std_impl {
390    ($size:expr, $width:ty) => {
391
392        if_alloc! {
393            use crate::elf::header::Header as ElfHeader;
394            use crate::error::Error;
395            #[cfg(any(feature = "std", feature = "endian_fd"))]
396            use crate::error::Result;
397
398            use scroll::{ctx, Pread};
399
400            use core::result;
401
402            if_std! {
403                use std::fs::File;
404                use std::io::{Read};
405            }
406
407            impl From<ElfHeader> for Header {
408                fn from(eh: ElfHeader) -> Self {
409                    Header {
410                        e_ident: eh.e_ident,
411                        e_type: eh.e_type,
412                        e_machine: eh.e_machine,
413                        e_version: eh.e_version,
414                        e_entry: eh.e_entry as $width,
415                        e_phoff: eh.e_phoff as $width,
416                        e_shoff: eh.e_shoff as $width,
417                        e_flags: eh.e_flags,
418                        e_ehsize: eh.e_ehsize,
419                        e_phentsize: eh.e_phentsize,
420                        e_phnum: eh.e_phnum,
421                        e_shentsize: eh.e_shentsize,
422                        e_shnum: eh.e_shnum,
423                        e_shstrndx: eh.e_shstrndx,
424                    }
425                }
426            }
427
428            impl From<Header> for ElfHeader {
429                fn from(eh: Header) -> Self {
430                    ElfHeader {
431                        e_ident: eh.e_ident,
432                        e_type: eh.e_type,
433                        e_machine: eh.e_machine,
434                        e_version: eh.e_version,
435                        e_entry: u64::from(eh.e_entry),
436                        e_phoff: u64::from(eh.e_phoff),
437                        e_shoff: u64::from(eh.e_shoff),
438                        e_flags: eh.e_flags,
439                        e_ehsize: eh.e_ehsize,
440                        e_phentsize: eh.e_phentsize,
441                        e_phnum: eh.e_phnum,
442                        e_shentsize: eh.e_shentsize,
443                        e_shnum: eh.e_shnum,
444                        e_shstrndx: eh.e_shstrndx,
445                    }
446                }
447            }
448
449            impl<'a> ctx::TryFromCtx<'a, scroll::Endian> for Header {
450                type Error = crate::error::Error;
451                fn try_from_ctx(bytes: &'a [u8], _: scroll::Endian) -> result::Result<(Self, usize), Self::Error> {
452                    let mut elf_header = Header::default();
453                    let offset = &mut 0;
454                    bytes.gread_inout(offset, &mut elf_header.e_ident)?;
455                    let endianness =
456                        match elf_header.e_ident[EI_DATA] {
457                            ELFDATA2LSB => scroll::LE,
458                            ELFDATA2MSB => scroll::BE,
459                            d => return Err(Error::Malformed(format!("invalid ELF endianness DATA type {:x}", d)).into()),
460                        };
461                    elf_header.e_type =      bytes.gread_with(offset, endianness)?;
462                    elf_header.e_machine =   bytes.gread_with(offset, endianness)?;
463                    elf_header.e_version =   bytes.gread_with(offset, endianness)?;
464                    elf_header.e_entry =     bytes.gread_with(offset, endianness)?;
465                    elf_header.e_phoff =     bytes.gread_with(offset, endianness)?;
466                    elf_header.e_shoff =     bytes.gread_with(offset, endianness)?;
467                    elf_header.e_flags =     bytes.gread_with(offset, endianness)?;
468                    elf_header.e_ehsize =    bytes.gread_with(offset, endianness)?;
469                    elf_header.e_phentsize = bytes.gread_with(offset, endianness)?;
470                    elf_header.e_phnum =     bytes.gread_with(offset, endianness)?;
471                    elf_header.e_shentsize = bytes.gread_with(offset, endianness)?;
472                    elf_header.e_shnum =     bytes.gread_with(offset, endianness)?;
473                    elf_header.e_shstrndx =  bytes.gread_with(offset, endianness)?;
474                    Ok((elf_header, SIZEOF_EHDR))
475                }
476            }
477
478            impl ctx::TryIntoCtx<scroll::Endian> for Header {
479                type Error = crate::error::Error;
480                /// a Pwrite impl for Header: **note** we use the endianness value in the header, and not a parameter
481                fn try_into_ctx(self, bytes: &mut [u8], _endianness: scroll::Endian) -> result::Result<usize, Self::Error> {
482                    use scroll::{Pwrite};
483                    let offset = &mut 0;
484                    let endianness =
485                        match self.e_ident[EI_DATA] {
486                            ELFDATA2LSB => scroll::LE,
487                            ELFDATA2MSB => scroll::BE,
488                            d => return Err(Error::Malformed(format!("invalid ELF DATA type {:x}", d)).into()),
489                        };
490                    for i in 0..self.e_ident.len() {
491                        bytes.gwrite(self.e_ident[i], offset)?;
492                    }
493                    bytes.gwrite_with(self.e_type      , offset, endianness)?;
494                    bytes.gwrite_with(self.e_machine   , offset, endianness)?;
495                    bytes.gwrite_with(self.e_version   , offset, endianness)?;
496                    bytes.gwrite_with(self.e_entry     , offset, endianness)?;
497                    bytes.gwrite_with(self.e_phoff     , offset, endianness)?;
498                    bytes.gwrite_with(self.e_shoff     , offset, endianness)?;
499                    bytes.gwrite_with(self.e_flags     , offset, endianness)?;
500                    bytes.gwrite_with(self.e_ehsize    , offset, endianness)?;
501                    bytes.gwrite_with(self.e_phentsize , offset, endianness)?;
502                    bytes.gwrite_with(self.e_phnum     , offset, endianness)?;
503                    bytes.gwrite_with(self.e_shentsize , offset, endianness)?;
504                    bytes.gwrite_with(self.e_shnum     , offset, endianness)?;
505                    bytes.gwrite_with(self.e_shstrndx  , offset, endianness)?;
506                    Ok(SIZEOF_EHDR)
507                }
508            }
509
510            impl Header {
511                /// Load a header from a file. **You must** ensure the seek is at the correct position.
512                #[cfg(feature = "std")]
513                pub fn from_fd(bytes: &mut File) -> Result<Header> {
514                    let mut elf_header = [0; $size];
515                    bytes.read_exact(&mut elf_header)?;
516                    Ok(*Header::from_bytes(&elf_header))
517                }
518
519                #[cfg(feature = "endian_fd")]
520                /// Parses an ELF header from the given bytes
521                pub fn parse(bytes: &[u8]) -> Result<Header> {
522                    use super::{EI_DATA, ELFDATA2LSB, ELFDATA2MSB, SIZEOF_IDENT};
523
524                    let mut elf_header = Header::default();
525                    let mut offset = &mut 0;
526                    for i in 0..SIZEOF_IDENT {
527                        elf_header.e_ident[i] = bytes.gread(&mut offset)?;
528                    }
529                    let endianness =
530                        match elf_header.e_ident[EI_DATA] {
531                            ELFDATA2LSB => scroll::LE,
532                            ELFDATA2MSB => scroll::BE,
533                            d => return Err(Error::Malformed(format!("invalid ELF DATA type {:x}", d)).into()),
534                        };
535                    elf_header.e_type =      bytes.gread_with(offset, endianness)?;
536                    elf_header.e_machine =   bytes.gread_with(offset, endianness)?;
537                    elf_header.e_version =   bytes.gread_with(offset, endianness)?;
538                    elf_header.e_entry =     bytes.gread_with(offset, endianness)?;
539                    elf_header.e_phoff =     bytes.gread_with(offset, endianness)?;
540                    elf_header.e_shoff =     bytes.gread_with(offset, endianness)?;
541                    elf_header.e_flags =     bytes.gread_with(offset, endianness)?;
542                    elf_header.e_ehsize =    bytes.gread_with(offset, endianness)?;
543                    elf_header.e_phentsize = bytes.gread_with(offset, endianness)?;
544                    elf_header.e_phnum =     bytes.gread_with(offset, endianness)?;
545                    elf_header.e_shentsize = bytes.gread_with(offset, endianness)?;
546                    elf_header.e_shnum =     bytes.gread_with(offset, endianness)?;
547                    elf_header.e_shstrndx =  bytes.gread_with(offset, endianness)?;
548                    Ok(elf_header)
549                }
550            }
551        } // end if_alloc
552    };
553}
554
555// tests
556
557macro_rules! elf_header_test {
558    ($class:expr) => {
559        #[cfg(test)]
560        mod tests {
561            use super::*;
562            use crate::container::{Container, Ctx};
563            use crate::elf::header::Header as ElfHeader;
564            use alloc::vec::Vec;
565            use scroll::{Pread, Pwrite};
566            #[test]
567            fn size_of() {
568                assert_eq!(::std::mem::size_of::<Header>(), SIZEOF_EHDR);
569            }
570            #[test]
571            fn header_read_write() {
572                let crt1: Vec<u8> = if $class == ELFCLASS64 {
573                    include!("../../etc/crt1.rs")
574                } else {
575                    include!("../../etc/crt132.rs")
576                };
577                let header: Header = crt1.pread(0).unwrap();
578                assert_eq!(header.e_type, ET_REL);
579                println!("header: {:?}", &header);
580                let mut bytes = [0u8; SIZEOF_EHDR];
581                bytes.pwrite(header, 0).unwrap();
582                let header2: Header = bytes.pread(0).unwrap();
583                assert_eq!(header, header2);
584            }
585            #[test]
586            fn elfheader_read_write() {
587                let (container, crt1): (Container, Vec<u8>) = if $class == ELFCLASS64 {
588                    (Container::Big, include!("../../etc/crt1.rs"))
589                } else {
590                    (Container::Little, include!("../../etc/crt132.rs"))
591                };
592                let header: Header = crt1.pread(0).unwrap();
593                assert_eq!(header.e_type, ET_REL);
594                println!("header: {:?}", &header);
595                let mut bytes = [0u8; SIZEOF_EHDR];
596                let header_ = Header::from(header.clone());
597                bytes.pwrite(header_, 0).unwrap();
598                let header2: Header = bytes.pread(0).unwrap();
599                assert_eq!(header, header2);
600                let header = ElfHeader::new(Ctx::from(container));
601                println!("header: {:?}", &header);
602
603                let mut bytes = vec![0; 100];
604                bytes.pwrite(header, 0).unwrap();
605            }
606        }
607    };
608}
609
610pub mod header32 {
611    pub use super::*;
612
613    pub const SIZEOF_EHDR: usize = 52;
614    pub const ELFCLASS: u8 = ELFCLASS32;
615
616    elf_header!(u32);
617    elf_header_std_impl!(SIZEOF_EHDR, u32);
618    elf_header_test!(ELFCLASS);
619}
620
621pub mod header64 {
622    pub use super::*;
623
624    pub const SIZEOF_EHDR: usize = 64;
625    pub const ELFCLASS: u8 = ELFCLASS64;
626
627    elf_header!(u64);
628    elf_header_std_impl!(SIZEOF_EHDR, u64);
629    elf_header_test!(ELFCLASS);
630}