mirror of
https://github.com/encounter/object.git
synced 2026-07-10 12:18:39 -07:00
write/elf: add Encoder (#910)
This is the struct writing component of `Writer`, without any state management. `Encoder` also includes size methods, replacing the need for `Class`. `build::elf::Builder` already does a lot of its own state management, so change it to use `Encoder`. Breaking change: the structs for writing need more information computed by the caller (string offsets and version string hashes). Added `Writer` methods to return string offsets.
This commit is contained in:
@@ -613,8 +613,8 @@ pub fn elfcopy<Elf: FileHeader<Endian = Endianness>>(
|
||||
for sym in &out_dynsyms {
|
||||
let in_dynsym = in_dynsyms.symbol(sym.in_sym)?;
|
||||
writer.write_dynamic_symbol(&object::write::elf::Sym {
|
||||
name: sym.name,
|
||||
section: sym.section,
|
||||
section: sym.section.map(|s| s.0),
|
||||
st_name: writer.dynamic_string_offset(sym.name),
|
||||
st_info: in_dynsym.st_info(),
|
||||
st_other: in_dynsym.st_other(),
|
||||
st_shndx: in_dynsym.st_shndx(endian),
|
||||
@@ -664,12 +664,15 @@ pub fn elfcopy<Elf: FileHeader<Endian = Endianness>>(
|
||||
writer.write_align_gnu_verdef();
|
||||
while let Some((verdef, mut verdauxs)) = verdefs.next()? {
|
||||
let verdaux = verdauxs.next()?.unwrap();
|
||||
let name = verdaux.name(endian, strings)?;
|
||||
let name_id = writer.get_dynamic_string(name);
|
||||
let verdef = object::write::elf::Verdef {
|
||||
version: verdef.vd_version.get(endian),
|
||||
flags: verdef.vd_flags.get(endian),
|
||||
index: verdef.vd_ndx.get(endian),
|
||||
aux_count: verdef.vd_cnt.get(endian),
|
||||
name: writer.get_dynamic_string(verdaux.name(endian, strings)?),
|
||||
name: writer.dynamic_string_offset(Some(name_id)),
|
||||
hash: elf::hash(name),
|
||||
};
|
||||
if verdef_shared_base {
|
||||
writer.write_gnu_verdef_shared(&verdef);
|
||||
@@ -689,16 +692,20 @@ pub fn elfcopy<Elf: FileHeader<Endian = Endianness>>(
|
||||
let strings = in_sections.strings(endian, in_data, link)?;
|
||||
writer.write_align_gnu_verneed();
|
||||
while let Some((verneed, mut vernauxs)) = verneeds.next()? {
|
||||
let file_id = writer.get_dynamic_string(verneed.file(endian, strings)?);
|
||||
writer.write_gnu_verneed(&object::write::elf::Verneed {
|
||||
version: verneed.vn_version.get(endian),
|
||||
aux_count: verneed.vn_cnt.get(endian),
|
||||
file: writer.get_dynamic_string(verneed.file(endian, strings)?),
|
||||
file: writer.dynamic_string_offset(Some(file_id)),
|
||||
});
|
||||
while let Some(vernaux) = vernauxs.next()? {
|
||||
let name = vernaux.name(endian, strings)?;
|
||||
let name_id = writer.get_dynamic_string(name);
|
||||
writer.write_gnu_vernaux(&object::write::elf::Vernaux {
|
||||
flags: vernaux.vna_flags.get(endian),
|
||||
index: vernaux.vna_other.get(endian),
|
||||
name: writer.get_dynamic_string(vernaux.name(endian, strings)?),
|
||||
name: writer.dynamic_string_offset(Some(name_id)),
|
||||
hash: elf::hash(name),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -731,8 +738,8 @@ pub fn elfcopy<Elf: FileHeader<Endian = Endianness>>(
|
||||
for sym in &out_syms {
|
||||
let in_sym = in_syms.symbol(sym.in_sym)?;
|
||||
writer.write_symbol(&object::write::elf::Sym {
|
||||
name: sym.name,
|
||||
section: sym.section,
|
||||
section: sym.section.map(|s| s.0),
|
||||
st_name: writer.string_offset(sym.name),
|
||||
st_info: in_sym.st_info(),
|
||||
st_other: in_sym.st_other(),
|
||||
st_shndx: in_sym.st_shndx(endian),
|
||||
@@ -819,7 +826,7 @@ pub fn elfcopy<Elf: FileHeader<Endian = Endianness>>(
|
||||
sh_info = out_sections_index[sh_info as usize].0;
|
||||
}
|
||||
writer.write_section_header(&object::write::elf::SectionHeader {
|
||||
name: out_section.name,
|
||||
sh_name: writer.section_name_offset(out_section.name),
|
||||
sh_type: in_section.sh_type(endian),
|
||||
sh_flags: in_section.sh_flags(endian),
|
||||
sh_addr: in_section.sh_addr(endian).into(),
|
||||
|
||||
@@ -70,13 +70,13 @@ pub fn elfstub(data: &[u8]) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
let mut st_size = sym.st_size(endian);
|
||||
let st_shndx = sym.st_shndx(endian);
|
||||
if sym.st_shndx(endian).index().is_some() {
|
||||
section = Some(stub_section_index);
|
||||
section = Some(stub_section_index.0);
|
||||
st_value = stub_offset + i as u64;
|
||||
st_size = 1;
|
||||
}
|
||||
|
||||
writer.write_dynamic_symbol(&Sym {
|
||||
name: id,
|
||||
st_name: writer.dynamic_string_offset(id),
|
||||
section,
|
||||
st_info: sym.st_info(),
|
||||
st_other: sym.st_other(),
|
||||
@@ -122,13 +122,15 @@ pub fn elfstub(data: &[u8]) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
let Some(verdaux) = verdauxs.next()? else {
|
||||
return Err("missing verdef name".into());
|
||||
};
|
||||
let name = writer.add_dynamic_string(verdaux.name(endian, strings)?);
|
||||
let name_bytes = verdaux.name(endian, strings)?;
|
||||
let name_id = writer.add_dynamic_string(name_bytes);
|
||||
writer.write_gnu_verdef(&Verdef {
|
||||
version: verdef.vd_version.get(endian),
|
||||
flags: verdef.vd_flags.get(endian),
|
||||
index: verdef.vd_ndx.get(endian),
|
||||
aux_count,
|
||||
name,
|
||||
name: writer.dynamic_string_offset(Some(name_id)),
|
||||
hash: elf::hash(name_bytes),
|
||||
});
|
||||
while let Some(verdaux) = verdauxs.next()? {
|
||||
let name = writer.add_dynamic_string(verdaux.name(endian, strings)?);
|
||||
@@ -147,18 +149,20 @@ pub fn elfstub(data: &[u8]) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
writer.set_gnu_verneed_count(verneed_count);
|
||||
while let Some((verneed, mut vernauxs)) = verneeds.next()? {
|
||||
let aux_count = vernauxs.clone().count() as u16;
|
||||
let file = writer.add_dynamic_string(verneed.file(endian, strings)?);
|
||||
let file_id = writer.add_dynamic_string(verneed.file(endian, strings)?);
|
||||
writer.write_gnu_verneed(&Verneed {
|
||||
version: verneed.vn_version.get(endian),
|
||||
aux_count,
|
||||
file,
|
||||
file: writer.dynamic_string_offset(Some(file_id)),
|
||||
});
|
||||
while let Some(vernaux) = vernauxs.next()? {
|
||||
let name = writer.add_dynamic_string(vernaux.name(endian, strings)?);
|
||||
let name_bytes = vernaux.name(endian, strings)?;
|
||||
let name_id = writer.add_dynamic_string(name_bytes);
|
||||
writer.write_gnu_vernaux(&Vernaux {
|
||||
flags: vernaux.vna_flags.get(endian),
|
||||
index: vernaux.vna_other.get(endian),
|
||||
name,
|
||||
name: writer.dynamic_string_offset(Some(name_id)),
|
||||
hash: elf::hash(name_bytes),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -241,7 +245,7 @@ pub fn elfstub(data: &[u8]) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
// PT_LOAD maps p_vaddr == p_offset so all section addresses are equal to offsets.
|
||||
writer.write_null_section_header();
|
||||
let index = writer.write_section_header(&SectionHeader {
|
||||
name: Some(stub_name_id),
|
||||
sh_name: writer.section_name_offset(Some(stub_name_id)),
|
||||
sh_type: elf::SHT_PROGBITS,
|
||||
sh_flags: elf::SHF_ALLOC,
|
||||
sh_addr: stub_offset,
|
||||
|
||||
@@ -758,7 +758,7 @@ fn find_move_sections(
|
||||
let mut blocks = Vec::new();
|
||||
let file_header_size = builder.file_header_size() as u64;
|
||||
let program_headers_size = (builder.program_headers_size()
|
||||
+ added_segments * builder.class().program_header_size())
|
||||
+ added_segments * builder.encoder().program_header_size())
|
||||
as u64;
|
||||
let interp = builder.interp_section();
|
||||
|
||||
|
||||
+397
-320
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -5,5 +5,8 @@
|
||||
|
||||
mod object;
|
||||
|
||||
mod encoder;
|
||||
pub use encoder::*;
|
||||
|
||||
mod writer;
|
||||
pub use writer::*;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::write::elf::encoder::*;
|
||||
use crate::write::elf::writer::*;
|
||||
use crate::write::string::StringId;
|
||||
use crate::write::*;
|
||||
@@ -799,11 +800,11 @@ impl<'a> Object<'a> {
|
||||
SymbolSection::Absolute => (elf::SHN_ABS, None),
|
||||
SymbolSection::Common => (elf::SHN_COMMON, None),
|
||||
SymbolSection::Section(id) => {
|
||||
(elf::SymbolSection(0), Some(section_offsets[id.0].index))
|
||||
(elf::SymbolSection(0), Some(section_offsets[id.0].index.0))
|
||||
}
|
||||
};
|
||||
writer.write_symbol(&Sym {
|
||||
name: symbol_offsets[index].str_id,
|
||||
st_name: writer.string_offset(symbol_offsets[index].str_id),
|
||||
section,
|
||||
st_info,
|
||||
st_other,
|
||||
@@ -880,7 +881,7 @@ impl<'a> Object<'a> {
|
||||
_ => 0,
|
||||
};
|
||||
writer.write_section_header(&SectionHeader {
|
||||
name: Some(section_offsets[index].str_id),
|
||||
sh_name: writer.section_name_offset(Some(section_offsets[index].str_id)),
|
||||
sh_type,
|
||||
sh_flags,
|
||||
sh_addr: 0,
|
||||
|
||||
+215
-925
File diff suppressed because it is too large
Load Diff
@@ -99,6 +99,17 @@ impl<'a> StringTable<'a> {
|
||||
self.offsets[id.0]
|
||||
}
|
||||
|
||||
/// Return the offset of an optional string.
|
||||
///
|
||||
/// Returns 0 if `id` is `None`. Otherwise see [`Self::get_offset`].
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn maybe_get_offset(&self, id: Option<StringId>) -> u32 {
|
||||
let Some(id) = id else {
|
||||
return 0;
|
||||
};
|
||||
self.get_offset(id)
|
||||
}
|
||||
|
||||
/// Append the string table to the given `Vec`, and
|
||||
/// calculate the list of string offsets.
|
||||
///
|
||||
|
||||
+11
-1
@@ -281,11 +281,21 @@ pub(crate) fn align_u64(offset: u64, size: u64) -> u64 {
|
||||
(offset + (size - 1)) & !(size - 1)
|
||||
}
|
||||
|
||||
pub(crate) fn write_align(buffer: &mut dyn WritableBuffer, size: usize) {
|
||||
pub(crate) fn write_align<W: WritableBuffer + ?Sized>(buffer: &mut W, size: usize) {
|
||||
let new_len = align(buffer.len(), size);
|
||||
buffer.resize(new_len);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn write_pod<T: Pod, W: WritableBuffer + ?Sized>(buffer: &mut W, val: &T) {
|
||||
buffer.write_bytes(bytes_of(val))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn write_pod_slice<T: Pod, W: WritableBuffer + ?Sized>(buffer: &mut W, val: &[T]) {
|
||||
buffer.write_bytes(bytes_of_slice(val))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user