Skip to content

Commit

Permalink
write: use Cow for Section::data (#370)
Browse files Browse the repository at this point in the history
  • Loading branch information
philipc authored Sep 1, 2021
1 parent f9831e6 commit 8255445
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 25 deletions.
2 changes: 1 addition & 1 deletion crates/examples/src/bin/objcopy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ fn main() {
if out_section.is_bss() {
out_section.append_bss(in_section.size(), in_section.align());
} else {
out_section.set_data(in_section.data().unwrap().into(), in_section.align());
out_section.set_data(in_section.data().unwrap(), in_section.align());
}
out_section.flags = in_section.flags();
out_sections.insert(in_section.index(), section_id);
Expand Down
4 changes: 2 additions & 2 deletions src/write/coff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct SymbolOffsets {
aux_count: u8,
}

impl Object {
impl<'a> Object<'a> {
pub(crate) fn coff_section_info(
&self,
section: StandardSection,
Expand Down Expand Up @@ -589,7 +589,7 @@ impl Object {
length: U32Bytes::new(LE, section.size as u32),
number_of_relocations: U16Bytes::new(LE, section.relocations.len() as u16),
number_of_linenumbers: U16Bytes::default(),
check_sum: U32Bytes::new(LE, checksum(section.data.as_slice())),
check_sum: U32Bytes::new(LE, checksum(section.data())),
number: U16Bytes::new(
LE,
section_offsets[section_index].associative_section,
Expand Down
2 changes: 1 addition & 1 deletion src/write/elf/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ struct SymbolOffsets {
str_id: Option<StringId>,
}

impl Object {
impl<'a> Object<'a> {
pub(crate) fn elf_section_info(
&self,
section: StandardSection,
Expand Down
2 changes: 1 addition & 1 deletion src/write/macho.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ struct SymbolOffsets {
str_id: Option<StringId>,
}

impl Object {
impl<'a> Object<'a> {
pub(crate) fn macho_set_subsections_via_symbols(&mut self) {
let flags = match self.flags {
FileFlags::MachO { flags } => flags,
Expand Down
55 changes: 35 additions & 20 deletions src/write/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Interface for writing object files.

use std::borrow::Cow;
use std::boxed::Box;
use std::collections::HashMap;
use std::string::String;
Expand Down Expand Up @@ -45,11 +46,11 @@ pub type Result<T> = result::Result<T, Error>;

/// A writable object file.
#[derive(Debug)]
pub struct Object {
pub struct Object<'a> {
format: BinaryFormat,
architecture: Architecture,
endian: Endianness,
sections: Vec<Section>,
sections: Vec<Section<'a>>,
standard_sections: HashMap<StandardSection, SectionId>,
symbols: Vec<Symbol>,
symbol_map: HashMap<Vec<u8>, SymbolId>,
Expand All @@ -63,9 +64,9 @@ pub struct Object {
tlv_bootstrap: Option<SymbolId>,
}

impl Object {
impl<'a> Object<'a> {
/// Create an empty object file.
pub fn new(format: BinaryFormat, architecture: Architecture, endian: Endianness) -> Object {
pub fn new(format: BinaryFormat, architecture: Architecture, endian: Endianness) -> Object<'a> {
Object {
format,
architecture,
Expand Down Expand Up @@ -124,16 +125,26 @@ impl Object {

/// Get the section with the given `SectionId`.
#[inline]
pub fn section(&self, section: SectionId) -> &Section {
pub fn section(&self, section: SectionId) -> &Section<'a> {
&self.sections[section.0]
}

/// Mutably get the section with the given `SectionId`.
#[inline]
pub fn section_mut(&mut self, section: SectionId) -> &mut Section {
pub fn section_mut(&mut self, section: SectionId) -> &mut Section<'a> {
&mut self.sections[section.0]
}

/// Set the data for an existing section.
///
/// Must not be called for sections that already have data, or that contain uninitialized data.
pub fn set_section_data<T>(&mut self, section: SectionId, data: T, align: u64)
where
T: Into<Cow<'a, [u8]>>,
{
self.sections[section.0].set_data(data, align)
}

/// Append data to an existing section. Returns the section offset of the data.
pub fn append_section_data(&mut self, section: SectionId, data: &[u8], align: u64) -> u64 {
self.sections[section.0].append_data(data, align)
Expand Down Expand Up @@ -168,7 +179,7 @@ impl Object {
kind,
size: 0,
align: 1,
data: Vec::new(),
data: Cow::Borrowed(&[]),
relocations: Vec::new(),
symbol: None,
flags: SectionFlags::None,
Expand Down Expand Up @@ -502,7 +513,7 @@ impl Object {
relocation: &Relocation,
addend: i64,
) -> Result<()> {
let data = &mut self.sections[section.0].data;
let data = self.sections[section.0].data_mut();
let offset = relocation.offset as usize;
match relocation.size {
32 => data.write_at(offset, &U32::new(self.endian, addend as u32)),
Expand Down Expand Up @@ -627,20 +638,20 @@ pub struct SectionId(usize);

/// A section in an object file.
#[derive(Debug)]
pub struct Section {
pub struct Section<'a> {
segment: Vec<u8>,
name: Vec<u8>,
kind: SectionKind,
size: u64,
align: u64,
data: Vec<u8>,
data: Cow<'a, [u8]>,
relocations: Vec<Relocation>,
symbol: Option<SymbolId>,
/// Section flags that are specific to each file format.
pub flags: SectionFlags,
}

impl Section {
impl<'a> Section<'a> {
/// Try to convert the name to a utf8 string.
#[inline]
pub fn name(&self) -> Option<&str> {
Expand All @@ -662,32 +673,36 @@ impl Section {
/// Set the data for a section.
///
/// Must not be called for sections that already have data, or that contain uninitialized data.
pub fn set_data(&mut self, data: Vec<u8>, align: u64) {
pub fn set_data<T>(&mut self, data: T, align: u64)
where
T: Into<Cow<'a, [u8]>>,
{
debug_assert!(!self.is_bss());
debug_assert_eq!(align & (align - 1), 0);
debug_assert!(self.data.is_empty());
self.size = data.len() as u64;
self.data = data;
self.data = data.into();
self.size = self.data.len() as u64;
self.align = align;
}

/// Append data to a section.
///
/// Must not be called for sections that contain uninitialized data.
pub fn append_data(&mut self, data: &[u8], align: u64) -> u64 {
pub fn append_data(&mut self, append_data: &[u8], align: u64) -> u64 {
debug_assert!(!self.is_bss());
debug_assert_eq!(align & (align - 1), 0);
if self.align < align {
self.align = align;
}
let align = align as usize;
let mut offset = self.data.len();
let data = self.data.to_mut();
let mut offset = data.len();
if offset & (align - 1) != 0 {
offset += align - (offset & (align - 1));
self.data.resize(offset, 0);
data.resize(offset, 0);
}
self.data.extend_from_slice(data);
self.size = self.data.len() as u64;
data.extend_from_slice(append_data);
self.size = data.len() as u64;
offset as u64
}

Expand Down Expand Up @@ -722,7 +737,7 @@ impl Section {
/// This requires that the section is not a bss section.
pub fn data_mut(&mut self) -> &mut [u8] {
debug_assert!(!self.is_bss());
&mut self.data
self.data.to_mut()
}
}

Expand Down

0 comments on commit 8255445

Please sign in to comment.