Experimental ARM64 support

Based on yaxpeax-arm, but with a heavy dose of
custom code to work around its limitations.

Please report any issues or unhandled relocations.
This commit is contained in:
Luke Street 2024-10-31 00:37:01 -06:00
parent 7f14b684bf
commit 424434edd6
13 changed files with 2930 additions and 20 deletions

66
Cargo.lock generated
View File

@ -434,6 +434,18 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "bitvec"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]] [[package]]
name = "block" name = "block"
version = "0.1.6" version = "0.1.6"
@ -1514,6 +1526,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]] [[package]]
name = "futures-channel" name = "futures-channel"
version = "0.3.30" version = "0.3.30"
@ -2861,7 +2879,7 @@ dependencies = [
[[package]] [[package]]
name = "objdiff-cli" name = "objdiff-cli"
version = "2.3.4" version = "2.4.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"argp", "argp",
@ -2883,7 +2901,7 @@ dependencies = [
[[package]] [[package]]
name = "objdiff-core" name = "objdiff-core"
version = "2.3.4" version = "2.4.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"arm-attr", "arm-attr",
@ -2919,11 +2937,13 @@ dependencies = [
"tsify-next", "tsify-next",
"unarm", "unarm",
"wasm-bindgen", "wasm-bindgen",
"yaxpeax-arch",
"yaxpeax-arm",
] ]
[[package]] [[package]]
name = "objdiff-gui" name = "objdiff-gui"
version = "2.3.4" version = "2.4.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@ -3495,6 +3515,12 @@ dependencies = [
"num_enum 0.5.11", "num_enum 0.5.11",
] ]
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.8.5" version = "0.8.5"
@ -4290,6 +4316,12 @@ dependencies = [
"futures-core", "futures-core",
] ]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]] [[package]]
name = "tauri-winres" name = "tauri-winres"
version = "0.1.1" version = "0.1.1"
@ -5525,6 +5557,15 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "wyz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
dependencies = [
"tap",
]
[[package]] [[package]]
name = "x11-dl" name = "x11-dl"
version = "2.21.0" version = "2.21.0"
@ -5598,6 +5639,25 @@ version = "0.8.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26" checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26"
[[package]]
name = "yaxpeax-arch"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36274fcc5403da2a7636ffda4d02eca12a1b2b8267b9d2e04447bd2ccfc72082"
dependencies = [
"num-traits",
]
[[package]]
name = "yaxpeax-arm"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1c6a2af41f88546a08df3bc77aadf7263884d6dffdac5b32dea7dc2df23f241"
dependencies = [
"bitvec",
"yaxpeax-arch",
]
[[package]] [[package]]
name = "yeslogic-fontconfig-sys" name = "yeslogic-fontconfig-sys"
version = "6.0.0" version = "6.0.0"

View File

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

View File

@ -20,6 +20,7 @@ Supports:
- MIPS (N64, PS1, PS2, PSP) - MIPS (N64, PS1, PS2, PSP)
- x86 (COFF only at the moment) - x86 (COFF only at the moment)
- ARM (GBA, DS, 3DS) - ARM (GBA, DS, 3DS)
- ARM64 (Switch, experimental)
See [Usage](#usage) for more information. See [Usage](#usage) for more information.

View File

@ -16,7 +16,7 @@ documentation = "https://docs.rs/objdiff-core"
crate-type = ["cdylib", "rlib"] crate-type = ["cdylib", "rlib"]
[features] [features]
all = ["config", "dwarf", "mips", "ppc", "x86", "arm", "bindings"] all = ["config", "dwarf", "mips", "ppc", "x86", "arm", "arm64", "bindings"]
any-arch = ["config", "dep:bimap", "dep:strum", "dep:similar", "dep:flagset", "dep:log", "dep:memmap2", "dep:byteorder", "dep:num-traits"] # Implicit, used to check if any arch is enabled any-arch = ["config", "dep:bimap", "dep:strum", "dep:similar", "dep:flagset", "dep:log", "dep:memmap2", "dep:byteorder", "dep:num-traits"] # Implicit, used to check if any arch is enabled
config = ["dep:bimap", "dep:globset", "dep:semver", "dep:serde_json", "dep:serde_yaml", "dep:serde", "dep:filetime"] config = ["dep:bimap", "dep:globset", "dep:semver", "dep:serde_json", "dep:serde_yaml", "dep:serde", "dep:filetime"]
dwarf = ["dep:gimli"] dwarf = ["dep:gimli"]
@ -24,6 +24,7 @@ mips = ["any-arch", "dep:rabbitizer"]
ppc = ["any-arch", "dep:cwdemangle", "dep:cwextab", "dep:ppc750cl"] ppc = ["any-arch", "dep:cwdemangle", "dep:cwextab", "dep:ppc750cl"]
x86 = ["any-arch", "dep:cpp_demangle", "dep:iced-x86", "dep:msvc-demangler"] x86 = ["any-arch", "dep:cpp_demangle", "dep:iced-x86", "dep:msvc-demangler"]
arm = ["any-arch", "dep:cpp_demangle", "dep:unarm", "dep:arm-attr"] arm = ["any-arch", "dep:cpp_demangle", "dep:unarm", "dep:arm-attr"]
arm64 = ["any-arch", "dep:cpp_demangle", "dep:yaxpeax-arch", "dep:yaxpeax-arm"]
bindings = ["dep:serde_json", "dep:prost", "dep:pbjson", "dep:serde", "dep:prost-build", "dep:pbjson-build"] bindings = ["dep:serde_json", "dep:prost", "dep:pbjson", "dep:serde", "dep:prost-build", "dep:pbjson-build"]
wasm = ["bindings", "any-arch", "dep:console_error_panic_hook", "dep:console_log", "dep:wasm-bindgen", "dep:tsify-next", "dep:log"] wasm = ["bindings", "any-arch", "dep:console_error_panic_hook", "dep:console_log", "dep:wasm-bindgen", "dep:tsify-next", "dep:log"]
@ -76,6 +77,10 @@ msvc-demangler = { version = "0.10", optional = true }
unarm = { version = "1.6", optional = true } unarm = { version = "1.6", optional = true }
arm-attr = { version = "0.1", optional = true } arm-attr = { version = "0.1", optional = true }
# arm64
yaxpeax-arch = { version = "0.3", default-features = false, features = ["std"], optional = true }
yaxpeax-arm = { version = "0.3", default-features = false, features = ["std"], optional = true }
[build-dependencies] [build-dependencies]
prost-build = { version = "0.13", optional = true } prost-build = { version = "0.13", optional = true }
pbjson-build = { version = "0.7", optional = true } pbjson-build = { version = "0.7", optional = true }

View File

@ -11,4 +11,5 @@ objdiff-core contains the core functionality of [objdiff](https://github.com/enc
- **`ppc`**: Enables the PowerPC backend powered by [ppc750cl](https://github.com/encounter/ppc750cl). - **`ppc`**: Enables the PowerPC backend powered by [ppc750cl](https://github.com/encounter/ppc750cl).
- **`x86`**: Enables the x86 backend powered by [iced-x86](https://crates.io/crates/iced-x86). - **`x86`**: Enables the x86 backend powered by [iced-x86](https://crates.io/crates/iced-x86).
- **`arm`**: Enables the ARM backend powered by [unarm](https://github.com/AetiasHax/unarm). - **`arm`**: Enables the ARM backend powered by [unarm](https://github.com/AetiasHax/unarm).
- **`arm64`**: Enables the ARM64 backend powered by [yaxpeax-arm](https://github.com/iximeow/yaxpeax-arm).
- **`bindings`**: Enables serialization and deserialization of objdiff data structures. - **`bindings`**: Enables serialization and deserialization of objdiff data structures.

View File

@ -124,11 +124,9 @@ impl ObjArch for ObjArchArm {
.get(&SectionIndex(section_index)) .get(&SectionIndex(section_index))
.map(|x| x.as_slice()) .map(|x| x.as_slice())
.unwrap_or(&fallback_mappings); .unwrap_or(&fallback_mappings);
let first_mapping_idx = let first_mapping_idx = mapping_symbols
match mapping_symbols.binary_search_by_key(&start_addr, |x| x.address) { .binary_search_by_key(&start_addr, |x| x.address)
Ok(idx) => idx, .unwrap_or_else(|idx| idx - 1);
Err(idx) => idx - 1,
};
let first_mapping = mapping_symbols[first_mapping_idx].mapping; let first_mapping = mapping_symbols[first_mapping_idx].mapping;
let mut mappings_iter = let mut mappings_iter =
@ -215,7 +213,7 @@ impl ObjArch for ObjArchArm {
address: address as u64, address: address as u64,
size: (parser.address - address) as u8, size: (parser.address - address) as u8,
op: ins.opcode_id(), op: ins.opcode_id(),
mnemonic: parsed_ins.mnemonic.to_string(), mnemonic: Cow::Borrowed(parsed_ins.mnemonic),
args, args,
reloc, reloc,
branch_dest, branch_dest,
@ -234,7 +232,7 @@ impl ObjArch for ObjArchArm {
section: &ObjSection, section: &ObjSection,
address: u64, address: u64,
reloc: &Relocation, reloc: &Relocation,
) -> anyhow::Result<i64> { ) -> Result<i64> {
let address = address as usize; let address = address as usize;
Ok(match reloc.flags() { Ok(match reloc.flags() {
// ARM calls // ARM calls

File diff suppressed because it is too large Load Diff

View File

@ -119,7 +119,7 @@ impl ObjArch for ObjArchMips {
let op = instruction.unique_id as u16; let op = instruction.unique_id as u16;
ops.push(op); ops.push(op);
let mnemonic = instruction.opcode_name().to_string(); let mnemonic = instruction.opcode_name();
let is_branch = instruction.is_branch(); let is_branch = instruction.is_branch();
let branch_offset = instruction.branch_offset(); let branch_offset = instruction.branch_offset();
let mut branch_dest = if is_branch { let mut branch_dest = if is_branch {
@ -202,7 +202,7 @@ impl ObjArch for ObjArchMips {
address: cur_addr as u64, address: cur_addr as u64,
size: 4, size: 4,
op, op,
mnemonic, mnemonic: Cow::Borrowed(mnemonic),
args, args,
reloc: reloc.cloned(), reloc: reloc.cloned(),
branch_dest, branch_dest,

View File

@ -12,6 +12,8 @@ use crate::{
#[cfg(feature = "arm")] #[cfg(feature = "arm")]
mod arm; mod arm;
#[cfg(feature = "arm64")]
mod arm64;
#[cfg(feature = "mips")] #[cfg(feature = "mips")]
pub mod mips; pub mod mips;
#[cfg(feature = "ppc")] #[cfg(feature = "ppc")]
@ -165,6 +167,8 @@ pub fn new_arch(object: &File) -> Result<Box<dyn ObjArch>> {
Architecture::I386 | Architecture::X86_64 => Box::new(x86::ObjArchX86::new(object)?), Architecture::I386 | Architecture::X86_64 => Box::new(x86::ObjArchX86::new(object)?),
#[cfg(feature = "arm")] #[cfg(feature = "arm")]
Architecture::Arm => Box::new(arm::ObjArchArm::new(object)?), Architecture::Arm => Box::new(arm::ObjArchArm::new(object)?),
#[cfg(feature = "arm64")]
Architecture::Aarch64 => Box::new(arm64::ObjArchArm64::new(object)?),
arch => bail!("Unsupported architecture: {arch:?}"), arch => bail!("Unsupported architecture: {arch:?}"),
}) })
} }

View File

@ -143,7 +143,7 @@ impl ObjArch for ObjArchPpc {
insts.push(ObjIns { insts.push(ObjIns {
address: cur_addr as u64, address: cur_addr as u64,
size: 4, size: 4,
mnemonic: simplified.mnemonic.to_string(), mnemonic: Cow::Borrowed(simplified.mnemonic),
args, args,
reloc: reloc.cloned(), reloc: reloc.cloned(),
op: ins.op as u16, op: ins.op as u16,

View File

@ -51,7 +51,7 @@ impl ObjArch for ObjArchX86 {
address: 0, address: 0,
size: 0, size: 0,
op: 0, op: 0,
mnemonic: String::new(), mnemonic: Cow::Borrowed("<invalid>"),
args: vec![], args: vec![],
reloc: None, reloc: None,
branch_dest: None, branch_dest: None,
@ -76,7 +76,7 @@ impl ObjArch for ObjArchX86 {
address, address,
size: instruction.len() as u8, size: instruction.len() as u8,
op, op,
mnemonic: String::new(), mnemonic: Cow::Borrowed("<invalid>"),
args: vec![], args: vec![],
reloc: reloc.cloned(), reloc: reloc.cloned(),
branch_dest: None, branch_dest: None,
@ -242,7 +242,8 @@ impl FormatterOutput for InstructionFormatterOutput {
fn write_mnemonic(&mut self, _instruction: &Instruction, text: &str) { fn write_mnemonic(&mut self, _instruction: &Instruction, text: &str) {
self.formatted.push_str(text); self.formatted.push_str(text);
self.ins.mnemonic = text.to_string(); // TODO: can iced-x86 guarantee 'static here?
self.ins.mnemonic = Cow::Owned(text.to_string());
} }
fn write_number( fn write_number(

View File

@ -132,7 +132,7 @@ impl Instruction {
address: instruction.address, address: instruction.address,
size: instruction.size as u32, size: instruction.size as u32,
opcode: instruction.op as u32, opcode: instruction.op as u32,
mnemonic: instruction.mnemonic.clone(), mnemonic: instruction.mnemonic.to_string(),
formatted: instruction.formatted.clone(), formatted: instruction.formatted.clone(),
arguments: instruction.args.iter().map(Argument::new).collect(), arguments: instruction.args.iter().map(Argument::new).collect(),
relocation: instruction.reloc.as_ref().map(|reloc| Relocation::new(object, reloc)), relocation: instruction.reloc.as_ref().map(|reloc| Relocation::new(object, reloc)),

View File

@ -103,7 +103,7 @@ pub struct ObjIns {
pub address: u64, pub address: u64,
pub size: u8, pub size: u8,
pub op: u16, pub op: u16,
pub mnemonic: String, pub mnemonic: Cow<'static, str>,
pub args: Vec<ObjInsArg>, pub args: Vec<ObjInsArg>,
pub reloc: Option<ObjReloc>, pub reloc: Option<ObjReloc>,
pub branch_dest: Option<u64>, pub branch_dest: Option<u64>,