mirror of
https://github.com/encounter/object.git
synced 2026-07-10 12:18:39 -07:00
write/elf: avoid temp Vec for strtab in SinglePhase mode (#916)
Change `StringTable::write` to allow writing directly to the WritableBuffer. Also add `Encoder::strtab`.
This commit is contained in:
+14
-13
@@ -1135,17 +1135,18 @@ impl<'data> Builder<'data> {
|
||||
));
|
||||
}
|
||||
|
||||
// Build string tables.
|
||||
let mut shstrtab_data = vec![0];
|
||||
shstrtab.write(1, &mut shstrtab_data)?;
|
||||
let mut strtab_data = vec![0];
|
||||
strtab.write(1, &mut strtab_data)?;
|
||||
let mut dynstr_data = vec![0];
|
||||
dynstr.write(1, &mut dynstr_data)?;
|
||||
|
||||
// Start reserving file ranges.
|
||||
let encoder = self.encoder();
|
||||
let address_size = u64::from(encoder.address_size());
|
||||
|
||||
// Build string tables.
|
||||
let mut shstrtab_data = Vec::new();
|
||||
let shstrtab_len = encoder.strtab(&mut shstrtab_data, &mut shstrtab)?;
|
||||
let mut strtab_data = Vec::new();
|
||||
let strtab_len = encoder.strtab(&mut strtab_data, &mut strtab)?;
|
||||
let mut dynstr_data = Vec::new();
|
||||
let dynstr_len = encoder.strtab(&mut dynstr_data, &mut dynstr)?;
|
||||
|
||||
// Start reserving file ranges.
|
||||
let mut offset = Offset(encoder.file_header_size());
|
||||
|
||||
let mut dynsym_addr = None;
|
||||
@@ -1236,7 +1237,7 @@ impl<'data> Builder<'data> {
|
||||
}
|
||||
SectionData::DynamicString => {
|
||||
dynstr_addr = Some(section.sh_addr);
|
||||
offset.reserve(dynstr_data.len() as u64, 1)
|
||||
offset.reserve(dynstr_len.into(), 1)
|
||||
}
|
||||
SectionData::Hash => {
|
||||
hash_addr = Some(section.sh_addr);
|
||||
@@ -1323,7 +1324,7 @@ impl<'data> Builder<'data> {
|
||||
out_sections[symtab_shndx_index as usize - 1].set_range(range);
|
||||
}
|
||||
if strtab_index != 0 {
|
||||
let range = offset.reserve(strtab_data.len() as u64, 1);
|
||||
let range = offset.reserve(strtab_len.into(), 1);
|
||||
out_sections[strtab_index as usize - 1].set_range(range);
|
||||
}
|
||||
|
||||
@@ -1342,7 +1343,7 @@ impl<'data> Builder<'data> {
|
||||
}
|
||||
|
||||
if shstrtab_index != 0 {
|
||||
let range = offset.reserve(shstrtab_data.len() as u64, 1);
|
||||
let range = offset.reserve(shstrtab_len.into(), 1);
|
||||
out_sections[shstrtab_index as usize - 1].set_range(range);
|
||||
}
|
||||
let e_shoff = if section_num != 0 {
|
||||
@@ -1438,7 +1439,7 @@ impl<'data> Builder<'data> {
|
||||
elf::DT_STRTAB => dynstr_addr.ok_or(Error::new(
|
||||
"Missing .dynstr section for DT_STRTAB",
|
||||
))?,
|
||||
elf::DT_STRSZ => dynstr_data.len() as u64,
|
||||
elf::DT_STRSZ => dynstr_len.into(),
|
||||
elf::DT_HASH => hash_addr.ok_or(Error::new(
|
||||
"Missing .hash section for DT_HASH",
|
||||
))?,
|
||||
|
||||
@@ -451,7 +451,7 @@ impl<'a> Writer<'a> {
|
||||
|
||||
debug_assert_eq!(self.strtab_offset, 0);
|
||||
// First 4 bytes of strtab are the length.
|
||||
self.strtab_len = self.strtab.write(4, &mut self.strtab_data)?;
|
||||
self.strtab_len = self.strtab.write(&mut self.strtab_data, 4)?;
|
||||
self.strtab_offset = self.reserve(self.strtab_len as u64, 1);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::elf;
|
||||
use crate::endian::*;
|
||||
use crate::pod;
|
||||
use crate::write::util::{write_align, write_pod, write_pod_slice};
|
||||
use crate::write::{self, Error, Result, WritableBuffer};
|
||||
use crate::write::{self, Error, Result, StringTable, WritableBuffer};
|
||||
|
||||
/// Alignment for .symtab_shndx.
|
||||
pub const ALIGN_SYMTAB_SHNDX: u64 = 4;
|
||||
@@ -692,6 +692,18 @@ impl<E: Endian> Encoder<E> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Write the data for a string table.
|
||||
///
|
||||
/// Returns the length of the written data.
|
||||
pub fn strtab<W: WritableBuffer + ?Sized>(
|
||||
self,
|
||||
buffer: &mut W,
|
||||
strtab: &mut StringTable<'_>,
|
||||
) -> Result<u32> {
|
||||
buffer.write_bytes(&[0]);
|
||||
strtab.write(buffer, 1)
|
||||
}
|
||||
|
||||
/// Return the size of a symbol.
|
||||
pub fn sym_size(self) -> u64 {
|
||||
if self.is_64 {
|
||||
|
||||
+12
-21
@@ -1282,11 +1282,8 @@ impl<'a> Writer<'a, SinglePhase> {
|
||||
// Thus we always write this if called.
|
||||
debug_assert_eq!(self.shstrtab_offset, 0);
|
||||
self.shstrtab_str_id = Some(self.add_section_name(b".shstrtab"));
|
||||
// Start with null section name.
|
||||
let mut data = vec![0];
|
||||
self.shstrtab_size = self.shstrtab.write(1, &mut data)?;
|
||||
self.shstrtab_offset = self.offset();
|
||||
self.write(&data);
|
||||
self.shstrtab_size = self.encoder.strtab(self.buffer, &mut self.shstrtab)?;
|
||||
Ok((self.shstrtab_offset, self.shstrtab_size))
|
||||
}
|
||||
|
||||
@@ -1301,11 +1298,8 @@ impl<'a> Writer<'a, SinglePhase> {
|
||||
}
|
||||
debug_assert_eq!(self.strtab_offset, 0);
|
||||
self.strtab_str_id = Some(self.add_section_name(b".strtab"));
|
||||
// Start with null section name.
|
||||
let mut data = vec![0];
|
||||
self.strtab_size = self.strtab.write(1, &mut data)?;
|
||||
self.strtab_offset = self.offset();
|
||||
self.write(&data);
|
||||
self.strtab_size = self.encoder.strtab(self.buffer, &mut self.strtab)?;
|
||||
Ok((self.strtab_offset, self.strtab_size))
|
||||
}
|
||||
|
||||
@@ -1320,11 +1314,8 @@ impl<'a> Writer<'a, SinglePhase> {
|
||||
}
|
||||
debug_assert_eq!(self.dynstr_offset, 0);
|
||||
self.dynstr_str_id = Some(self.add_section_name(b".dynstr"));
|
||||
// Start with null section name.
|
||||
let mut data = vec![0];
|
||||
self.dynstr_size = self.dynstr.write(1, &mut data)?;
|
||||
self.dynstr_offset = self.offset();
|
||||
self.write(&data);
|
||||
self.dynstr_size = self.encoder.strtab(self.buffer, &mut self.dynstr)?;
|
||||
Ok((self.dynstr_offset, self.dynstr_size))
|
||||
}
|
||||
|
||||
@@ -1554,9 +1545,9 @@ impl<'a> Writer<'a, TwoPhase> {
|
||||
if self.layout.section_num == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
// Start with null section name.
|
||||
self.mode.shstrtab_data = vec![0];
|
||||
self.shstrtab_size = self.shstrtab.write(1, &mut self.mode.shstrtab_data)?;
|
||||
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(())
|
||||
}
|
||||
@@ -1607,9 +1598,9 @@ impl<'a> Writer<'a, TwoPhase> {
|
||||
if !self.strtab_needed() {
|
||||
return Ok(());
|
||||
}
|
||||
// Start with null string.
|
||||
self.mode.strtab_data = vec![0];
|
||||
self.strtab_size = self.strtab.write(1, &mut self.mode.strtab_data)?;
|
||||
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(())
|
||||
}
|
||||
@@ -1789,9 +1780,9 @@ impl<'a> Writer<'a, TwoPhase> {
|
||||
if !self.dynstr_needed() {
|
||||
return Ok(0);
|
||||
}
|
||||
// Start with null string.
|
||||
self.mode.dynstr_data = vec![0];
|
||||
self.dynstr_size = self.dynstr.write(1, &mut self.mode.dynstr_data)?;
|
||||
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)
|
||||
}
|
||||
|
||||
+1
-1
@@ -603,7 +603,7 @@ impl<'a> Object<'a> {
|
||||
let strtab_offset = offset;
|
||||
// Start with null name.
|
||||
let mut strtab_data = vec![0];
|
||||
strtab.write(1, &mut strtab_data)?;
|
||||
strtab.write(&mut strtab_data, 1)?;
|
||||
write_align(&mut strtab_data, pointer_align);
|
||||
offset += strtab_data.len() as u64;
|
||||
|
||||
|
||||
+11
-11
@@ -1,6 +1,6 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::write::{Error, Result};
|
||||
use crate::write::{Error, Result, WritableBuffer};
|
||||
|
||||
#[cfg(feature = "write_std")]
|
||||
type IndexSet<K> = indexmap::IndexSet<K>;
|
||||
@@ -104,7 +104,7 @@ impl<'a> StringTable<'a> {
|
||||
self.get_offset(id)
|
||||
}
|
||||
|
||||
/// Append the string table to the given `Vec`, and
|
||||
/// Append the string table to the given buffer, and
|
||||
/// calculate the list of string offsets.
|
||||
///
|
||||
/// `base` is the initial string table offset. For example,
|
||||
@@ -117,7 +117,7 @@ impl<'a> StringTable<'a> {
|
||||
/// - `write` has already been called
|
||||
/// - any string contains a null byte
|
||||
/// - the string table size is > `u32::MAX`
|
||||
pub fn write(&mut self, base: u32, w: &mut Vec<u8>) -> Result<u32> {
|
||||
pub fn write<W: WritableBuffer + ?Sized>(&mut self, w: &mut W, base: u32) -> Result<u32> {
|
||||
if !self.in_order && !self.offsets.is_empty() {
|
||||
return Err(Error("string table already written".into()));
|
||||
}
|
||||
@@ -128,8 +128,8 @@ impl<'a> StringTable<'a> {
|
||||
if self.in_order {
|
||||
debug_assert_eq!(self.base, base);
|
||||
for string in &self.strings {
|
||||
w.extend_from_slice(string);
|
||||
w.push(0);
|
||||
w.write_bytes(string);
|
||||
w.write_bytes(&[0]);
|
||||
}
|
||||
return u32::try_from(self.size)
|
||||
.map_err(|_| Error("string table size overflow".into()));
|
||||
@@ -148,8 +148,8 @@ impl<'a> StringTable<'a> {
|
||||
self.offsets[id] = (offset - len) as u32;
|
||||
} else {
|
||||
self.offsets[id] = offset as u32;
|
||||
w.extend_from_slice(string);
|
||||
w.push(0);
|
||||
w.write_bytes(string);
|
||||
w.write_bytes(&[0]);
|
||||
offset += len;
|
||||
previous = string;
|
||||
}
|
||||
@@ -253,7 +253,7 @@ mod tests {
|
||||
let id3 = table.add(b"foobar");
|
||||
|
||||
let mut data = vec![0];
|
||||
assert_eq!(table.write(1, &mut data), Ok(12));
|
||||
assert_eq!(table.write(&mut data, 1), Ok(12));
|
||||
assert_eq!(data, b"\0foobar\0foo\0");
|
||||
|
||||
assert_eq!(table.get_offset(id0), 11);
|
||||
@@ -262,7 +262,7 @@ mod tests {
|
||||
assert_eq!(table.get_offset(id3), 1);
|
||||
|
||||
let mut data = Vec::new();
|
||||
assert!(table.write(1, &mut data).is_err());
|
||||
assert!(table.write(&mut data, 1).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -274,7 +274,7 @@ mod tests {
|
||||
let id3 = table.add(b"foobar");
|
||||
|
||||
let mut data = vec![0];
|
||||
assert_eq!(table.write(1, &mut data), Ok(17));
|
||||
assert_eq!(table.write(&mut data, 1), Ok(17));
|
||||
assert_eq!(data, b"\0\0foo\0bar\0foobar\0");
|
||||
|
||||
assert_eq!(table.get_offset(id0), 1);
|
||||
@@ -284,7 +284,7 @@ mod tests {
|
||||
|
||||
// Not documented or expected to be needed, but multiple writes aren't prevented.
|
||||
let mut data2 = vec![0];
|
||||
assert_eq!(table.write(1, &mut data2), Ok(17));
|
||||
assert_eq!(table.write(&mut data2, 1), Ok(17));
|
||||
assert_eq!(data, data2);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -349,7 +349,7 @@ impl<'a> Object<'a> {
|
||||
let strtab_offset = offset;
|
||||
let mut strtab_data = Vec::new();
|
||||
// First 4 bytes of strtab are the length.
|
||||
let strtab_len = strtab.write(4, &mut strtab_data)?;
|
||||
let strtab_len = strtab.write(&mut strtab_data, 4)?;
|
||||
offset += strtab_len as u64;
|
||||
|
||||
// Start writing.
|
||||
|
||||
Reference in New Issue
Block a user