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