From c45f37eb1021f83a37ff5b30648a688bea8df180 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Tue, 30 Apr 2024 20:40:14 -0600 Subject: [PATCH] Update ppc750cl (10x faster!) & upgrade deps --- Cargo.lock | 129 +++++++++++------------------------ Cargo.toml | 33 +++++---- src/analysis/cfa.rs | 8 +-- src/analysis/mod.rs | 2 +- src/analysis/slices.rs | 75 ++++++++++++--------- src/analysis/tracker.rs | 6 +- src/analysis/vm.rs | 145 ++++++++++++++++++++++------------------ src/util/asm.rs | 27 ++++---- 8 files changed, 200 insertions(+), 225 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 66a954b..e63fc53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,9 +49,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" dependencies = [ "backtrace", ] @@ -122,9 +122,9 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bincode" @@ -165,16 +165,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "bstr" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c" -dependencies = [ - "memchr", - "serde", -] - [[package]] name = "byteorder" version = "1.5.0" @@ -277,10 +267,9 @@ dependencies = [ "base16ct", "base64", "cwdemangle", - "dol", "enable-ansi-support", "filetime", - "fixedbitset 0.5.0", + "fixedbitset 0.5.7", "flagset", "flate2", "glob", @@ -295,7 +284,7 @@ dependencies = [ "nintendo-lz", "num_enum", "objdiff-core", - "object 0.34.0", + "object 0.35.0", "once_cell", "orthrus-ncompress", "owo-colors", @@ -330,16 +319,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "dol" -version = "0.1.0" -source = "git+https://github.com/encounter/ppc750cl?rev=4a2bbbc6f84dcb76255ab6f3595a8d4a0ce96618#4a2bbbc6f84dcb76255ab6f3595a8d4a0ce96618" -dependencies = [ - "bincode", - "serde", - "thiserror", -] - [[package]] name = "either" version = "1.10.0" @@ -391,9 +370,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "fixedbitset" -version = "0.5.0" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b51ee430d5ff16df7998870eb0b4775383ac5bc450f5a2ed547394fe2d617131" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flagset" @@ -406,9 +385,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", @@ -451,20 +430,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" -[[package]] -name = "globset" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" -dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata 0.4.6", - "regex-syntax 0.8.2", - "serde", -] - [[package]] name = "hashbrown" version = "0.14.3" @@ -509,9 +474,9 @@ checksum = "d9f1a0777d972970f204fdf8ef319f1f4f8459131636d7e3c96c5d59570d0fa6" [[package]] name = "indexmap" -version = "2.2.5" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown", @@ -578,9 +543,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "memmap2" @@ -662,23 +627,19 @@ dependencies = [ [[package]] name = "objdiff-core" version = "1.0.0" -source = "git+https://github.com/encounter/objdiff?rev=a5668b484b3db9e85d2aa8aeb84b37bff6077df6#a5668b484b3db9e85d2aa8aeb84b37bff6077df6" +source = "git+https://github.com/encounter/objdiff?rev=2c46286affd11fe37f620ba919a3e57c4b80ccdb#2c46286affd11fe37f620ba919a3e57c4b80ccdb" dependencies = [ "anyhow", "byteorder", "cwdemangle", "filetime", "flagset", - "globset", "log", "memmap2", "num-traits", - "object 0.34.0", + "object 0.35.0", "ppc750cl", - "semver", "serde", - "serde_json", - "serde_yaml", "similar", ] @@ -693,9 +654,9 @@ dependencies = [ [[package]] name = "object" -version = "0.34.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7090bae93f8585aad99e595b7073c5de9ba89fbd6b4e9f0cdd7a10177273ac8" +checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" dependencies = [ "crc32fast", "hashbrown", @@ -767,12 +728,8 @@ checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "ppc750cl" -version = "0.2.0" -source = "git+https://github.com/encounter/ppc750cl?rev=4a2bbbc6f84dcb76255ab6f3595a8d4a0ce96618#4a2bbbc6f84dcb76255ab6f3595a8d4a0ce96618" -dependencies = [ - "num-traits", - "serde", -] +version = "0.3.0" +source = "git+https://github.com/encounter/ppc750cl?rev=6cbd7d888c7082c2c860f66cbb9848d633f753ed#6cbd7d888c7082c2c860f66cbb9848d633f753ed" [[package]] name = "proc-macro-crate" @@ -815,9 +772,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -844,9 +801,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", @@ -919,26 +876,20 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d36299972b96b8ae7e8f04ecbf75fb41a27bf3781af00abcf57609774cb911" -[[package]] -name = "semver" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" - [[package]] name = "serde" -version = "1.0.197" +version = "1.0.199" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.199" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" dependencies = [ "proc-macro2", "quote", @@ -947,9 +898,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ "itoa", "ryu", @@ -958,9 +909,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", @@ -969,9 +920,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.32" +version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd075d994154d4a774f95b51fb96bdc2832b0ea48425c92546073816cda1f2f" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ "indexmap", "itoa", @@ -1002,15 +953,15 @@ dependencies = [ [[package]] name = "similar" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21" +checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640" [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "snafu" @@ -1246,9 +1197,9 @@ checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "unsafe-libyaml" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "valuable" diff --git a/Cargo.toml b/Cargo.toml index 8eea1c7..c6d05ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,48 +24,47 @@ lto = "thin" strip = "debuginfo" [dependencies] -anyhow = { version = "1.0.81", features = ["backtrace"] } +anyhow = { version = "1.0.82", features = ["backtrace"] } ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "write_symbol_table" } argp = "0.3.0" base16ct = "0.2.0" -base64 = "0.22.0" +base64 = "0.22.1" cwdemangle = "1.0.0" -dol = { git = "https://github.com/encounter/ppc750cl", rev = "4a2bbbc6f84dcb76255ab6f3595a8d4a0ce96618" } enable-ansi-support = "0.2.1" filetime = "0.2.23" -fixedbitset = "0.5.0" +fixedbitset = "0.5.7" flagset = { version = "0.4.5", features = ["serde"] } -flate2 = "1.0.28" +flate2 = "1.0.30" glob = "0.3.1" hex = "0.4.3" indent = "0.1.1" -indexmap = "2.2.5" +indexmap = "2.2.6" itertools = "0.12.1" log = "0.4.21" -memchr = "2.7.1" +memchr = "2.7.2" memmap2 = "0.9.4" multimap = "0.10.0" nintendo-lz = "0.1.3" num_enum = "0.7.2" -objdiff-core = { git = "https://github.com/encounter/objdiff", rev = "a5668b484b3db9e85d2aa8aeb84b37bff6077df6", features = ["ppc"] } +objdiff-core = { git = "https://github.com/encounter/objdiff", rev = "2c46286affd11fe37f620ba919a3e57c4b80ccdb", features = ["ppc"] } #objdiff-core = { path = "../objdiff/objdiff-core", features = ["ppc"] } -object = { version = "0.34.0", features = ["read_core", "std", "elf", "write_std"], default-features = false } +object = { version = "0.35.0", features = ["read_core", "std", "elf", "write_std"], default-features = false } once_cell = "1.19.0" orthrus-ncompress = "0.2.0" owo-colors = { version = "4.0.0", features = ["supports-colors"] } path-slash = "0.2.1" petgraph = { version = "0.6.4", default-features = false } -ppc750cl = { git = "https://github.com/encounter/ppc750cl", rev = "4a2bbbc6f84dcb76255ab6f3595a8d4a0ce96618" } -rayon = "1.9.0" -regex = "1.10.3" +ppc750cl = { git = "https://github.com/encounter/ppc750cl", rev = "6cbd7d888c7082c2c860f66cbb9848d633f753ed" } +rayon = "1.10.0" +regex = "1.10.4" rustc-hash = "1.1.0" sanitise-file-name = "1.0.0" -serde = "1.0.197" -serde_json = "1.0.114" -serde_repr = "0.1.18" -serde_yaml = "0.9.32" +serde = "1.0.199" +serde_json = "1.0.116" +serde_repr = "0.1.19" +serde_yaml = "0.9.34" sha-1 = "0.10.1" -smallvec = "1.13.1" +smallvec = "1.13.2" supports-color = "3.0.0" syntect = { version = "5.2.0", features = ["parsing", "regex-fancy", "dump-load"], default-features = false } tracing = "0.1.40" diff --git a/src/analysis/cfa.rs b/src/analysis/cfa.rs index ad77c27..09d3982 100644 --- a/src/analysis/cfa.rs +++ b/src/analysis/cfa.rs @@ -499,12 +499,12 @@ pub fn locate_sda_bases(obj: &mut ObjInfo) -> Result { executor.push(entry_addr, VM::new(), false); let result = executor.run( obj, - |ExecCbData { executor, vm, result, ins_addr: _, section: _, ins, block_start: _ }| { + |ExecCbData { executor, vm, result, ins_addr, section: _, ins: _, block_start: _ }| { match result { StepResult::Continue | StepResult::LoadStore { .. } => { return Ok(ExecCbResult::Continue); } - StepResult::Illegal => bail!("Illegal instruction @ {:#010X}", ins.addr), + StepResult::Illegal => bail!("Illegal instruction @ {}", ins_addr), StepResult::Jump(target) => { if let BranchTarget::Address(RelocationTarget::Address(addr)) = target { return Ok(ExecCbResult::Jump(addr)); @@ -558,10 +558,10 @@ pub fn locate_bss_memsets(obj: &mut ObjInfo) -> Result> { executor.push(entry_addr, VM::new(), false); executor.run( obj, - |ExecCbData { executor: _, vm, result, ins_addr: _, section: _, ins, block_start: _ }| { + |ExecCbData { executor: _, vm, result, ins_addr, section: _, ins: _, block_start: _ }| { match result { StepResult::Continue | StepResult::LoadStore { .. } => Ok(ExecCbResult::Continue), - StepResult::Illegal => bail!("Illegal instruction @ {:#010X}", ins.addr), + StepResult::Illegal => bail!("Illegal instruction @ {}", ins_addr), StepResult::Jump(_target) => Ok(ExecCbResult::End(())), StepResult::Branch(branches) => { for branch in branches { diff --git a/src/analysis/mod.rs b/src/analysis/mod.rs index dcc273f..c53d9a3 100644 --- a/src/analysis/mod.rs +++ b/src/analysis/mod.rs @@ -19,7 +19,7 @@ pub mod tracker; pub mod vm; pub fn disassemble(section: &ObjSection, address: u32) -> Option { - read_u32(section, address).map(|code| Ins::new(code, address)) + read_u32(section, address).map(Ins::new) } pub fn read_u32(section: &ObjSection, address: u32) -> Option { diff --git a/src/analysis/slices.rs b/src/analysis/slices.rs index 85b95c4..4f4420a 100644 --- a/src/analysis/slices.rs +++ b/src/analysis/slices.rs @@ -1,4 +1,5 @@ use std::{ + borrow::Cow, collections::{btree_map, BTreeMap, BTreeSet}, ops::Range, }; @@ -43,54 +44,64 @@ pub enum TailCallResult { type BlockRange = Range; -#[inline(always)] -fn next_ins(section: &ObjSection, ins: &Ins) -> Option { disassemble(section, ins.addr + 4) } - type InsCheck = dyn Fn(&Ins) -> bool; #[inline(always)] fn check_sequence( section: &ObjSection, - ins: &Ins, + addr: SectionAddress, + ins: Option<&Ins>, sequence: &[(&InsCheck, &InsCheck)], ) -> Result { let mut found = false; for &(first, second) in sequence { - if first(ins) { - if let Some(next) = next_ins(section, ins) { - if second(&next) - // Also check the following instruction, in case the scheduler - // put something in between. - || (!next.is_branch() && matches!(next_ins(section, &next), Some(ins) if second(&ins))) - { - found = true; - break; - } - } + let Some(ins) = + ins.map(Cow::Borrowed).or_else(|| disassemble(section, addr.address).map(Cow::Owned)) + else { + continue; + }; + if !first(&ins) { + continue; + } + let Some(next) = disassemble(section, addr.address + 4) else { + continue; + }; + if second(&next) + // Also check the following instruction, in case the scheduler + // put something in between. + || (!next.is_branch() + && matches!(disassemble(section, addr.address + 8), Some(ins) if second(&ins))) + { + found = true; + break; } } Ok(found) } -fn check_prologue_sequence(section: &ObjSection, ins: &Ins) -> Result { +fn check_prologue_sequence( + section: &ObjSection, + addr: SectionAddress, + ins: Option<&Ins>, +) -> Result { #[inline(always)] fn is_mflr(ins: &Ins) -> bool { // mfspr r0, LR - ins.op == Opcode::Mfspr && ins.field_rD() == 0 && ins.field_spr() == 8 + ins.op == Opcode::Mfspr && ins.field_rd() == 0 && ins.field_spr() == 8 } #[inline(always)] fn is_stwu(ins: &Ins) -> bool { // stwu r1, d(r1) - ins.op == Opcode::Stwu && ins.field_rS() == 1 && ins.field_rA() == 1 + ins.op == Opcode::Stwu && ins.field_rs() == 1 && ins.field_ra() == 1 } #[inline(always)] fn is_stw(ins: &Ins) -> bool { // stw r0, d(r1) - ins.op == Opcode::Stw && ins.field_rS() == 0 && ins.field_rA() == 1 + ins.op == Opcode::Stw && ins.field_rs() == 0 && ins.field_ra() == 1 } - check_sequence(section, ins, &[(&is_stwu, &is_mflr), (&is_mflr, &is_stw)]) + check_sequence(section, addr, ins, &[(&is_stwu, &is_mflr), (&is_mflr, &is_stw)]) } impl FunctionSlices { @@ -132,14 +143,14 @@ impl FunctionSlices { #[inline(always)] fn is_lwz(ins: &Ins) -> bool { // lwz r1, d(r) - ins.op == Opcode::Lwz && ins.field_rD() == 1 + ins.op == Opcode::Lwz && ins.field_rd() == 1 } if is_lwz(ins) { self.has_r1_load = true; return Ok(()); // Possibly instead of a prologue } - if check_prologue_sequence(section, ins)? { + if check_prologue_sequence(section, addr, Some(ins))? { if let Some(prologue) = self.prologue { if prologue != addr && prologue != addr - 4 { bail!("Found duplicate prologue: {:#010X} and {:#010X}", prologue, addr) @@ -160,20 +171,20 @@ impl FunctionSlices { #[inline(always)] fn is_mtlr(ins: &Ins) -> bool { // mtspr LR, r0 - ins.op == Opcode::Mtspr && ins.field_rS() == 0 && ins.field_spr() == 8 + ins.op == Opcode::Mtspr && ins.field_rs() == 0 && ins.field_spr() == 8 } #[inline(always)] fn is_addi(ins: &Ins) -> bool { // addi r1, r1, SIMM - ins.op == Opcode::Addi && ins.field_rD() == 1 && ins.field_rA() == 1 + ins.op == Opcode::Addi && ins.field_rd() == 1 && ins.field_ra() == 1 } #[inline(always)] fn is_or(ins: &Ins) -> bool { // or r1, rA, rB - ins.op == Opcode::Or && ins.field_rD() == 1 + ins.op == Opcode::Or && ins.field_rd() == 1 } - if check_sequence(section, ins, &[(&is_mtlr, &is_addi), (&is_or, &is_mtlr)])? { + if check_sequence(section, addr, Some(ins), &[(&is_mtlr, &is_addi), (&is_or, &is_mtlr)])? { if let Some(epilogue) = self.epilogue { if epilogue != addr { bail!("Found duplicate epilogue: {:#010X} and {:#010X}", epilogue, addr) @@ -513,11 +524,12 @@ impl FunctionSlices { { // FIXME this is real bad if !self.has_conditional_blr { - if let Some(ins) = disassemble(section, end.address - 4) { + let ins_addr = end - 4; + if let Some(ins) = disassemble(section, ins_addr.address) { if ins.op == Opcode::B { if let Some(RelocationTarget::Address(target)) = ins - .branch_dest() - .and_then(|addr| section_address_for(obj, end - 4, addr)) + .branch_dest(ins_addr.address) + .and_then(|addr| section_address_for(obj, ins_addr, addr)) { if self.function_references.contains(&target) { for branches in self.branches.values() { @@ -617,8 +629,7 @@ impl FunctionSlices { if self.prologue.is_none() { let mut current_address = function_start; while current_address < addr { - let ins = disassemble(target_section, current_address.address).unwrap(); - match check_prologue_sequence(target_section, &ins) { + match check_prologue_sequence(target_section, current_address, None) { Ok(true) => { log::debug!( "Prologue discovered @ {}; known tail call: {}", @@ -703,7 +714,7 @@ impl FunctionSlices { #[inline] fn is_conditional_blr(ins: &Ins) -> bool { - ins.op == Opcode::Bclr && ins.field_BO() & 0b10100 != 0b10100 + ins.op == Opcode::Bclr && ins.field_bo() & 0b10100 != 0b10100 } #[inline] diff --git a/src/analysis/tracker.rs b/src/analysis/tracker.rs index 440d86d..3ea05d9 100644 --- a/src/analysis/tracker.rs +++ b/src/analysis/tracker.rs @@ -219,8 +219,8 @@ impl Tracker { match ins.op { // addi rD, rA, SIMM Opcode::Addi | Opcode::Addic | Opcode::Addic_ => { - let source = ins.field_rA(); - let target = ins.field_rD(); + let source = ins.field_ra() as usize; + let target = ins.field_rd() as usize; if let Some(value) = self.gpr_address(obj, ins_addr, &vm.gpr[target].value) { if (source == 2 @@ -258,7 +258,7 @@ impl Tracker { } // ori rA, rS, UIMM Opcode::Ori => { - let target = ins.field_rA(); + let target = ins.field_ra() as usize; if let Some(value) = self.gpr_address(obj, ins_addr, &vm.gpr[target].value) { if let (Some(hi_addr), Some(lo_addr)) = diff --git a/src/analysis/vm.rs b/src/analysis/vm.rs index 6eab374..50d3353 100644 --- a/src/analysis/vm.rs +++ b/src/analysis/vm.rs @@ -199,8 +199,8 @@ impl VM { } // add rD, rA, rB Opcode::Add => { - let left = self.gpr[ins.field_rA()].value; - let right = self.gpr[ins.field_rB()].value; + let left = self.gpr[ins.field_ra() as usize].value; + let right = self.gpr[ins.field_rb() as usize].value; let value = match (left, right) { (GprValue::Constant(left), GprValue::Constant(right)) => { GprValue::Constant(left.wrapping_add(right)) @@ -215,20 +215,20 @@ impl VM { ) => GprValue::Address(RelocationTarget::Address(right + left)), _ => GprValue::Unknown, }; - self.gpr[ins.field_rD()].set_direct(value); + self.gpr[ins.field_rd() as usize].set_direct(value); } // addis rD, rA, SIMM Opcode::Addis => { if let Some(target) = relocation_target_for(obj, ins_addr, None /* TODO */).ok().flatten() { - debug_assert_eq!(ins.field_rA(), 0); - self.gpr[ins.field_rD()].set_hi(GprValue::Address(target), ins_addr); + debug_assert_eq!(ins.field_ra(), 0); + self.gpr[ins.field_rd() as usize].set_hi(GprValue::Address(target), ins_addr); } else { - let left = if ins.field_rA() == 0 { + let left = if ins.field_ra() == 0 { GprValue::Constant(0) } else { - self.gpr[ins.field_rA()].value + self.gpr[ins.field_ra() as usize].value }; let value = match left { GprValue::Constant(value) => { @@ -236,11 +236,11 @@ impl VM { } _ => GprValue::Unknown, }; - if ins.field_rA() == 0 { + if ins.field_ra() == 0 { // lis rD, SIMM - self.gpr[ins.field_rD()].set_hi(value, ins_addr); + self.gpr[ins.field_rd() as usize].set_hi(value, ins_addr); } else { - self.gpr[ins.field_rD()].set_direct(value); + self.gpr[ins.field_rd() as usize].set_direct(value); } } } @@ -251,16 +251,16 @@ impl VM { if let Some(target) = relocation_target_for(obj, ins_addr, None /* TODO */).ok().flatten() { - self.gpr[ins.field_rD()].set_lo( + self.gpr[ins.field_rd() as usize].set_lo( GprValue::Address(target), ins_addr, - self.gpr[ins.field_rA()], + self.gpr[ins.field_ra() as usize], ); } else { - let left = if ins.field_rA() == 0 && ins.op == Opcode::Addi { + let left = if ins.field_ra() == 0 && ins.op == Opcode::Addi { GprValue::Constant(0) } else { - self.gpr[ins.field_rA()].value + self.gpr[ins.field_ra() as usize].value }; let value = match left { GprValue::Constant(value) => { @@ -271,19 +271,26 @@ impl VM { ), _ => GprValue::Unknown, }; - if ins.field_rA() == 0 { + if ins.field_ra() == 0 { // li rD, SIMM - self.gpr[ins.field_rD()].set_direct(value); + self.gpr[ins.field_rd() as usize].set_direct(value); } else { - self.gpr[ins.field_rD()].set_lo(value, ins_addr, self.gpr[ins.field_rA()]); + self.gpr[ins.field_rd() as usize].set_lo( + value, + ins_addr, + self.gpr[ins.field_ra() as usize], + ); } } } // subf rD, rA, rB // subfc rD, rA, rB Opcode::Subf | Opcode::Subfc => { - self.gpr[ins.field_rD()].set_direct( - match (self.gpr[ins.field_rA()].value, self.gpr[ins.field_rB()].value) { + self.gpr[ins.field_rd() as usize].set_direct( + match ( + self.gpr[ins.field_ra() as usize].value, + self.gpr[ins.field_rb() as usize].value, + ) { (GprValue::Constant(left), GprValue::Constant(right)) => { GprValue::Constant((!left).wrapping_add(right).wrapping_add(1)) } @@ -293,48 +300,54 @@ impl VM { } // subfic rD, rA, SIMM Opcode::Subfic => { - self.gpr[ins.field_rD()].set_direct(match self.gpr[ins.field_rA()].value { - GprValue::Constant(value) => GprValue::Constant( - (!value).wrapping_add(ins.field_simm() as u32).wrapping_add(1), - ), - _ => GprValue::Unknown, - }); + self.gpr[ins.field_rd() as usize].set_direct( + match self.gpr[ins.field_ra() as usize].value { + GprValue::Constant(value) => GprValue::Constant( + (!value).wrapping_add(ins.field_simm() as u32).wrapping_add(1), + ), + _ => GprValue::Unknown, + }, + ); } // ori rA, rS, UIMM Opcode::Ori => { if let Some(target) = relocation_target_for(obj, ins_addr, None /* TODO */).ok().flatten() { - self.gpr[ins.field_rA()].set_lo( + self.gpr[ins.field_ra() as usize].set_lo( GprValue::Address(target), ins_addr, - self.gpr[ins.field_rS()], + self.gpr[ins.field_rs() as usize], ); } else { - let value = match self.gpr[ins.field_rS()].value { + let value = match self.gpr[ins.field_rs() as usize].value { GprValue::Constant(value) => { GprValue::Constant(value | ins.field_uimm() as u32) } _ => GprValue::Unknown, }; - self.gpr[ins.field_rA()].set_lo(value, ins_addr, self.gpr[ins.field_rS()]); + self.gpr[ins.field_ra() as usize].set_lo( + value, + ins_addr, + self.gpr[ins.field_rs() as usize], + ); } } // or rA, rS, rB Opcode::Or => { - if ins.field_rS() == ins.field_rB() { + if ins.field_rs() == ins.field_rb() { // Register copy - self.gpr[ins.field_rA()] = self.gpr[ins.field_rS()]; + self.gpr[ins.field_ra() as usize] = self.gpr[ins.field_rs() as usize]; } else { - let left = self.gpr[ins.field_rS()].value; - let right = self.gpr[ins.field_rB()].value; + let left = self.gpr[ins.field_rs() as usize].value; + let right = self.gpr[ins.field_rb() as usize].value; let value = match (left, right) { (GprValue::Constant(left), GprValue::Constant(right)) => { GprValue::Constant(left | right) } _ => GprValue::Unknown, }; - self.gpr[ins.field_rA()].set_direct(value); + self.gpr[ins.field_ra() as usize].set_direct(value); } } // cmp [crfD], [L], rA, rB @@ -342,34 +355,34 @@ impl VM { // cmpl [crfD], [L], rA, rB // cmpli [crfD], [L], rA, UIMM Opcode::Cmp | Opcode::Cmpi | Opcode::Cmpl | Opcode::Cmpli => { - if ins.field_L() == 0 { - let left_reg = ins.field_rA(); + if ins.field_l() == 0 { + let left_reg = ins.field_ra() as usize; let left = self.gpr[left_reg].value; let (right, signed) = match ins.op { - Opcode::Cmp => (self.gpr[ins.field_rB()].value, true), - Opcode::Cmpl => (self.gpr[ins.field_rB()].value, false), + Opcode::Cmp => (self.gpr[ins.field_rb() as usize].value, true), + Opcode::Cmpl => (self.gpr[ins.field_rb() as usize].value, false), Opcode::Cmpi => (GprValue::Constant(ins.field_simm() as u32), true), Opcode::Cmpli => (GprValue::Constant(ins.field_uimm() as u32), false), _ => unreachable!(), }; - let crf = ins.field_crfD(); - self.cr[crf] = Cr { signed, left, right }; - self.gpr[left_reg].value = GprValue::ComparisonResult(crf as u8); + let crf = ins.field_crfd(); + self.cr[crf as usize] = Cr { signed, left, right }; + self.gpr[left_reg].value = GprValue::ComparisonResult(crf); } } // rlwinm rA, rS, SH, MB, ME // rlwnm rA, rS, rB, MB, ME Opcode::Rlwinm | Opcode::Rlwnm => { let value = if let Some(shift) = match ins.op { - Opcode::Rlwinm => Some(ins.field_SH() as u32), - Opcode::Rlwnm => match self.gpr[ins.field_rB()].value { + Opcode::Rlwinm => Some(ins.field_sh() as u32), + Opcode::Rlwnm => match self.gpr[ins.field_rb() as usize].value { GprValue::Constant(value) => Some(value), _ => None, }, _ => unreachable!(), } { - let mask = mask_value(ins.field_MB() as u32, ins.field_ME() as u32); - match self.gpr[ins.field_rS()].value { + let mask = mask_value(ins.field_mb() as u32, ins.field_me() as u32); + match self.gpr[ins.field_rs() as usize].value { GprValue::Constant(value) => { GprValue::Constant(value.rotate_left(shift) & mask) } @@ -383,7 +396,7 @@ impl VM { } else { GprValue::Unknown }; - self.gpr[ins.field_rA()].set_direct(value); + self.gpr[ins.field_ra() as usize].set_direct(value); } // b[l][a] target_addr // b[c][l][a] BO, BI, target_addr @@ -391,7 +404,7 @@ impl VM { // b[c]lr[l] BO, BI Opcode::B | Opcode::Bc | Opcode::Bcctr | Opcode::Bclr => { // HACK for `bla 0x60` in __OSDBJump - if ins.op == Opcode::B && ins.field_LK() && ins.field_AA() { + if ins.op == Opcode::B && ins.field_lk() && ins.field_aa() { return StepResult::Jump(BranchTarget::Unknown); } @@ -409,7 +422,7 @@ impl VM { GprValue::Address(target) => BranchTarget::Address(target), GprValue::LoadIndexed { address, max_offset } // FIXME: avoids treating bctrl indirect calls as jump tables - if !ins.field_LK() => { + if !ins.field_lk() => { BranchTarget::JumpTable { address, size: max_offset.and_then(|n| n.checked_add(4)) } } _ => BranchTarget::Unknown, @@ -417,7 +430,7 @@ impl VM { } Opcode::Bclr => BranchTarget::Return, _ => { - let value = ins.branch_dest().unwrap(); + let value = ins.branch_dest(ins_addr.address).unwrap(); if let Some(target) = section_address_for(obj, ins_addr, value) { BranchTarget::Address(target) } else { @@ -427,7 +440,7 @@ impl VM { }; // If branching with link, use function call semantics - if ins.field_LK() { + if ins.field_lk() { return StepResult::Branch(vec![ Branch { target: BranchTarget::Address(RelocationTarget::Address(ins_addr + 4)), @@ -439,7 +452,7 @@ impl VM { } // Branch always - if ins.op == Opcode::B || ins.field_BO() & 0b10100 == 0b10100 { + if ins.op == Opcode::B || ins.field_bo() & 0b10100 == 0b10100 { return StepResult::Jump(branch_target); } @@ -452,19 +465,19 @@ impl VM { vm: self.clone_all(), }, // Branch taken - Branch { target: branch_target, link: ins.field_LK(), vm: self.clone_all() }, + Branch { target: branch_target, link: ins.field_lk(), vm: self.clone_all() }, ]; // Use tracked CR to calculate new register values for branches - let crf = ins.field_BI() >> 2; - let crb = (ins.field_BI() & 3) as u8; + let crf = (ins.field_bi() >> 2) as usize; + let crb = ins.field_bi() & 3; let (f_val, t_val) = split_values_by_crb(crb, self.cr[crf].left, self.cr[crf].right); - if ins.field_BO() & 0b11110 == 0b00100 { + if ins.field_bo() & 0b11110 == 0b00100 { // Branch if false branches[0].vm.set_comparison_result(t_val, crf); branches[1].vm.set_comparison_result(f_val, crf); - } else if ins.field_BO() & 0b11110 == 0b01100 { + } else if ins.field_bo() & 0b11110 == 0b01100 { // Branch if true branches[0].vm.set_comparison_result(f_val, crf); branches[1].vm.set_comparison_result(t_val, crf); @@ -474,8 +487,8 @@ impl VM { } // lwzx rD, rA, rB Opcode::Lwzx => { - let left = self.gpr[ins.field_rA()].address(obj, ins_addr); - let right = self.gpr[ins.field_rB()].value; + let left = self.gpr[ins.field_ra() as usize].address(obj, ins_addr); + let right = self.gpr[ins.field_rb() as usize].value; let value = match (left, right) { (Some(address), GprValue::Range { min: _, max, .. }) if /*min == 0 &&*/ max < u32::MAX - 4 && max & 3 == 0 => @@ -492,12 +505,12 @@ impl VM { } _ => GprValue::Unknown, }; - self.gpr[ins.field_rD()].set_direct(value); + self.gpr[ins.field_rd() as usize].set_direct(value); } // mtspr SPR, rS Opcode::Mtspr => match ins.field_spr() { - 8 => self.lr = self.gpr[ins.field_rS()].value, - 9 => self.ctr = self.gpr[ins.field_rS()].value, + 8 => self.lr = self.gpr[ins.field_rs() as usize].value, + 9 => self.ctr = self.gpr[ins.field_rs() as usize].value, _ => {} }, // mfspr rD, SPR @@ -507,14 +520,14 @@ impl VM { 9 => self.ctr, _ => GprValue::Unknown, }; - self.gpr[ins.field_rD()].set_direct(value); + self.gpr[ins.field_rd() as usize].set_direct(value); } // rfi Opcode::Rfi => { return StepResult::Jump(BranchTarget::Unknown); } op if is_load_store_op(op) => { - let source = ins.field_rA(); + let source = ins.field_ra() as usize; let mut result = StepResult::Continue; if let GprValue::Address(target) = self.gpr[source].value { if is_update_op(op) { @@ -549,13 +562,13 @@ impl VM { self.gpr[source].set_direct(GprValue::Unknown); } if is_load_op(op) { - self.gpr[ins.field_rD()].set_direct(GprValue::Unknown); + self.gpr[ins.field_rd() as usize].set_direct(GprValue::Unknown); } return result; } _ => { - for field in ins.defs() { - if let Some(Argument::GPR(GPR(reg))) = field.argument() { + for argument in ins.defs() { + if let Argument::GPR(GPR(reg)) = argument { self.gpr[reg as usize].set_direct(GprValue::Unknown); } } diff --git a/src/util/asm.rs b/src/util/asm.rs index 9a0133d..71fae77 100644 --- a/src/util/asm.rs +++ b/src/util/asm.rs @@ -6,7 +6,7 @@ use std::{ use anyhow::{anyhow, bail, ensure, Context, Result}; use itertools::Itertools; -use ppc750cl::{disasm_iter, Argument, Ins, Opcode}; +use ppc750cl::{Argument, Ins, InsIter, Opcode}; use crate::{ obj::{ @@ -67,15 +67,15 @@ where W: Write + ?Sized { // Generate local jump labels if section.kind == ObjSectionKind::Code { - for ins in disasm_iter(§ion.data, section.address as u32) { - if let Some(address) = ins.branch_dest() { - if ins.field_AA() || !section.contains(address) { + for (addr, ins) in InsIter::new(§ion.data, section.address as u32) { + if let Some(address) = ins.branch_dest(addr) { + if ins.field_aa() || !section.contains(address) { continue; } // Replace section-relative jump relocations (generated by GCC) // These aren't always possible to express accurately in GNU assembler - if matches!(relocations.get(&ins.addr), Some(reloc) if reloc.addend == 0) { + if matches!(relocations.get(&addr), Some(reloc) if reloc.addend == 0) { continue; } @@ -102,7 +102,7 @@ where W: Write + ?Sized { target_symbol_idx = Some(symbol_idx); } if let Some(symbol_idx) = target_symbol_idx { - relocations.insert(ins.addr, ObjReloc { + relocations.insert(addr, ObjReloc { kind: match ins.op { Opcode::B => ObjRelocKind::PpcRel24, Opcode::Bc => ObjRelocKind::PpcRel14, @@ -243,10 +243,10 @@ fn write_code_chunk( where W: Write + ?Sized, { - for ins in disasm_iter(data, address) { - let reloc = relocations.get(&ins.addr); - let file_offset = section.file_offset + (ins.addr as u64 - section.address); - write_ins(w, symbols, ins, reloc, file_offset, section.virtual_address)?; + for (addr, ins) in InsIter::new(data, address) { + let reloc = relocations.get(&addr); + let file_offset = section.file_offset + (addr as u64 - section.address); + write_ins(w, symbols, addr, ins, reloc, file_offset, section.virtual_address)?; } Ok(()) } @@ -254,6 +254,7 @@ where fn write_ins( w: &mut W, symbols: &[ObjSymbol], + addr: u32, mut ins: Ins, reloc: Option<&ObjReloc>, file_offset: u64, @@ -265,7 +266,7 @@ where write!( w, "/* {:08X} {:08X} {:02X} {:02X} {:02X} {:02X} */\t", - ins.addr as u64 + section_vaddr.unwrap_or(0), + addr as u64 + section_vaddr.unwrap_or(0), file_offset, (ins.code >> 24) & 0xFF, (ins.code >> 16) & 0xFF, @@ -290,10 +291,10 @@ where write!(w, ".4byte {:#010X} /* invalid */", ins.code)?; } else if is_illegal_instruction(ins.code) { let sins = ins.simplified(); - write!(w, ".4byte {:#010X} /* illegal: {} */", sins.ins.code, sins)?; + write!(w, ".4byte {:#010X} /* illegal: {} */", ins.code, sins)?; } else { let sins = ins.simplified(); - write!(w, "{}{}", sins.mnemonic, sins.ins.suffix())?; + write!(w, "{}", sins.mnemonic)?; let mut writing_offset = false; for (i, arg) in sins.args.iter().enumerate() {