Fix resolving symbols for section-relative relocations

Also fixes MIPS `j` handling when jumping within the function.

Reworks `ObjReloc` struct to be a little more sensible.
This commit is contained in:
Luke Street 2024-10-11 18:09:18 -06:00
parent 83de98b5ee
commit 676488433f
11 changed files with 198 additions and 140 deletions

30
Cargo.lock generated
View File

@ -1526,15 +1526,15 @@ dependencies = [
[[package]] [[package]]
name = "futures-core" name = "futures-core"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]] [[package]]
name = "futures-io" name = "futures-io"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]] [[package]]
name = "futures-lite" name = "futures-lite"
@ -1551,9 +1551,9 @@ dependencies = [
[[package]] [[package]]
name = "futures-macro" name = "futures-macro"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1562,21 +1562,21 @@ dependencies = [
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
[[package]] [[package]]
name = "futures-task" name = "futures-task"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]] [[package]]
name = "futures-util" name = "futures-util"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-io", "futures-io",
@ -2861,7 +2861,7 @@ dependencies = [
[[package]] [[package]]
name = "objdiff-cli" name = "objdiff-cli"
version = "2.3.1" version = "2.3.2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"argp", "argp",
@ -2883,7 +2883,7 @@ dependencies = [
[[package]] [[package]]
name = "objdiff-core" name = "objdiff-core"
version = "2.3.1" version = "2.3.2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"arm-attr", "arm-attr",
@ -2923,7 +2923,7 @@ dependencies = [
[[package]] [[package]]
name = "objdiff-gui" name = "objdiff-gui"
version = "2.3.1" version = "2.3.2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",

View File

@ -13,7 +13,7 @@ strip = "debuginfo"
codegen-units = 1 codegen-units = 1
[workspace.package] [workspace.package]
version = "2.3.1" version = "2.3.2"
authors = ["Luke Street <luke@street.dev>"] authors = ["Luke Street <luke@street.dev>"]
edition = "2021" edition = "2021"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"

View File

@ -70,7 +70,6 @@ feature-depth = 1
# A list of advisory IDs to ignore. Note that ignored advisories will still # A list of advisory IDs to ignore. Note that ignored advisories will still
# output a note when they are encountered. # output a note when they are encountered.
ignore = [ ignore = [
"RUSTSEC-2024-0370",
#{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" }, #{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" },
#"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish #"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish
#{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" }, #{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" },
@ -240,7 +239,7 @@ allow-git = []
[sources.allow-org] [sources.allow-org]
# github.com organizations to allow git sources for # github.com organizations to allow git sources for
github = ["encounter"] github = ["notify-rs"]
# gitlab.com organizations to allow git sources for # gitlab.com organizations to allow git sources for
gitlab = [] gitlab = []
# bitbucket.org organizations to allow git sources for # bitbucket.org organizations to allow git sources for

View File

@ -83,7 +83,7 @@ impl ObjArch for ObjArchMips {
&self, &self,
address: u64, address: u64,
code: &[u8], code: &[u8],
_section_index: usize, section_index: usize,
relocations: &[ObjReloc], relocations: &[ObjReloc],
line_info: &BTreeMap<u64, u32>, line_info: &BTreeMap<u64, u32>,
config: &DiffObjConfig, config: &DiffObjConfig,
@ -140,11 +140,18 @@ impl ObjArch for ObjArchMips {
| OperandType::cpu_label | OperandType::cpu_label
| OperandType::cpu_branch_target_label => { | OperandType::cpu_branch_target_label => {
if let Some(reloc) = reloc { if let Some(reloc) = reloc {
if matches!(&reloc.target_section, Some(s) if s == ".text") // If the relocation target is within the current function, we can
&& reloc.target.address > start_address // convert it into a relative branch target. Note that we check
&& reloc.target.address < end_address // target_address > start_address instead of >= so that recursive
// tail calls are not considered branch targets.
let target_address =
reloc.target.address.checked_add_signed(reloc.addend);
if reloc.target.orig_section_index == Some(section_index)
&& matches!(target_address, Some(addr) if addr > start_address && addr < end_address)
{ {
args.push(ObjInsArg::BranchDest(reloc.target.address)); let target_address = target_address.unwrap();
args.push(ObjInsArg::BranchDest(target_address));
branch_dest = Some(target_address);
} else { } else {
push_reloc(&mut args, reloc)?; push_reloc(&mut args, reloc)?;
branch_dest = None; branch_dest = None;

View File

@ -70,9 +70,13 @@ impl FunctionDiff {
// let (_section, symbol) = object.section_symbol(symbol_ref); // let (_section, symbol) = object.section_symbol(symbol_ref);
// Symbol::from(symbol) // Symbol::from(symbol)
// }); // });
let instructions = symbol_diff.instructions.iter().map(InstructionDiff::from).collect(); let instructions = symbol_diff
.instructions
.iter()
.map(|ins_diff| InstructionDiff::new(object, ins_diff))
.collect();
Self { Self {
symbol: Some(Symbol::from(symbol)), symbol: Some(Symbol::new(symbol)),
// diff_symbol, // diff_symbol,
instructions, instructions,
match_percent: symbol_diff.match_percent, match_percent: symbol_diff.match_percent,
@ -90,8 +94,8 @@ impl DataDiff {
} }
} }
impl<'a> From<&'a ObjSymbol> for Symbol { impl Symbol {
fn from(value: &'a ObjSymbol) -> Self { pub fn new(value: &ObjSymbol) -> Self {
Self { Self {
name: value.name.to_string(), name: value.name.to_string(),
demangled_name: value.demangled_name.clone(), demangled_name: value.demangled_name.clone(),
@ -122,29 +126,29 @@ fn symbol_flags(value: ObjSymbolFlagSet) -> u32 {
flags flags
} }
impl<'a> From<&'a ObjIns> for Instruction { impl Instruction {
fn from(value: &'a ObjIns) -> Self { pub fn new(object: &ObjInfo, instruction: &ObjIns) -> Self {
Self { Self {
address: value.address, address: instruction.address,
size: value.size as u32, size: instruction.size as u32,
opcode: value.op as u32, opcode: instruction.op as u32,
mnemonic: value.mnemonic.clone(), mnemonic: instruction.mnemonic.clone(),
formatted: value.formatted.clone(), formatted: instruction.formatted.clone(),
arguments: value.args.iter().map(Argument::from).collect(), arguments: instruction.args.iter().map(Argument::new).collect(),
relocation: value.reloc.as_ref().map(Relocation::from), relocation: instruction.reloc.as_ref().map(|reloc| Relocation::new(object, reloc)),
branch_dest: value.branch_dest, branch_dest: instruction.branch_dest,
line_number: value.line, line_number: instruction.line,
original: value.orig.clone(), original: instruction.orig.clone(),
} }
} }
} }
impl<'a> From<&'a ObjInsArg> for Argument { impl Argument {
fn from(value: &'a ObjInsArg) -> Self { pub fn new(value: &ObjInsArg) -> Self {
Self { Self {
value: Some(match value { value: Some(match value {
ObjInsArg::PlainText(s) => argument::Value::PlainText(s.to_string()), ObjInsArg::PlainText(s) => argument::Value::PlainText(s.to_string()),
ObjInsArg::Arg(v) => argument::Value::Argument(ArgumentValue::from(v)), ObjInsArg::Arg(v) => argument::Value::Argument(ArgumentValue::new(v)),
ObjInsArg::Reloc => argument::Value::Relocation(ArgumentRelocation {}), ObjInsArg::Reloc => argument::Value::Relocation(ArgumentRelocation {}),
ObjInsArg::BranchDest(dest) => argument::Value::BranchDest(*dest), ObjInsArg::BranchDest(dest) => argument::Value::BranchDest(*dest),
}), }),
@ -152,8 +156,8 @@ impl<'a> From<&'a ObjInsArg> for Argument {
} }
} }
impl From<&ObjInsArgValue> for ArgumentValue { impl ArgumentValue {
fn from(value: &ObjInsArgValue) -> Self { pub fn new(value: &ObjInsArgValue) -> Self {
Self { Self {
value: Some(match value { value: Some(match value {
ObjInsArgValue::Signed(v) => argument_value::Value::Signed(*v), ObjInsArgValue::Signed(v) => argument_value::Value::Signed(*v),
@ -164,42 +168,39 @@ impl From<&ObjInsArgValue> for ArgumentValue {
} }
} }
impl<'a> From<&'a ObjReloc> for Relocation { impl Relocation {
fn from(value: &ObjReloc) -> Self { pub fn new(object: &ObjInfo, reloc: &ObjReloc) -> Self {
Self { Self {
r#type: match value.flags { r#type: match reloc.flags {
object::RelocationFlags::Elf { r_type } => r_type, object::RelocationFlags::Elf { r_type } => r_type,
object::RelocationFlags::MachO { r_type, .. } => r_type as u32, object::RelocationFlags::MachO { r_type, .. } => r_type as u32,
object::RelocationFlags::Coff { typ } => typ as u32, object::RelocationFlags::Coff { typ } => typ as u32,
object::RelocationFlags::Xcoff { r_rtype, .. } => r_rtype as u32, object::RelocationFlags::Xcoff { r_rtype, .. } => r_rtype as u32,
_ => unreachable!(), _ => unreachable!(),
}, },
type_name: String::new(), // TODO type_name: object.arch.display_reloc(reloc.flags).into_owned(),
target: Some(RelocationTarget::from(&value.target)), target: Some(RelocationTarget {
symbol: Some(Symbol::new(&reloc.target)),
addend: reloc.addend,
}),
} }
} }
} }
impl<'a> From<&'a ObjSymbol> for RelocationTarget { impl InstructionDiff {
fn from(value: &'a ObjSymbol) -> Self { pub fn new(object: &ObjInfo, instruction_diff: &ObjInsDiff) -> Self {
Self { symbol: Some(Symbol::from(value)), addend: value.addend }
}
}
impl<'a> From<&'a ObjInsDiff> for InstructionDiff {
fn from(value: &'a ObjInsDiff) -> Self {
Self { Self {
instruction: value.ins.as_ref().map(Instruction::from), instruction: instruction_diff.ins.as_ref().map(|ins| Instruction::new(object, ins)),
diff_kind: DiffKind::from(value.kind) as i32, diff_kind: DiffKind::from(instruction_diff.kind) as i32,
branch_from: value.branch_from.as_ref().map(InstructionBranchFrom::from), branch_from: instruction_diff.branch_from.as_ref().map(InstructionBranchFrom::new),
branch_to: value.branch_to.as_ref().map(InstructionBranchTo::from), branch_to: instruction_diff.branch_to.as_ref().map(InstructionBranchTo::new),
arg_diff: value.arg_diff.iter().map(ArgumentDiff::from).collect(), arg_diff: instruction_diff.arg_diff.iter().map(ArgumentDiff::new).collect(),
} }
} }
} }
impl From<&Option<ObjInsArgDiff>> for ArgumentDiff { impl ArgumentDiff {
fn from(value: &Option<ObjInsArgDiff>) -> Self { pub fn new(value: &Option<ObjInsArgDiff>) -> Self {
Self { diff_index: value.as_ref().map(|v| v.idx as u32) } Self { diff_index: value.as_ref().map(|v| v.idx as u32) }
} }
} }
@ -228,8 +229,8 @@ impl From<ObjDataDiffKind> for DiffKind {
} }
} }
impl<'a> From<&'a ObjInsBranchFrom> for InstructionBranchFrom { impl InstructionBranchFrom {
fn from(value: &'a ObjInsBranchFrom) -> Self { pub fn new(value: &ObjInsBranchFrom) -> Self {
Self { Self {
instruction_index: value.ins_idx.iter().map(|&x| x as u32).collect(), instruction_index: value.ins_idx.iter().map(|&x| x as u32).collect(),
branch_index: value.branch_idx as u32, branch_index: value.branch_idx as u32,
@ -237,8 +238,8 @@ impl<'a> From<&'a ObjInsBranchFrom> for InstructionBranchFrom {
} }
} }
impl<'a> From<&'a ObjInsBranchTo> for InstructionBranchTo { impl InstructionBranchTo {
fn from(value: &'a ObjInsBranchTo) -> Self { pub fn new(value: &ObjInsBranchTo) -> Self {
Self { instruction_index: value.ins_idx as u32, branch_index: value.branch_idx as u32 } Self { instruction_index: value.ins_idx as u32, branch_index: value.branch_idx as u32 }
} }
} }

View File

@ -9,7 +9,7 @@ use crate::{
DiffObjConfig, ObjInsArgDiff, ObjInsBranchFrom, ObjInsBranchTo, ObjInsDiff, ObjInsDiffKind, DiffObjConfig, ObjInsArgDiff, ObjInsBranchFrom, ObjInsBranchTo, ObjInsDiff, ObjInsDiffKind,
ObjSymbolDiff, ObjSymbolDiff,
}, },
obj::{ObjInfo, ObjInsArg, ObjReloc, ObjSymbol, ObjSymbolFlags, SymbolRef}, obj::{ObjInfo, ObjInsArg, ObjReloc, ObjSymbolFlags, SymbolRef},
}; };
pub fn process_code_symbol( pub fn process_code_symbol(
@ -45,6 +45,8 @@ pub fn no_diff_code(out: &ProcessCodeResult, symbol_ref: SymbolRef) -> Result<Ob
} }
pub fn diff_code( pub fn diff_code(
left_obj: &ObjInfo,
right_obj: &ObjInfo,
left_out: &ProcessCodeResult, left_out: &ProcessCodeResult,
right_out: &ProcessCodeResult, right_out: &ProcessCodeResult,
left_symbol_ref: SymbolRef, left_symbol_ref: SymbolRef,
@ -60,7 +62,7 @@ pub fn diff_code(
let mut diff_state = InsDiffState::default(); let mut diff_state = InsDiffState::default();
for (left, right) in left_diff.iter_mut().zip(right_diff.iter_mut()) { for (left, right) in left_diff.iter_mut().zip(right_diff.iter_mut()) {
let result = compare_ins(config, left, right, &mut diff_state)?; let result = compare_ins(config, left_obj, right_obj, left, right, &mut diff_state)?;
left.kind = result.kind; left.kind = result.kind;
right.kind = result.kind; right.kind = result.kind;
left.arg_diff = result.left_args_diff; left.arg_diff = result.left_args_diff;
@ -170,12 +172,33 @@ fn resolve_branches(vec: &mut [ObjInsDiff]) {
} }
} }
fn address_eq(left: &ObjSymbol, right: &ObjSymbol) -> bool { fn address_eq(left: &ObjReloc, right: &ObjReloc) -> bool {
left.address as i64 + left.addend == right.address as i64 + right.addend left.target.address as i64 + left.addend == right.target.address as i64 + right.addend
}
fn section_name_eq(
left_obj: &ObjInfo,
right_obj: &ObjInfo,
left_orig_section_index: usize,
right_orig_section_index: usize,
) -> bool {
let Some(left_section) =
left_obj.sections.iter().find(|s| s.orig_index == left_orig_section_index)
else {
return false;
};
let Some(right_section) =
right_obj.sections.iter().find(|s| s.orig_index == right_orig_section_index)
else {
return false;
};
left_section.name == right_section.name
} }
fn reloc_eq( fn reloc_eq(
config: &DiffObjConfig, config: &DiffObjConfig,
left_obj: &ObjInfo,
right_obj: &ObjInfo,
left_reloc: Option<&ObjReloc>, left_reloc: Option<&ObjReloc>,
right_reloc: Option<&ObjReloc>, right_reloc: Option<&ObjReloc>,
) -> bool { ) -> bool {
@ -189,23 +212,26 @@ fn reloc_eq(
return true; return true;
} }
let name_matches = left.target.name == right.target.name; let symbol_name_matches = left.target.name == right.target.name;
match (&left.target_section, &right.target_section) { match (&left.target.orig_section_index, &right.target.orig_section_index) {
(Some(sl), Some(sr)) => { (Some(sl), Some(sr)) => {
// Match if section and name or address match // Match if section and name or address match
sl == sr && (name_matches || address_eq(&left.target, &right.target)) section_name_eq(left_obj, right_obj, *sl, *sr)
&& (symbol_name_matches || address_eq(left, right))
} }
(Some(_), None) => false, (Some(_), None) => false,
(None, Some(_)) => { (None, Some(_)) => {
// Match if possibly stripped weak symbol // Match if possibly stripped weak symbol
name_matches && right.target.flags.0.contains(ObjSymbolFlags::Weak) symbol_name_matches && right.target.flags.0.contains(ObjSymbolFlags::Weak)
} }
(None, None) => name_matches, (None, None) => symbol_name_matches,
} }
} }
fn arg_eq( fn arg_eq(
config: &DiffObjConfig, config: &DiffObjConfig,
left_obj: &ObjInfo,
right_obj: &ObjInfo,
left: &ObjInsArg, left: &ObjInsArg,
right: &ObjInsArg, right: &ObjInsArg,
left_diff: &ObjInsDiff, left_diff: &ObjInsDiff,
@ -227,6 +253,8 @@ fn arg_eq(
matches!(right, ObjInsArg::Reloc) matches!(right, ObjInsArg::Reloc)
&& reloc_eq( && reloc_eq(
config, config,
left_obj,
right_obj,
left_diff.ins.as_ref().and_then(|i| i.reloc.as_ref()), left_diff.ins.as_ref().and_then(|i| i.reloc.as_ref()),
right_diff.ins.as_ref().and_then(|i| i.reloc.as_ref()), right_diff.ins.as_ref().and_then(|i| i.reloc.as_ref()),
) )
@ -257,6 +285,8 @@ struct InsDiffResult {
fn compare_ins( fn compare_ins(
config: &DiffObjConfig, config: &DiffObjConfig,
left_obj: &ObjInfo,
right_obj: &ObjInfo,
left: &ObjInsDiff, left: &ObjInsDiff,
right: &ObjInsDiff, right: &ObjInsDiff,
state: &mut InsDiffState, state: &mut InsDiffState,
@ -283,7 +313,7 @@ fn compare_ins(
state.diff_count += 1; state.diff_count += 1;
} }
for (a, b) in left_ins.args.iter().zip(&right_ins.args) { for (a, b) in left_ins.args.iter().zip(&right_ins.args) {
if arg_eq(config, a, b, left, right) { if arg_eq(config, left_obj, right_obj, a, b, left, right) {
result.left_args_diff.push(None); result.left_args_diff.push(None);
result.right_args_diff.push(None); result.right_args_diff.push(None);
} else { } else {

View File

@ -94,9 +94,9 @@ fn display_reloc_name<E>(
mut cb: impl FnMut(DiffText) -> Result<(), E>, mut cb: impl FnMut(DiffText) -> Result<(), E>,
) -> Result<(), E> { ) -> Result<(), E> {
cb(DiffText::Symbol(&reloc.target))?; cb(DiffText::Symbol(&reloc.target))?;
match reloc.target.addend.cmp(&0i64) { match reloc.addend.cmp(&0i64) {
Ordering::Greater => cb(DiffText::Basic(&format!("+{:#x}", reloc.target.addend))), Ordering::Greater => cb(DiffText::Basic(&format!("+{:#x}", reloc.addend))),
Ordering::Less => cb(DiffText::Basic(&format!("-{:#x}", -reloc.target.addend))), Ordering::Less => cb(DiffText::Basic(&format!("-{:#x}", -reloc.addend))),
_ => Ok(()), _ => Ok(()),
} }
} }

View File

@ -411,6 +411,8 @@ pub fn diff_objs(
let left_code = process_code_symbol(left_obj, left_symbol_ref, config)?; let left_code = process_code_symbol(left_obj, left_symbol_ref, config)?;
let right_code = process_code_symbol(right_obj, right_symbol_ref, config)?; let right_code = process_code_symbol(right_obj, right_symbol_ref, config)?;
let (left_diff, right_diff) = diff_code( let (left_diff, right_diff) = diff_code(
left_obj,
right_obj,
&left_code, &left_code,
&right_code, &right_code,
left_symbol_ref, left_symbol_ref,
@ -424,6 +426,8 @@ pub fn diff_objs(
let (prev_obj, prev_out) = prev.as_mut().unwrap(); let (prev_obj, prev_out) = prev.as_mut().unwrap();
let prev_code = process_code_symbol(prev_obj, prev_symbol_ref, config)?; let prev_code = process_code_symbol(prev_obj, prev_symbol_ref, config)?;
let (_, prev_diff) = diff_code( let (_, prev_diff) = diff_code(
left_obj,
right_obj,
&right_code, &right_code,
&prev_code, &prev_code,
right_symbol_ref, right_symbol_ref,
@ -592,6 +596,8 @@ fn generate_mapping_symbols(
ObjSectionKind::Code => { ObjSectionKind::Code => {
let target_code = process_code_symbol(target_obj, target_symbol_ref, config)?; let target_code = process_code_symbol(target_obj, target_symbol_ref, config)?;
let (left_diff, _right_diff) = diff_code( let (left_diff, _right_diff) = diff_code(
target_obj,
base_obj,
&target_code, &target_code,
base_code.as_ref().unwrap(), base_code.as_ref().unwrap(),
target_symbol_ref, target_symbol_ref,

View File

@ -131,7 +131,7 @@ pub struct ObjSymbol {
pub size_known: bool, pub size_known: bool,
pub kind: ObjSymbolKind, pub kind: ObjSymbolKind,
pub flags: ObjSymbolFlagSet, pub flags: ObjSymbolFlagSet,
pub addend: i64, pub orig_section_index: Option<usize>,
/// Original virtual address (from .note.split section) /// Original virtual address (from .note.split section)
pub virtual_address: Option<u64>, pub virtual_address: Option<u64>,
/// Original index in object symbol table /// Original index in object symbol table
@ -155,7 +155,7 @@ pub struct ObjReloc {
pub flags: RelocationFlags, pub flags: RelocationFlags,
pub address: u64, pub address: u64,
pub target: ObjSymbol, pub target: ObjSymbol,
pub target_section: Option<String>, pub addend: i64,
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]

View File

@ -13,8 +13,8 @@ use object::{
endian::LittleEndian as LE, endian::LittleEndian as LE,
pe::{ImageAuxSymbolFunctionBeginEnd, ImageLinenumber}, pe::{ImageAuxSymbolFunctionBeginEnd, ImageLinenumber},
read::coff::{CoffFile, CoffHeader, ImageSymbol}, read::coff::{CoffFile, CoffHeader, ImageSymbol},
BinaryFormat, File, Object, ObjectSection, ObjectSymbol, RelocationTarget, SectionIndex, BinaryFormat, File, Object, ObjectSection, ObjectSymbol, RelocationTarget, Section,
SectionKind, Symbol, SymbolIndex, SymbolKind, SymbolScope, SymbolSection, SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolKind, SymbolScope,
}; };
use crate::{ use crate::{
@ -41,7 +41,6 @@ fn to_obj_symbol(
arch: &dyn ObjArch, arch: &dyn ObjArch,
obj_file: &File<'_>, obj_file: &File<'_>,
symbol: &Symbol<'_, '_>, symbol: &Symbol<'_, '_>,
addend: i64,
split_meta: Option<&SplitMeta>, split_meta: Option<&SplitMeta>,
) -> Result<ObjSymbol> { ) -> Result<ObjSymbol> {
let mut name = symbol.name().context("Failed to process symbol name")?; let mut name = symbol.name().context("Failed to process symbol name")?;
@ -111,7 +110,7 @@ fn to_obj_symbol(
size_known: symbol.size() != 0, size_known: symbol.size() != 0,
kind, kind,
flags, flags,
addend, orig_section_index: symbol.section_index().map(|i| i.0),
virtual_address, virtual_address,
original_index: Some(symbol.index().0), original_index: Some(symbol.index().0),
bytes: bytes.to_vec(), bytes: bytes.to_vec(),
@ -177,7 +176,7 @@ fn symbols_by_section(
continue; continue;
} }
} }
result.push(to_obj_symbol(arch, obj_file, symbol, 0, split_meta)?); result.push(to_obj_symbol(arch, obj_file, symbol, split_meta)?);
} }
result.sort_by(|a, b| a.address.cmp(&b.address).then(a.size.cmp(&b.size))); result.sort_by(|a, b| a.address.cmp(&b.address).then(a.size.cmp(&b.size)));
let mut iter = result.iter_mut().peekable(); let mut iter = result.iter_mut().peekable();
@ -217,7 +216,7 @@ fn symbols_by_section(
ObjSectionKind::Data | ObjSectionKind::Bss => ObjSymbolKind::Object, ObjSectionKind::Data | ObjSectionKind::Bss => ObjSymbolKind::Object,
}, },
flags: Default::default(), flags: Default::default(),
addend: 0, orig_section_index: Some(section.orig_index),
virtual_address: None, virtual_address: None,
original_index: None, original_index: None,
bytes: Vec::new(), bytes: Vec::new(),
@ -234,7 +233,7 @@ fn common_symbols(
obj_file obj_file
.symbols() .symbols()
.filter(Symbol::is_common) .filter(Symbol::is_common)
.map(|symbol| to_obj_symbol(arch, obj_file, &symbol, 0, split_meta)) .map(|symbol| to_obj_symbol(arch, obj_file, &symbol, split_meta))
.collect::<Result<Vec<ObjSymbol>>>() .collect::<Result<Vec<ObjSymbol>>>()
} }
@ -245,10 +244,18 @@ fn best_symbol<'r, 'data, 'file>(
symbols: &'r [Symbol<'data, 'file>], symbols: &'r [Symbol<'data, 'file>],
address: u64, address: u64,
) -> Option<&'r Symbol<'data, 'file>> { ) -> Option<&'r Symbol<'data, 'file>> {
let closest_symbol_index = match symbols.binary_search_by_key(&address, |s| s.address()) { let mut closest_symbol_index = match symbols.binary_search_by_key(&address, |s| s.address()) {
Ok(index) => Some(index), Ok(index) => Some(index),
Err(index) => index.checked_sub(1), Err(index) => index.checked_sub(1),
}?; }?;
// The binary search may not find the first symbol at the address, so work backwards
let target_address = symbols[closest_symbol_index].address();
while let Some(prev_index) = closest_symbol_index.checked_sub(1) {
if symbols[prev_index].address() != target_address {
break;
}
closest_symbol_index = prev_index;
}
let mut best_symbol: Option<&'r Symbol<'data, 'file>> = None; let mut best_symbol: Option<&'r Symbol<'data, 'file>> = None;
for symbol in symbols.iter().skip(closest_symbol_index) { for symbol in symbols.iter().skip(closest_symbol_index) {
if symbol.address() > address { if symbol.address() > address {
@ -276,24 +283,15 @@ fn best_symbol<'r, 'data, 'file>(
fn find_section_symbol( fn find_section_symbol(
arch: &dyn ObjArch, arch: &dyn ObjArch,
obj_file: &File<'_>, obj_file: &File<'_>,
section: &Section,
section_symbols: &[Symbol<'_, '_>], section_symbols: &[Symbol<'_, '_>],
target: &Symbol<'_, '_>,
address: u64, address: u64,
split_meta: Option<&SplitMeta>, split_meta: Option<&SplitMeta>,
) -> Result<ObjSymbol> { ) -> Result<ObjSymbol> {
if let Some(symbol) = best_symbol(section_symbols, address) { if let Some(symbol) = best_symbol(section_symbols, address) {
return to_obj_symbol( return to_obj_symbol(arch, obj_file, symbol, split_meta);
arch,
obj_file,
symbol,
address as i64 - symbol.address() as i64,
split_meta,
);
} }
// Fallback to section symbol // Fallback to section symbol
let section_index =
target.section_index().ok_or_else(|| anyhow::Error::msg("Unknown section index"))?;
let section = obj_file.section_by_index(section_index)?;
Ok(ObjSymbol { Ok(ObjSymbol {
name: section.name()?.to_string(), name: section.name()?.to_string(),
demangled_name: None, demangled_name: None,
@ -303,7 +301,7 @@ fn find_section_symbol(
size_known: false, size_known: false,
kind: ObjSymbolKind::Section, kind: ObjSymbolKind::Section,
flags: Default::default(), flags: Default::default(),
addend: address as i64 - section.address() as i64, orig_section_index: Some(section.index().0),
virtual_address: None, virtual_address: None,
original_index: None, original_index: None,
bytes: Vec::new(), bytes: Vec::new(),
@ -314,7 +312,7 @@ fn relocations_by_section(
arch: &dyn ObjArch, arch: &dyn ObjArch,
obj_file: &File<'_>, obj_file: &File<'_>,
section: &ObjSection, section: &ObjSection,
section_symbols: &[Symbol<'_, '_>], section_symbols: &[Vec<Symbol<'_, '_>>],
split_meta: Option<&SplitMeta>, split_meta: Option<&SplitMeta>,
) -> Result<Vec<ObjReloc>> { ) -> Result<Vec<ObjReloc>> {
let obj_section = obj_file.section_by_index(SectionIndex(section.orig_index))?; let obj_section = obj_file.section_by_index(SectionIndex(section.orig_index))?;
@ -339,37 +337,36 @@ fn relocations_by_section(
_ => bail!("Unhandled relocation target: {:?}", reloc.target()), _ => bail!("Unhandled relocation target: {:?}", reloc.target()),
}; };
let flags = reloc.flags(); // TODO validate reloc here? let flags = reloc.flags(); // TODO validate reloc here?
let target_section = match symbol.section() { let mut addend = if reloc.has_implicit_addend() {
SymbolSection::Common => Some(".comm".to_string()),
SymbolSection::Section(idx) => {
obj_file.section_by_index(idx).and_then(|s| s.name().map(|s| s.to_string())).ok()
}
_ => None,
};
let addend = if reloc.has_implicit_addend() {
arch.implcit_addend(obj_file, section, address, &reloc)? arch.implcit_addend(obj_file, section, address, &reloc)?
} else { } else {
reloc.addend() reloc.addend()
}; };
// println!("Reloc: {reloc:?}, symbol: {symbol:?}, addend: {addend:#x}");
let target = match symbol.kind() { let target = match symbol.kind() {
SymbolKind::Text | SymbolKind::Data | SymbolKind::Label | SymbolKind::Unknown => { SymbolKind::Text | SymbolKind::Data | SymbolKind::Label | SymbolKind::Unknown => {
to_obj_symbol(arch, obj_file, &symbol, addend, split_meta) to_obj_symbol(arch, obj_file, &symbol, split_meta)?
} }
SymbolKind::Section => { SymbolKind::Section => {
ensure!(addend >= 0, "Negative addend in reloc: {addend}"); ensure!(addend >= 0, "Negative addend in section reloc: {addend}");
find_section_symbol( let section_index = symbol
.section_index()
.ok_or_else(|| anyhow!("Section symbol {symbol:?} has no section index"))?;
let section = obj_file.section_by_index(section_index)?;
let symbol = find_section_symbol(
arch, arch,
obj_file, obj_file,
section_symbols, &section,
&symbol, &section_symbols[section_index.0],
addend as u64, addend as u64,
split_meta, split_meta,
) )?;
// Adjust addend to be relative to the selected symbol
addend = (symbol.address - section.address()) as i64;
symbol
} }
kind => Err(anyhow!("Unhandled relocation symbol type {kind:?}")), kind => bail!("Unhandled relocation symbol type {kind:?}"),
}?; };
relocations.push(ObjReloc { flags, address, target, target_section }); relocations.push(ObjReloc { flags, address, target, addend });
} }
Ok(relocations) Ok(relocations)
} }
@ -591,7 +588,7 @@ fn update_combined_symbol(symbol: ObjSymbol, address_change: i64) -> Result<ObjS
size_known: symbol.size_known, size_known: symbol.size_known,
kind: symbol.kind, kind: symbol.kind,
flags: symbol.flags, flags: symbol.flags,
addend: symbol.addend, orig_section_index: symbol.orig_section_index,
virtual_address: if let Some(virtual_address) = symbol.virtual_address { virtual_address: if let Some(virtual_address) = symbol.virtual_address {
Some((virtual_address as i64 + address_change).try_into()?) Some((virtual_address as i64 + address_change).try_into()?)
} else { } else {
@ -618,7 +615,7 @@ fn combine_sections(section: ObjSection, combine: ObjSection) -> Result<ObjSecti
flags: reloc.flags, flags: reloc.flags,
address: (reloc.address as i64 + address_change).try_into()?, address: (reloc.address as i64 + address_change).try_into()?,
target: reloc.target, // TODO: Should be updated? target: reloc.target, // TODO: Should be updated?
target_section: reloc.target_section, // TODO: Same as above addend: reloc.addend,
}); });
} }
@ -698,27 +695,38 @@ pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<ObjInfo> {
let obj_file = File::parse(data)?; let obj_file = File::parse(data)?;
let arch = new_arch(&obj_file)?; let arch = new_arch(&obj_file)?;
let split_meta = split_meta(&obj_file)?; let split_meta = split_meta(&obj_file)?;
let mut sections = filter_sections(&obj_file, split_meta.as_ref())?;
let mut name_counts: HashMap<String, u32> = HashMap::new(); // Create sorted symbol list for each section
for section in &mut sections { let mut section_symbols = Vec::with_capacity(obj_file.sections().count());
for section in obj_file.sections() {
let mut symbols = obj_file let mut symbols = obj_file
.symbols() .symbols()
.filter(|s| s.section_index() == Some(SectionIndex(section.orig_index))) .filter(|s| s.section_index() == Some(section.index()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
symbols.sort_by_key(|s| s.address()); symbols.sort_by_key(|s| s.address());
let section_index = section.index().0;
if section_index >= section_symbols.len() {
section_symbols.resize_with(section_index + 1, Vec::new);
}
section_symbols[section_index] = symbols;
}
let mut sections = filter_sections(&obj_file, split_meta.as_ref())?;
let mut section_name_counts: HashMap<String, u32> = HashMap::new();
for section in &mut sections {
section.symbols = symbols_by_section( section.symbols = symbols_by_section(
arch.as_ref(), arch.as_ref(),
&obj_file, &obj_file,
section, section,
&symbols, &section_symbols[section.orig_index],
split_meta.as_ref(), split_meta.as_ref(),
&mut name_counts, &mut section_name_counts,
)?; )?;
section.relocations = relocations_by_section( section.relocations = relocations_by_section(
arch.as_ref(), arch.as_ref(),
&obj_file, &obj_file,
section, section,
&symbols, &section_symbols,
split_meta.as_ref(), split_meta.as_ref(),
)?; )?;
} }

View File

@ -3,7 +3,6 @@ use std::default::Default;
use egui::{text::LayoutJob, Id, Label, Response, RichText, Sense, Widget}; use egui::{text::LayoutJob, Id, Label, Response, RichText, Sense, Widget};
use egui_extras::TableRow; use egui_extras::TableRow;
use objdiff_core::{ use objdiff_core::{
arch::ObjArch,
diff::{ diff::{
display::{display_diff, DiffText, HighlightKind}, display::{display_diff, DiffText, HighlightKind},
ObjDiff, ObjInsDiff, ObjInsDiffKind, ObjDiff, ObjInsDiff, ObjInsDiffKind,
@ -77,7 +76,7 @@ impl FunctionViewState {
fn ins_hover_ui( fn ins_hover_ui(
ui: &mut egui::Ui, ui: &mut egui::Ui,
arch: &dyn ObjArch, obj: &ObjInfo,
section: &ObjSection, section: &ObjSection,
ins: &ObjIns, ins: &ObjIns,
symbol: &ObjSymbol, symbol: &ObjSymbol,
@ -120,10 +119,17 @@ fn ins_hover_ui(
} }
if let Some(reloc) = &ins.reloc { if let Some(reloc) = &ins.reloc {
ui.label(format!("Relocation type: {}", arch.display_reloc(reloc.flags))); ui.label(format!("Relocation type: {}", obj.arch.display_reloc(reloc.flags)));
ui.colored_label(appearance.highlight_color, format!("Name: {}", reloc.target.name)); ui.colored_label(appearance.highlight_color, format!("Name: {}", reloc.target.name));
if let Some(section) = &reloc.target_section { if let Some(orig_section_index) = reloc.target.orig_section_index {
ui.colored_label(appearance.highlight_color, format!("Section: {section}")); if let Some(section) =
obj.sections.iter().find(|s| s.orig_index == orig_section_index)
{
ui.colored_label(
appearance.highlight_color,
format!("Section: {}", section.name),
);
}
ui.colored_label( ui.colored_label(
appearance.highlight_color, appearance.highlight_color,
format!("Address: {:x}", reloc.target.address), format!("Address: {:x}", reloc.target.address),
@ -132,9 +138,10 @@ fn ins_hover_ui(
appearance.highlight_color, appearance.highlight_color,
format!("Size: {:x}", reloc.target.size), format!("Size: {:x}", reloc.target.size),
); );
if let Some(s) = arch if let Some(s) = obj
.arch
.guess_data_type(ins) .guess_data_type(ins)
.and_then(|ty| arch.display_data_type(ty, &reloc.target.bytes)) .and_then(|ty| obj.arch.display_data_type(ty, &reloc.target.bytes))
{ {
ui.colored_label(appearance.highlight_color, s); ui.colored_label(appearance.highlight_color, s);
} }
@ -370,7 +377,7 @@ fn asm_col_ui(
if let Some(ins) = &ins_diff.ins { if let Some(ins) = &ins_diff.ins {
response.context_menu(|ui| ins_context_menu(ui, section, ins, symbol)); response.context_menu(|ui| ins_context_menu(ui, section, ins, symbol));
response.on_hover_ui_at_pointer(|ui| { response.on_hover_ui_at_pointer(|ui| {
ins_hover_ui(ui, ctx.obj.arch.as_ref(), section, ins, symbol, appearance) ins_hover_ui(ui, ctx.obj, section, ins, symbol, appearance)
}) })
} else { } else {
response response