Skip to content

Commit 1fd901a

Browse files
AetiasHaxencounter
andauthored
Option to combine data sections (#76)
Co-authored-by: Luke Street <[email protected]>
1 parent 759d559 commit 1fd901a

File tree

6 files changed

+139
-16
lines changed

6 files changed

+139
-16
lines changed

objdiff-cli/src/cmd/diff.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -809,23 +809,28 @@ impl FunctionDiffUi {
809809

810810
fn reload(&mut self) -> Result<()> {
811811
let prev = self.right_obj.take();
812+
let config = diff::DiffObjConfig {
813+
relax_reloc_diffs: self.relax_reloc_diffs,
814+
space_between_args: true, // TODO
815+
combine_data_sections: false, // TODO
816+
x86_formatter: Default::default(), // TODO
817+
mips_abi: Default::default(), // TODO
818+
mips_instr_category: Default::default(), // TODO
819+
};
812820
let target = self
813821
.target_path
814822
.as_deref()
815-
.map(|p| obj::read::read(p).with_context(|| format!("Loading {}", p.display())))
823+
.map(|p| {
824+
obj::read::read(p, &config).with_context(|| format!("Loading {}", p.display()))
825+
})
816826
.transpose()?;
817827
let base = self
818828
.base_path
819829
.as_deref()
820-
.map(|p| obj::read::read(p).with_context(|| format!("Loading {}", p.display())))
830+
.map(|p| {
831+
obj::read::read(p, &config).with_context(|| format!("Loading {}", p.display()))
832+
})
821833
.transpose()?;
822-
let config = diff::DiffObjConfig {
823-
relax_reloc_diffs: self.relax_reloc_diffs,
824-
space_between_args: true, // TODO
825-
x86_formatter: Default::default(), // TODO
826-
mips_abi: Default::default(), // TODO
827-
mips_instr_category: Default::default(), // TODO
828-
};
829834
let result = diff::diff_objs(&config, target.as_ref(), base.as_ref(), prev.as_ref())?;
830835

831836
let left_sym = target.as_ref().and_then(|o| find_function(o, &self.symbol_name));

objdiff-cli/src/cmd/report.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,17 +230,21 @@ fn report_object(
230230
}
231231
_ => {}
232232
}
233+
let config = diff::DiffObjConfig { relax_reloc_diffs: true, ..Default::default() };
233234
let target = object
234235
.target_path
235236
.as_ref()
236-
.map(|p| obj::read::read(p).with_context(|| format!("Failed to open {}", p.display())))
237+
.map(|p| {
238+
obj::read::read(p, &config).with_context(|| format!("Failed to open {}", p.display()))
239+
})
237240
.transpose()?;
238241
let base = object
239242
.base_path
240243
.as_ref()
241-
.map(|p| obj::read::read(p).with_context(|| format!("Failed to open {}", p.display())))
244+
.map(|p| {
245+
obj::read::read(p, &config).with_context(|| format!("Failed to open {}", p.display()))
246+
})
242247
.transpose()?;
243-
let config = diff::DiffObjConfig { relax_reloc_diffs: true, ..Default::default() };
244248
let result = diff::diff_objs(&config, target.as_ref(), base.as_ref(), None)?;
245249
let mut unit = ReportUnit {
246250
name: object.name().to_string(),

objdiff-core/src/diff/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ pub struct DiffObjConfig {
102102
pub relax_reloc_diffs: bool,
103103
#[serde(default = "default_true")]
104104
pub space_between_args: bool,
105+
pub combine_data_sections: bool,
105106
// x86
106107
pub x86_formatter: X86Formatter,
107108
// MIPS
@@ -114,6 +115,7 @@ impl Default for DiffObjConfig {
114115
Self {
115116
relax_reloc_diffs: false,
116117
space_between_args: true,
118+
combine_data_sections: false,
117119
x86_formatter: Default::default(),
118120
mips_abi: Default::default(),
119121
mips_instr_category: Default::default(),

objdiff-core/src/obj/read.rs

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{fs, io::Cursor, path::Path};
1+
use std::{collections::HashSet, fs, io::Cursor, path::Path};
22

33
use anyhow::{anyhow, bail, ensure, Context, Result};
44
use byteorder::{BigEndian, ReadBytesExt};
@@ -11,6 +11,7 @@ use object::{
1111

1212
use crate::{
1313
arch::{new_arch, ObjArch},
14+
diff::DiffObjConfig,
1415
obj::{
1516
split_meta::{SplitMeta, SPLITMETA_SECTION},
1617
ObjInfo, ObjReloc, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags,
@@ -361,7 +362,105 @@ fn line_info(obj_file: &File<'_>, sections: &mut [ObjSection]) -> Result<()> {
361362
Ok(())
362363
}
363364

364-
pub fn read(obj_path: &Path) -> Result<ObjInfo> {
365+
fn update_combined_symbol(symbol: ObjSymbol, address_change: i64) -> Result<ObjSymbol> {
366+
Ok(ObjSymbol {
367+
name: symbol.name,
368+
demangled_name: symbol.demangled_name,
369+
address: (symbol.address as i64 + address_change).try_into()?,
370+
section_address: (symbol.section_address as i64 + address_change).try_into()?,
371+
size: symbol.size,
372+
size_known: symbol.size_known,
373+
flags: symbol.flags,
374+
addend: symbol.addend,
375+
virtual_address: if let Some(virtual_address) = symbol.virtual_address {
376+
Some((virtual_address as i64 + address_change).try_into()?)
377+
} else {
378+
None
379+
},
380+
})
381+
}
382+
383+
fn combine_sections(section: ObjSection, combine: ObjSection) -> Result<ObjSection> {
384+
let mut data = section.data;
385+
data.extend(combine.data);
386+
387+
let address_change: i64 = (section.address + section.size) as i64 - combine.address as i64;
388+
let mut symbols = section.symbols;
389+
for symbol in combine.symbols {
390+
symbols.push(update_combined_symbol(symbol, address_change)?);
391+
}
392+
393+
let mut relocations = section.relocations;
394+
for reloc in combine.relocations {
395+
relocations.push(ObjReloc {
396+
flags: reloc.flags,
397+
address: (reloc.address as i64 + address_change).try_into()?,
398+
target: reloc.target, // TODO: Should be updated?
399+
target_section: reloc.target_section, // TODO: Same as above
400+
});
401+
}
402+
403+
let mut line_info = section.line_info;
404+
for (addr, line) in combine.line_info {
405+
let key = (addr as i64 + address_change).try_into()?;
406+
line_info.insert(key, line);
407+
}
408+
409+
Ok(ObjSection {
410+
name: section.name,
411+
kind: section.kind,
412+
address: section.address,
413+
size: section.size + combine.size,
414+
data,
415+
orig_index: section.orig_index,
416+
symbols,
417+
relocations,
418+
virtual_address: section.virtual_address,
419+
line_info,
420+
})
421+
}
422+
423+
fn combine_data_sections(sections: &mut Vec<ObjSection>) -> Result<()> {
424+
let names_to_combine: HashSet<_> = sections
425+
.iter()
426+
.filter(|s| s.kind == ObjSectionKind::Data)
427+
.map(|s| s.name.clone())
428+
.collect();
429+
430+
for name in names_to_combine {
431+
// Take section with lowest index
432+
let (mut section_index, _) = sections
433+
.iter()
434+
.enumerate()
435+
.filter(|(_, s)| s.name == name)
436+
.min_by_key(|(_, s)| s.orig_index)
437+
// Should not happen
438+
.context("No combine section found with name")?;
439+
let mut section = sections.remove(section_index);
440+
441+
// Remove equally named sections
442+
let mut combines = vec![];
443+
for i in (0..sections.len()).rev() {
444+
if sections[i].name != name || sections[i].orig_index == section.orig_index {
445+
continue;
446+
}
447+
combines.push(sections.remove(i));
448+
if i < section_index {
449+
section_index -= 1;
450+
}
451+
}
452+
453+
// Combine sections ordered by index
454+
combines.sort_unstable_by_key(|c| c.orig_index);
455+
for combine in combines {
456+
section = combine_sections(section, combine)?;
457+
}
458+
sections.insert(section_index, section);
459+
}
460+
Ok(())
461+
}
462+
463+
pub fn read(obj_path: &Path, config: &DiffObjConfig) -> Result<ObjInfo> {
365464
let (data, timestamp) = {
366465
let file = fs::File::open(obj_path)?;
367466
let timestamp = FileTime::from_last_modification_time(&file.metadata()?);
@@ -377,6 +476,9 @@ pub fn read(obj_path: &Path) -> Result<ObjInfo> {
377476
section.relocations =
378477
relocations_by_section(arch.as_ref(), &obj_file, section, split_meta.as_ref())?;
379478
}
479+
if config.combine_data_sections {
480+
combine_data_sections(&mut sections)?;
481+
}
380482
line_info(&obj_file, &mut sections)?;
381483
let common = common_symbols(arch.as_ref(), &obj_file, split_meta.as_ref())?;
382484
Ok(ObjInfo { arch, path: obj_path.to_owned(), timestamp, sections, common, split_meta })

objdiff-gui/src/app.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,16 @@ impl eframe::App for App {
559559
{
560560
config.queue_reload = true;
561561
}
562+
if ui
563+
.checkbox(
564+
&mut config.diff_obj_config.combine_data_sections,
565+
"Combine data sections",
566+
)
567+
.on_hover_text("Combines data sections with equal names.")
568+
.changed()
569+
{
570+
config.queue_reload = true;
571+
}
562572
});
563573
});
564574
});

objdiff-gui/src/jobs/objdiff.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ fn run_build(
236236
total,
237237
&cancel,
238238
)?;
239-
Some(read::read(target_path).with_context(|| {
239+
Some(read::read(target_path, &config.diff_obj_config).with_context(|| {
240240
format!("Failed to read object '{}'", target_path.display())
241241
})?)
242242
}
@@ -253,7 +253,7 @@ fn run_build(
253253
&cancel,
254254
)?;
255255
Some(
256-
read::read(base_path)
256+
read::read(base_path, &config.diff_obj_config)
257257
.with_context(|| format!("Failed to read object '{}'", base_path.display()))?,
258258
)
259259
}

0 commit comments

Comments
 (0)