Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  writer.rs   Sprache: unbekannt

 
//! Helper for writing ELF files.
use alloc::string::String;
use alloc::vec::Vec;
use core::mem;

use crate::elf;
use crate::endian::*;
use crate::pod;
use crate::write::string::{StringId, StringTable};
use crate::write::util;
use crate::write::{Error, Result, WritableBuffer};

const ALIGN_SYMTAB_SHNDX: usize = 4;
const ALIGN_HASH: usize = 4;
const ALIGN_GNU_VERSYM: usize = 2;
const ALIGN_GNU_VERDEF: usize = 4;
const ALIGN_GNU_VERNEED: usize = 4;

/// The index of an ELF section.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SectionIndex(pub u32);

/// The index of an ELF symbol.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SymbolIndex(pub u32);

/// A helper for writing ELF files.
///
/// Writing uses a two phase approach. The first phase builds up all of the information
/// that may need to be known ahead of time:
/// - build string tables
/// - reserve section indices
/// - reserve symbol indices
/// - reserve file ranges for headers and sections
///
/// Some of the information has ordering requirements. For example, strings must be added
/// to string tables before reserving the file range for the string table. Symbol indices
/// must be reserved after reserving the section indices they reference. There are debug
/// asserts to check some of these requirements.
///
/// The second phase writes everything out in order. Thus the caller must ensure writing
/// is in the same order that file ranges were reserved. There are debug asserts to assist
/// with checking this.
#[allow(missing_debug_implementations)]
pub struct Writer<'a> {
    endian: Endianness,
    is_64: bool,
    is_mips64el: bool,
    elf_align: usize,

    buffer: &'a mut dyn WritableBuffer,
    len: usize,

    segment_offset: usize,
    segment_num: u32,

    section_offset: usize,
    section_num: u32,

    shstrtab: StringTable<'a>,
    shstrtab_str_id: Option<StringId>,
    shstrtab_index: SectionIndex,
    shstrtab_offset: usize,
    shstrtab_data: Vec<u8>,

    need_strtab: bool,
    strtab: StringTable<'a>,
    strtab_str_id: Option<StringId>,
    strtab_index: SectionIndex,
    strtab_offset: usize,
    strtab_data: Vec<u8>,

    symtab_str_id: Option<StringId>,
    symtab_index: SectionIndex,
    symtab_offset: usize,
    symtab_num: u32,

    need_symtab_shndx: bool,
    symtab_shndx_str_id: Option<StringId>,
    symtab_shndx_offset: usize,
    symtab_shndx_data: Vec<u8>,

    need_dynstr: bool,
    dynstr: StringTable<'a>,
    dynstr_str_id: Option<StringId>,
    dynstr_index: SectionIndex,
    dynstr_offset: usize,
    dynstr_data: Vec<u8>,

    dynsym_str_id: Option<StringId>,
    dynsym_index: SectionIndex,
    dynsym_offset: usize,
    dynsym_num: u32,

    dynamic_str_id: Option<StringId>,
    dynamic_offset: usize,
    dynamic_num: usize,

    hash_str_id: Option<StringId>,
    hash_offset: usize,
    hash_size: usize,

    gnu_hash_str_id: Option<StringId>,
    gnu_hash_offset: usize,
    gnu_hash_size: usize,

    gnu_versym_str_id: Option<StringId>,
    gnu_versym_offset: usize,

    gnu_verdef_str_id: Option<StringId>,
    gnu_verdef_offset: usize,
    gnu_verdef_size: usize,
    gnu_verdef_count: u16,
    gnu_verdef_remaining: u16,
    gnu_verdaux_remaining: u16,

    gnu_verneed_str_id: Option<StringId>,
    gnu_verneed_offset: usize,
    gnu_verneed_size: usize,
    gnu_verneed_count: u16,
    gnu_verneed_remaining: u16,
    gnu_vernaux_remaining: u16,

    gnu_attributes_str_id: Option<StringId>,
    gnu_attributes_offset: usize,
    gnu_attributes_size: usize,
}

impl<'a> Writer<'a> {
    /// Create a new `Writer` for the given endianness and ELF class.
    pub fn new(endian: Endianness, is_64: bool, buffer: &'a mut dyn WritableBuffer) -> Self {
        let elf_align = if is_64 { 8 } else { 4 };
        Writer {
            endian,
            is_64,
            // Determined later.
            is_mips64el: false,
            elf_align,

            buffer,
            len: 0,

            segment_offset: 0,
            segment_num: 0,

            section_offset: 0,
            section_num: 0,

            shstrtab: StringTable::default(),
            shstrtab_str_id: None,
            shstrtab_index: SectionIndex(0),
            shstrtab_offset: 0,
            shstrtab_data: Vec::new(),

            need_strtab: false,
            strtab: StringTable::default(),
            strtab_str_id: None,
            strtab_index: SectionIndex(0),
            strtab_offset: 0,
            strtab_data: Vec::new(),

            symtab_str_id: None,
            symtab_index: SectionIndex(0),
            symtab_offset: 0,
            symtab_num: 0,

            need_symtab_shndx: false,
            symtab_shndx_str_id: None,
            symtab_shndx_offset: 0,
            symtab_shndx_data: Vec::new(),

            need_dynstr: false,
            dynstr: StringTable::default(),
            dynstr_str_id: None,
            dynstr_index: SectionIndex(0),
            dynstr_offset: 0,
            dynstr_data: Vec::new(),

            dynsym_str_id: None,
            dynsym_index: SectionIndex(0),
            dynsym_offset: 0,
            dynsym_num: 0,

            dynamic_str_id: None,
            dynamic_offset: 0,
            dynamic_num: 0,

            hash_str_id: None,
            hash_offset: 0,
            hash_size: 0,

            gnu_hash_str_id: None,
            gnu_hash_offset: 0,
            gnu_hash_size: 0,

            gnu_versym_str_id: None,
            gnu_versym_offset: 0,

            gnu_verdef_str_id: None,
            gnu_verdef_offset: 0,
            gnu_verdef_size: 0,
            gnu_verdef_count: 0,
            gnu_verdef_remaining: 0,
            gnu_verdaux_remaining: 0,

            gnu_verneed_str_id: None,
            gnu_verneed_offset: 0,
            gnu_verneed_size: 0,
            gnu_verneed_count: 0,
            gnu_verneed_remaining: 0,
            gnu_vernaux_remaining: 0,

            gnu_attributes_str_id: None,
            gnu_attributes_offset: 0,
            gnu_attributes_size: 0,
        }
    }

    /// Get the file class that will be written.
    fn class(&self) -> Class {
        Class { is_64: self.is_64 }
    }

    /// Return the current file length that has been reserved.
    pub fn reserved_len(&self) -> usize {
        self.len
    }

    /// Return the current file length that has been written.
    #[allow(clippy::len_without_is_empty)]
    pub fn len(&self) -> usize {
        self.buffer.len()
    }

    /// Reserve a file range with the given size and starting alignment.
    ///
    /// Returns the aligned offset of the start of the range.
    ///
    /// `align_start` must be a power of two.
    pub fn reserve(&mut self, len: usize, align_start: usize) -> usize {
        if align_start > 1 {
            self.len = util::align(self.len, align_start);
        }
        let offset = self.len;
        self.len += len;
        offset
    }

    /// Write alignment padding bytes.
    pub fn write_align(&mut self, align_start: usize) {
        if align_start > 1 {
            util::write_align(self.buffer, align_start);
        }
    }

    /// Write data.
    ///
    /// This is typically used to write section data.
    pub fn write(&mut self, data: &[u8]) {
        self.buffer.write_bytes(data);
    }

    /// Reserve the file range up to the given file offset.
    pub fn reserve_until(&mut self, offset: usize) {
        debug_assert!(self.len <= offset);
        self.len = offset;
    }

    /// Write padding up to the given file offset.
    pub fn pad_until(&mut self, offset: usize) {
        debug_assert!(self.buffer.len() <= offset);
        self.buffer.resize(offset);
    }

    /// Reserve the range for the file header.
    ///
    /// This must be at the start of the file.
    pub fn reserve_file_header(&mut self) {
        debug_assert_eq!(self.len, 0);
        self.reserve(self.class().file_header_size(), 1);
    }

    /// Write the file header.
    ///
    /// This must be at the start of the file.
    ///
    /// Fields that can be derived from known information are automatically set by this function.
    pub fn write_file_header(&mut self, header: &FileHeader) -> Result<()> {
        debug_assert_eq!(self.buffer.len(), 0);

        self.is_mips64el =
            self.is_64 && self.endian.is_little_endian() && header.e_machine == elf::EM_MIPS;

        // Start writing.
        self.buffer
            .reserve(self.len)
            .map_err(|_| Error(String::from("Cannot allocate buffer")))?;

        // Write file header.
        let e_ident = elf::Ident {
            magic: elf::ELFMAG,
            class: if self.is_64 {
                elf::ELFCLASS64
            } else {
                elf::ELFCLASS32
            },
            data: if self.endian.is_little_endian() {
                elf::ELFDATA2LSB
            } else {
                elf::ELFDATA2MSB
            },
            version: elf::EV_CURRENT,
            os_abi: header.os_abi,
            abi_version: header.abi_version,
            padding: [0; 7],
        };

        let e_ehsize = self.class().file_header_size() as u16;

        let e_phoff = self.segment_offset as u64;
        let e_phentsize = if self.segment_num == 0 {
            0
        } else {
            self.class().program_header_size() as u16
        };
        // TODO: overflow
        let e_phnum = self.segment_num as u16;

        let e_shoff = self.section_offset as u64;
        let e_shentsize = if self.section_num == 0 {
            0
        } else {
            self.class().section_header_size() as u16
        };
        let e_shnum = if self.section_num >= elf::SHN_LORESERVE.into() {
            0
        } else {
            self.section_num as u16
        };
        let e_shstrndx = if self.shstrtab_index.0 >= elf::SHN_LORESERVE.into() {
            elf::SHN_XINDEX
        } else {
            self.shstrtab_index.0 as u16
        };

        let endian = self.endian;
        if self.is_64 {
            let file = elf::FileHeader64 {
                e_ident,
                e_type: U16::new(endian, header.e_type),
                e_machine: U16::new(endian, header.e_machine),
                e_version: U32::new(endian, elf::EV_CURRENT.into()),
                e_entry: U64::new(endian, header.e_entry),
                e_phoff: U64::new(endian, e_phoff),
                e_shoff: U64::new(endian, e_shoff),
                e_flags: U32::new(endian, header.e_flags),
                e_ehsize: U16::new(endian, e_ehsize),
                e_phentsize: U16::new(endian, e_phentsize),
                e_phnum: U16::new(endian, e_phnum),
                e_shentsize: U16::new(endian, e_shentsize),
                e_shnum: U16::new(endian, e_shnum),
                e_shstrndx: U16::new(endian, e_shstrndx),
            };
            self.buffer.write(&file)
        } else {
            let file = elf::FileHeader32 {
                e_ident,
                e_type: U16::new(endian, header.e_type),
                e_machine: U16::new(endian, header.e_machine),
                e_version: U32::new(endian, elf::EV_CURRENT.into()),
                e_entry: U32::new(endian, header.e_entry as u32),
                e_phoff: U32::new(endian, e_phoff as u32),
                e_shoff: U32::new(endian, e_shoff as u32),
                e_flags: U32::new(endian, header.e_flags),
                e_ehsize: U16::new(endian, e_ehsize),
                e_phentsize: U16::new(endian, e_phentsize),
                e_phnum: U16::new(endian, e_phnum),
                e_shentsize: U16::new(endian, e_shentsize),
                e_shnum: U16::new(endian, e_shnum),
                e_shstrndx: U16::new(endian, e_shstrndx),
            };
            self.buffer.write(&file);
        }

        Ok(())
    }

    /// Reserve the range for the program headers.
    pub fn reserve_program_headers(&mut self, num: u32) {
        debug_assert_eq!(self.segment_offset, 0);
        if num == 0 {
            return;
        }
        self.segment_num = num;
        self.segment_offset = self.reserve(
            num as usize * self.class().program_header_size(),
            self.elf_align,
        );
    }

    /// Write alignment padding bytes prior to the program headers.
    pub fn write_align_program_headers(&mut self) {
        if self.segment_offset == 0 {
            return;
        }
        util::write_align(self.buffer, self.elf_align);
        debug_assert_eq!(self.segment_offset, self.buffer.len());
    }

    /// Write a program header.
    pub fn write_program_header(&mut self, header: &ProgramHeader) {
        let endian = self.endian;
        if self.is_64 {
            let header = elf::ProgramHeader64 {
                p_type: U32::new(endian, header.p_type),
                p_flags: U32::new(endian, header.p_flags),
                p_offset: U64::new(endian, header.p_offset),
                p_vaddr: U64::new(endian, header.p_vaddr),
                p_paddr: U64::new(endian, header.p_paddr),
                p_filesz: U64::new(endian, header.p_filesz),
                p_memsz: U64::new(endian, header.p_memsz),
                p_align: U64::new(endian, header.p_align),
            };
            self.buffer.write(&header);
        } else {
            let header = elf::ProgramHeader32 {
                p_type: U32::new(endian, header.p_type),
                p_offset: U32::new(endian, header.p_offset as u32),
                p_vaddr: U32::new(endian, header.p_vaddr as u32),
                p_paddr: U32::new(endian, header.p_paddr as u32),
                p_filesz: U32::new(endian, header.p_filesz as u32),
                p_memsz: U32::new(endian, header.p_memsz as u32),
                p_flags: U32::new(endian, header.p_flags),
                p_align: U32::new(endian, header.p_align as u32),
            };
            self.buffer.write(&header);
        }
    }

    /// Reserve the section index for the null section header.
    ///
    /// The null section header is usually automatically reserved,
    /// but this can be used to force an empty section table.
    ///
    /// This must be called before [`Self::reserve_section_headers`].
    pub fn reserve_null_section_index(&mut self) -> SectionIndex {
        debug_assert_eq!(self.section_num, 0);
        if self.section_num == 0 {
            self.section_num = 1;
        }
        SectionIndex(0)
    }

    /// Reserve a section table index.
    ///
    /// Automatically also reserves the null section header if required.
    ///
    /// This must be called before [`Self::reserve_section_headers`].
    pub fn reserve_section_index(&mut self) -> SectionIndex {
        debug_assert_eq!(self.section_offset, 0);
        if self.section_num == 0 {
            self.section_num = 1;
        }
        let index = self.section_num;
        self.section_num += 1;
        SectionIndex(index)
    }

    /// Reserve the range for the section headers.
    ///
    /// This function does nothing if no sections were reserved.
    /// This must be called after [`Self::reserve_section_index`]
    /// and other functions that reserve section indices.
    pub fn reserve_section_headers(&mut self) {
        debug_assert_eq!(self.section_offset, 0);
        if self.section_num == 0 {
            return;
        }
        self.section_offset = self.reserve(
            self.section_num as usize * self.class().section_header_size(),
            self.elf_align,
        );
    }

    /// Write the null section header.
    ///
    /// This must be the first section header that is written.
    /// This function does nothing if no sections were reserved.
    pub fn write_null_section_header(&mut self) {
        if self.section_num == 0 {
            return;
        }
        util::write_align(self.buffer, self.elf_align);
        debug_assert_eq!(self.section_offset, self.buffer.len());
        self.write_section_header(&SectionHeader {
            name: None,
            sh_type: 0,
            sh_flags: 0,
            sh_addr: 0,
            sh_offset: 0,
            sh_size: if self.section_num >= elf::SHN_LORESERVE.into() {
                self.section_num.into()
            } else {
                0
            },
            sh_link: if self.shstrtab_index.0 >= elf::SHN_LORESERVE.into() {
                self.shstrtab_index.0
            } else {
                0
            },
            // TODO: e_phnum overflow
            sh_info: 0,
            sh_addralign: 0,
            sh_entsize: 0,
        });
    }

    /// Write a section header.
    pub fn write_section_header(&mut self, section: &SectionHeader) {
        let sh_name = if let Some(name) = section.name {
            self.shstrtab.get_offset(name) as u32
        } else {
            0
        };
        let endian = self.endian;
        if self.is_64 {
            let section = elf::SectionHeader64 {
                sh_name: U32::new(endian, sh_name),
                sh_type: U32::new(endian, section.sh_type),
                sh_flags: U64::new(endian, section.sh_flags),
                sh_addr: U64::new(endian, section.sh_addr),
                sh_offset: U64::new(endian, section.sh_offset),
                sh_size: U64::new(endian, section.sh_size),
                sh_link: U32::new(endian, section.sh_link),
                sh_info: U32::new(endian, section.sh_info),
                sh_addralign: U64::new(endian, section.sh_addralign),
                sh_entsize: U64::new(endian, section.sh_entsize),
            };
            self.buffer.write(§ion);
        } else {
            let section = elf::SectionHeader32 {
                sh_name: U32::new(endian, sh_name),
                sh_type: U32::new(endian, section.sh_type),
                sh_flags: U32::new(endian, section.sh_flags as u32),
                sh_addr: U32::new(endian, section.sh_addr as u32),
                sh_offset: U32::new(endian, section.sh_offset as u32),
                sh_size: U32::new(endian, section.sh_size as u32),
                sh_link: U32::new(endian, section.sh_link),
                sh_info: U32::new(endian, section.sh_info),
                sh_addralign: U32::new(endian, section.sh_addralign as u32),
                sh_entsize: U32::new(endian, section.sh_entsize as u32),
            };
            self.buffer.write(§ion);
        }
    }

    /// Add a section name to the section header string table.
    ///
    /// This will be stored in the `.shstrtab` section.
    ///
    /// This must be called before [`Self::reserve_shstrtab`].
    pub fn add_section_name(&mut self, name: &'a [u8]) -> StringId {
        debug_assert_eq!(self.shstrtab_offset, 0);
        self.shstrtab.add(name)
    }

    /// Reserve the range for the section header string table.
    ///
    /// This range is used for a section named `.shstrtab`.
    ///
    /// This function does nothing if no sections were reserved.
    /// This must be called after [`Self::add_section_name`].
    /// and other functions that reserve section names and indices.
    pub fn reserve_shstrtab(&mut self) {
        debug_assert_eq!(self.shstrtab_offset, 0);
        if self.section_num == 0 {
            return;
        }
        // Start with null section name.
        self.shstrtab_data = vec![0];
        self.shstrtab.write(1, &mut self.shstrtab_data);
        self.shstrtab_offset = self.reserve(self.shstrtab_data.len(), 1);
    }

    /// Write the section header string table.
    ///
    /// This function does nothing if the section was not reserved.
    pub fn write_shstrtab(&mut self) {
        if self.shstrtab_offset == 0 {
            return;
        }
        debug_assert_eq!(self.shstrtab_offset, self.buffer.len());
        self.buffer.write_bytes(&self.shstrtab_data);
    }

    /// Reserve the section index for the section header string table.
    ///
    /// This must be called before [`Self::reserve_shstrtab`]
    /// and [`Self::reserve_section_headers`].
    pub fn reserve_shstrtab_section_index(&mut self) -> SectionIndex {
        self.reserve_shstrtab_section_index_with_name(&b".shstrtab"[..])
    }

    /// Reserve the section index for the section header string table.
    ///
    /// This must be called before [`Self::reserve_shstrtab`]
    /// and [`Self::reserve_section_headers`].
    pub fn reserve_shstrtab_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
        debug_assert_eq!(self.shstrtab_index, SectionIndex(0));
        self.shstrtab_str_id = Some(self.add_section_name(name));
        self.shstrtab_index = self.reserve_section_index();
        self.shstrtab_index
    }

    /// Write the section header for the section header string table.
    ///
    /// This function does nothing if the section index was not reserved.
    pub fn write_shstrtab_section_header(&mut self) {
        if self.shstrtab_index == SectionIndex(0) {
            return;
        }
        self.write_section_header(&SectionHeader {
            name: self.shstrtab_str_id,
            sh_type: elf::SHT_STRTAB,
            sh_flags: 0,
            sh_addr: 0,
            sh_offset: self.shstrtab_offset as u64,
            sh_size: self.shstrtab_data.len() as u64,
            sh_link: 0,
            sh_info: 0,
            sh_addralign: 1,
            sh_entsize: 0,
        });
    }

    /// Add a string to the string table.
    ///
    /// This will be stored in the `.strtab` section.
    ///
    /// This must be called before [`Self::reserve_strtab`].
    pub fn add_string(&mut self, name: &'a [u8]) -> StringId {
        debug_assert_eq!(self.strtab_offset, 0);
        self.need_strtab = true;
        self.strtab.add(name)
    }

    /// Return true if `.strtab` is needed.
    pub fn strtab_needed(&self) -> bool {
        self.need_strtab
    }

    /// Require the string table even if no strings were added.
    pub fn require_strtab(&mut self) {
        self.need_strtab = true;
    }

    /// Reserve the range for the string table.
    ///
    /// This range is used for a section named `.strtab`.
    ///
    /// This function does nothing if a string table is not required.
    /// This must be called after [`Self::add_string`].
    pub fn reserve_strtab(&mut self) {
        debug_assert_eq!(self.strtab_offset, 0);
        if !self.need_strtab {
            return;
        }
        // Start with null string.
        self.strtab_data = vec![0];
        self.strtab.write(1, &mut self.strtab_data);
        self.strtab_offset = self.reserve(self.strtab_data.len(), 1);
    }

    /// Write the string table.
    ///
    /// This function does nothing if the section was not reserved.
    pub fn write_strtab(&mut self) {
        if self.strtab_offset == 0 {
            return;
        }
        debug_assert_eq!(self.strtab_offset, self.buffer.len());
        self.buffer.write_bytes(&self.strtab_data);
    }

    /// Reserve the section index for the string table.
    ///
    /// You should check [`Self::strtab_needed`] before calling this
    /// unless you have other means of knowing if this section is needed.
    ///
    /// This must be called before [`Self::reserve_section_headers`].
    pub fn reserve_strtab_section_index(&mut self) -> SectionIndex {
        self.reserve_strtab_section_index_with_name(&b".strtab"[..])
    }

    /// Reserve the section index for the string table.
    ///
    /// You should check [`Self::strtab_needed`] before calling this
    /// unless you have other means of knowing if this section is needed.
    ///
    /// This must be called before [`Self::reserve_section_headers`].
    pub fn reserve_strtab_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
        debug_assert_eq!(self.strtab_index, SectionIndex(0));
        self.strtab_str_id = Some(self.add_section_name(name));
        self.strtab_index = self.reserve_section_index();
        self.strtab_index
    }

    /// Write the section header for the string table.
    ///
    /// This function does nothing if the section index was not reserved.
    pub fn write_strtab_section_header(&mut self) {
        if self.strtab_index == SectionIndex(0) {
            return;
        }
        self.write_section_header(&SectionHeader {
            name: self.strtab_str_id,
            sh_type: elf::SHT_STRTAB,
            sh_flags: 0,
            sh_addr: 0,
            sh_offset: self.strtab_offset as u64,
            sh_size: self.strtab_data.len() as u64,
            sh_link: 0,
            sh_info: 0,
            sh_addralign: 1,
            sh_entsize: 0,
        });
    }

    /// Reserve the null symbol table entry.
    ///
    /// This will be stored in the `.symtab` section.
    ///
    /// The null symbol table entry is usually automatically reserved,
    /// but this can be used to force an empty symbol table.
    ///
    /// This must be called before [`Self::reserve_symtab`].
    pub fn reserve_null_symbol_index(&mut self) -> SymbolIndex {
        debug_assert_eq!(self.symtab_offset, 0);
        debug_assert_eq!(self.symtab_num, 0);
        self.symtab_num = 1;
        // The symtab must link to a strtab.
        self.need_strtab = true;
        SymbolIndex(0)
    }

    /// Reserve a symbol table entry.
    ///
    /// This will be stored in the `.symtab` section.
    ///
    /// `section_index` is used to determine whether `.symtab_shndx` is required.
    ///
    /// Automatically also reserves the null symbol if required.
    /// Callers may assume that the returned indices will be sequential
    /// starting at 1.
    ///
    /// This must be called before [`Self::reserve_symtab`] and
    /// [`Self::reserve_symtab_shndx`].
    pub fn reserve_symbol_index(&mut self, section_index: Option<SectionIndex>) -> SymbolIndex {
        debug_assert_eq!(self.symtab_offset, 0);
        debug_assert_eq!(self.symtab_shndx_offset, 0);
        if self.symtab_num == 0 {
            self.symtab_num = 1;
            // The symtab must link to a strtab.
            self.need_strtab = true;
        }
        let index = self.symtab_num;
        self.symtab_num += 1;
        if let Some(section_index) = section_index {
            if section_index.0 >= elf::SHN_LORESERVE.into() {
                self.need_symtab_shndx = true;
            }
        }
        SymbolIndex(index)
    }

    /// Return the number of reserved symbol table entries.
    ///
    /// Includes the null symbol.
    pub fn symbol_count(&self) -> u32 {
        self.symtab_num
    }

    /// Reserve the range for the symbol table.
    ///
    /// This range is used for a section named `.symtab`.
    /// This function does nothing if no symbols were reserved.
    /// This must be called after [`Self::reserve_symbol_index`].
    pub fn reserve_symtab(&mut self) {
        debug_assert_eq!(self.symtab_offset, 0);
        if self.symtab_num == 0 {
            return;
        }
        self.symtab_offset = self.reserve(
            self.symtab_num as usize * self.class().sym_size(),
            self.elf_align,
        );
    }

    /// Write the null symbol.
    ///
    /// This must be the first symbol that is written.
    /// This function does nothing if no symbols were reserved.
    pub fn write_null_symbol(&mut self) {
        if self.symtab_num == 0 {
            return;
        }
        util::write_align(self.buffer, self.elf_align);
        debug_assert_eq!(self.symtab_offset, self.buffer.len());
        if self.is_64 {
            self.buffer.write(&elf::Sym64::<Endianness>::default());
        } else {
            self.buffer.write(&elf::Sym32::<Endianness>::default());
        }

        if self.need_symtab_shndx {
            self.symtab_shndx_data.write_pod(&U32::new(self.endian, 0));
        }
    }

    /// Write a symbol.
    pub fn write_symbol(&mut self, sym: &Sym) {
        let st_name = if let Some(name) = sym.name {
            self.strtab.get_offset(name) as u32
        } else {
            0
        };
        let st_shndx = if let Some(section) = sym.section {
            if section.0 >= elf::SHN_LORESERVE as u32 {
                elf::SHN_XINDEX
            } else {
                section.0 as u16
            }
        } else {
            sym.st_shndx
        };

        let endian = self.endian;
        if self.is_64 {
            let sym = elf::Sym64 {
                st_name: U32::new(endian, st_name),
                st_info: sym.st_info,
                st_other: sym.st_other,
                st_shndx: U16::new(endian, st_shndx),
                st_value: U64::new(endian, sym.st_value),
                st_size: U64::new(endian, sym.st_size),
            };
            self.buffer.write(&sym);
        } else {
            let sym = elf::Sym32 {
                st_name: U32::new(endian, st_name),
                st_info: sym.st_info,
                st_other: sym.st_other,
                st_shndx: U16::new(endian, st_shndx),
                st_value: U32::new(endian, sym.st_value as u32),
                st_size: U32::new(endian, sym.st_size as u32),
            };
            self.buffer.write(&sym);
        }

        if self.need_symtab_shndx {
            let section_index = sym.section.unwrap_or(SectionIndex(0));
            self.symtab_shndx_data
                .write_pod(&U32::new(self.endian, section_index.0));
        }
    }

    /// Reserve the section index for the symbol table.
    ///
    /// This must be called before [`Self::reserve_section_headers`].
    pub fn reserve_symtab_section_index(&mut self) -> SectionIndex {
        self.reserve_symtab_section_index_with_name(&b".symtab"[..])
    }

    /// Reserve the section index for the symbol table.
    ///
    /// This must be called before [`Self::reserve_section_headers`].
    pub fn reserve_symtab_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
        debug_assert_eq!(self.symtab_index, SectionIndex(0));
        self.symtab_str_id = Some(self.add_section_name(name));
        self.symtab_index = self.reserve_section_index();
        self.symtab_index
    }

    /// Return the section index of the symbol table.
    pub fn symtab_index(&mut self) -> SectionIndex {
        self.symtab_index
    }

    /// Write the section header for the symbol table.
    ///
    /// This function does nothing if the section index was not reserved.
    pub fn write_symtab_section_header(&mut self, num_local: u32) {
        if self.symtab_index == SectionIndex(0) {
            return;
        }
        self.write_section_header(&SectionHeader {
            name: self.symtab_str_id,
            sh_type: elf::SHT_SYMTAB,
            sh_flags: 0,
            sh_addr: 0,
            sh_offset: self.symtab_offset as u64,
            sh_size: self.symtab_num as u64 * self.class().sym_size() as u64,
            sh_link: self.strtab_index.0,
            sh_info: num_local,
            sh_addralign: self.elf_align as u64,
            sh_entsize: self.class().sym_size() as u64,
        });
    }

    /// Return true if `.symtab_shndx` is needed.
    pub fn symtab_shndx_needed(&self) -> bool {
        self.need_symtab_shndx
    }

    /// Require the extended section indices for the symbol table even
    /// if no section indices are too large.
    pub fn require_symtab_shndx(&mut self) {
        self.need_symtab_shndx = true;
    }

    /// Reserve the range for the extended section indices for the symbol table.
    ///
    /// This range is used for a section named `.symtab_shndx`.
    /// This also reserves a section index.
    ///
    /// This function does nothing if extended section indices are not needed.
    /// This must be called after [`Self::reserve_symbol_index`].
    pub fn reserve_symtab_shndx(&mut self) {
        debug_assert_eq!(self.symtab_shndx_offset, 0);
        if !self.need_symtab_shndx {
            return;
        }
        self.symtab_shndx_offset = self.reserve(self.symtab_num as usize * 4, ALIGN_SYMTAB_SHNDX);
        self.symtab_shndx_data.reserve(self.symtab_num as usize * 4);
    }

    /// Write the extended section indices for the symbol table.
    ///
    /// This function does nothing if the section was not reserved.
    pub fn write_symtab_shndx(&mut self) {
        if self.symtab_shndx_offset == 0 {
            return;
        }
        util::write_align(self.buffer, ALIGN_SYMTAB_SHNDX);
        debug_assert_eq!(self.symtab_shndx_offset, self.buffer.len());
        debug_assert_eq!(self.symtab_num as usize * 4, self.symtab_shndx_data.len());
        self.buffer.write_bytes(&self.symtab_shndx_data);
    }

    /// Reserve the section index for the extended section indices symbol table.
    ///
    /// You should check [`Self::symtab_shndx_needed`] before calling this
    /// unless you have other means of knowing if this section is needed.
    ///
    /// This must be called before [`Self::reserve_section_headers`].
    pub fn reserve_symtab_shndx_section_index(&mut self) -> SectionIndex {
        self.reserve_symtab_shndx_section_index_with_name(&b".symtab_shndx"[..])
    }

    /// Reserve the section index for the extended section indices symbol table.
    ///
    /// You should check [`Self::symtab_shndx_needed`] before calling this
    /// unless you have other means of knowing if this section is needed.
    ///
    /// This must be called before [`Self::reserve_section_headers`].
    pub fn reserve_symtab_shndx_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
        debug_assert!(self.symtab_shndx_str_id.is_none());
        self.symtab_shndx_str_id = Some(self.add_section_name(name));
        self.reserve_section_index()
    }

    /// Write the section header for the extended section indices for the symbol table.
    ///
    /// This function does nothing if the section index was not reserved.
    pub fn write_symtab_shndx_section_header(&mut self) {
        if self.symtab_shndx_str_id.is_none() {
            return;
        }
        let sh_size = if self.symtab_shndx_offset == 0 {
            0
        } else {
            (self.symtab_num * 4) as u64
        };
        self.write_section_header(&SectionHeader {
            name: self.symtab_shndx_str_id,
            sh_type: elf::SHT_SYMTAB_SHNDX,
            sh_flags: 0,
            sh_addr: 0,
            sh_offset: self.symtab_shndx_offset as u64,
            sh_size,
            sh_link: self.symtab_index.0,
            sh_info: 0,
            sh_addralign: ALIGN_SYMTAB_SHNDX as u64,
            sh_entsize: 4,
        });
    }

    /// Add a string to the dynamic string table.
    ///
    /// This will be stored in the `.dynstr` section.
    ///
    /// This must be called before [`Self::reserve_dynstr`].
    pub fn add_dynamic_string(&mut self, name: &'a [u8]) -> StringId {
        debug_assert_eq!(self.dynstr_offset, 0);
        self.need_dynstr = true;
        self.dynstr.add(name)
    }

    /// Get a string that was previously added to the dynamic string table.
    ///
    /// Panics if the string was not added.
    pub fn get_dynamic_string(&self, name: &'a [u8]) -> StringId {
        self.dynstr.get_id(name)
    }

    /// Return true if `.dynstr` is needed.
    pub fn dynstr_needed(&self) -> bool {
        self.need_dynstr
    }

    /// Require the dynamic string table even if no strings were added.
    pub fn require_dynstr(&mut self) {
        self.need_dynstr = true;
    }

    /// Reserve the range for the dynamic string table.
    ///
    /// This range is used for a section named `.dynstr`.
    ///
    /// This function does nothing if no dynamic strings were defined.
    /// This must be called after [`Self::add_dynamic_string`].
    pub fn reserve_dynstr(&mut self) -> usize {
        debug_assert_eq!(self.dynstr_offset, 0);
        if !self.need_dynstr {
            return 0;
        }
        // Start with null string.
        self.dynstr_data = vec![0];
        self.dynstr.write(1, &mut self.dynstr_data);
        self.dynstr_offset = self.reserve(self.dynstr_data.len(), 1);
        self.dynstr_offset
    }

    /// Return the size of the dynamic string table.
    ///
    /// This must be called after [`Self::reserve_dynstr`].
    pub fn dynstr_len(&mut self) -> usize {
        debug_assert_ne!(self.dynstr_offset, 0);
        self.dynstr_data.len()
    }

    /// Write the dynamic string table.
    ///
    /// This function does nothing if the section was not reserved.
    pub fn write_dynstr(&mut self) {
        if self.dynstr_offset == 0 {
            return;
        }
        debug_assert_eq!(self.dynstr_offset, self.buffer.len());
        self.buffer.write_bytes(&self.dynstr_data);
    }

    /// Reserve the section index for the dynamic string table.
    ///
    /// You should check [`Self::dynstr_needed`] before calling this
    /// unless you have other means of knowing if this section is needed.
    ///
    /// This must be called before [`Self::reserve_section_headers`].
    pub fn reserve_dynstr_section_index(&mut self) -> SectionIndex {
        self.reserve_dynstr_section_index_with_name(&b".dynstr"[..])
    }

    /// Reserve the section index for the dynamic string table.
    ///
    /// You should check [`Self::dynstr_needed`] before calling this
    /// unless you have other means of knowing if this section is needed.
    ///
    /// This must be called before [`Self::reserve_section_headers`].
    pub fn reserve_dynstr_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
        debug_assert_eq!(self.dynstr_index, SectionIndex(0));
        self.dynstr_str_id = Some(self.add_section_name(name));
        self.dynstr_index = self.reserve_section_index();
        self.dynstr_index
    }

    /// Return the section index of the dynamic string table.
    pub fn dynstr_index(&mut self) -> SectionIndex {
        self.dynstr_index
    }

    /// Write the section header for the dynamic string table.
    ///
    /// This function does nothing if the section index was not reserved.
    pub fn write_dynstr_section_header(&mut self, sh_addr: u64) {
        if self.dynstr_index == SectionIndex(0) {
            return;
        }
        self.write_section_header(&SectionHeader {
            name: self.dynstr_str_id,
            sh_type: elf::SHT_STRTAB,
            sh_flags: elf::SHF_ALLOC.into(),
            sh_addr,
            sh_offset: self.dynstr_offset as u64,
            sh_size: self.dynstr_data.len() as u64,
            sh_link: 0,
            sh_info: 0,
            sh_addralign: 1,
            sh_entsize: 0,
        });
    }

    /// Reserve the null dynamic symbol table entry.
    ///
    /// This will be stored in the `.dynsym` section.
    ///
    /// The null dynamic symbol table entry is usually automatically reserved,
    /// but this can be used to force an empty dynamic symbol table.
    ///
    /// This must be called before [`Self::reserve_dynsym`].
    pub fn reserve_null_dynamic_symbol_index(&mut self) -> SymbolIndex {
        debug_assert_eq!(self.dynsym_offset, 0);
        debug_assert_eq!(self.dynsym_num, 0);
        self.dynsym_num = 1;
        SymbolIndex(0)
    }

    /// Reserve a dynamic symbol table entry.
    ///
    /// This will be stored in the `.dynsym` section.
    ///
    /// Automatically also reserves the null symbol if required.
    /// Callers may assume that the returned indices will be sequential
    /// starting at 1.
    ///
    /// This must be called before [`Self::reserve_dynsym`].
    pub fn reserve_dynamic_symbol_index(&mut self) -> SymbolIndex {
        debug_assert_eq!(self.dynsym_offset, 0);
        if self.dynsym_num == 0 {
            self.dynsym_num = 1;
        }
        let index = self.dynsym_num;
        self.dynsym_num += 1;
        SymbolIndex(index)
    }

    /// Return the number of reserved dynamic symbols.
    ///
    /// Includes the null symbol.
    pub fn dynamic_symbol_count(&mut self) -> u32 {
        self.dynsym_num
    }

    /// Reserve the range for the dynamic symbol table.
    ///
    /// This range is used for a section named `.dynsym`.
    ///
    /// This function does nothing if no dynamic symbols were reserved.
    /// This must be called after [`Self::reserve_dynamic_symbol_index`].
    pub fn reserve_dynsym(&mut self) -> usize {
        debug_assert_eq!(self.dynsym_offset, 0);
        if self.dynsym_num == 0 {
            return 0;
        }
        self.dynsym_offset = self.reserve(
            self.dynsym_num as usize * self.class().sym_size(),
            self.elf_align,
        );
        self.dynsym_offset
    }

    /// Write the null dynamic symbol.
    ///
    /// This must be the first dynamic symbol that is written.
    /// This function does nothing if no dynamic symbols were reserved.
    pub fn write_null_dynamic_symbol(&mut self) {
        if self.dynsym_num == 0 {
            return;
        }
        util::write_align(self.buffer, self.elf_align);
        debug_assert_eq!(self.dynsym_offset, self.buffer.len());
        if self.is_64 {
            self.buffer.write(&elf::Sym64::<Endianness>::default());
        } else {
            self.buffer.write(&elf::Sym32::<Endianness>::default());
        }
    }

    /// Write a dynamic symbol.
    pub fn write_dynamic_symbol(&mut self, sym: &Sym) {
        let st_name = if let Some(name) = sym.name {
            self.dynstr.get_offset(name) as u32
        } else {
            0
        };

        let st_shndx = if let Some(section) = sym.section {
            if section.0 >= elf::SHN_LORESERVE as u32 {
                // TODO: we don't actually write out .dynsym_shndx yet.
                // This is unlikely to be needed though.
                elf::SHN_XINDEX
            } else {
                section.0 as u16
            }
        } else {
            sym.st_shndx
        };

        let endian = self.endian;
        if self.is_64 {
            let sym = elf::Sym64 {
                st_name: U32::new(endian, st_name),
                st_info: sym.st_info,
                st_other: sym.st_other,
                st_shndx: U16::new(endian, st_shndx),
                st_value: U64::new(endian, sym.st_value),
                st_size: U64::new(endian, sym.st_size),
            };
            self.buffer.write(&sym);
        } else {
            let sym = elf::Sym32 {
                st_name: U32::new(endian, st_name),
                st_info: sym.st_info,
                st_other: sym.st_other,
                st_shndx: U16::new(endian, st_shndx),
                st_value: U32::new(endian, sym.st_value as u32),
                st_size: U32::new(endian, sym.st_size as u32),
            };
            self.buffer.write(&sym);
        }
    }

    /// Reserve the section index for the dynamic symbol table.
    ///
    /// This must be called before [`Self::reserve_section_headers`].
    pub fn reserve_dynsym_section_index(&mut self) -> SectionIndex {
        self.reserve_dynsym_section_index_with_name(&b".dynsym"[..])
    }

    /// Reserve the section index for the dynamic symbol table.
    ///
    /// This must be called before [`Self::reserve_section_headers`].
    pub fn reserve_dynsym_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
        debug_assert_eq!(self.dynsym_index, SectionIndex(0));
        self.dynsym_str_id = Some(self.add_section_name(name));
        self.dynsym_index = self.reserve_section_index();
        self.dynsym_index
    }

    /// Return the section index of the dynamic symbol table.
    pub fn dynsym_index(&mut self) -> SectionIndex {
        self.dynsym_index
    }

    /// Write the section header for the dynamic symbol table.
    ///
    /// This function does nothing if the section index was not reserved.
    pub fn write_dynsym_section_header(&mut self, sh_addr: u64, num_local: u32) {
        if self.dynsym_index == SectionIndex(0) {
            return;
        }
        self.write_section_header(&SectionHeader {
            name: self.dynsym_str_id,
            sh_type: elf::SHT_DYNSYM,
            sh_flags: elf::SHF_ALLOC.into(),
            sh_addr,
            sh_offset: self.dynsym_offset as u64,
            sh_size: self.dynsym_num as u64 * self.class().sym_size() as u64,
            sh_link: self.dynstr_index.0,
            sh_info: num_local,
            sh_addralign: self.elf_align as u64,
            sh_entsize: self.class().sym_size() as u64,
        });
    }

    /// Reserve the range for the `.dynamic` section.
    ///
    /// This function does nothing if `dynamic_num` is zero.
    pub fn reserve_dynamic(&mut self, dynamic_num: usize) -> usize {
        debug_assert_eq!(self.dynamic_offset, 0);
        if dynamic_num == 0 {
            return 0;
        }
        self.dynamic_num = dynamic_num;
        self.dynamic_offset = self.reserve_dynamics(dynamic_num);
        self.dynamic_offset
    }

    /// Write alignment padding bytes prior to the `.dynamic` section.
    ///
    /// This function does nothing if the section was not reserved.
    pub fn write_align_dynamic(&mut self) {
        if self.dynamic_offset == 0 {
            return;
        }
        util::write_align(self.buffer, self.elf_align);
        debug_assert_eq!(self.dynamic_offset, self.buffer.len());
    }

    /// Reserve a file range for the given number of dynamic entries.
    ///
    /// Returns the offset of the range.
    pub fn reserve_dynamics(&mut self, dynamic_num: usize) -> usize {
        self.reserve(dynamic_num * self.class().dyn_size(), self.elf_align)
    }

    /// Write a dynamic string entry.
    pub fn write_dynamic_string(&mut self, tag: u32, id: StringId) {
        self.write_dynamic(tag, self.dynstr.get_offset(id) as u64);
    }

    /// Write a dynamic value entry.
    pub fn write_dynamic(&mut self, d_tag: u32, d_val: u64) {
        let endian = self.endian;
        if self.is_64 {
            let d = elf::Dyn64 {
                d_tag: U64::new(endian, d_tag.into()),
                d_val: U64::new(endian, d_val),
            };
            self.buffer.write(&d);
        } else {
            let d = elf::Dyn32 {
                d_tag: U32::new(endian, d_tag),
                d_val: U32::new(endian, d_val as u32),
            };
            self.buffer.write(&d);
        }
    }

    /// Reserve the section index for the dynamic table.
    pub fn reserve_dynamic_section_index(&mut self) -> SectionIndex {
        debug_assert!(self.dynamic_str_id.is_none());
        self.dynamic_str_id = Some(self.add_section_name(&b".dynamic"[..]));
        self.reserve_section_index()
    }

    /// Write the section header for the dynamic table.
    ///
    /// This function does nothing if the section index was not reserved.
    pub fn write_dynamic_section_header(&mut self, sh_addr: u64) {
        if self.dynamic_str_id.is_none() {
            return;
        }
        self.write_section_header(&SectionHeader {
            name: self.dynamic_str_id,
            sh_type: elf::SHT_DYNAMIC,
            sh_flags: (elf::SHF_WRITE | elf::SHF_ALLOC).into(),
            sh_addr,
            sh_offset: self.dynamic_offset as u64,
            sh_size: (self.dynamic_num * self.class().dyn_size()) as u64,
            sh_link: self.dynstr_index.0,
            sh_info: 0,
            sh_addralign: self.elf_align as u64,
            sh_entsize: self.class().dyn_size() as u64,
        });
    }

    /// Reserve a file range for a SysV hash section.
    ///
    /// `symbol_count` is the number of symbols in the hash,
    /// not the total number of symbols.
    pub fn reserve_hash(&mut self, bucket_count: u32, chain_count: u32) -> usize {
        self.hash_size = self.class().hash_size(bucket_count, chain_count);
        self.hash_offset = self.reserve(self.hash_size, ALIGN_HASH);
        self.hash_offset
    }

    /// Write a SysV hash section.
    ///
    /// `chain_count` is the number of symbols in the hash.
    /// The argument to `hash` will be in the range `0..chain_count`.
    pub fn write_hash<F>(&mut self, bucket_count: u32, chain_count: u32, hash: F)
    where
        F: Fn(u32) -> Option<u32>,
    {
        let mut buckets = vec![U32::new(self.endian, 0); bucket_count as usize];
        let mut chains = vec![U32::new(self.endian, 0); chain_count as usize];
        for i in 0..chain_count {
            if let Some(hash) = hash(i) {
                let bucket = hash % bucket_count;
                chains[i as usize] = buckets[bucket as usize];
                buckets[bucket as usize] = U32::new(self.endian, i);
            }
        }

        util::write_align(self.buffer, ALIGN_HASH);
        debug_assert_eq!(self.hash_offset, self.buffer.len());
        self.buffer.write(&elf::HashHeader {
            bucket_count: U32::new(self.endian, bucket_count),
            chain_count: U32::new(self.endian, chain_count),
        });
        self.buffer.write_slice(&buckets);
        self.buffer.write_slice(&chains);
    }

    /// Reserve the section index for the SysV hash table.
    pub fn reserve_hash_section_index(&mut self) -> SectionIndex {
        self.reserve_hash_section_index_with_name(&b".hash"[..])
    }

    /// Reserve the section index for the SysV hash table.
    pub fn reserve_hash_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
        debug_assert!(self.hash_str_id.is_none());
        self.hash_str_id = Some(self.add_section_name(name));
        self.reserve_section_index()
    }

    /// Write the section header for the SysV hash table.
    ///
    /// This function does nothing if the section index was not reserved.
    pub fn write_hash_section_header(&mut self, sh_addr: u64) {
        if self.hash_str_id.is_none() {
            return;
        }
        self.write_section_header(&SectionHeader {
            name: self.hash_str_id,
            sh_type: elf::SHT_HASH,
            sh_flags: elf::SHF_ALLOC.into(),
            sh_addr,
            sh_offset: self.hash_offset as u64,
            sh_size: self.hash_size as u64,
            sh_link: self.dynsym_index.0,
            sh_info: 0,
            sh_addralign: ALIGN_HASH as u64,
            sh_entsize: 4,
        });
    }

    /// Reserve a file range for a GNU hash section.
    ///
    /// `symbol_count` is the number of symbols in the hash,
    /// not the total number of symbols.
    pub fn reserve_gnu_hash(
        &mut self,
        bloom_count: u32,
        bucket_count: u32,
        symbol_count: u32,
    ) -> usize {
        self.gnu_hash_size = self
            .class()
            .gnu_hash_size(bloom_count, bucket_count, symbol_count);
        self.gnu_hash_offset = self.reserve(self.gnu_hash_size, self.elf_align);
        self.gnu_hash_offset
    }

    /// Write a GNU hash section.
    ///
    /// `symbol_count` is the number of symbols in the hash.
    /// The argument to `hash` will be in the range `0..symbol_count`.
    ///
    /// This requires that symbols are already sorted by bucket.
    pub fn write_gnu_hash<F>(
        &mut self,
        symbol_base: u32,
        bloom_shift: u32,
        bloom_count: u32,
        bucket_count: u32,
        symbol_count: u32,
        hash: F,
    ) where
        F: Fn(u32) -> u32,
    {
        util::write_align(self.buffer, self.elf_align);
        debug_assert_eq!(self.gnu_hash_offset, self.buffer.len());
        self.buffer.write(&elf::GnuHashHeader {
            bucket_count: U32::new(self.endian, bucket_count),
            symbol_base: U32::new(self.endian, symbol_base),
            bloom_count: U32::new(self.endian, bloom_count),
            bloom_shift: U32::new(self.endian, bloom_shift),
        });

        // Calculate and write bloom filter.
        if self.is_64 {
            let mut bloom_filters = vec![0; bloom_count as usize];
            for i in 0..symbol_count {
                let h = hash(i);
                bloom_filters[((h / 64) & (bloom_count - 1)) as usize] |=
                    1 << (h % 64) | 1 << ((h >> bloom_shift) % 64);
            }
            for bloom_filter in bloom_filters {
                self.buffer.write(&U64::new(self.endian, bloom_filter));
            }
        } else {
            let mut bloom_filters = vec![0; bloom_count as usize];
            for i in 0..symbol_count {
                let h = hash(i);
                bloom_filters[((h / 32) & (bloom_count - 1)) as usize] |=
                    1 << (h % 32) | 1 << ((h >> bloom_shift) % 32);
            }
            for bloom_filter in bloom_filters {
                self.buffer.write(&U32::new(self.endian, bloom_filter));
            }
        }

        // Write buckets.
        //
        // This requires that symbols are already sorted by bucket.
        let mut bucket = 0;
        for i in 0..symbol_count {
            let symbol_bucket = hash(i) % bucket_count;
            while bucket < symbol_bucket {
                self.buffer.write(&U32::new(self.endian, 0));
                bucket += 1;
            }
            if bucket == symbol_bucket {
                self.buffer.write(&U32::new(self.endian, symbol_base + i));
                bucket += 1;
            }
        }
        while bucket < bucket_count {
            self.buffer.write(&U32::new(self.endian, 0));
            bucket += 1;
        }

        // Write hash values.
        for i in 0..symbol_count {
            let mut h = hash(i);
            if i == symbol_count - 1 || h % bucket_count != hash(i + 1) % bucket_count {
                h |= 1;
            } else {
                h &= !1;
            }
            self.buffer.write(&U32::new(self.endian, h));
        }
    }

    /// Reserve the section index for the GNU hash table.
    pub fn reserve_gnu_hash_section_index(&mut self) -> SectionIndex {
        self.reserve_gnu_hash_section_index_with_name(&b".gnu.hash"[..])
    }

    /// Reserve the section index for the GNU hash table.
    pub fn reserve_gnu_hash_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
        debug_assert!(self.gnu_hash_str_id.is_none());
        self.gnu_hash_str_id = Some(self.add_section_name(name));
        self.reserve_section_index()
    }

    /// Write the section header for the GNU hash table.
    ///
    /// This function does nothing if the section index was not reserved.
    pub fn write_gnu_hash_section_header(&mut self, sh_addr: u64) {
        if self.gnu_hash_str_id.is_none() {
            return;
        }
        self.write_section_header(&SectionHeader {
            name: self.gnu_hash_str_id,
            sh_type: elf::SHT_GNU_HASH,
            sh_flags: elf::SHF_ALLOC.into(),
            sh_addr,
            sh_offset: self.gnu_hash_offset as u64,
            sh_size: self.gnu_hash_size as u64,
            sh_link: self.dynsym_index.0,
            sh_info: 0,
            sh_addralign: self.elf_align as u64,
            sh_entsize: if self.is_64 { 0 } else { 4 },
        });
    }

    /// Reserve the range for the `.gnu.version` section.
    ///
    /// This function does nothing if no dynamic symbols were reserved.
    pub fn reserve_gnu_versym(&mut self) -> usize {
        debug_assert_eq!(self.gnu_versym_offset, 0);
        if self.dynsym_num == 0 {
            return 0;
        }
        self.gnu_versym_offset = self.reserve(self.dynsym_num as usize * 2, ALIGN_GNU_VERSYM);
        self.gnu_versym_offset
    }

    /// Write the null symbol version entry.
    ///
    /// This must be the first symbol version that is written.
    /// This function does nothing if no dynamic symbols were reserved.
    pub fn write_null_gnu_versym(&mut self) {
        if self.dynsym_num == 0 {
            return;
        }
        util::write_align(self.buffer, ALIGN_GNU_VERSYM);
        debug_assert_eq!(self.gnu_versym_offset, self.buffer.len());
        self.write_gnu_versym(0);
    }

    /// Write a symbol version entry.
    pub fn write_gnu_versym(&mut self, versym: u16) {
        self.buffer.write(&U16::new(self.endian, versym));
    }

    /// Reserve the section index for the `.gnu.version` section.
    pub fn reserve_gnu_versym_section_index(&mut self) -> SectionIndex {
        self.reserve_gnu_versym_section_index_with_name(&b".gnu.version"[..])
    }

    /// Reserve the section index for the `.gnu.version` section.
    pub fn reserve_gnu_versym_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
        debug_assert!(self.gnu_versym_str_id.is_none());
        self.gnu_versym_str_id = Some(self.add_section_name(name));
        self.reserve_section_index()
    }

    /// Write the section header for the `.gnu.version` section.
    ///
    /// This function does nothing if the section index was not reserved.
    pub fn write_gnu_versym_section_header(&mut self, sh_addr: u64) {
        if self.gnu_versym_str_id.is_none() {
            return;
        }
        self.write_section_header(&SectionHeader {
            name: self.gnu_versym_str_id,
            sh_type: elf::SHT_GNU_VERSYM,
            sh_flags: elf::SHF_ALLOC.into(),
            sh_addr,
            sh_offset: self.gnu_versym_offset as u64,
            sh_size: self.class().gnu_versym_size(self.dynsym_num as usize) as u64,
            sh_link: self.dynsym_index.0,
            sh_info: 0,
            sh_addralign: ALIGN_GNU_VERSYM as u64,
            sh_entsize: 2,
        });
    }

    /// Reserve the range for the `.gnu.version_d` section.
    pub fn reserve_gnu_verdef(&mut self, verdef_count: usize, verdaux_count: usize) -> usize {
        debug_assert_eq!(self.gnu_verdef_offset, 0);
        if verdef_count == 0 {
            return 0;
        }
        self.gnu_verdef_size = self.class().gnu_verdef_size(verdef_count, verdaux_count);
        self.gnu_verdef_offset = self.reserve(self.gnu_verdef_size, ALIGN_GNU_VERDEF);
        self.gnu_verdef_count = verdef_count as u16;
        self.gnu_verdef_remaining = self.gnu_verdef_count;
        self.gnu_verdef_offset
    }

    /// Write alignment padding bytes prior to a `.gnu.version_d` section.
    pub fn write_align_gnu_verdef(&mut self) {
        if self.gnu_verdef_offset == 0 {
            return;
        }
        util::write_align(self.buffer, ALIGN_GNU_VERDEF);
        debug_assert_eq!(self.gnu_verdef_offset, self.buffer.len());
    }

    /// Write a version definition entry.
    pub fn write_gnu_verdef(&mut self, verdef: &Verdef) {
        debug_assert_ne!(self.gnu_verdef_remaining, 0);
        self.gnu_verdef_remaining -= 1;
        let vd_next = if self.gnu_verdef_remaining == 0 {
            0
        } else {
            mem::size_of::<elf::Verdef<Endianness>>() as u32
                + verdef.aux_count as u32 * mem::size_of::<elf::Verdaux<Endianness>>() as u32
        };

        debug_assert_ne!(verdef.aux_count, 0);
        self.gnu_verdaux_remaining = verdef.aux_count;
        let vd_aux = mem::size_of::<elf::Verdef<Endianness>>() as u32;

        self.buffer.write(&elf::Verdef {
            vd_version: U16::new(self.endian, verdef.version),
            vd_flags: U16::new(self.endian, verdef.flags),
            vd_ndx: U16::new(self.endian, verdef.index),
            vd_cnt: U16::new(self.endian, verdef.aux_count),
            vd_hash: U32::new(self.endian, elf::hash(self.dynstr.get_string(verdef.name))),
            vd_aux: U32::new(self.endian, vd_aux),
            vd_next: U32::new(self.endian, vd_next),
        });
        self.write_gnu_verdaux(verdef.name);
    }

    /// Write a version definition entry that shares the names of the next definition.
    ///
    /// This is typically useful when there are only two versions (including the base)
    /// and they have the same name.
    pub fn write_gnu_verdef_shared(&mut self, verdef: &Verdef) {
        debug_assert_ne!(self.gnu_verdef_remaining, 0);
        self.gnu_verdef_remaining -= 1;
        debug_assert_ne!(self.gnu_verdef_remaining, 0);
        let vd_next = mem::size_of::<elf::Verdef<Endianness>>() as u32;

        debug_assert_ne!(verdef.aux_count, 0);
        self.gnu_verdaux_remaining = 0;
        let vd_aux = 2 * mem::size_of::<elf::Verdef<Endianness>>() as u32;

        self.buffer.write(&elf::Verdef {
            vd_version: U16::new(self.endian, verdef.version),
            vd_flags: U16::new(self.endian, verdef.flags),
            vd_ndx: U16::new(self.endian, verdef.index),
            vd_cnt: U16::new(self.endian, verdef.aux_count),
            vd_hash: U32::new(self.endian, elf::hash(self.dynstr.get_string(verdef.name))),
            vd_aux: U32::new(self.endian, vd_aux),
            vd_next: U32::new(self.endian, vd_next),
        });
    }

    /// Write a version definition auxiliary entry.
    pub fn write_gnu_verdaux(&mut self, name: StringId) {
        debug_assert_ne!(self.gnu_verdaux_remaining, 0);
        self.gnu_verdaux_remaining -= 1;
        let vda_next = if self.gnu_verdaux_remaining == 0 {
            0
        } else {
            mem::size_of::<elf::Verdaux<Endianness>>() as u32
        };
        self.buffer.write(&elf::Verdaux {
            vda_name: U32::new(self.endian, self.dynstr.get_offset(name) as u32),
            vda_next: U32::new(self.endian, vda_next),
        });
    }

    /// Reserve the section index for the `.gnu.version_d` section.
    pub fn reserve_gnu_verdef_section_index(&mut self) -> SectionIndex {
        self.reserve_gnu_verdef_section_index_with_name(&b".gnu.version_d"[..])
    }

    /// Reserve the section index for the `.gnu.version_d` section.
    pub fn reserve_gnu_verdef_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
        debug_assert!(self.gnu_verdef_str_id.is_none());
        self.gnu_verdef_str_id = Some(self.add_section_name(name));
        self.reserve_section_index()
    }

    /// Write the section header for the `.gnu.version_d` section.
    ///
    /// This function does nothing if the section index was not reserved.
    pub fn write_gnu_verdef_section_header(&mut self, sh_addr: u64) {
        if self.gnu_verdef_str_id.is_none() {
            return;
        }
        self.write_section_header(&SectionHeader {
            name: self.gnu_verdef_str_id,
            sh_type: elf::SHT_GNU_VERDEF,
            sh_flags: elf::SHF_ALLOC.into(),
            sh_addr,
            sh_offset: self.gnu_verdef_offset as u64,
            sh_size: self.gnu_verdef_size as u64,
            sh_link: self.dynstr_index.0,
            sh_info: self.gnu_verdef_count.into(),
            sh_addralign: ALIGN_GNU_VERDEF as u64,
            sh_entsize: 0,
        });
    }

    /// Reserve the range for the `.gnu.version_r` section.
    pub fn reserve_gnu_verneed(&mut self, verneed_count: usize, vernaux_count: usize) -> usize {
        debug_assert_eq!(self.gnu_verneed_offset, 0);
        if verneed_count == 0 {
            return 0;
        }
        self.gnu_verneed_size = self.class().gnu_verneed_size(verneed_count, vernaux_count);
        self.gnu_verneed_offset = self.reserve(self.gnu_verneed_size, ALIGN_GNU_VERNEED);
        self.gnu_verneed_count = verneed_count as u16;
        self.gnu_verneed_remaining = self.gnu_verneed_count;
        self.gnu_verneed_offset
    }

    /// Write alignment padding bytes prior to a `.gnu.version_r` section.
    pub fn write_align_gnu_verneed(&mut self) {
        if self.gnu_verneed_offset == 0 {
            return;
        }
        util::write_align(self.buffer, ALIGN_GNU_VERNEED);
        debug_assert_eq!(self.gnu_verneed_offset, self.buffer.len());
    }

    /// Write a version need entry.
    pub fn write_gnu_verneed(&mut self, verneed: &Verneed) {
        debug_assert_ne!(self.gnu_verneed_remaining, 0);
        self.gnu_verneed_remaining -= 1;
        let vn_next = if self.gnu_verneed_remaining == 0 {
            0
        } else {
            mem::size_of::<elf::Verneed<Endianness>>() as u32
                + verneed.aux_count as u32 * mem::size_of::<elf::Vernaux<Endianness>>() as u32
        };

        self.gnu_vernaux_remaining = verneed.aux_count;
        let vn_aux = if verneed.aux_count == 0 {
            0
        } else {
            mem::size_of::<elf::Verneed<Endianness>>() as u32
        };

        self.buffer.write(&elf::Verneed {
            vn_version: U16::new(self.endian, verneed.version),
            vn_cnt: U16::new(self.endian, verneed.aux_count),
            vn_file: U32::new(self.endian, self.dynstr.get_offset(verneed.file) as u32),
            vn_aux: U32::new(self.endian, vn_aux),
            vn_next: U32::new(self.endian, vn_next),
        });
    }

    /// Write a version need auxiliary entry.
    pub fn write_gnu_vernaux(&mut self, vernaux: &Vernaux) {
        debug_assert_ne!(self.gnu_vernaux_remaining, 0);
        self.gnu_vernaux_remaining -= 1;
        let vna_next = if self.gnu_vernaux_remaining == 0 {
            0
        } else {
            mem::size_of::<elf::Vernaux<Endianness>>() as u32
        };
        self.buffer.write(&elf::Vernaux {
            vna_hash: U32::new(self.endian, elf::hash(self.dynstr.get_string(vernaux.name))),
            vna_flags: U16::new(self.endian, vernaux.flags),
            vna_other: U16::new(self.endian, vernaux.index),
            vna_name: U32::new(self.endian, self.dynstr.get_offset(vernaux.name) as u32),
            vna_next: U32::new(self.endian, vna_next),
        });
    }

    /// Reserve the section index for the `.gnu.version_r` section.
    pub fn reserve_gnu_verneed_section_index(&mut self) -> SectionIndex {
        self.reserve_gnu_verneed_section_index_with_name(&b".gnu.version_r"[..])
    }

--> --------------------

--> maximum size reached

--> --------------------

[ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge