Skip to content

Commit f73fef4

Browse files
authored
Refactor and simplify the elf module a bit (#796)
* Eliminate the `ElfFirmwareImage` struct * Eliminate redundant `RomSegment` struct, rename `CodeSegment` to `Segment` * Re-export types which need to be public from `elf` module * Update `CHANGELOG.md` * Remove unused `segments_with_load_addresses` function
1 parent 11a5b7b commit f73fef4

File tree

9 files changed

+89
-151
lines changed

9 files changed

+89
-151
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2323
- The `command`, `elf` and `error` modules are no longer public (#772)
2424
- `write-bin` now works for files whose lengths are not divisible by 4 (#780, #788)
2525
- `get_usb_pid` is now `usb_pid` and no longer needlessly returns a `Result` (#795)
26+
- `CodeSegment` and `RomSegment` have been merged into a single `Segment` struct (#796)
2627

2728
### Fixed
2829

@@ -34,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3435
### Removed
3536

3637
- Removed the `libudev` feature (#742)
38+
- The `FirmwareImage` trait no longer includes the `segments_with_load_addresses` function (#796)
3739

3840
## [3.3.0] - 2025-01-13
3941

espflash/src/cli/mod.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use indicatif::{style::ProgressStyle, HumanCount, ProgressBar};
2626
use log::{debug, info, warn};
2727
use miette::{IntoDiagnostic, Result, WrapErr};
2828
use serialport::{FlowControl, SerialPortInfo, SerialPortType, UsbPortInfo};
29+
use xmas_elf::ElfFile;
2930

3031
use self::{
3132
config::Config,
@@ -34,8 +35,7 @@ use self::{
3435
};
3536
use crate::{
3637
connection::reset::{ResetAfterOperation, ResetBeforeOperation},
37-
elf::ElfFirmwareImage,
38-
error::{Error, MissingPartition, MissingPartitionTable},
38+
error::{ElfError, Error, MissingPartition, MissingPartitionTable},
3939
flasher::{
4040
parse_partition_table,
4141
FlashData,
@@ -595,14 +595,16 @@ pub fn save_elf_as_image(
595595
skip_padding: bool,
596596
xtal_freq: XtalFrequency,
597597
) -> Result<()> {
598-
let image = ElfFirmwareImage::try_from(elf_data)?;
598+
let elf = ElfFile::new(elf_data)
599+
.map_err(ElfError::from)
600+
.into_diagnostic()?;
599601

600602
if merge {
601603
// To get a chip revision, the connection is needed
602604
// For simplicity, the revision None is used
603605
let image =
604606
chip.into_target()
605-
.get_flash_image(&image, flash_data.clone(), None, xtal_freq)?;
607+
.get_flash_image(&elf, flash_data.clone(), None, xtal_freq)?;
606608

607609
display_image_size(image.app_size(), image.part_size());
608610

@@ -636,7 +638,7 @@ pub fn save_elf_as_image(
636638
} else {
637639
let image = chip
638640
.into_target()
639-
.get_flash_image(&image, flash_data, None, xtal_freq)?;
641+
.get_flash_image(&elf, flash_data, None, xtal_freq)?;
640642

641643
display_image_size(image.app_size(), image.part_size());
642644

espflash/src/elf.rs

Lines changed: 38 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -9,77 +9,45 @@ use std::{
99
};
1010

1111
use xmas_elf::{
12-
program::Type,
1312
sections::{SectionData, ShType},
1413
ElfFile,
1514
};
1615

17-
use crate::{
18-
error::{ElfError, Error},
19-
targets::Chip,
20-
};
16+
use crate::targets::Chip;
2117

2218
/// Operations for working with firmware images
2319
pub trait FirmwareImage<'a> {
2420
/// Firmware image entry point
2521
fn entry(&self) -> u32;
2622

2723
/// Firmware image segments
28-
fn segments(&'a self) -> Box<dyn Iterator<Item = CodeSegment<'a>> + 'a>;
29-
30-
/// Firmware image segments, with their associated load addresses
31-
fn segments_with_load_addresses(&'a self) -> Box<dyn Iterator<Item = CodeSegment<'a>> + 'a>;
24+
fn segments(&'a self) -> Box<dyn Iterator<Item = Segment<'a>> + 'a>;
3225

3326
/// Firmware image ROM segments
34-
fn rom_segments(&'a self, chip: Chip) -> Box<dyn Iterator<Item = CodeSegment<'a>> + 'a> {
27+
fn rom_segments(&'a self, chip: Chip) -> Box<dyn Iterator<Item = Segment<'a>> + 'a> {
3528
Box::new(
3629
self.segments()
3730
.filter(move |segment| chip.into_target().addr_is_flash(segment.addr)),
3831
)
3932
}
4033

4134
/// Firmware image RAM segments
42-
fn ram_segments(&'a self, chip: Chip) -> Box<dyn Iterator<Item = CodeSegment<'a>> + 'a> {
35+
fn ram_segments(&'a self, chip: Chip) -> Box<dyn Iterator<Item = Segment<'a>> + 'a> {
4336
Box::new(
4437
self.segments()
4538
.filter(move |segment| !chip.into_target().addr_is_flash(segment.addr)),
4639
)
4740
}
4841
}
4942

50-
/// A firmware image built from an ELF file
51-
#[derive(Debug)]
52-
pub struct ElfFirmwareImage<'a> {
53-
elf: ElfFile<'a>,
54-
}
55-
56-
impl<'a> ElfFirmwareImage<'a> {
57-
pub fn new(elf: ElfFile<'a>) -> Self {
58-
Self { elf }
59-
}
60-
}
61-
62-
impl<'a> TryFrom<&'a [u8]> for ElfFirmwareImage<'a> {
63-
type Error = Error;
64-
65-
fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
66-
let elf = ElfFile::new(value).map_err(ElfError::from)?;
67-
68-
let image = ElfFirmwareImage::new(elf);
69-
70-
Ok(image)
71-
}
72-
}
73-
74-
impl<'a> FirmwareImage<'a> for ElfFirmwareImage<'a> {
43+
impl<'a> FirmwareImage<'a> for ElfFile<'a> {
7544
fn entry(&self) -> u32 {
76-
self.elf.header.pt2.entry_point() as u32
45+
self.header.pt2.entry_point() as u32
7746
}
7847

79-
fn segments(&'a self) -> Box<dyn Iterator<Item = CodeSegment<'a>> + 'a> {
48+
fn segments(&'a self) -> Box<dyn Iterator<Item = Segment<'a>> + 'a> {
8049
Box::new(
81-
self.elf
82-
.section_iter()
50+
self.section_iter()
8351
.filter(|header| {
8452
header.size() > 0
8553
&& header.get_type() == Ok(ShType::ProgBits)
@@ -88,50 +56,33 @@ impl<'a> FirmwareImage<'a> for ElfFirmwareImage<'a> {
8856
})
8957
.flat_map(move |header| {
9058
let addr = header.address() as u32;
91-
let data = match header.get_data(&self.elf) {
59+
let data = match header.get_data(self) {
9260
Ok(SectionData::Undefined(data)) => data,
9361
_ => return None,
9462
};
95-
Some(CodeSegment::new(addr, data))
96-
}),
97-
)
98-
}
99-
100-
fn segments_with_load_addresses(&'a self) -> Box<dyn Iterator<Item = CodeSegment<'a>> + 'a> {
101-
Box::new(
102-
self.elf
103-
.program_iter()
104-
.filter(|header| {
105-
header.file_size() > 0
106-
&& header.get_type() == Ok(Type::Load)
107-
&& header.offset() > 0
108-
})
109-
.flat_map(move |header| {
110-
let addr = header.physical_addr() as u32;
111-
let from = header.offset() as usize;
112-
let to = header.offset() as usize + header.file_size() as usize;
113-
let data = &self.elf.input[from..to];
114-
Some(CodeSegment::new(addr, data))
63+
Some(Segment::new(addr, data))
11564
}),
11665
)
11766
}
11867
}
11968

120-
#[derive(Eq, Clone, Default)]
12169
/// A segment of code from the source ELF
122-
pub struct CodeSegment<'a> {
70+
#[derive(Default, Clone, Eq)]
71+
pub struct Segment<'a> {
12372
/// Base address of the code segment
12473
pub addr: u32,
125-
data: Cow<'a, [u8]>,
74+
/// Segment data
75+
pub data: Cow<'a, [u8]>,
12676
}
12777

128-
impl<'a> CodeSegment<'a> {
78+
impl<'a> Segment<'a> {
12979
pub fn new(addr: u32, data: &'a [u8]) -> Self {
130-
let mut segment = CodeSegment {
80+
let mut segment = Segment {
13181
addr,
13282
data: Cow::Borrowed(data),
13383
};
13484
segment.pad_align(4);
85+
13586
segment
13687
}
13788

@@ -149,7 +100,7 @@ impl<'a> CodeSegment<'a> {
149100
(Cow::Owned(data), Cow::Owned(tail))
150101
}
151102
};
152-
let new = CodeSegment {
103+
let new = Segment {
153104
addr: self.addr,
154105
data: head,
155106
};
@@ -183,28 +134,39 @@ impl<'a> CodeSegment<'a> {
183134
self.data = Cow::Owned(data);
184135
}
185136
}
137+
138+
/// Borrow the segment for the given lifetime
139+
pub fn borrow<'b>(&'b self) -> Segment<'b>
140+
where
141+
'a: 'b,
142+
{
143+
Segment {
144+
addr: self.addr,
145+
data: Cow::Borrowed(self.data.as_ref()),
146+
}
147+
}
186148
}
187149

188-
impl AddAssign<&'_ [u8]> for CodeSegment<'_> {
150+
impl AddAssign<&'_ [u8]> for Segment<'_> {
189151
fn add_assign(&mut self, rhs: &'_ [u8]) {
190152
let mut data = take(&mut self.data).into_owned();
191153
data.extend_from_slice(rhs);
192154
self.data = Cow::Owned(data);
193155
}
194156
}
195157

196-
impl AddAssign<&'_ CodeSegment<'_>> for CodeSegment<'_> {
197-
fn add_assign(&mut self, rhs: &'_ CodeSegment<'_>) {
158+
#[allow(clippy::suspicious_op_assign_impl)]
159+
impl AddAssign<&'_ Segment<'_>> for Segment<'_> {
160+
fn add_assign(&mut self, rhs: &'_ Segment<'_>) {
198161
let mut data = take(&mut self.data).into_owned();
199-
// pad or truncate
200-
#[allow(clippy::suspicious_op_assign_impl)]
162+
// Pad or truncate:
201163
data.resize((rhs.addr - self.addr) as usize, 0);
202164
data.extend_from_slice(rhs.data());
203165
self.data = Cow::Owned(data);
204166
}
205167
}
206168

207-
impl Debug for CodeSegment<'_> {
169+
impl Debug for Segment<'_> {
208170
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
209171
f.debug_struct("CodeSegment")
210172
.field("addr", &self.addr)
@@ -213,50 +175,20 @@ impl Debug for CodeSegment<'_> {
213175
}
214176
}
215177

216-
impl PartialEq for CodeSegment<'_> {
178+
impl PartialEq for Segment<'_> {
217179
fn eq(&self, other: &Self) -> bool {
218180
self.addr.eq(&other.addr)
219181
}
220182
}
221183

222-
impl PartialOrd for CodeSegment<'_> {
184+
impl PartialOrd for Segment<'_> {
223185
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
224186
Some(self.cmp(other))
225187
}
226188
}
227189

228-
impl Ord for CodeSegment<'_> {
190+
impl Ord for Segment<'_> {
229191
fn cmp(&self, other: &Self) -> Ordering {
230192
self.addr.cmp(&other.addr)
231193
}
232194
}
233-
234-
/// A segment of data to write to the flash
235-
#[derive(Debug, Clone)]
236-
pub struct RomSegment<'a> {
237-
/// ROM address at which the segment begins
238-
pub addr: u32,
239-
/// Segment data
240-
pub data: Cow<'a, [u8]>,
241-
}
242-
243-
impl<'a> RomSegment<'a> {
244-
pub fn borrow<'b>(&'b self) -> RomSegment<'b>
245-
where
246-
'a: 'b,
247-
{
248-
RomSegment {
249-
addr: self.addr,
250-
data: Cow::Borrowed(self.data.as_ref()),
251-
}
252-
}
253-
}
254-
255-
impl<'a> From<CodeSegment<'a>> for RomSegment<'a> {
256-
fn from(segment: CodeSegment<'a>) -> Self {
257-
RomSegment {
258-
addr: segment.addr,
259-
data: segment.data,
260-
}
261-
}
262-
}

0 commit comments

Comments
 (0)