//! Helper for writing ELF files. use alloc::string::String; use alloc::vec::Vec; use core::mem; use crate::elf; use crate::endian::*; use crate::write::string::{StringId, StringTable}; use crate::write::util; use crate::write::{Error, Result, WritableBuffer}; /// 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, shstrtab_index: SectionIndex, shstrtab_offset: usize, shstrtab_data: Vec, need_strtab: bool, strtab: StringTable<'a>, strtab_str_id: Option, strtab_index: SectionIndex, strtab_offset: usize, strtab_data: Vec, symtab_str_id: Option, symtab_index: SectionIndex, symtab_offset: usize, symtab_num: u32, need_symtab_shndx: bool, symtab_shndx_str_id: Option, symtab_shndx_offset: usize, symtab_shndx_data: Vec, need_dynstr: bool, dynstr: StringTable<'a>, dynstr_str_id: Option, dynstr_index: SectionIndex, dynstr_offset: usize, dynstr_data: Vec, dynsym_str_id: Option, dynsym_index: SectionIndex, dynsym_offset: usize, dynsym_num: u32, dynamic_str_id: Option, dynamic_offset: usize, dynamic_num: usize, hash_str_id: Option, hash_offset: usize, hash_size: usize, gnu_hash_str_id: Option, gnu_hash_offset: usize, gnu_hash_size: usize, gnu_versym_str_id: Option, gnu_versym_offset: usize, gnu_verdef_str_id: Option, 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, gnu_verneed_offset: usize, gnu_verneed_size: usize, gnu_verneed_count: u16, gnu_verneed_remaining: u16, gnu_vernaux_remaining: u16, } 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, } } /// 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. pub fn reserve(&mut self, len: usize, align_start: usize) -> usize { if len == 0 { return self.len; } 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) { 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); } fn file_header_size(&self) -> usize { if self.is_64 { mem::size_of::>() } else { mem::size_of::>() } } /// 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.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.file_header_size() as u16; let e_phoff = self.segment_offset as u64; let e_phentsize = if self.segment_num == 0 { 0 } else { self.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.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(()) } fn program_header_size(&self) -> usize { if self.is_64 { mem::size_of::>() } else { mem::size_of::>() } } /// 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.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) } fn section_header_size(&self) -> usize { if self.is_64 { mem::size_of::>() } else { mem::size_of::>() } } /// 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.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 { debug_assert_eq!(self.shstrtab_index, SectionIndex(0)); self.shstrtab_str_id = Some(self.add_section_name(&b".shstrtab"[..])); 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 } /// Reserve the range for the string table. /// /// This range is used for a section named `.strtab`. /// /// This function does nothing if no strings or symbols were defined. /// 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. /// /// This must be called before [`Self::reserve_section_headers`]. pub fn reserve_strtab_section_index(&mut self) -> SectionIndex { debug_assert_eq!(self.strtab_index, SectionIndex(0)); self.strtab_str_id = Some(self.add_section_name(&b".strtab"[..])); 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) -> 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 } fn symbol_size(&self) -> usize { if self.is_64 { mem::size_of::>() } else { mem::size_of::>() } } /// 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.symbol_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::::default()); } else { self.buffer.write(&elf::Sym32::::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 { debug_assert_eq!(self.symtab_index, SectionIndex(0)); self.symtab_str_id = Some(self.add_section_name(&b".symtab"[..])); 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.symbol_size() as u64, sh_link: self.strtab_index.0, sh_info: num_local, sh_addralign: self.elf_align as u64, sh_entsize: self.symbol_size() as u64, }); } /// Return true if `.symtab_shndx` is needed. pub fn symtab_shndx_needed(&self) -> bool { self.need_symtab_shndx } /// 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, 4); 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; } 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 { debug_assert!(self.symtab_shndx_str_id.is_none()); self.symtab_shndx_str_id = Some(self.add_section_name(&b".symtab_shndx"[..])); 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: 4, 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 } /// 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 or symbols were defined. /// This must be called after [`Self::add_dynamic_string`]. pub fn reserve_dynstr(&mut self) { debug_assert_eq!(self.dynstr_offset, 0); if !self.need_dynstr { return; } // 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); } /// 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. /// /// This must be called before [`Self::reserve_section_headers`]. pub fn reserve_dynstr_section_index(&mut self) -> SectionIndex { debug_assert_eq!(self.dynstr_index, SectionIndex(0)); self.dynstr_str_id = Some(self.add_section_name(&b".dynstr"[..])); 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; // The symtab must link to a strtab. self.need_dynstr = true; 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; // The symtab must link to a strtab. self.need_dynstr = true; } 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) { debug_assert_eq!(self.dynsym_offset, 0); if self.dynsym_num == 0 { return; } self.dynsym_offset = self.reserve( self.dynsym_num as usize * self.symbol_size(), self.elf_align, ); } /// 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::::default()); } else { self.buffer.write(&elf::Sym32::::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 { debug_assert_eq!(self.dynsym_index, SectionIndex(0)); self.dynsym_str_id = Some(self.add_section_name(&b".dynsym"[..])); 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.symbol_size() as u64, sh_link: self.dynstr_index.0, sh_info: num_local, sh_addralign: self.elf_align as u64, sh_entsize: self.symbol_size() as u64, }); } fn dyn_size(&self) -> usize { if self.is_64 { mem::size_of::>() } else { mem::size_of::>() } } /// 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) { debug_assert_eq!(self.dynamic_offset, 0); if dynamic_num == 0 { return; } self.dynamic_num = dynamic_num; self.dynamic_offset = self.reserve(dynamic_num * self.dyn_size(), self.elf_align); } /// 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()); } /// 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) { debug_assert!(self.dynamic_offset <= self.buffer.len()); 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); } debug_assert!( self.dynamic_offset + self.dynamic_num * self.dyn_size() >= self.buffer.len() ); } /// 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.dyn_size()) as u64, sh_link: self.dynstr_index.0, sh_info: 0, sh_addralign: self.elf_align as u64, sh_entsize: self.dyn_size() as u64, }); } fn rel_size(&self, is_rela: bool) -> usize { if self.is_64 { if is_rela { mem::size_of::>() } else { mem::size_of::>() } } else { if is_rela { mem::size_of::>() } else { mem::size_of::>() } } } /// 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) { self.hash_size = mem::size_of::>() + bucket_count as usize * 4 + chain_count as usize * 4; self.hash_offset = self.reserve(self.hash_size, self.elf_align); } /// 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(&mut self, bucket_count: u32, chain_count: u32, hash: F) where F: Fn(u32) -> Option, { 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, self.elf_align); 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 { debug_assert!(self.hash_str_id.is_none()); self.hash_str_id = Some(self.add_section_name(&b".hash"[..])); 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: self.elf_align 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) { self.gnu_hash_size = mem::size_of::>() + bloom_count as usize * self.elf_align + bucket_count as usize * 4 + symbol_count as usize * 4; self.gnu_hash_offset = self.reserve(self.gnu_hash_size, self.elf_align); } /// 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( &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 { debug_assert!(self.gnu_hash_str_id.is_none()); self.gnu_hash_str_id = Some(self.add_section_name(&b".gnu.hash"[..])); 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: 0, }); } /// 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) { debug_assert_eq!(self.gnu_versym_offset, 0); if self.dynsym_num == 0 { return; } self.gnu_versym_offset = self.reserve(self.dynsym_num as usize * 2, 2); } /// 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, 2); 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 { debug_assert!(self.gnu_versym_str_id.is_none()); self.gnu_versym_str_id = Some(self.add_section_name(&b".gnu.version"[..])); 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.dynsym_num as u64 * 2, sh_link: self.dynsym_index.0, sh_info: 0, sh_addralign: 2, 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) { debug_assert_eq!(self.gnu_verdef_offset, 0); if verdef_count == 0 { return; } self.gnu_verdef_size = verdef_count * mem::size_of::>() + verdaux_count * mem::size_of::>(); self.gnu_verdef_offset = self.reserve(self.gnu_verdef_size, self.elf_align); self.gnu_verdef_count = verdef_count as u16; self.gnu_verdef_remaining = self.gnu_verdef_count; } /// 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, self.elf_align); 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::>() as u32 + verdef.aux_count as u32 * mem::size_of::>() as u32 }; self.gnu_verdaux_remaining = verdef.aux_count; let vd_aux = if verdef.aux_count == 0 { 0 } else { mem::size_of::>() 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 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::>() 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 { debug_assert!(self.gnu_verdef_str_id.is_none()); self.gnu_verdef_str_id = Some(self.add_section_name(&b".gnu.version_d"[..])); 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: self.elf_align 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) { debug_assert_eq!(self.gnu_verneed_offset, 0); if verneed_count == 0 { return; } self.gnu_verneed_size = verneed_count * mem::size_of::>() + vernaux_count * mem::size_of::>(); self.gnu_verneed_offset = self.reserve(self.gnu_verneed_size, self.elf_align); self.gnu_verneed_count = verneed_count as u16; self.gnu_verneed_remaining = self.gnu_verneed_count; } /// 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, self.elf_align); 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::>() as u32 + verneed.aux_count as u32 * mem::size_of::>() as u32 }; self.gnu_vernaux_remaining = verneed.aux_count; let vn_aux = if verneed.aux_count == 0 { 0 } else { mem::size_of::>() 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::>() 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 { debug_assert!(self.gnu_verneed_str_id.is_none()); self.gnu_verneed_str_id = Some(self.add_section_name(&b".gnu.version_r"[..])); self.reserve_section_index() } /// Write the section header for the `.gnu.version_r` section. /// /// This function does nothing if the section index was not reserved. pub fn write_gnu_verneed_section_header(&mut self, sh_addr: u64) { if self.gnu_verneed_str_id.is_none() { return; } self.write_section_header(&SectionHeader { name: self.gnu_verneed_str_id, sh_type: elf::SHT_GNU_VERNEED, sh_flags: elf::SHF_ALLOC.into(), sh_addr, sh_offset: self.gnu_verneed_offset as u64, sh_size: self.gnu_verneed_size as u64, sh_link: self.dynstr_index.0, sh_info: self.gnu_verneed_count.into(), sh_addralign: self.elf_align as u64, sh_entsize: 0, }); } /// Reserve a file range for the given number of relocations. /// /// Returns the offset of the range. pub fn reserve_relocations(&mut self, count: usize, is_rela: bool) -> usize { self.reserve(count * self.rel_size(is_rela), self.elf_align) } /// Write alignment padding bytes prior to a relocation section. pub fn write_align_relocation(&mut self) { util::write_align(self.buffer, self.elf_align); } /// Write a relocation. pub fn write_relocation(&mut self, is_rela: bool, rel: &Rel) { let endian = self.endian; if self.is_64 { if is_rela { let rel = elf::Rela64 { r_offset: U64::new(endian, rel.r_offset), r_info: elf::Rela64::r_info(endian, self.is_mips64el, rel.r_sym, rel.r_type), r_addend: I64::new(endian, rel.r_addend), }; self.buffer.write(&rel); } else { let rel = elf::Rel64 { r_offset: U64::new(endian, rel.r_offset), r_info: elf::Rel64::r_info(endian, rel.r_sym, rel.r_type), }; self.buffer.write(&rel); } } else { if is_rela { let rel = elf::Rela32 { r_offset: U32::new(endian, rel.r_offset as u32), r_info: elf::Rel32::r_info(endian, rel.r_sym, rel.r_type as u8), r_addend: I32::new(endian, rel.r_addend as i32), }; self.buffer.write(&rel); } else { let rel = elf::Rel32 { r_offset: U32::new(endian, rel.r_offset as u32), r_info: elf::Rel32::r_info(endian, rel.r_sym, rel.r_type as u8), }; self.buffer.write(&rel); } } } /// Write the section header for a relocation section. /// /// `section` is the index of the section the relocations apply to, /// or 0 if none. /// /// `symtab` is the index of the symbol table the relocations refer to, /// or 0 if none. /// /// `offset` is the file offset of the relocations. pub fn write_relocation_section_header( &mut self, name: StringId, section: SectionIndex, symtab: SectionIndex, offset: usize, count: usize, is_rela: bool, ) { self.write_section_header(&SectionHeader { name: Some(name), sh_type: if is_rela { elf::SHT_RELA } else { elf::SHT_REL }, sh_flags: elf::SHF_INFO_LINK.into(), sh_addr: 0, sh_offset: offset as u64, sh_size: (count * self.rel_size(is_rela)) as u64, sh_link: symtab.0, sh_info: section.0, sh_addralign: self.elf_align as u64, sh_entsize: self.rel_size(is_rela) as u64, }); } /// Reserve a file range for a COMDAT section. /// /// `count` is the number of sections in the COMDAT group. /// /// Returns the offset of the range. pub fn reserve_comdat(&mut self, count: usize) -> usize { self.reserve((count + 1) * 4, 4) } /// Write `GRP_COMDAT` at the start of the COMDAT section. pub fn write_comdat_header(&mut self) { util::write_align(self.buffer, 4); self.buffer.write(&U32::new(self.endian, elf::GRP_COMDAT)); } /// Write an entry in a COMDAT section. pub fn write_comdat_entry(&mut self, entry: SectionIndex) { self.buffer.write(&U32::new(self.endian, entry.0)); } /// Write the section header for a COMDAT section. pub fn write_comdat_section_header( &mut self, name: StringId, symtab: SectionIndex, symbol: SymbolIndex, offset: usize, count: usize, ) { self.write_section_header(&SectionHeader { name: Some(name), sh_type: elf::SHT_GROUP, sh_flags: 0, sh_addr: 0, sh_offset: offset as u64, sh_size: ((count + 1) * 4) as u64, sh_link: symtab.0, sh_info: symbol.0, sh_addralign: 4, sh_entsize: 4, }); } } /// Native endian version of [`elf::FileHeader64`]. #[allow(missing_docs)] #[derive(Debug, Clone)] pub struct FileHeader { pub os_abi: u8, pub abi_version: u8, pub e_type: u16, pub e_machine: u16, pub e_entry: u64, pub e_flags: u32, } /// Native endian version of [`elf::ProgramHeader64`]. #[allow(missing_docs)] #[derive(Debug, Clone)] pub struct ProgramHeader { pub p_type: u32, pub p_flags: u32, pub p_offset: u64, pub p_vaddr: u64, pub p_paddr: u64, pub p_filesz: u64, pub p_memsz: u64, pub p_align: u64, } /// Native endian version of [`elf::SectionHeader64`]. #[allow(missing_docs)] #[derive(Debug, Clone)] pub struct SectionHeader { pub name: Option, pub sh_type: u32, pub sh_flags: u64, pub sh_addr: u64, pub sh_offset: u64, pub sh_size: u64, pub sh_link: u32, pub sh_info: u32, pub sh_addralign: u64, pub sh_entsize: u64, } /// Native endian version of [`elf::Sym64`]. #[allow(missing_docs)] #[derive(Debug, Clone)] pub struct Sym { pub name: Option, pub section: Option, pub st_info: u8, pub st_other: u8, pub st_shndx: u16, pub st_value: u64, pub st_size: u64, } /// Unified native endian version of [`elf::Rel64`] and [`elf::Rela64`]. #[allow(missing_docs)] #[derive(Debug, Clone)] pub struct Rel { pub r_offset: u64, pub r_sym: u32, pub r_type: u32, pub r_addend: i64, } /// Information required for writing [`elf::Verdef`]. #[allow(missing_docs)] #[derive(Debug, Clone)] pub struct Verdef { pub version: u16, pub flags: u16, pub index: u16, pub aux_count: u16, /// The name for the first [`elf::Verdaux`] entry. pub name: StringId, } /// Information required for writing [`elf::Verneed`]. #[allow(missing_docs)] #[derive(Debug, Clone)] pub struct Verneed { pub version: u16, pub aux_count: u16, pub file: StringId, } /// Information required for writing [`elf::Vernaux`]. #[allow(missing_docs)] #[derive(Debug, Clone)] pub struct Vernaux { pub flags: u16, pub index: u16, pub name: StringId, }