use alloc::string::String;
use alloc::vec::Vec;
use crate::elf;
use crate::endian::*;
use crate::write::elf::encoder::*;
use crate::write::string::{StringId, StringTable};
use crate::write::util;
use crate::write::{CountingBuffer, Error, GrowableBuffer, Result, WritableBuffer};
#[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);
pub trait Mode: ModeSealed {}
use private::ModeSealed;
mod private {
use super::*;
#[allow(private_interfaces)]
pub trait ModeSealed {
fn string_table() -> StringTable<'static>;
fn reserve(
&self,
buffer: &mut dyn WritableBuffer,
encoder: Encoder<Endianness>,
) -> Result<()>;
fn need_offset(offset: u64) -> bool;
fn set_offset(dest: &mut u64, offset: u64);
fn set_size(dest: &mut u64, size: u64);
fn set_section_index(dest: &mut u32, index: SectionIndex);
fn set_section_name(
dest: &mut Option<StringId>,
shstrtab: &mut StringTable<'_>,
name: &'static [u8],
);
fn set_count<T: Copy + PartialOrd>(dest: &mut T, count: T);
}
}
#[allow(missing_debug_implementations)]
pub struct Writer<'a, M: Mode = TwoPhase> {
mode: M,
encoder: Encoder<Endianness>,
buffer: CountingBuffer<&'a mut dyn WritableBuffer>,
header: FileHeader,
layout: FileHeaderLayout,
written_segment_num: u32,
written_section_num: u32,
shstrtab: StringTable<'a>,
shstrtab_str_id: Option<StringId>,
shstrtab_offset: u64,
shstrtab_size: u32,
need_strtab: bool,
strtab: StringTable<'a>,
strtab_str_id: Option<StringId>,
strtab_index: SectionIndex,
strtab_offset: u64,
strtab_size: u32,
symtab_str_id: Option<StringId>,
symtab_index: SectionIndex,
symtab_offset: u64,
symtab_num: u32,
written_symtab_num: u32,
need_symtab_shndx: bool,
symtab_shndx_str_id: Option<StringId>,
symtab_shndx_offset: u64,
symtab_shndx_data: Vec<u8>,
need_dynstr: bool,
dynstr: StringTable<'a>,
dynstr_str_id: Option<StringId>,
dynstr_index: SectionIndex,
dynstr_offset: u64,
dynstr_size: u32,
dynsym_str_id: Option<StringId>,
dynsym_index: SectionIndex,
dynsym_offset: u64,
dynsym_num: u32,
written_dynsym_num: u32,
dynamic_str_id: Option<StringId>,
dynamic_offset: u64,
dynamic_num: u64,
written_dynamic_num: u64,
hash_str_id: Option<StringId>,
hash_offset: u64,
hash_size: u64,
gnu_hash_str_id: Option<StringId>,
gnu_hash_offset: u64,
gnu_hash_size: u64,
gnu_versym_str_id: Option<StringId>,
gnu_versym_offset: u64,
gnu_versym_num: u32,
written_versym_num: u32,
gnu_verdef_str_id: Option<StringId>,
gnu_verdef_offset: u64,
gnu_verdef_count: u16,
gnu_verdaux_count: usize,
written_verdaux_count: usize,
gnu_verdef_remaining: u16,
gnu_verdaux_remaining: u16,
gnu_verneed_str_id: Option<StringId>,
gnu_verneed_offset: u64,
gnu_verneed_count: u16,
gnu_vernaux_count: usize,
written_vernaux_count: usize,
gnu_verneed_remaining: u16,
gnu_vernaux_remaining: u16,
gnu_attributes_str_id: Option<StringId>,
gnu_attributes_offset: u64,
gnu_attributes_size: u64,
}
impl<'a, M: Mode> Writer<'a, M> {
fn new_with_mode(
endian: Endianness,
is_64: bool,
buffer: &'a mut dyn WritableBuffer,
mode: M,
) -> Self {
Writer {
mode,
encoder: Encoder::new(endian, is_64, elf::EM_NONE),
buffer: CountingBuffer::new(buffer),
header: FileHeader::default(),
layout: FileHeaderLayout::default(),
written_segment_num: 0,
written_section_num: 0,
shstrtab: M::string_table(),
shstrtab_str_id: None,
shstrtab_offset: 0,
shstrtab_size: 0,
need_strtab: false,
strtab: M::string_table(),
strtab_str_id: None,
strtab_index: SectionIndex(0),
strtab_offset: 0,
strtab_size: 0,
symtab_str_id: None,
symtab_index: SectionIndex(0),
symtab_offset: 0,
symtab_num: 0,
written_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: M::string_table(),
dynstr_str_id: None,
dynstr_index: SectionIndex(0),
dynstr_offset: 0,
dynstr_size: 0,
dynsym_str_id: None,
dynsym_index: SectionIndex(0),
dynsym_offset: 0,
dynsym_num: 0,
written_dynsym_num: 0,
dynamic_str_id: None,
dynamic_offset: 0,
dynamic_num: 0,
written_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_versym_num: 0,
written_versym_num: 0,
gnu_verdef_str_id: None,
gnu_verdef_offset: 0,
gnu_verdef_count: 0,
gnu_verdaux_count: 0,
written_verdaux_count: 0,
gnu_verdef_remaining: 0,
gnu_verdaux_remaining: 0,
gnu_verneed_str_id: None,
gnu_verneed_offset: 0,
gnu_verneed_count: 0,
gnu_vernaux_count: 0,
written_vernaux_count: 0,
gnu_verneed_remaining: 0,
gnu_vernaux_remaining: 0,
gnu_attributes_str_id: None,
gnu_attributes_offset: 0,
gnu_attributes_size: 0,
}
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> u64 {
self.buffer.count()
}
pub fn offset(&self) -> u64 {
self.buffer.count()
}
pub fn write_align(&mut self, align_start: u64) -> u64 {
if align_start > 1 {
self.buffer.write_align(align_start);
}
self.offset()
}
pub fn write(&mut self, data: &[u8]) {
self.buffer.write_bytes(data);
}
pub fn pad_until(&mut self, offset: u64) {
debug_assert!(self.offset() <= offset);
self.buffer.resize(offset);
}
pub fn write_file_header(&mut self, header: &FileHeader) -> Result<()> {
debug_assert_eq!(self.buffer.count(), 0);
self.mode.reserve(&mut self.buffer, self.encoder)?;
self.header = header.clone();
self.encoder.set_machine(header.e_machine);
self.encoder
.file_header(&mut self.buffer, &self.header, &self.layout)
}
pub fn write_align_program_headers(&mut self) -> u64 {
if !M::need_offset(self.layout.e_phoff) {
return 0;
}
let offset = self.write_align(self.encoder.address_size());
M::set_offset(&mut self.layout.e_phoff, offset);
offset
}
pub fn write_program_header(&mut self, header: &ProgramHeader) {
self.encoder.program_header(&mut self.buffer, header);
self.written_segment_num += 1;
M::set_count(&mut self.layout.segment_num, self.written_segment_num);
}
pub fn write_null_section_header(&mut self) -> u64 {
if !M::need_offset(self.layout.e_shoff) {
return 0;
}
let offset = self.write_align(self.encoder.address_size());
M::set_offset(&mut self.layout.e_shoff, offset);
self.encoder
.null_section_header(&mut self.buffer, &self.layout);
self.written_section_num = 1;
M::set_count(&mut self.layout.section_num, self.written_section_num);
offset
}
pub fn write_section_header(&mut self, section: &SectionHeader) -> SectionIndex {
self.encoder.section_header(&mut self.buffer, section);
let index = SectionIndex(self.written_section_num);
self.written_section_num += 1;
M::set_count(&mut self.layout.section_num, self.written_section_num);
index
}
pub fn add_section_name(&mut self, name: &'a [u8]) -> StringId {
debug_assert_eq!(self.shstrtab_offset, 0);
self.shstrtab.add(name)
}
pub fn section_name_offset(&self, id: Option<StringId>) -> u32 {
id.map_or(0, |id| self.shstrtab.get_offset(id))
}
pub fn write_shstrtab_section_header(&mut self) {
if self.shstrtab_str_id.is_none() {
return;
}
debug_assert_ne!(self.shstrtab_offset, 0);
let index = self.write_section_header(&SectionHeader {
sh_name: self.section_name_offset(self.shstrtab_str_id),
sh_offset: self.shstrtab_offset,
sh_size: self.shstrtab_size.into(),
..self.encoder.strtab_section_header()
});
M::set_section_index(&mut self.layout.shstrtab_index, index);
}
pub fn add_string(&mut self, name: &'a [u8]) -> StringId {
debug_assert_eq!(self.strtab_offset, 0);
self.strtab.add(name)
}
pub fn string_offset(&self, id: Option<StringId>) -> u32 {
id.map_or(0, |id| self.strtab.get_offset(id))
}
pub fn write_strtab_section_header(&mut self) {
if self.strtab_str_id.is_none() {
return;
}
let index = self.write_section_header(&SectionHeader {
sh_name: self.section_name_offset(self.strtab_str_id),
sh_offset: self.strtab_offset,
sh_size: self.strtab_size.into(),
..self.encoder.strtab_section_header()
});
M::set_section_index(&mut self.strtab_index.0, index);
}
pub fn write_null_symbol(&mut self) -> u64 {
if !M::need_offset(self.symtab_offset) {
return 0;
}
let offset = self.write_align(self.encoder.address_size());
M::set_offset(&mut self.symtab_offset, offset);
M::set_section_name(&mut self.symtab_str_id, &mut self.shstrtab, b".symtab");
self.encoder.null_symbol(&mut self.buffer);
if M::need_offset(self.symtab_shndx_offset) {
self.encoder.u32(&mut self.symtab_shndx_data, 0u32);
}
self.written_symtab_num = 1;
M::set_count(&mut self.symtab_num, self.written_symtab_num);
self.need_strtab = true;
offset
}
pub fn write_symbol(&mut self, sym: &Sym) -> SymbolIndex {
let section = self.encoder.symbol(&mut self.buffer, sym);
if M::need_offset(self.symtab_shndx_offset) {
let section_index = if let Some(section) = section {
self.need_symtab_shndx = true;
section
} else {
0
};
self.encoder.u32(&mut self.symtab_shndx_data, section_index);
}
let index = SymbolIndex(self.written_symtab_num);
self.written_symtab_num += 1;
M::set_count(&mut self.symtab_num, self.written_symtab_num);
index
}
pub fn write_symtab_section_header(&mut self, num_local: u32) {
if self.symtab_str_id.is_none() {
return;
}
let index = self.write_section_header(&SectionHeader {
sh_name: self.section_name_offset(self.symtab_str_id),
sh_offset: self.symtab_offset,
sh_size: self.symtab_num as u64 * self.encoder.sym_size(),
..self
.encoder
.symtab_section_header(self.strtab_index.0, num_local)
});
M::set_section_index(&mut self.symtab_index.0, index);
}
pub fn write_symtab_shndx(&mut self) -> u64 {
if !self.need_symtab_shndx {
self.symtab_shndx_data = Vec::new();
return 0;
}
let offset = self.write_align(ALIGN_SYMTAB_SHNDX);
M::set_offset(&mut self.symtab_shndx_offset, offset);
M::set_section_name(
&mut self.symtab_shndx_str_id,
&mut self.shstrtab,
b".symtab_shndx",
);
self.buffer.write_bytes(&self.symtab_shndx_data);
self.symtab_shndx_data = Vec::new();
offset
}
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 {
sh_name: self.section_name_offset(self.symtab_shndx_str_id),
sh_offset: self.symtab_shndx_offset,
sh_size,
..self
.encoder
.symtab_shndx_section_header(self.symtab_index.0)
});
}
pub fn add_dynamic_string(&mut self, name: &'a [u8]) -> StringId {
debug_assert_eq!(self.dynstr_offset, 0);
self.dynstr.add(name)
}
pub fn get_dynamic_string(&self, name: &'a [u8]) -> StringId {
self.dynstr.get_id(name)
}
pub fn dynamic_string_offset(&self, id: Option<StringId>) -> u32 {
id.map_or(0, |id| self.dynstr.get_offset(id))
}
pub fn write_dynstr_section_header(&mut self, sh_addr: u64) {
if self.dynstr_str_id.is_none() {
return;
}
let index = self.write_section_header(&SectionHeader {
sh_name: self.section_name_offset(self.dynstr_str_id),
sh_addr,
sh_offset: self.dynstr_offset,
sh_size: self.dynstr_size.into(),
..self.encoder.dynstr_section_header()
});
M::set_section_index(&mut self.dynstr_index.0, index);
}
pub fn write_null_dynamic_symbol(&mut self) -> u64 {
if !M::need_offset(self.dynsym_offset) {
return 0;
}
let offset = self.write_align(self.encoder.address_size());
M::set_offset(&mut self.dynsym_offset, offset);
M::set_section_name(&mut self.dynsym_str_id, &mut self.shstrtab, b".dynsym");
self.encoder.null_symbol(&mut self.buffer);
self.written_dynsym_num = 1;
M::set_count(&mut self.dynsym_num, self.written_dynsym_num);
self.need_dynstr = true;
offset
}
pub fn write_dynamic_symbol(&mut self, sym: &Sym) -> SymbolIndex {
let _ = self.encoder.symbol(&mut self.buffer, sym);
let index = SymbolIndex(self.written_dynsym_num);
self.written_dynsym_num += 1;
M::set_count(&mut self.dynsym_num, self.written_dynsym_num);
index
}
pub fn write_dynsym_section_header(&mut self, sh_addr: u64, num_local: u32) {
if self.dynsym_str_id.is_none() {
return;
}
let index = self.write_section_header(&SectionHeader {
sh_name: self.section_name_offset(self.dynsym_str_id),
sh_addr,
sh_offset: self.dynsym_offset,
sh_size: self.dynsym_num as u64 * self.encoder.sym_size(),
..self
.encoder
.dynsym_section_header(self.dynstr_index.0, num_local)
});
M::set_section_index(&mut self.dynsym_index.0, index);
}
pub fn write_align_dynamic(&mut self) -> u64 {
if !M::need_offset(self.dynamic_offset) {
return 0;
}
let offset = self.write_align(self.encoder.address_size());
M::set_offset(&mut self.dynamic_offset, offset);
M::set_section_name(&mut self.dynamic_str_id, &mut self.shstrtab, b".dynamic");
offset
}
pub fn write_dynamic_string(&mut self, tag: elf::DynamicTag, id: StringId) -> Result<()> {
self.write_dynamic(tag, self.dynstr.get_offset(id).into())
}
pub fn write_dynamic(&mut self, d_tag: elf::DynamicTag, d_val: u64) -> Result<()> {
self.encoder.dynamic(&mut self.buffer, d_tag, d_val)?;
self.written_dynamic_num += 1;
M::set_count(&mut self.dynamic_num, self.written_dynamic_num);
Ok(())
}
pub fn write_dynamic_section_header(&mut self, sh_addr: u64) {
if self.dynamic_str_id.is_none() {
return;
}
self.write_section_header(&SectionHeader {
sh_name: self.section_name_offset(self.dynamic_str_id),
sh_addr,
sh_offset: self.dynamic_offset,
sh_size: self.dynamic_num * self.encoder.dyn_size(),
..self.encoder.dynamic_section_header(self.dynstr_index.0)
});
}
pub fn write_hash<F>(&mut self, bucket_count: u32, symbol_count: u32, hash: F) -> u64
where
F: Fn(u32) -> Option<u32>,
{
let offset = self.write_align(ALIGN_HASH);
M::set_offset(&mut self.hash_offset, offset);
M::set_section_name(&mut self.hash_str_id, &mut self.shstrtab, b".hash");
self.encoder
.hash_table(&mut self.buffer, bucket_count, symbol_count, hash);
let size = self.offset() - self.hash_offset;
M::set_size(&mut self.hash_size, size);
offset
}
pub fn write_hash_section_header(&mut self, sh_addr: u64) {
if self.hash_str_id.is_none() {
return;
}
self.write_section_header(&SectionHeader {
sh_name: self.section_name_offset(self.hash_str_id),
sh_addr,
sh_offset: self.hash_offset,
sh_size: self.hash_size,
..self.encoder.hash_section_header(self.dynsym_index.0)
});
}
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,
) -> u64
where
F: Fn(u32) -> u32,
{
let offset = self.write_align(self.encoder.address_size());
M::set_offset(&mut self.gnu_hash_offset, offset);
M::set_section_name(&mut self.gnu_hash_str_id, &mut self.shstrtab, b".gnu.hash");
self.encoder.gnu_hash_table(
&mut self.buffer,
&GnuHashTable {
bloom_shift,
bloom_count,
bucket_count,
symbol_base,
symbol_count,
},
hash,
);
let size = self.offset() - self.gnu_hash_offset;
M::set_size(&mut self.gnu_hash_size, size);
offset
}
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 {
sh_name: self.section_name_offset(self.gnu_hash_str_id),
sh_addr,
sh_offset: self.gnu_hash_offset,
sh_size: self.gnu_hash_size,
..self.encoder.gnu_hash_section_header(self.dynsym_index.0)
});
}
pub fn write_null_gnu_versym(&mut self) -> u64 {
if !M::need_offset(self.gnu_versym_offset) {
return 0;
}
let offset = self.write_align(ALIGN_GNU_VERSYM);
M::set_offset(&mut self.gnu_versym_offset, offset);
M::set_section_name(
&mut self.gnu_versym_str_id,
&mut self.shstrtab,
b".gnu.version",
);
self.write_gnu_versym(elf::VER_NDX_LOCAL.into());
offset
}
pub fn write_gnu_versym(&mut self, versym: elf::VersymIndex) {
self.encoder.gnu_versym(&mut self.buffer, versym);
self.written_versym_num += 1;
M::set_count(&mut self.gnu_versym_num, self.written_versym_num);
}
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 {
sh_name: self.section_name_offset(self.gnu_versym_str_id),
sh_addr,
sh_offset: self.gnu_versym_offset,
sh_size: self.encoder.gnu_versym_size(self.gnu_versym_num),
..self.encoder.gnu_versym_section_header(self.dynsym_index.0)
});
}
fn write_align_gnu_verdef_impl(&mut self) -> u64 {
if !M::need_offset(self.gnu_verdef_offset) {
return 0;
}
let offset = self.write_align(ALIGN_GNU_VERDEF);
M::set_offset(&mut self.gnu_verdef_offset, offset);
M::set_section_name(
&mut self.gnu_verdef_str_id,
&mut self.shstrtab,
b".gnu.version_d",
);
offset
}
pub fn write_gnu_verdef(&mut self, verdef: &Verdef) {
debug_assert_ne!(self.gnu_verdef_remaining, 0);
self.gnu_verdef_remaining -= 1;
debug_assert_ne!(verdef.aux_count, 0);
self.gnu_verdaux_remaining = verdef.aux_count;
self.written_verdaux_count += usize::from(verdef.aux_count);
M::set_count(&mut self.gnu_verdaux_count, self.written_verdaux_count);
self.encoder
.gnu_verdef(&mut self.buffer, self.gnu_verdef_remaining != 0, verdef);
}
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);
debug_assert_ne!(verdef.aux_count, 0);
self.gnu_verdaux_remaining = 0;
self.encoder.gnu_verdef_shared(&mut self.buffer, verdef);
}
pub fn write_gnu_verdaux(&mut self, name: StringId) {
debug_assert_ne!(self.gnu_verdaux_remaining, 0);
self.gnu_verdaux_remaining -= 1;
self.encoder.gnu_verdaux(
&mut self.buffer,
self.gnu_verdaux_remaining != 0,
self.dynstr.get_offset(name),
);
}
pub fn write_gnu_verdef_section_header(&mut self, sh_addr: u64) {
if self.gnu_verdef_str_id.is_none() {
return;
}
let sh_size = self
.encoder
.gnu_verdef_size(self.gnu_verdef_count, self.gnu_verdaux_count);
self.write_section_header(&SectionHeader {
sh_name: self.section_name_offset(self.gnu_verdef_str_id),
sh_addr,
sh_offset: self.gnu_verdef_offset,
sh_size,
..self
.encoder
.gnu_verdef_section_header(self.dynstr_index.0, self.gnu_verdef_count)
});
}
fn write_align_gnu_verneed_impl(&mut self) -> u64 {
if !M::need_offset(self.gnu_verneed_offset) {
return 0;
}
let offset = self.write_align(ALIGN_GNU_VERNEED);
M::set_offset(&mut self.gnu_verneed_offset, offset);
M::set_section_name(
&mut self.gnu_verneed_str_id,
&mut self.shstrtab,
b".gnu.version_r",
);
offset
}
pub fn write_gnu_verneed(&mut self, verneed: &Verneed) {
debug_assert_ne!(self.gnu_verneed_remaining, 0);
self.gnu_verneed_remaining -= 1;
if verneed.aux_count != 0 {
self.gnu_vernaux_remaining = verneed.aux_count;
self.written_vernaux_count += usize::from(verneed.aux_count);
M::set_count(&mut self.gnu_vernaux_count, self.written_vernaux_count);
};
self.encoder
.gnu_verneed(&mut self.buffer, self.gnu_verneed_remaining != 0, verneed);
}
pub fn write_gnu_vernaux(&mut self, vernaux: &Vernaux) {
debug_assert_ne!(self.gnu_vernaux_remaining, 0);
self.gnu_vernaux_remaining -= 1;
self.encoder
.gnu_vernaux(&mut self.buffer, self.gnu_vernaux_remaining != 0, vernaux);
}
pub fn write_gnu_verneed_section_header(&mut self, sh_addr: u64) {
if self.gnu_verneed_str_id.is_none() {
return;
}
let sh_size = self
.encoder
.gnu_verneed_size(self.gnu_verneed_count, self.gnu_vernaux_count);
self.write_section_header(&SectionHeader {
sh_name: self.section_name_offset(self.gnu_verneed_str_id),
sh_addr,
sh_offset: self.gnu_verneed_offset,
sh_size,
..self
.encoder
.gnu_verneed_section_header(self.dynstr_index.0, self.gnu_verneed_count)
});
}
pub fn write_gnu_attributes_section_header(&mut self) {
if self.gnu_attributes_str_id.is_none() {
return;
}
self.write_section_header(&SectionHeader {
sh_name: self.section_name_offset(self.gnu_attributes_str_id),
sh_offset: self.gnu_attributes_offset,
sh_size: self.gnu_attributes_size,
sh_link: self.dynstr_index.0,
..self.encoder.gnu_attributes_section_header()
});
}
pub fn write_gnu_attributes(&mut self, data: &[u8]) -> u64 {
if !M::need_offset(self.gnu_attributes_offset) {
return 0;
}
let offset = self.offset();
M::set_offset(&mut self.gnu_attributes_offset, offset);
M::set_section_name(
&mut self.gnu_attributes_str_id,
&mut self.shstrtab,
b".gnu.attributes",
);
self.buffer.write_bytes(data);
let size = self.offset() - self.gnu_attributes_offset;
M::set_size(&mut self.gnu_attributes_size, size);
offset
}
pub fn write_align_relocation(&mut self) -> u64 {
self.write_align(self.encoder.address_size())
}
pub fn write_relocation(&mut self, is_rela: bool, rel: &Rel) {
self.encoder.relocation(&mut self.buffer, is_rela, rel);
}
pub fn write_relocation_section_header(
&mut self,
name: StringId,
section: SectionIndex,
symtab: SectionIndex,
offset: u64,
count: usize,
is_rela: bool,
) {
self.write_section_header(&SectionHeader {
sh_name: self.section_name_offset(Some(name)),
sh_offset: offset,
sh_size: count as u64 * self.encoder.rel_size(is_rela),
sh_link: symtab.0,
sh_info: section.0,
..self.encoder.relocation_section_header(is_rela)
});
}
pub fn write_relative_relocation_section_header(
&mut self,
name: StringId,
offset: u64,
size: u64,
) {
self.write_section_header(&SectionHeader {
sh_name: self.section_name_offset(Some(name)),
sh_offset: offset,
sh_size: size,
..self.encoder.relative_relocation_section_header()
});
}
pub fn write_comdat_header(&mut self) {
self.buffer.write_align(4);
self.encoder.u32(&mut self.buffer, elf::GRP_COMDAT);
}
pub fn write_comdat_entry(&mut self, entry: SectionIndex) {
self.encoder.u32(&mut self.buffer, entry.0);
}
pub fn write_comdat_section_header(
&mut self,
name: StringId,
symtab: SectionIndex,
symbol: SymbolIndex,
offset: u64,
count: usize,
) {
self.write_section_header(&SectionHeader {
sh_name: self.section_name_offset(Some(name)),
sh_offset: offset,
sh_size: ((count + 1) * 4) as u64,
sh_link: symtab.0,
sh_info: symbol.0,
..self.encoder.comdat_section_header()
});
}
pub fn attributes_writer(&self) -> AttributesWriter {
AttributesWriter::new(self.encoder.endian())
}
}
pub type SinglePhaseWriter<'a> = Writer<'a, SinglePhase>;
#[derive(Debug)]
pub struct SinglePhase(());
impl Mode for SinglePhase {}
#[allow(private_interfaces)]
impl ModeSealed for SinglePhase {
fn string_table() -> StringTable<'static> {
StringTable::new_in_order(1)
}
fn reserve(
&self,
_buffer: &mut dyn WritableBuffer,
_encoder: Encoder<Endianness>,
) -> Result<()> {
Ok(())
}
fn need_offset(offset: u64) -> bool {
debug_assert_eq!(offset, 0);
true
}
fn set_offset(dest: &mut u64, offset: u64) {
debug_assert_eq!(*dest, 0);
*dest = offset;
}
fn set_size(dest: &mut u64, size: u64) {
debug_assert_eq!(*dest, 0);
*dest = size;
}
fn set_section_index(dest: &mut u32, index: SectionIndex) {
debug_assert_eq!(*dest, 0);
*dest = index.0;
}
fn set_section_name(
dest: &mut Option<StringId>,
shstrtab: &mut StringTable<'_>,
name: &'static [u8],
) {
debug_assert!(dest.is_none());
*dest = Some(shstrtab.add(name));
}
fn set_count<T: Copy + PartialOrd>(dest: &mut T, count: T) {
debug_assert!(*dest < count);
*dest = count;
}
}
impl<'a> Writer<'a, SinglePhase> {
pub fn new_single_phase(
endian: Endianness,
is_64: bool,
buffer: &'a mut dyn GrowableBuffer,
) -> Self {
Writer::new_with_mode(endian, is_64, buffer.as_writable(), SinglePhase(()))
}
pub fn write_file_header_to(&mut self, buffer: &mut dyn WritableBuffer) -> Result<()> {
let len = self.offset();
if !self.encoder.is_64() && len > u64::from(u32::MAX) {
return Err(Error(format!("File size overflow: {len:#x}")));
}
if self.layout.section_num >= elf::SHN_LORESERVE.into() {
return Err(Error(String::from(
"single phase write doesn't support e_shnum overflow",
)));
}
self.encoder.file_header(buffer, &self.header, &self.layout)
}
pub fn write_program_headers_placeholder(&mut self, count: u32) -> (u64, u64) {
if count == 0 {
return (0, 0);
}
let offset = self.offset();
debug_assert_eq!(offset, self.encoder.file_header_size());
SinglePhase::set_offset(&mut self.layout.e_phoff, offset);
SinglePhase::set_count(&mut self.layout.segment_num, count);
self.written_segment_num = count;
let size = u64::from(count) * self.encoder.program_header_size();
self.buffer.write_zeros(size);
(offset, size)
}
pub fn write_headers_to(
&mut self,
buffer: &mut dyn WritableBuffer,
program_headers: &[ProgramHeader],
) -> Result<()> {
debug_assert_eq!(program_headers.len(), self.layout.segment_num as usize);
self.write_file_header_to(buffer)?;
for header in program_headers {
self.encoder.program_header(buffer, header);
}
Ok(())
}
pub fn write_program_header_to(
&mut self,
buffer: &mut dyn WritableBuffer,
header: &ProgramHeader,
) {
self.encoder.program_header(buffer, header);
}
pub fn write_shstrtab(&mut self) -> Result<(u64, u32)> {
debug_assert_eq!(self.shstrtab_offset, 0);
self.shstrtab_str_id = Some(self.add_section_name(b".shstrtab"));
self.shstrtab_offset = self.offset();
self.shstrtab_size = self.encoder.strtab(&mut self.buffer, &mut self.shstrtab)?;
Ok((self.shstrtab_offset, self.shstrtab_size))
}
pub fn write_strtab(&mut self) -> Result<(u64, u32)> {
if !self.need_strtab && self.strtab.is_empty() {
return Ok((0, 0));
}
debug_assert_eq!(self.strtab_offset, 0);
self.strtab_str_id = Some(self.add_section_name(b".strtab"));
self.strtab_offset = self.offset();
self.strtab_size = self.encoder.strtab(&mut self.buffer, &mut self.strtab)?;
Ok((self.strtab_offset, self.strtab_size))
}
pub fn write_dynstr(&mut self) -> Result<(u64, u32)> {
if !self.need_dynstr && self.dynstr.is_empty() {
return Ok((0, 0));
}
debug_assert_eq!(self.dynstr_offset, 0);
self.dynstr_str_id = Some(self.add_section_name(b".dynstr"));
self.dynstr_offset = self.offset();
self.dynstr_size = self.encoder.strtab(&mut self.buffer, &mut self.dynstr)?;
Ok((self.dynstr_offset, self.dynstr_size))
}
pub fn write_align_gnu_verdef(&mut self, count: u16) -> u64 {
if count == 0 {
return 0;
}
self.gnu_verdef_count = count;
self.gnu_verdef_remaining = count;
self.write_align_gnu_verdef_impl()
}
pub fn write_align_gnu_verneed(&mut self, count: u16) -> u64 {
if count == 0 {
return 0;
}
self.gnu_verneed_count = count;
self.gnu_verneed_remaining = count;
self.write_align_gnu_verneed_impl()
}
}
#[derive(Debug)]
pub struct TwoPhase {
len: u64,
shstrtab_data: Vec<u8>,
strtab_data: Vec<u8>,
dynstr_data: Vec<u8>,
}
impl Mode for TwoPhase {}
#[allow(private_interfaces)]
impl ModeSealed for TwoPhase {
fn string_table() -> StringTable<'static> {
StringTable::new()
}
fn reserve(&self, buffer: &mut dyn WritableBuffer, encoder: Encoder<Endianness>) -> Result<()> {
let len = self.len;
if !encoder.is_64() && len > u64::from(u32::MAX) {
return Err(Error(format!("File size overflow: {len:#x}")));
}
buffer
.reserve(len)
.map_err(|_| Error(String::from("Cannot allocate buffer")))
}
fn need_offset(offset: u64) -> bool {
offset != 0
}
fn set_offset(dest: &mut u64, offset: u64) {
debug_assert_eq!(*dest, offset);
}
fn set_size(dest: &mut u64, size: u64) {
debug_assert_eq!(*dest, size);
}
fn set_section_index(dest: &mut u32, index: SectionIndex) {
debug_assert_eq!(*dest, index.0);
}
fn set_section_name(
dest: &mut Option<StringId>,
shstrtab: &mut StringTable<'_>,
name: &'static [u8],
) {
debug_assert_eq!(*dest, Some(shstrtab.get_id(name)));
}
fn set_count<T: Copy + PartialOrd>(dest: &mut T, count: T) {
debug_assert!(*dest >= count);
}
}
impl<'a> Writer<'a, TwoPhase> {
pub fn new(endian: Endianness, is_64: bool, buffer: &'a mut dyn WritableBuffer) -> Self {
let mode = TwoPhase {
len: 0,
shstrtab_data: Vec::new(),
strtab_data: Vec::new(),
dynstr_data: Vec::new(),
};
Writer::new_with_mode(endian, is_64, buffer, mode)
}
pub fn reserved_len(&self) -> u64 {
self.mode.len
}
pub fn reserve(&mut self, len: u64, align_start: u64) -> u64 {
if align_start > 1 {
self.mode.len = util::align(self.mode.len, align_start);
}
let offset = self.mode.len;
self.mode.len += len;
offset
}
pub fn reserve_until(&mut self, offset: u64) {
debug_assert!(self.mode.len <= offset);
self.mode.len = offset;
}
pub fn reserve_file_header(&mut self) {
debug_assert_eq!(self.mode.len, 0);
self.reserve(self.encoder.file_header_size(), 1);
}
pub fn reserve_program_headers(&mut self, num: u32) {
debug_assert_eq!(self.layout.e_phoff, 0);
if num == 0 {
return;
}
self.layout.segment_num = num;
self.layout.e_phoff = self.reserve(
num as u64 * self.encoder.program_header_size(),
self.encoder.address_size(),
);
}
pub fn reserve_null_section_index(&mut self) -> SectionIndex {
debug_assert_eq!(self.layout.section_num, 0);
if self.layout.section_num == 0 {
self.layout.section_num = 1;
}
SectionIndex(0)
}
pub fn reserve_section_index(&mut self) -> SectionIndex {
debug_assert_eq!(self.layout.e_shoff, 0);
if self.layout.section_num == 0 {
self.layout.section_num = 1;
}
let index = self.layout.section_num;
self.layout.section_num += 1;
SectionIndex(index)
}
pub fn reserve_section_headers(&mut self) {
debug_assert_eq!(self.layout.e_shoff, 0);
if self.layout.section_num == 0 {
return;
}
self.layout.e_shoff = self.reserve(
self.layout.section_num as u64 * self.encoder.section_header_size(),
self.encoder.address_size(),
);
}
pub fn reserve_shstrtab(&mut self) -> Result<()> {
debug_assert_eq!(self.shstrtab_offset, 0);
if self.layout.section_num == 0 {
return Ok(());
}
self.shstrtab_size = self
.encoder
.strtab(&mut self.mode.shstrtab_data, &mut self.shstrtab)?;
self.shstrtab_offset = self.reserve(self.shstrtab_size as u64, 1);
Ok(())
}
pub fn write_shstrtab(&mut self) {
if self.shstrtab_offset == 0 {
return;
}
debug_assert_eq!(self.shstrtab_offset, self.offset());
self.buffer.write_bytes(&self.mode.shstrtab_data);
}
pub fn reserve_shstrtab_section_index(&mut self) -> SectionIndex {
debug_assert_eq!(self.layout.shstrtab_index, 0);
self.shstrtab_str_id = Some(self.add_section_name(b".shstrtab"));
self.layout.shstrtab_index = self.reserve_section_index().0;
SectionIndex(self.layout.shstrtab_index)
}
pub fn strtab_needed(&self) -> bool {
self.need_strtab || !self.strtab.is_empty()
}
pub fn require_strtab(&mut self) {
self.need_strtab = true;
}
pub fn reserve_strtab(&mut self) -> Result<()> {
debug_assert_eq!(self.strtab_offset, 0);
if !self.strtab_needed() {
return Ok(());
}
self.strtab_size = self
.encoder
.strtab(&mut self.mode.strtab_data, &mut self.strtab)?;
self.strtab_offset = self.reserve(self.strtab_size as u64, 1);
Ok(())
}
pub fn write_strtab(&mut self) {
if self.strtab_offset == 0 {
return;
}
debug_assert_eq!(self.strtab_offset, self.offset());
self.buffer.write_bytes(&self.mode.strtab_data);
}
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
}
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 u64 * self.encoder.sym_size(),
self.encoder.address_size(),
);
}
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
}
pub fn symtab_index(&mut self) -> SectionIndex {
self.symtab_index
}
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.symtab_shndx_needed() {
return;
}
self.symtab_shndx_offset = self.reserve(self.symtab_num as u64 * 4, ALIGN_SYMTAB_SHNDX);
self.symtab_shndx_data.reserve(self.symtab_num as usize * 4);
}
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()
}
pub fn dynstr_needed(&self) -> bool {
self.need_dynstr || !self.dynstr.is_empty()
}
pub fn require_dynstr(&mut self) {
self.need_dynstr = true;
}
pub fn reserve_dynstr(&mut self) -> Result<u64> {
debug_assert_eq!(self.dynstr_offset, 0);
if !self.dynstr_needed() {
return Ok(0);
}
self.dynstr_size = self
.encoder
.strtab(&mut self.mode.dynstr_data, &mut self.dynstr)?;
self.dynstr_offset = self.reserve(self.dynstr_size as u64, 1);
Ok(self.dynstr_offset)
}
pub fn dynstr_len(&self) -> u32 {
if !self.dynstr_needed() {
return 0;
}
debug_assert_ne!(self.dynstr_offset, 0);
self.dynstr_size
}
pub fn write_dynstr(&mut self) {
if self.dynstr_offset == 0 {
return;
}
debug_assert_eq!(self.dynstr_offset, self.offset());
self.buffer.write_bytes(&self.mode.dynstr_data);
}
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
}
pub fn dynstr_index(&mut self) -> SectionIndex {
self.dynstr_index
}
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;
self.need_dynstr = true;
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;
self.need_dynstr = true;
}
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) -> u64 {
debug_assert_eq!(self.dynsym_offset, 0);
if self.dynsym_num == 0 {
return 0;
}
self.dynsym_offset = self.reserve(
self.dynsym_num as u64 * self.encoder.sym_size(),
self.encoder.address_size(),
);
self.dynsym_offset
}
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
}
pub fn dynsym_index(&mut self) -> SectionIndex {
self.dynsym_index
}
pub fn reserve_dynamic(&mut self, dynamic_num: usize) -> u64 {
debug_assert_eq!(self.dynamic_offset, 0);
if dynamic_num == 0 {
return 0;
}
self.dynamic_num = dynamic_num as u64;
self.dynamic_offset = self.reserve(
self.dynamic_num * self.encoder.dyn_size(),
self.encoder.address_size(),
);
self.dynamic_offset
}
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 reserve_hash(&mut self, bucket_count: u32, symbol_count: u32) -> u64 {
let size = self.encoder.hash_size(bucket_count, symbol_count);
self.hash_offset = self.reserve(size, ALIGN_HASH);
self.hash_size = size;
self.hash_offset
}
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()
}
pub fn reserve_gnu_hash(
&mut self,
bloom_count: u32,
bucket_count: u32,
symbol_count: u32,
) -> u64 {
let size = self
.encoder
.gnu_hash_size(bloom_count, bucket_count, symbol_count);
self.gnu_hash_offset = self.reserve(size, self.encoder.address_size());
self.gnu_hash_size = size;
self.gnu_hash_offset
}
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()
}
pub fn reserve_gnu_versym(&mut self) -> u64 {
debug_assert_eq!(self.gnu_versym_offset, 0);
if self.dynsym_num == 0 {
return 0;
}
self.gnu_versym_num = self.dynsym_num;
let size = self.encoder.gnu_versym_size(self.gnu_versym_num);
self.gnu_versym_offset = self.reserve(size, ALIGN_GNU_VERSYM);
self.gnu_versym_offset
}
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()
}
pub fn reserve_gnu_verdef(&mut self, verdef_count: u16, verdaux_count: usize) -> u64 {
debug_assert_eq!(self.gnu_verdef_offset, 0);
if verdef_count == 0 {
return 0;
}
let size = self.encoder.gnu_verdef_size(verdef_count, verdaux_count);
self.gnu_verdef_offset = self.reserve(size, ALIGN_GNU_VERDEF);
self.gnu_verdef_count = verdef_count;
self.gnu_verdaux_count = verdaux_count;
self.gnu_verdef_remaining = self.gnu_verdef_count;
self.gnu_verdef_offset
}
pub fn write_align_gnu_verdef(&mut self) {
self.write_align_gnu_verdef_impl();
}
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()
}
pub fn reserve_gnu_verneed(&mut self, verneed_count: u16, vernaux_count: usize) -> u64 {
debug_assert_eq!(self.gnu_verneed_offset, 0);
if verneed_count == 0 {
return 0;
}
let size = self.encoder.gnu_verneed_size(verneed_count, vernaux_count);
self.gnu_verneed_offset = self.reserve(size, ALIGN_GNU_VERNEED);
self.gnu_verneed_count = verneed_count;
self.gnu_vernaux_count = vernaux_count;
self.gnu_verneed_remaining = self.gnu_verneed_count;
self.gnu_verneed_offset
}
pub fn write_align_gnu_verneed(&mut self) {
self.write_align_gnu_verneed_impl();
}
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()
}
pub fn reserve_gnu_attributes_section_index(&mut self) -> SectionIndex {
debug_assert!(self.gnu_attributes_str_id.is_none());
self.gnu_attributes_str_id = Some(self.add_section_name(b".gnu.attributes"));
self.reserve_section_index()
}
pub fn reserve_gnu_attributes(&mut self, gnu_attributes_size: u64) -> u64 {
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(gnu_attributes_size, 1);
self.gnu_attributes_offset
}
pub fn reserve_relocations(&mut self, count: usize, is_rela: bool) -> u64 {
self.reserve(
count as u64 * self.encoder.rel_size(is_rela),
self.encoder.address_size(),
)
}
pub fn reserve_comdat(&mut self, count: usize) -> u64 {
self.reserve((count as u64 + 1) * 4, 4)
}
}