Compare commits

..

No commits in common. "main" and "v3.0.0" have entirely different histories.
main ... v3.0.0

5 changed files with 19 additions and 70 deletions

View File

@ -90,23 +90,17 @@ file as well. You can then add `objdiff.json` to your `.gitignore` to prevent it
"build_base": true, "build_base": true,
"watch_patterns": [ "watch_patterns": [
"*.c", "*.c",
"*.cc",
"*.cp", "*.cp",
"*.cpp", "*.cpp",
"*.cxx", "*.cxx",
"*.c++",
"*.h", "*.h",
"*.hh",
"*.hp", "*.hp",
"*.hpp", "*.hpp",
"*.hxx", "*.hxx",
"*.h++",
"*.pch",
"*.pch++",
"*.inc",
"*.s", "*.s",
"*.S", "*.S",
"*.asm", "*.asm",
"*.inc",
"*.py", "*.py",
"*.yml", "*.yml",
"*.txt", "*.txt",

View File

@ -57,23 +57,17 @@
}, },
"default": [ "default": [
"*.c", "*.c",
"*.cc",
"*.cp", "*.cp",
"*.cpp", "*.cpp",
"*.cxx", "*.cxx",
"*.c++",
"*.h", "*.h",
"*.hh",
"*.hp", "*.hp",
"*.hpp", "*.hpp",
"*.hxx", "*.hxx",
"*.h++",
"*.pch",
"*.pch++",
"*.inc",
"*.s", "*.s",
"*.S", "*.S",
"*.asm", "*.asm",
"*.inc",
"*.py", "*.py",
"*.yml", "*.yml",
"*.txt", "*.txt",

View File

@ -675,7 +675,7 @@ fn make_symbol_ref(symbol: &object::Symbol) -> Result<ExtabSymbolRef> {
#[derive(Debug)] #[derive(Debug)]
struct PoolReference { struct PoolReference {
addr_src_gpr: powerpc::GPR, addr_src_gpr: powerpc::GPR,
addr_offset: i64, addr_offset: i16,
addr_dst_gpr: Option<powerpc::GPR>, addr_dst_gpr: Option<powerpc::GPR>,
} }
@ -683,20 +683,16 @@ struct PoolReference {
// If so, return information pertaining to where the instruction is getting that address from and // If so, return information pertaining to where the instruction is getting that address from and
// what it's doing with the address (e.g. copying it into another register, adding an offset, etc). // what it's doing with the address (e.g. copying it into another register, adding an offset, etc).
fn get_pool_reference_for_inst( fn get_pool_reference_for_inst(
ins: powerpc::Ins, opcode: powerpc::Opcode,
simplified: &powerpc::ParsedIns, simplified: &powerpc::ParsedIns,
) -> Option<PoolReference> { ) -> Option<PoolReference> {
use powerpc::{Argument, Opcode}; use powerpc::{Argument, Opcode};
let args = &simplified.args; let args = &simplified.args;
if flow_analysis::guess_data_type_from_load_store_inst_op(ins.op).is_some() { if flow_analysis::guess_data_type_from_load_store_inst_op(opcode).is_some() {
match (args[1], args[2]) { match (args[1], args[2]) {
(Argument::Offset(offset), Argument::GPR(addr_src_gpr)) => { (Argument::Offset(offset), Argument::GPR(addr_src_gpr)) => {
// e.g. lwz. Immediate offset. // e.g. lwz. Immediate offset.
Some(PoolReference { Some(PoolReference { addr_src_gpr, addr_offset: offset.0, addr_dst_gpr: None })
addr_src_gpr,
addr_offset: offset.0 as i64,
addr_dst_gpr: None,
})
} }
(Argument::GPR(addr_src_gpr), Argument::GPR(_offset_gpr)) => { (Argument::GPR(addr_src_gpr), Argument::GPR(_offset_gpr)) => {
// e.g. lwzx. The offset is in a register and was likely calculated from an index. // e.g. lwzx. The offset is in a register and was likely calculated from an index.
@ -716,51 +712,17 @@ fn get_pool_reference_for_inst(
// If either of these match, we also want to return the destination register that the // If either of these match, we also want to return the destination register that the
// address is being copied into so that we can detect any future references to that new // address is being copied into so that we can detect any future references to that new
// register as well. // register as well.
match (ins.op, args[0], args[1], args[2]) { match (opcode, args[0], args[1], args[2]) {
( (
// `addi` or `subi`
Opcode::Addi, Opcode::Addi,
Argument::GPR(addr_dst_gpr), Argument::GPR(addr_dst_gpr),
Argument::GPR(addr_src_gpr), Argument::GPR(addr_src_gpr),
Argument::Simm(simm), Argument::Simm(simm),
) => { ) => Some(PoolReference {
let offset = if simplified.mnemonic == "addi" { simm.0 } else { -simm.0 };
Some(PoolReference {
addr_src_gpr, addr_src_gpr,
addr_offset: offset as i64, addr_offset: simm.0,
addr_dst_gpr: Some(addr_dst_gpr), addr_dst_gpr: Some(addr_dst_gpr),
}) }),
}
(
// `addis`
Opcode::Addis,
Argument::GPR(addr_dst_gpr),
Argument::GPR(addr_src_gpr),
Argument::Uimm(uimm), // Note: `addis` uses UIMM, unlike `addi`, `subi`, and `subis`
) => {
assert_eq!(simplified.mnemonic, "addis");
let offset = (uimm.0 as i64) << 16;
Some(PoolReference {
addr_src_gpr,
addr_offset: offset,
addr_dst_gpr: Some(addr_dst_gpr),
})
}
(
// `subis`
Opcode::Addis,
Argument::GPR(addr_dst_gpr),
Argument::GPR(addr_src_gpr),
Argument::Simm(simm),
) => {
assert_eq!(simplified.mnemonic, "subis");
let offset = (simm.0 as i64) << 16;
Some(PoolReference {
addr_src_gpr,
addr_offset: offset,
addr_dst_gpr: Some(addr_dst_gpr),
})
}
( (
// `mr` or `mr.` // `mr` or `mr.`
Opcode::Or, Opcode::Or,
@ -815,13 +777,13 @@ fn clear_overwritten_gprs(ins: powerpc::Ins, gpr_pool_relocs: &mut BTreeMap<u8,
// Also, if this instruction is accessing the middle of a symbol instead of the start, we add an // Also, if this instruction is accessing the middle of a symbol instead of the start, we add an
// addend to indicate that. // addend to indicate that.
fn make_fake_pool_reloc( fn make_fake_pool_reloc(
offset: i64, offset: i16,
cur_addr: u32, cur_addr: u32,
pool_reloc: &Relocation, pool_reloc: &Relocation,
symbols: &[Symbol], symbols: &[Symbol],
) -> Option<Relocation> { ) -> Option<Relocation> {
let pool_reloc = resolve_relocation(symbols, pool_reloc); let pool_reloc = resolve_relocation(symbols, pool_reloc);
let offset_from_pool = pool_reloc.relocation.addend + offset; let offset_from_pool = pool_reloc.relocation.addend + offset as i64;
let target_address = pool_reloc.symbol.address.checked_add_signed(offset_from_pool)?; let target_address = pool_reloc.symbol.address.checked_add_signed(offset_from_pool)?;
let target_symbol; let target_symbol;
let addend; let addend;
@ -984,7 +946,7 @@ fn generate_fake_pool_relocations_for_function(
clear_overwritten_gprs(ins, &mut gpr_pool_relocs); clear_overwritten_gprs(ins, &mut gpr_pool_relocs);
} }
} }
} else if let Some(pool_ref) = get_pool_reference_for_inst(ins, &simplified) { } else if let Some(pool_ref) = get_pool_reference_for_inst(ins.op, &simplified) {
// This instruction doesn't have a real relocation, so it may be a reference to one of // This instruction doesn't have a real relocation, so it may be a reference to one of
// the already-loaded pools. // the already-loaded pools.
if let Some(pool_reloc) = gpr_pool_relocs.get(&pool_ref.addr_src_gpr.0) { if let Some(pool_reloc) = gpr_pool_relocs.get(&pool_ref.addr_src_gpr.0) {
@ -1003,7 +965,7 @@ fn generate_fake_pool_relocations_for_function(
// with the offset within the .data section of an array variable into r21. // with the offset within the .data section of an array variable into r21.
// Then the body of the loop will `lwzx` one of the array elements from r21. // Then the body of the loop will `lwzx` one of the array elements from r21.
let mut new_reloc = pool_reloc.clone(); let mut new_reloc = pool_reloc.clone();
new_reloc.addend += pool_ref.addr_offset; new_reloc.addend += pool_ref.addr_offset as i64;
gpr_pool_relocs.insert(addr_dst_gpr.0, new_reloc); gpr_pool_relocs.insert(addr_dst_gpr.0, new_reloc);
} else { } else {
clear_overwritten_gprs(ins, &mut gpr_pool_relocs); clear_overwritten_gprs(ins, &mut gpr_pool_relocs);

View File

@ -204,9 +204,8 @@ pub struct ScratchConfig {
pub const CONFIG_FILENAMES: [&str; 3] = ["objdiff.json", "objdiff.yml", "objdiff.yaml"]; pub const CONFIG_FILENAMES: [&str; 3] = ["objdiff.json", "objdiff.yml", "objdiff.yaml"];
pub const DEFAULT_WATCH_PATTERNS: &[&str] = &[ pub const DEFAULT_WATCH_PATTERNS: &[&str] = &[
"*.c", "*.cc", "*.cp", "*.cpp", "*.cxx", "*.c++", "*.h", "*.hh", "*.hp", "*.hpp", "*.hxx", "*.c", "*.cp", "*.cpp", "*.cxx", "*.h", "*.hp", "*.hpp", "*.hxx", "*.s", "*.S", "*.asm",
"*.h++", "*.pch", "*.pch++", "*.inc", "*.s", "*.S", "*.asm", "*.py", "*.yml", "*.txt", "*.inc", "*.py", "*.yml", "*.txt", "*.json",
"*.json",
]; ];
pub const DEFAULT_IGNORE_PATTERNS: &[&str] = &["build/**/*"]; pub const DEFAULT_IGNORE_PATTERNS: &[&str] = &["build/**/*"];

View File

@ -130,7 +130,7 @@ fn map_symbols(
/// When inferring a symbol's size, we ignore symbols that start with specific prefixes. They are /// When inferring a symbol's size, we ignore symbols that start with specific prefixes. They are
/// usually emitted as branch targets and do not represent the start of a function or object. /// usually emitted as branch targets and do not represent the start of a function or object.
fn is_local_label(symbol: &Symbol) -> bool { fn is_local_label(symbol: &Symbol) -> bool {
const LABEL_PREFIXES: &[&str] = &[".L", "LAB_", "switchD_"]; const LABEL_PREFIXES: &[&str] = &[".L", "LAB_"];
symbol.size == 0 symbol.size == 0
&& symbol.flags.contains(SymbolFlag::Local) && symbol.flags.contains(SymbolFlag::Local)
&& LABEL_PREFIXES.iter().any(|p| symbol.name.starts_with(p)) && LABEL_PREFIXES.iter().any(|p| symbol.name.starts_with(p))