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;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SectionIndex(pub u32);
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SymbolIndex(pub u32);
#[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> {
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,
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,
}
}
fn class(&self) -> Class {
Class { is_64: self.is_64 }
}
pub fn reserved_len(&self) -> usize {
self.len
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.buffer.len()
}
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
}
pub fn write_align(&mut self, align_start: usize) {
if align_start > 1 {
util::write_align(self.buffer, align_start);
}
}
pub fn write(&mut self, data: &[u8]) {
self.buffer.write_bytes(data);
}
pub fn reserve_until(&mut self, offset: usize) {
debug_assert!(self.len <= offset);
self.len = offset;
}
pub fn pad_until(&mut self, offset: usize) {
debug_assert!(self.buffer.len() <= offset);
self.buffer.resize(offset);
}
pub fn reserve_file_header(&mut self) {
debug_assert_eq!(self.len, 0);
self.reserve(self.class().file_header_size(), 1);
}
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;
self.buffer
.reserve(self.len)
.map_err(|_| Error(String::from("Cannot allocate buffer")))?;
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
};
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(())
}
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,
);
}
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());
}
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);
}
}
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)
}
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)
}
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,
);
}
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
},
sh_info: 0,
sh_addralign: 0,
sh_entsize: 0,
});
}
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);
}
}
pub fn add_section_name(&mut self, name: &'a [u8]) -> StringId {
debug_assert_eq!(self.shstrtab_offset, 0);
self.shstrtab.add(name)
}
pub fn reserve_shstrtab(&mut self) {
debug_assert_eq!(self.shstrtab_offset, 0);
if self.section_num == 0 {
return;
}
self.shstrtab_data = vec![0];
self.shstrtab.write(1, &mut self.shstrtab_data);
self.shstrtab_offset = self.reserve(self.shstrtab_data.len(), 1);
}
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);
}
pub fn reserve_shstrtab_section_index(&mut self) -> SectionIndex {
self.reserve_shstrtab_section_index_with_name(&b".shstrtab"[..])
}
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
}
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,
});
}
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)
}
pub fn strtab_needed(&self) -> bool {
self.need_strtab
}
pub fn require_strtab(&mut self) {
self.need_strtab = true;
}
pub fn reserve_strtab(&mut self) {
debug_assert_eq!(self.strtab_offset, 0);
if !self.need_strtab {
return;
}
self.strtab_data = vec![0];
self.strtab.write(1, &mut self.strtab_data);
self.strtab_offset = self.reserve(self.strtab_data.len(), 1);
}
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);
}
pub fn reserve_strtab_section_index(&mut self) -> SectionIndex {
self.reserve_strtab_section_index_with_name(&b".strtab"[..])
}
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
}
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,
});
}
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;
self.need_strtab = true;
SymbolIndex(0)
}
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;
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)
}
pub fn symbol_count(&self) -> u32 {
self.symtab_num
}
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,
);
}
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));
}
}
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));
}
}
pub fn reserve_symtab_section_index(&mut self) -> SectionIndex {
self.reserve_symtab_section_index_with_name(&b".symtab"[..])
}
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
}
pub fn symtab_index(&mut self) -> SectionIndex {
self.symtab_index
}
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,
});
}
pub fn symtab_shndx_needed(&self) -> bool {
self.need_symtab_shndx
}
pub fn require_symtab_shndx(&mut self) {
self.need_symtab_shndx = true;
}
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);
}
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);
}
pub fn reserve_symtab_shndx_section_index(&mut self) -> SectionIndex {
self.reserve_symtab_shndx_section_index_with_name(&b".symtab_shndx"[..])
}
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()
}
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,
});
}
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)
}
pub fn get_dynamic_string(&self, name: &'a [u8]) -> StringId {
self.dynstr.get_id(name)
}
pub fn dynstr_needed(&self) -> bool {
self.need_dynstr
}
pub fn require_dynstr(&mut self) {
self.need_dynstr = true;
}
pub fn reserve_dynstr(&mut self) -> usize {
debug_assert_eq!(self.dynstr_offset, 0);
if !self.need_dynstr {
return 0;
}
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
}
pub fn dynstr_len(&mut self) -> usize {
debug_assert_ne!(self.dynstr_offset, 0);
self.dynstr_data.len()
}
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);
}
pub fn reserve_dynstr_section_index(&mut self) -> SectionIndex {
self.reserve_dynstr_section_index_with_name(&b".dynstr"[..])
}
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
}
pub fn dynstr_index(&mut self) -> SectionIndex {
self.dynstr_index
}
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,
});
}
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)
}
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)
}
pub fn dynamic_symbol_count(&mut self) -> u32 {
self.dynsym_num
}
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
}
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());
}
}
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 {
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);
}
}
pub fn reserve_dynsym_section_index(&mut self) -> SectionIndex {
self.reserve_dynsym_section_index_with_name(&b".dynsym"[..])
}
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
}
pub fn dynsym_index(&mut self) -> SectionIndex {
self.dynsym_index
}
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,
});
}
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
}
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());
}
pub fn reserve_dynamics(&mut self, dynamic_num: usize) -> usize {
self.reserve(dynamic_num * self.class().dyn_size(), self.elf_align)
}
pub fn write_dynamic_string(&mut self, tag: u32, id: StringId) {
self.write_dynamic(tag, self.dynstr.get_offset(id) as u64);
}
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);
}
}
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()
}
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,
});
}
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
}
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);
}
pub fn reserve_hash_section_index(&mut self) -> SectionIndex {
self.reserve_hash_section_index_with_name(&b".hash"[..])
}
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()
}
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,
});
}
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
}
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),
});
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));
}
}
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;
}
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));
}
}
pub fn reserve_gnu_hash_section_index(&mut self) -> SectionIndex {
self.reserve_gnu_hash_section_index_with_name(&b".gnu.hash"[..])
}
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()
}
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 },
});
}
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
}
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);
}
pub fn write_gnu_versym(&mut self, versym: u16) {
self.buffer.write(&U16::new(self.endian, versym));
}
pub fn reserve_gnu_versym_section_index(&mut self) -> SectionIndex {
self.reserve_gnu_versym_section_index_with_name(&b".gnu.version"[..])
}
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()
}
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,
});
}
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
}
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());
}
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);
}
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),
});
}
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),
});
}
pub fn reserve_gnu_verdef_section_index(&mut self) -> SectionIndex {
self.reserve_gnu_verdef_section_index_with_name(&b".gnu.version_d"[..])
}
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()
}
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,
});
}
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
}
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());
}
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),
});
}
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),
});
}
pub fn reserve_gnu_verneed_section_index(&mut self) -> SectionIndex {
self.reserve_gnu_verneed_section_index_with_name(&b".gnu.version_r"[..])
}
pub fn reserve_gnu_verneed_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex {
debug_assert!(self.gnu_verneed_str_id.is_none());
self.gnu_verneed_str_id = Some(self.add_section_name(name));
self.reserve_section_index()
}
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: ALIGN_GNU_VERNEED as u64,
sh_entsize: 0,
});
}
pub fn reserve_gnu_attributes_section_index(&mut self) -> SectionIndex {
self.reserve_gnu_attributes_section_index_with_name(&b".gnu.attributes"[..])
}
pub fn reserve_gnu_attributes_section_index_with_name(
&mut self,
name: &'a [u8],
) -> SectionIndex {
debug_assert!(self.gnu_attributes_str_id.is_none());
self.gnu_attributes_str_id = Some(self.add_section_name(name));
self.reserve_section_index()
}
pub fn reserve_gnu_attributes(&mut self, gnu_attributes_size: usize) -> usize {
debug_assert_eq!(self.gnu_attributes_offset, 0);
if gnu_attributes_size == 0 {
return 0;
}
self.gnu_attributes_size = gnu_attributes_size;
self.gnu_attributes_offset = self.reserve(self.gnu_attributes_size, self.elf_align);
self.gnu_attributes_offset
}
pub fn write_gnu_attributes_section_header(&mut self) {
if self.gnu_attributes_str_id.is_none() {
return;
}
self.write_section_header(&SectionHeader {
name: self.gnu_attributes_str_id,
sh_type: elf::SHT_GNU_ATTRIBUTES,
sh_flags: 0,
sh_addr: 0,
sh_offset: self.gnu_attributes_offset as u64,
sh_size: self.gnu_attributes_size as u64,
sh_link: self.dynstr_index.0,
sh_info: 0, sh_addralign: self.elf_align as u64,
sh_entsize: 0,
});
}
pub fn write_gnu_attributes(&mut self, data: &[u8]) {
if self.gnu_attributes_offset == 0 {
return;
}
util::write_align(self.buffer, self.elf_align);
debug_assert_eq!(self.gnu_attributes_offset, self.buffer.len());
self.buffer.write_bytes(data);
}
pub fn reserve_relocations(&mut self, count: usize, is_rela: bool) -> usize {
self.reserve(count * self.class().rel_size(is_rela), self.elf_align)
}
pub fn write_align_relocation(&mut self) {
util::write_align(self.buffer, self.elf_align);
}
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);
}
}
}
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.class().rel_size(is_rela)) as u64,
sh_link: symtab.0,
sh_info: section.0,
sh_addralign: self.elf_align as u64,
sh_entsize: self.class().rel_size(is_rela) as u64,
});
}
pub fn reserve_comdat(&mut self, count: usize) -> usize {
self.reserve((count + 1) * 4, 4)
}
pub fn write_comdat_header(&mut self) {
util::write_align(self.buffer, 4);
self.buffer.write(&U32::new(self.endian, elf::GRP_COMDAT));
}
pub fn write_comdat_entry(&mut self, entry: SectionIndex) {
self.buffer.write(&U32::new(self.endian, entry.0));
}
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,
});
}
pub fn attributes_writer(&self) -> AttributesWriter {
AttributesWriter::new(self.endian)
}
}
#[allow(missing_debug_implementations)]
pub struct AttributesWriter {
endian: Endianness,
data: Vec<u8>,
subsection_offset: usize,
subsubsection_offset: usize,
}
impl AttributesWriter {
pub fn new(endian: Endianness) -> Self {
AttributesWriter {
endian,
data: vec![0x41],
subsection_offset: 0,
subsubsection_offset: 0,
}
}
pub fn start_subsection(&mut self, vendor: &[u8]) {
debug_assert_eq!(self.subsection_offset, 0);
debug_assert_eq!(self.subsubsection_offset, 0);
self.subsection_offset = self.data.len();
self.data.extend_from_slice(&[0; 4]);
self.data.extend_from_slice(vendor);
self.data.push(0);
}
pub fn end_subsection(&mut self) {
debug_assert_ne!(self.subsection_offset, 0);
debug_assert_eq!(self.subsubsection_offset, 0);
let length = self.data.len() - self.subsection_offset;
self.data[self.subsection_offset..][..4]
.copy_from_slice(pod::bytes_of(&U32::new(self.endian, length as u32)));
self.subsection_offset = 0;
}
pub fn start_subsubsection(&mut self, tag: u8) {
debug_assert_ne!(self.subsection_offset, 0);
debug_assert_eq!(self.subsubsection_offset, 0);
self.subsubsection_offset = self.data.len();
self.data.push(tag);
self.data.extend_from_slice(&[0; 4]);
}
pub fn write_subsubsection_index(&mut self, index: u32) {
debug_assert_ne!(self.subsection_offset, 0);
debug_assert_ne!(self.subsubsection_offset, 0);
util::write_uleb128(&mut self.data, u64::from(index));
}
pub fn write_subsubsection_indices(&mut self, indices: &[u8]) {
debug_assert_ne!(self.subsection_offset, 0);
debug_assert_ne!(self.subsubsection_offset, 0);
self.data.extend_from_slice(indices);
self.data.push(0);
}
pub fn write_attribute_tag(&mut self, tag: u64) {
debug_assert_ne!(self.subsection_offset, 0);
debug_assert_ne!(self.subsubsection_offset, 0);
util::write_uleb128(&mut self.data, tag);
}
pub fn write_attribute_integer(&mut self, value: u64) {
debug_assert_ne!(self.subsection_offset, 0);
debug_assert_ne!(self.subsubsection_offset, 0);
util::write_uleb128(&mut self.data, value);
}
pub fn write_attribute_string(&mut self, value: &[u8]) {
debug_assert_ne!(self.subsection_offset, 0);
debug_assert_ne!(self.subsubsection_offset, 0);
self.data.extend_from_slice(value);
self.data.push(0);
}
pub fn write_subsubsection_attributes(&mut self, attributes: &[u8]) {
debug_assert_ne!(self.subsection_offset, 0);
debug_assert_ne!(self.subsubsection_offset, 0);
self.data.extend_from_slice(attributes);
}
pub fn end_subsubsection(&mut self) {
debug_assert_ne!(self.subsection_offset, 0);
debug_assert_ne!(self.subsubsection_offset, 0);
let length = self.data.len() - self.subsubsection_offset;
self.data[self.subsubsection_offset + 1..][..4]
.copy_from_slice(pod::bytes_of(&U32::new(self.endian, length as u32)));
self.subsubsection_offset = 0;
}
pub fn data(self) -> Vec<u8> {
debug_assert_eq!(self.subsection_offset, 0);
debug_assert_eq!(self.subsubsection_offset, 0);
self.data
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct Class {
pub is_64: bool,
}
impl Class {
pub fn align(self) -> usize {
if self.is_64 {
8
} else {
4
}
}
pub fn file_header_size(self) -> usize {
if self.is_64 {
mem::size_of::<elf::FileHeader64<Endianness>>()
} else {
mem::size_of::<elf::FileHeader32<Endianness>>()
}
}
pub fn program_header_size(self) -> usize {
if self.is_64 {
mem::size_of::<elf::ProgramHeader64<Endianness>>()
} else {
mem::size_of::<elf::ProgramHeader32<Endianness>>()
}
}
pub fn section_header_size(self) -> usize {
if self.is_64 {
mem::size_of::<elf::SectionHeader64<Endianness>>()
} else {
mem::size_of::<elf::SectionHeader32<Endianness>>()
}
}
pub fn sym_size(self) -> usize {
if self.is_64 {
mem::size_of::<elf::Sym64<Endianness>>()
} else {
mem::size_of::<elf::Sym32<Endianness>>()
}
}
pub fn rel_size(self, is_rela: bool) -> usize {
if self.is_64 {
if is_rela {
mem::size_of::<elf::Rela64<Endianness>>()
} else {
mem::size_of::<elf::Rel64<Endianness>>()
}
} else {
if is_rela {
mem::size_of::<elf::Rela32<Endianness>>()
} else {
mem::size_of::<elf::Rel32<Endianness>>()
}
}
}
pub fn dyn_size(self) -> usize {
if self.is_64 {
mem::size_of::<elf::Dyn64<Endianness>>()
} else {
mem::size_of::<elf::Dyn32<Endianness>>()
}
}
pub fn hash_size(self, bucket_count: u32, chain_count: u32) -> usize {
mem::size_of::<elf::HashHeader<Endianness>>()
+ bucket_count as usize * 4
+ chain_count as usize * 4
}
pub fn gnu_hash_size(self, bloom_count: u32, bucket_count: u32, symbol_count: u32) -> usize {
let bloom_size = if self.is_64 { 8 } else { 4 };
mem::size_of::<elf::GnuHashHeader<Endianness>>()
+ bloom_count as usize * bloom_size
+ bucket_count as usize * 4
+ symbol_count as usize * 4
}
pub fn gnu_versym_size(self, symbol_count: usize) -> usize {
symbol_count * 2
}
pub fn gnu_verdef_size(self, verdef_count: usize, verdaux_count: usize) -> usize {
verdef_count * mem::size_of::<elf::Verdef<Endianness>>()
+ verdaux_count * mem::size_of::<elf::Verdaux<Endianness>>()
}
pub fn gnu_verneed_size(self, verneed_count: usize, vernaux_count: usize) -> usize {
verneed_count * mem::size_of::<elf::Verneed<Endianness>>()
+ vernaux_count * mem::size_of::<elf::Vernaux<Endianness>>()
}
}
#[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,
}
#[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,
}
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct SectionHeader {
pub name: Option<StringId>,
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,
}
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct Sym {
pub name: Option<StringId>,
pub section: Option<SectionIndex>,
pub st_info: u8,
pub st_other: u8,
pub st_shndx: u16,
pub st_value: u64,
pub st_size: u64,
}
#[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,
}
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct Verdef {
pub version: u16,
pub flags: u16,
pub index: u16,
pub aux_count: u16,
pub name: StringId,
}
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct Verneed {
pub version: u16,
pub aux_count: u16,
pub file: StringId,
}
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct Vernaux {
pub flags: u16,
pub index: u16,
pub name: StringId,
}