Skip to content

Commit e296ec9

Browse files
committed
More symbol sorting logic on read
1 parent 80a243f commit e296ec9

2 files changed

Lines changed: 49 additions & 60 deletions

File tree

objdiff-core/src/diff/display.rs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -812,19 +812,15 @@ pub fn display_sections(
812812
}
813813
let section_diff = &diff.sections[section_idx];
814814
let reverse_fn_order = section.kind == SectionKind::Code && reverse_fn_order;
815-
symbols.sort_by(|a, b| {
816-
let a = &obj.symbols[a.symbol];
817-
let b = &obj.symbols[b.symbol];
818-
section_symbol_sort(a, b)
819-
.then_with(|| {
820-
if reverse_fn_order {
821-
b.address.cmp(&a.address)
822-
} else {
823-
a.address.cmp(&b.address)
824-
}
825-
})
826-
.then_with(|| a.size.cmp(&b.size))
827-
});
815+
if reverse_fn_order {
816+
symbols.sort_by(|a, b| {
817+
let a = &obj.symbols[a.symbol];
818+
let b = &obj.symbols[b.symbol];
819+
section_symbol_sort(a, b)
820+
.then_with(|| b.address.cmp(&a.address))
821+
.then_with(|| a.size.cmp(&b.size))
822+
});
823+
}
828824
sections.push(SectionDisplay {
829825
id: section.id.clone(),
830826
name: if section.flags.contains(SectionFlag::Combined) {

objdiff-core/src/obj/read.rs

Lines changed: 40 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use alloc::{
88
use core::{cmp::Ordering, num::NonZeroU64};
99

1010
use anyhow::{Context, Result, anyhow, bail, ensure};
11-
use itertools::Itertools;
1211
use object::{Object as _, ObjectSection as _, ObjectSymbol as _};
1312

1413
use crate::{
@@ -164,19 +163,37 @@ fn map_symbols(
164163
split_meta: Option<&SplitMeta>,
165164
config: &DiffObjConfig,
166165
) -> Result<(Vec<Symbol>, Vec<usize>)> {
167-
let symbol_count = obj_file.symbols().count();
168-
let mut symbols = Vec::<Symbol>::with_capacity(symbol_count + obj_file.sections().count());
169-
let mut symbol_indices = Vec::<usize>::with_capacity(symbol_count + 1);
170-
let obj_symbols = obj_file.symbols();
171166
// symbols() is not guaranteed to be sorted by address.
172167
// We sort it here to fix pairing bugs with diff algorithms that assume the symbols are ordered.
173168
// Sorting everything here once is less expensive than sorting subsets later in expensive loops.
174-
let obj_symbols =
175-
obj_symbols.sorted_by_key(|symbol| (symbol.section_index().map(|i| i.0), symbol.address()));
169+
let mut max_index = 0;
170+
let mut obj_symbols = obj_file
171+
.symbols()
172+
.inspect(|sym| max_index = max_index.max(sym.index().0))
173+
.collect::<Vec<_>>();
174+
obj_symbols.sort_by(|a, b| {
175+
// Sort symbols by section index, placing absolute symbols last
176+
a.section_index()
177+
.map_or(usize::MAX, |s| s.0)
178+
.cmp(&b.section_index().map_or(usize::MAX, |s| s.0))
179+
.then_with(|| {
180+
// Sort section symbols first in a section
181+
if a.kind() == object::SymbolKind::Section {
182+
Ordering::Less
183+
} else if b.kind() == object::SymbolKind::Section {
184+
Ordering::Greater
185+
} else {
186+
Ordering::Equal
187+
}
188+
})
189+
// Sort by address within section
190+
.then_with(|| a.address().cmp(&b.address()))
191+
// If there are multiple symbols with the same address, smaller symbol first
192+
.then_with(|| a.size().cmp(&b.size()))
193+
});
194+
let mut symbols = Vec::<Symbol>::with_capacity(obj_symbols.len() + obj_file.sections().count());
195+
let mut symbol_indices = vec![usize::MAX; max_index + 1];
176196
for obj_symbol in obj_symbols {
177-
if symbol_indices.len() <= obj_symbol.index().0 {
178-
symbol_indices.resize(obj_symbol.index().0 + 1, usize::MAX);
179-
}
180197
let symbol = map_symbol(arch, obj_file, &obj_symbol, section_indices, split_meta, config)?;
181198
symbol_indices[obj_symbol.index().0] = symbols.len();
182199
symbols.push(symbol);
@@ -246,40 +263,18 @@ fn is_local_label(symbol: &Symbol) -> bool {
246263
}
247264

248265
fn infer_symbol_sizes(arch: &dyn Arch, symbols: &mut [Symbol], sections: &[Section]) -> Result<()> {
249-
// Create a sorted list of symbol indices by section
250-
let mut symbols_with_section = Vec::<usize>::with_capacity(symbols.len());
251-
for (i, symbol) in symbols.iter().enumerate() {
252-
if symbol.section.is_some() {
253-
symbols_with_section.push(i);
254-
}
255-
}
256-
symbols_with_section.sort_by(|a, b| {
257-
let a = &symbols[*a];
258-
let b = &symbols[*b];
259-
a.section
260-
.unwrap_or(usize::MAX)
261-
.cmp(&b.section.unwrap_or(usize::MAX))
262-
.then_with(|| {
263-
// Sort section symbols first
264-
if a.kind == SymbolKind::Section {
265-
Ordering::Less
266-
} else if b.kind == SymbolKind::Section {
267-
Ordering::Greater
268-
} else {
269-
Ordering::Equal
270-
}
271-
})
272-
.then_with(|| a.address.cmp(&b.address))
273-
.then_with(|| a.size.cmp(&b.size))
274-
});
266+
// Above, we've sorted the symbols by section and then by address.
275267

276268
// Set symbol sizes based on the next symbol's address
277269
let mut iter_idx = 0;
278270
let mut last_end = (0, 0);
279-
while iter_idx < symbols_with_section.len() {
280-
let symbol_idx = symbols_with_section[iter_idx];
271+
while iter_idx < symbols.len() {
272+
let symbol_idx = iter_idx;
281273
let symbol = &symbols[symbol_idx];
282-
let section_idx = symbol.section.unwrap();
274+
let Some(section_idx) = symbol.section else {
275+
// Start of absolute symbols
276+
break;
277+
};
283278
iter_idx += 1;
284279
if symbol.size != 0 {
285280
if symbol.kind != SymbolKind::Section {
@@ -292,10 +287,9 @@ fn infer_symbol_sizes(arch: &dyn Arch, symbols: &mut [Symbol], sections: &[Secti
292287
continue;
293288
}
294289
let next_symbol = loop {
295-
if iter_idx >= symbols_with_section.len() {
290+
let Some(next_symbol) = symbols.get(iter_idx) else {
296291
break None;
297-
}
298-
let next_symbol = &symbols[symbols_with_section[iter_idx]];
292+
};
299293
if next_symbol.section != Some(section_idx) {
300294
break None;
301295
}
@@ -351,9 +345,11 @@ fn map_sections(
351345
split_meta: Option<&SplitMeta>,
352346
) -> Result<(Vec<Section>, Vec<usize>)> {
353347
let mut section_names = BTreeMap::<String, usize>::new();
354-
let section_count = obj_file.sections().count();
348+
let mut max_index = 0;
349+
let section_count =
350+
obj_file.sections().inspect(|s| max_index = max_index.max(s.index().0)).count();
355351
let mut result = Vec::<Section>::with_capacity(section_count);
356-
let mut section_indices = Vec::<usize>::with_capacity(section_count + 1);
352+
let mut section_indices = vec![usize::MAX; max_index + 1];
357353
for section in obj_file.sections() {
358354
let name = section.name().context("Failed to process section name")?;
359355
let kind = map_section_kind(&section);
@@ -378,9 +374,6 @@ fn map_sections(
378374
let id = format!("{name}-{unique_id}");
379375
*unique_id += 1;
380376

381-
if section_indices.len() <= section.index().0 {
382-
section_indices.resize(section.index().0 + 1, usize::MAX);
383-
}
384377
section_indices[section.index().0] = result.len();
385378
result.push(Section {
386379
id,

0 commit comments

Comments
 (0)