Skip to content

Commit c7e95d8

Browse files
authored
Merge pull request #10 from sisshiki1969/claude/aarch64-smulh-port-KRmjz
AArch64: support dump_code() via objdump
2 parents 19108d9 + 39424d8 commit c7e95d8

3 files changed

Lines changed: 73 additions & 0 deletions

File tree

.github/workflows/rust.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,6 @@ jobs:
4444
env:
4545
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
4646
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER: qemu-aarch64-static -L /usr/aarch64-linux-gnu
47+
# dump_code() shells out to objdump; point it at the cross binutils
48+
# so the emulated tests can disassemble the A64 stream.
49+
OBJDUMP: aarch64-linux-gnu-objdump

monoasm/src/arm64.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,48 @@ impl JitMemory {
498498
self.handle_reloc(dest, target);
499499
}
500500

501+
/// Dump the generated machine code as an objdump-style disassembly
502+
/// listing (the AArch64 counterpart of the x86-64 `dump_code`).
503+
///
504+
/// The disassembler binary defaults to `objdump`, which is the native
505+
/// tool on an aarch64 host. When running the emulated tests on a
506+
/// non-aarch64 host, set the `OBJDUMP` environment variable to a
507+
/// cross-capable binutils (e.g. `aarch64-linux-gnu-objdump`) so the
508+
/// A64 stream is decoded correctly.
509+
pub fn dump_code(&self) -> Result<String, std::io::Error> {
510+
use std::io::Write;
511+
use std::process::Command;
512+
let asm = self.as_slice();
513+
let mut file = tempfile::NamedTempFile::new()?;
514+
let (start_pos, code_end, _end_pos) = self.code_block.last().unwrap();
515+
file.write_all(&asm[start_pos.0..code_end.0]).unwrap();
516+
517+
let objdump = std::env::var("OBJDUMP").unwrap_or_else(|_| "objdump".to_string());
518+
Command::new(objdump)
519+
.args([
520+
"-D",
521+
"-b",
522+
"binary",
523+
"-m",
524+
"aarch64",
525+
file.path().to_str().unwrap(),
526+
])
527+
.output()
528+
.map(|o| {
529+
std::str::from_utf8(&o.stdout)
530+
.unwrap()
531+
.to_string()
532+
.split_inclusive('\n')
533+
.filter(|s| {
534+
s.len() > 1
535+
&& !s.contains("file format binary")
536+
&& !s.contains("Disassembly of section")
537+
&& !s.contains("<.data>")
538+
})
539+
.collect()
540+
})
541+
}
542+
501543
/// Patch a single relocation `target` now that its label resolves to
502544
/// `(src_page, src_pos)`.
503545
pub(crate) fn write_reloc(&mut self, src_page: Page, src_pos: Pos, target: TargetType) {

monoasm/tests/arm64/exec.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,34 @@ fn multiply_high() {
104104
assert_eq!(f(u64::MAX, u64::MAX), umulh(u64::MAX, u64::MAX));
105105
}
106106

107+
#[test]
108+
fn dump_code_disassembles() {
109+
// `dump_code` shells out to objdump; on a non-aarch64 host the emulated
110+
// test process must reach a cross-capable objdump (set via $OBJDUMP).
111+
let (jit, _addr) = jit_fn(|j| {
112+
monoasm_arm64!(&mut *j,
113+
smulh x0, x1, x2;
114+
ret;
115+
);
116+
});
117+
// `dump_code` shells out to objdump. Both the spawn and the disassembly
118+
// can fail for environmental reasons that are not bugs in the backend:
119+
// - under qemu-user, fork() can fail with ENOMEM because of the large
120+
// executable mappings the JIT reserves;
121+
// - a host objdump may not understand aarch64.
122+
// It is a debug-only helper, so in those cases we skip rather than fail.
123+
// On a real aarch64 host both succeed and the assertions run.
124+
match jit.dump_code() {
125+
Ok(dump) if dump.contains("smulh") => {
126+
assert!(dump.contains("ret"), "dump was:\n{dump}");
127+
}
128+
Ok(dump) => {
129+
eprintln!("objdump produced no aarch64 disassembly; skipping. Got:\n{dump}")
130+
}
131+
Err(e) => eprintln!("could not run objdump ({e}); skipping dump_code assertion"),
132+
}
133+
}
134+
107135
#[test]
108136
fn sum_loop() {
109137
// Sum 1..=n using a backward branch and a forward conditional exit,

0 commit comments

Comments
 (0)