goblin/elf/
section_header.rs

1macro_rules! elf_section_header {
2    ($size:ident) => {
3        // XXX: Do not import scroll traits here.
4        // See: https://github.com/rust-lang/rust/issues/65090#issuecomment-538668155
5
6        #[repr(C)]
7        #[derive(Copy, Clone, Eq, PartialEq, Default)]
8        #[cfg_attr(
9            feature = "alloc",
10            derive(scroll::Pread, scroll::Pwrite, scroll::SizeWith)
11        )]
12        /// Section Headers are typically used by humans and static linkers for additional information or how to relocate the object
13        ///
14        /// **NOTE** section headers are strippable from a binary without any loss of portability/executability; _do not_ rely on them being there!
15        pub struct SectionHeader {
16            /// Section name (string tbl index)
17            pub sh_name: u32,
18            /// Section type
19            pub sh_type: u32,
20            /// Section flags
21            pub sh_flags: $size,
22            /// Section virtual addr at execution
23            pub sh_addr: $size,
24            /// Section file offset
25            pub sh_offset: $size,
26            /// Section size in bytes
27            pub sh_size: $size,
28            /// Link to another section
29            pub sh_link: u32,
30            /// Additional section information
31            pub sh_info: u32,
32            /// Section alignment
33            pub sh_addralign: $size,
34            /// Entry size if section holds table
35            pub sh_entsize: $size,
36        }
37
38        use plain;
39        // Declare that this is a plain type.
40        unsafe impl plain::Plain for SectionHeader {}
41
42        impl ::core::fmt::Debug for SectionHeader {
43            fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
44                f.debug_struct("SectionHeader")
45                    .field("sh_name", &self.sh_name)
46                    .field("sh_type", &sht_to_str(self.sh_type))
47                    .field("sh_flags", &format_args!("0x{:x}", self.sh_flags))
48                    .field("sh_addr", &format_args!("0x{:x}", self.sh_addr))
49                    .field("sh_offset", &format_args!("0x{:x}", self.sh_offset))
50                    .field("sh_size", &format_args!("0x{:x}", self.sh_size))
51                    .field("sh_link", &format_args!("0x{:x}", self.sh_link))
52                    .field("sh_info", &format_args!("0x{:x}", self.sh_info))
53                    .field("sh_addralign", &format_args!("0x{:x}", self.sh_addralign))
54                    .field("sh_entsize", &format_args!("0x{:x}", self.sh_entsize))
55                    .finish()
56            }
57        }
58    };
59}
60
61/// Undefined section.
62pub const SHN_UNDEF: u32 = 0;
63/// Start of reserved indices.
64pub const SHN_LORESERVE: u32 = 0xff00;
65/// Start of processor-specific.
66pub const SHN_LOPROC: u32 = 0xff00;
67/// Order section before all others (Solaris).
68pub const SHN_BEFORE: u32 = 0xff00;
69/// Order section after all others (Solaris).
70pub const SHN_AFTER: u32 = 0xff01;
71/// End of processor-specific.
72pub const SHN_HIPROC: u32 = 0xff1f;
73/// Start of OS-specific.
74pub const SHN_LOOS: u32 = 0xff20;
75/// End of OS-specific.
76pub const SHN_HIOS: u32 = 0xff3f;
77/// Associated symbol is absolute.
78pub const SHN_ABS: u32 = 0xfff1;
79/// Associated symbol is common.
80pub const SHN_COMMON: u32 = 0xfff2;
81/// Index is in extra table.
82pub const SHN_XINDEX: u32 = 0xffff;
83/// End of reserved indices.
84pub const SHN_HIRESERVE: u32 = 0xffff;
85
86// === Legal values for sh_type (section type). ===
87/// Section header table entry unused.
88pub const SHT_NULL: u32 = 0;
89/// Program data.
90pub const SHT_PROGBITS: u32 = 1;
91/// Symbol table.
92pub const SHT_SYMTAB: u32 = 2;
93/// String table.
94pub const SHT_STRTAB: u32 = 3;
95/// Relocation entries with addends.
96pub const SHT_RELA: u32 = 4;
97/// Symbol hash table.
98pub const SHT_HASH: u32 = 5;
99/// Dynamic linking information.
100pub const SHT_DYNAMIC: u32 = 6;
101/// Notes.
102pub const SHT_NOTE: u32 = 7;
103/// Program space with no data (bss).
104pub const SHT_NOBITS: u32 = 8;
105/// Relocation entries, no addends.
106pub const SHT_REL: u32 = 9;
107/// Reserved.
108pub const SHT_SHLIB: u32 = 10;
109/// Dynamic linker symbol table.
110pub const SHT_DYNSYM: u32 = 11;
111/// Array of constructors.
112pub const SHT_INIT_ARRAY: u32 = 14;
113/// Array of destructors.
114pub const SHT_FINI_ARRAY: u32 = 15;
115/// Array of pre-constructors.
116pub const SHT_PREINIT_ARRAY: u32 = 16;
117/// Section group.
118pub const SHT_GROUP: u32 = 17;
119/// Extended section indeces.
120pub const SHT_SYMTAB_SHNDX: u32 = 18;
121/// Number of defined types.
122pub const SHT_NUM: u32 = 19;
123/// Start OS-specific.
124pub const SHT_LOOS: u32 = 0x6000_0000;
125/// Object attributes.
126pub const SHT_GNU_ATTRIBUTES: u32 = 0x6fff_fff5;
127/// GNU-style hash table.
128pub const SHT_GNU_HASH: u32 = 0x6fff_fff6;
129/// Prelink library list.
130pub const SHT_GNU_LIBLIST: u32 = 0x6fff_fff7;
131/// Checksum for DSO content.
132pub const SHT_CHECKSUM: u32 = 0x6fff_fff8;
133/// Sun-specific low bound.
134pub const SHT_LOSUNW: u32 = 0x6fff_fffa;
135pub const SHT_SUNW_MOVE: u32 = 0x6fff_fffa;
136pub const SHT_SUNW_COMDAT: u32 = 0x6fff_fffb;
137pub const SHT_SUNW_SYMINFO: u32 = 0x6fff_fffc;
138/// Version definition section.
139pub const SHT_GNU_VERDEF: u32 = 0x6fff_fffd;
140/// Version needs section.
141pub const SHT_GNU_VERNEED: u32 = 0x6fff_fffe;
142/// Version symbol table.
143pub const SHT_GNU_VERSYM: u32 = 0x6fff_ffff;
144/// Sun-specific high bound.
145pub const SHT_HISUNW: u32 = 0x6fff_ffff;
146/// End OS-specific type.
147pub const SHT_HIOS: u32 = 0x6fff_ffff;
148/// Start of processor-specific.
149pub const SHT_LOPROC: u32 = 0x7000_0000;
150/// X86-64 unwind information.
151pub const SHT_X86_64_UNWIND: u32 = 0x7000_0001;
152/// End of processor-specific.
153pub const SHT_HIPROC: u32 = 0x7fff_ffff;
154/// Start of application-specific.
155pub const SHT_LOUSER: u32 = 0x8000_0000;
156/// End of application-specific.
157pub const SHT_HIUSER: u32 = 0x8fff_ffff;
158
159// Legal values for sh_flags (section flags)
160/// Writable.
161pub const SHF_WRITE: u32 = 0x1;
162/// Occupies memory during execution.
163pub const SHF_ALLOC: u32 = 0x2;
164/// Executable.
165pub const SHF_EXECINSTR: u32 = 0x4;
166/// Might be merged.
167pub const SHF_MERGE: u32 = 0x10;
168/// Contains nul-terminated strings.
169pub const SHF_STRINGS: u32 = 0x20;
170/// `sh_info' contains SHT index.
171pub const SHF_INFO_LINK: u32 = 0x40;
172/// Preserve order after combining.
173pub const SHF_LINK_ORDER: u32 = 0x80;
174/// Non-standard OS specific handling required.
175pub const SHF_OS_NONCONFORMING: u32 = 0x100;
176/// Section is member of a group.
177pub const SHF_GROUP: u32 = 0x200;
178/// Section hold thread-local data.
179pub const SHF_TLS: u32 = 0x400;
180/// Section with compressed data.
181pub const SHF_COMPRESSED: u32 = 0x800;
182/// OS-specific..
183pub const SHF_MASKOS: u32 = 0x0ff0_0000;
184/// Processor-specific.
185pub const SHF_MASKPROC: u32 = 0xf000_0000;
186/// Special ordering requirement (Solaris).
187pub const SHF_ORDERED: u32 = 1 << 30;
188/// Number of "regular" section header flags
189pub const SHF_NUM_REGULAR_FLAGS: usize = 12;
190/// Section is excluded unless referenced or allocated (Solaris).
191pub const SHF_EXCLUDE: u32 = 0x80000000; // 1U << 31
192
193pub const SHF_FLAGS: [u32; SHF_NUM_REGULAR_FLAGS] = [
194    SHF_WRITE,
195    SHF_ALLOC,
196    SHF_EXECINSTR,
197    SHF_MERGE,
198    SHF_STRINGS,
199    SHF_INFO_LINK,
200    SHF_LINK_ORDER,
201    SHF_OS_NONCONFORMING,
202    SHF_GROUP,
203    SHF_TLS,
204    SHF_COMPRESSED,
205    SHF_ORDERED,
206];
207
208pub fn sht_to_str(sht: u32) -> &'static str {
209    match sht {
210        SHT_NULL => "SHT_NULL",
211        SHT_PROGBITS => "SHT_PROGBITS",
212        SHT_SYMTAB => "SHT_SYMTAB",
213        SHT_STRTAB => "SHT_STRTAB",
214        SHT_RELA => "SHT_RELA",
215        SHT_HASH => "SHT_HASH",
216        SHT_DYNAMIC => "SHT_DYNAMIC",
217        SHT_NOTE => "SHT_NOTE",
218        SHT_NOBITS => "SHT_NOBITS",
219        SHT_REL => "SHT_REL",
220        SHT_SHLIB => "SHT_SHLIB",
221        SHT_DYNSYM => "SHT_DYNSYM",
222        SHT_INIT_ARRAY => "SHT_INIT_ARRAY",
223        SHT_FINI_ARRAY => "SHT_FINI_ARRAY",
224        SHT_PREINIT_ARRAY => "SHT_PREINIT_ARRAY",
225        SHT_GROUP => "SHT_GROUP",
226        SHT_SYMTAB_SHNDX => "SHT_SYMTAB_SHNDX",
227        SHT_NUM => "SHT_NUM",
228        SHT_LOOS => "SHT_LOOS",
229        SHT_GNU_ATTRIBUTES => "SHT_GNU_ATTRIBUTES",
230        SHT_GNU_HASH => "SHT_GNU_HASH",
231        SHT_GNU_LIBLIST => "SHT_GNU_LIBLIST",
232        SHT_CHECKSUM => "SHT_CHECKSUM",
233        SHT_SUNW_MOVE => "SHT_SUNW_MOVE",
234        SHT_SUNW_COMDAT => "SHT_SUNW_COMDAT",
235        SHT_SUNW_SYMINFO => "SHT_SUNW_SYMINFO",
236        SHT_GNU_VERDEF => "SHT_GNU_VERDEF",
237        SHT_GNU_VERNEED => "SHT_GNU_VERNEED",
238        SHT_GNU_VERSYM => "SHT_GNU_VERSYM",
239        SHT_LOPROC => "SHT_LOPROC",
240        SHT_X86_64_UNWIND => "SHT_X86_64_UNWIND",
241        SHT_HIPROC => "SHT_HIPROC",
242        SHT_LOUSER => "SHT_LOUSER",
243        SHT_HIUSER => "SHT_HIUSER",
244        _ => "UNKNOWN_SHT",
245    }
246}
247
248pub fn shf_to_str(shf: u32) -> &'static str {
249    match shf {
250        SHF_WRITE => "SHF_WRITE",
251        SHF_ALLOC => "SHF_ALLOC",
252        SHF_EXECINSTR => "SHF_EXECINSTR",
253        SHF_MERGE => "SHF_MERGE",
254        SHF_STRINGS => "SHF_STRINGS",
255        SHF_INFO_LINK => "SHF_INFO_LINK",
256        SHF_LINK_ORDER => "SHF_LINK_ORDER",
257        SHF_OS_NONCONFORMING => "SHF_OS_NONCONFORMING",
258        SHF_GROUP => "SHF_GROUP",
259        SHF_TLS => "SHF_TLS",
260        SHF_COMPRESSED => "SHF_COMPRESSED",
261        //SHF_MASKOS..SHF_MASKPROC => "SHF_OSFLAG",
262        SHF_ORDERED => "SHF_ORDERED",
263        _ => "SHF_UNKNOWN",
264    }
265}
266
267macro_rules! elf_section_header_std_impl { ($size:ty) => {
268
269    #[cfg(test)]
270    mod tests {
271        use super::*;
272        #[test]
273        fn size_of() {
274            assert_eq!(::std::mem::size_of::<SectionHeader>(), SIZEOF_SHDR);
275        }
276    }
277
278    if_alloc! {
279        use crate::elf::section_header::SectionHeader as ElfSectionHeader;
280
281        use plain::Plain;
282        use alloc::vec::Vec;
283
284        if_std! {
285            use crate::error::Result;
286
287            use std::fs::File;
288            use std::io::{Read, Seek};
289            use std::io::SeekFrom::Start;
290        }
291
292        impl From<SectionHeader> for ElfSectionHeader {
293            fn from(sh: SectionHeader) -> Self {
294                ElfSectionHeader {
295                    sh_name: sh.sh_name as usize,
296                    sh_type: sh.sh_type,
297                    sh_flags: u64::from(sh.sh_flags),
298                    sh_addr: u64::from(sh.sh_addr),
299                    sh_offset: u64::from(sh.sh_offset),
300                    sh_size: u64::from(sh.sh_size),
301                    sh_link: sh.sh_link,
302                    sh_info: sh.sh_info,
303                    sh_addralign: u64::from(sh.sh_addralign),
304                    sh_entsize: u64::from(sh.sh_entsize),
305                }
306            }
307        }
308        impl From<ElfSectionHeader> for SectionHeader {
309            fn from(sh: ElfSectionHeader) -> Self {
310                SectionHeader {
311                    sh_name     : sh.sh_name as u32,
312                    sh_type     : sh.sh_type,
313                    sh_flags    : sh.sh_flags as $size,
314                    sh_addr     : sh.sh_addr as $size,
315                    sh_offset   : sh.sh_offset as $size,
316                    sh_size     : sh.sh_size as $size,
317                    sh_link     : sh.sh_link,
318                    sh_info     : sh.sh_info,
319                    sh_addralign: sh.sh_addralign as $size,
320                    sh_entsize  : sh.sh_entsize as $size,
321                }
322            }
323        }
324
325        impl SectionHeader {
326            // FIXME: > 65535 sections
327            pub fn from_bytes(bytes: &[u8], shnum: usize) -> Vec<SectionHeader> {
328                let mut shdrs = vec![SectionHeader::default(); shnum];
329                shdrs.copy_from_bytes(bytes).expect("buffer is too short for given number of entries");
330                shdrs
331            }
332
333            #[cfg(feature = "std")]
334            // FIXME: > 65535 sections
335            pub fn from_fd(fd: &mut File, offset: u64, shnum: usize) -> Result<Vec<SectionHeader>> {
336                let mut shdrs = vec![SectionHeader::default(); shnum];
337                fd.seek(Start(offset))?;
338                unsafe {
339                    fd.read_exact(plain::as_mut_bytes(&mut *shdrs))?;
340                }
341                Ok(shdrs)
342            }
343        }
344    } // end if_alloc
345};}
346
347pub mod section_header32 {
348    pub use crate::elf::section_header::*;
349
350    elf_section_header!(u32);
351
352    pub const SIZEOF_SHDR: usize = 40;
353
354    elf_section_header_std_impl!(u32);
355}
356
357pub mod section_header64 {
358
359    pub use crate::elf::section_header::*;
360
361    elf_section_header!(u64);
362
363    pub const SIZEOF_SHDR: usize = 64;
364
365    elf_section_header_std_impl!(u64);
366}
367
368///////////////////////////////
369// Std/analysis/Unified Structs
370///////////////////////////////
371
372if_alloc! {
373    use crate::error;
374    use core::fmt;
375    use core::result;
376    use core::ops::Range;
377    use scroll::ctx;
378    use crate::container::{Container, Ctx};
379
380    #[cfg(feature = "endian_fd")]
381    use alloc::vec::Vec;
382
383    #[derive(Default, PartialEq, Clone)]
384    /// A unified SectionHeader - convertable to and from 32-bit and 64-bit variants
385    pub struct SectionHeader {
386        /// Section name (string tbl index)
387        pub sh_name: usize,
388        /// Section type
389        pub sh_type: u32,
390        /// Section flags
391        pub sh_flags: u64,
392        /// Section virtual addr at execution
393        pub sh_addr: u64,
394        /// Section file offset
395        pub sh_offset: u64,
396        /// Section size in bytes
397        pub sh_size: u64,
398        /// Link to another section
399        pub sh_link: u32,
400        /// Additional section information
401        pub sh_info: u32,
402        /// Section alignment
403        pub sh_addralign: u64,
404        /// Entry size if section holds table
405        pub sh_entsize: u64,
406    }
407
408    impl SectionHeader {
409        /// Return the size of the underlying section header, given a `Ctx`
410        #[inline]
411        pub fn size(ctx: Ctx) -> usize {
412            use scroll::ctx::SizeWith;
413            Self::size_with(&ctx)
414        }
415        pub fn new() -> Self {
416            SectionHeader {
417                sh_name: 0,
418                sh_type: SHT_PROGBITS,
419                sh_flags: u64::from(SHF_ALLOC),
420                sh_addr: 0,
421                sh_offset: 0,
422                sh_size: 0,
423                sh_link: 0,
424                sh_info: 0,
425                sh_addralign: 2 << 8,
426                sh_entsize: 0,
427            }
428        }
429        /// Returns this section header's file offset range,
430        /// if the section occupies space in fhe file.
431        pub fn file_range(&self) -> Option<Range<usize>> {
432            // Sections with type SHT_NOBITS have no data in the file itself,
433            // they only exist in memory.
434            if self.sh_type == SHT_NOBITS {
435                None
436            } else {
437                Some(self.sh_offset as usize..(self.sh_offset as usize).saturating_add(self.sh_size as usize))
438            }
439        }
440        /// Returns this section header's virtual memory range
441        pub fn vm_range(&self) -> Range<usize> {
442            self.sh_addr as usize..(self.sh_addr as usize).saturating_add(self.sh_size as usize)
443        }
444        /// Parse `count` section headers from `bytes` at `offset`, using the given `ctx`
445        /// Assuming this is read from the whole file, it will check offset.
446        #[cfg(feature = "endian_fd")]
447        pub fn parse(bytes: &[u8], offset: usize, count: usize, ctx: Ctx) -> error::Result<Vec<SectionHeader>> {
448            // Zero offset means no section headers, not even the null section header.
449            if offset == 0 {
450                return Ok(Vec::new());
451            }
452            Self::parse_from(bytes, offset, count, ctx)
453        }
454        /// Parse `count` section headers from `bytes` at `offset`, using the given `ctx`
455        /// without performing any offset checking to allow parsing relatively
456        #[cfg(feature = "endian_fd")]
457        pub fn parse_from(bytes: &[u8], mut offset: usize, mut count: usize, ctx: Ctx) -> error::Result<Vec<SectionHeader>> {
458            use scroll::Pread;
459            let empty_sh = bytes.gread_with::<SectionHeader>(&mut offset, ctx)?;
460            if count == 0 as usize {
461                // Zero count means either no section headers or the number of section headers
462                // overflows SHN_LORESERVE, in which case the count is stored in the sh_size field
463                // of the null section header.
464                count = empty_sh.sh_size as usize;
465            }
466
467            // Sanity check to avoid OOM
468            if count > bytes.len() / Self::size(ctx) {
469                return Err(error::Error::BufferTooShort(count, "section headers"));
470            }
471            let mut section_headers = Vec::with_capacity(count);
472            section_headers.push(empty_sh);
473            for _ in 1..count {
474                let shdr = bytes.gread_with(&mut offset, ctx)?;
475                section_headers.push(shdr);
476            }
477            Ok(section_headers)
478        }
479        pub fn check_size(&self, size: usize) -> error::Result<()> {
480            if self.sh_type == SHT_NOBITS || self.sh_size == 0 {
481                return Ok(());
482            }
483            let (end, overflow) = self.sh_offset.overflowing_add(self.sh_size);
484            if overflow || end > size as u64 {
485                let message = format!("Section {} size ({}) + offset ({}) is out of bounds. Overflowed: {}",
486                    self.sh_name, self.sh_offset, self.sh_size, overflow);
487                return Err(error::Error::Malformed(message));
488            }
489            let (_, overflow) = self.sh_addr.overflowing_add(self.sh_size);
490            if overflow {
491                let message = format!("Section {} size ({}) + addr ({}) is out of bounds. Overflowed: {}",
492                    self.sh_name, self.sh_addr, self.sh_size, overflow);
493                return Err(error::Error::Malformed(message));
494            }
495            Ok(())
496        }
497        pub fn is_relocation(&self) -> bool {
498            self.sh_type == SHT_RELA
499        }
500        pub fn is_executable(&self) -> bool {
501            self.is_alloc() && self.sh_flags as u32 & SHF_EXECINSTR == SHF_EXECINSTR
502        }
503        pub fn is_writable(&self) -> bool {
504            self.is_alloc() && self.sh_flags as u32 & SHF_WRITE == SHF_WRITE
505        }
506        pub fn is_alloc(&self) -> bool {
507            self.sh_flags as u32 & SHF_ALLOC == SHF_ALLOC
508        }
509    }
510
511    impl fmt::Debug for SectionHeader {
512        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
513            f.debug_struct("SectionHeader")
514                .field("sh_name", &self.sh_name)
515                .field("sh_type", &sht_to_str(self.sh_type))
516                .field("sh_flags", &format_args!("0x{:x}", self.sh_flags))
517                .field("sh_addr", &format_args!("0x{:x}", self.sh_addr))
518                .field("sh_offset", &format_args!("0x{:x}", self.sh_offset))
519                .field("sh_size", &format_args!("0x{:x}", self.sh_size))
520                .field("sh_link", &format_args!("0x{:x}", self.sh_link))
521                .field("sh_info", &format_args!("0x{:x}", self.sh_info))
522                .field("sh_addralign", &format_args!("0x{:x}", self.sh_addralign))
523                .field("sh_entsize", &format_args!("0x{:x}", self.sh_entsize))
524                .finish()
525        }
526    }
527
528    impl ctx::SizeWith<Ctx> for SectionHeader {
529        fn size_with( &Ctx { container, .. }: &Ctx) -> usize {
530            match container {
531                Container::Little => {
532                    section_header32::SIZEOF_SHDR
533                },
534                Container::Big => {
535                    section_header64::SIZEOF_SHDR
536                },
537            }
538        }
539    }
540
541    impl<'a> ctx::TryFromCtx<'a, Ctx> for SectionHeader {
542        type Error = crate::error::Error;
543        fn try_from_ctx(bytes: &'a [u8], Ctx {container, le}: Ctx) -> result::Result<(Self, usize), Self::Error> {
544            use scroll::Pread;
545            let res = match container {
546                Container::Little => {
547                    (bytes.pread_with::<section_header32::SectionHeader>(0, le)?.into(), section_header32::SIZEOF_SHDR)
548                },
549                Container::Big => {
550                    (bytes.pread_with::<section_header64::SectionHeader>(0, le)?.into(), section_header64::SIZEOF_SHDR)
551                }
552            };
553            Ok(res)
554        }
555    }
556
557    impl ctx::TryIntoCtx<Ctx> for SectionHeader {
558        type Error = crate::error::Error;
559        fn try_into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) -> result::Result<usize, Self::Error> {
560            use scroll::Pwrite;
561            match container {
562                Container::Little => {
563                    let shdr: section_header32::SectionHeader = self.into();
564                    Ok(bytes.pwrite_with(shdr, 0, le)?)
565                },
566                Container::Big => {
567                    let shdr: section_header64::SectionHeader = self.into();
568                    Ok(bytes.pwrite_with(shdr, 0, le)?)
569                }
570            }
571        }
572    }
573    impl ctx::IntoCtx<Ctx> for SectionHeader {
574        fn into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) {
575            use scroll::Pwrite;
576            match container {
577                Container::Little => {
578                    let shdr: section_header32::SectionHeader = self.into();
579                    bytes.pwrite_with(shdr, 0, le).unwrap();
580                },
581                Container::Big => {
582                    let shdr: section_header64::SectionHeader = self.into();
583                    bytes.pwrite_with(shdr, 0, le).unwrap();
584                }
585            }
586        }
587    }
588} // end if_alloc