From 130746bc856f5c2eb5672cceb0e1304ee2c95b1e Mon Sep 17 00:00:00 2001 From: johannst Date: Wed, 28 Feb 2024 18:32:44 +0000 Subject: deploy: 7cc72737a0140f5f71e9d83d4f87503eb4c7604f --- src/juicebox_asm/asm.rs.html | 7 +- src/juicebox_asm/imm.rs.html | 3 +- src/juicebox_asm/insn.rs.html | 31 +++++++- src/juicebox_asm/insn/add.rs.html | 3 +- src/juicebox_asm/insn/call.rs.html | 3 +- src/juicebox_asm/insn/cmp.rs.html | 3 +- src/juicebox_asm/insn/dec.rs.html | 3 +- src/juicebox_asm/insn/jmp.rs.html | 3 +- src/juicebox_asm/insn/jnz.rs.html | 3 +- src/juicebox_asm/insn/jz.rs.html | 3 +- src/juicebox_asm/insn/mov.rs.html | 3 +- src/juicebox_asm/insn/nop.rs.html | 3 +- src/juicebox_asm/insn/pop.rs.html | 30 +++++++ src/juicebox_asm/insn/push.rs.html | 30 +++++++ src/juicebox_asm/insn/ret.rs.html | 3 +- src/juicebox_asm/insn/test.rs.html | 3 +- src/juicebox_asm/label.rs.html | 3 +- src/juicebox_asm/lib.rs.html | 7 +- src/juicebox_asm/reg.rs.html | 5 +- src/juicebox_asm/rt.rs.html | 155 ++++++++++++++++++++++++++++++++----- 20 files changed, 263 insertions(+), 41 deletions(-) create mode 100644 src/juicebox_asm/insn/pop.rs.html create mode 100644 src/juicebox_asm/insn/push.rs.html (limited to 'src/juicebox_asm') diff --git a/src/juicebox_asm/asm.rs.html b/src/juicebox_asm/asm.rs.html index fd5f0d5..e58260d 100644 --- a/src/juicebox_asm/asm.rs.html +++ b/src/juicebox_asm/asm.rs.html @@ -1,4 +1,5 @@ -asm.rs - source
1
+asm.rs - source
+    
1
 2
 3
 4
@@ -418,14 +419,14 @@
     fn resolve(&mut self, label: &mut Label) {
         if let Some(loc) = label.location() {
             // For now we only support disp32 as label location.
-            let loc = i32::try_from(loc).expect("Label location did not fit into i32.");
+            let loc = i32::try_from(loc).expect("Label location did not fit into i32.");
 
             // Resolve any pending relocations for the label.
             for off in label.offsets_mut().drain() {
                 // Displacement is relative to the next instruction following the jump.
                 // We record the offset to patch at the first byte of the disp32 therefore we need
                 // to account for that in the disp computation.
-                let disp32 = loc - i32::try_from(off).expect("Label offset did not fit into i32") - 4 /* account for the disp32 */;
+                let disp32 = loc - i32::try_from(off).expect("Label offset did not fit into i32") - 4 /* account for the disp32 */;
 
                 // Patch the relocation with the disp32.
                 self.emit_at(off, &disp32.to_ne_bytes());
diff --git a/src/juicebox_asm/imm.rs.html b/src/juicebox_asm/imm.rs.html
index e0b6592..306b800 100644
--- a/src/juicebox_asm/imm.rs.html
+++ b/src/juicebox_asm/imm.rs.html
@@ -1,4 +1,5 @@
-imm.rs - source
1
+imm.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn.rs.html b/src/juicebox_asm/insn.rs.html
index a367feb..7198773 100644
--- a/src/juicebox_asm/insn.rs.html
+++ b/src/juicebox_asm/insn.rs.html
@@ -1,4 +1,5 @@
-insn.rs - source
1
+insn.rs - source
+    
1
 2
 3
 4
@@ -71,6 +72,20 @@
 71
 72
 73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
 
//! Trait definitions of various instructions.
 
 mod add;
@@ -82,6 +97,8 @@
 mod jz;
 mod mov;
 mod nop;
+mod pop;
+mod push;
 mod ret;
 mod test;
 
@@ -136,6 +153,18 @@
     fn mov(&mut self, op1: T, op2: U);
 }
 
+/// Trait for [`push`](https://www.felixcloutier.com/x86/push) instruction kinds.
+pub trait Push<T> {
+    /// Emit a push instruction.
+    fn push(&mut self, op1: T);
+}
+
+/// Trait for [`pop`](https://www.felixcloutier.com/x86/pop) instruction kinds.
+pub trait Pop<T> {
+    /// Emit a pop instruction.
+    fn pop(&mut self, op1: T);
+}
+
 /// Trait for [`test`](https://www.felixcloutier.com/x86/test) instruction kinds.
 pub trait Test<T, U> {
     /// Emit a logical compare instruction.
diff --git a/src/juicebox_asm/insn/add.rs.html b/src/juicebox_asm/insn/add.rs.html
index d7d8c39..a6ac132 100644
--- a/src/juicebox_asm/insn/add.rs.html
+++ b/src/juicebox_asm/insn/add.rs.html
@@ -1,4 +1,5 @@
-add.rs - source
1
+add.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/call.rs.html b/src/juicebox_asm/insn/call.rs.html
index e88996d..3a70194 100644
--- a/src/juicebox_asm/insn/call.rs.html
+++ b/src/juicebox_asm/insn/call.rs.html
@@ -1,4 +1,5 @@
-call.rs - source
1
+call.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/cmp.rs.html b/src/juicebox_asm/insn/cmp.rs.html
index 4e28818..c8bcee2 100644
--- a/src/juicebox_asm/insn/cmp.rs.html
+++ b/src/juicebox_asm/insn/cmp.rs.html
@@ -1,4 +1,5 @@
-cmp.rs - source
1
+cmp.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/dec.rs.html b/src/juicebox_asm/insn/dec.rs.html
index 5a10063..1eed3b2 100644
--- a/src/juicebox_asm/insn/dec.rs.html
+++ b/src/juicebox_asm/insn/dec.rs.html
@@ -1,4 +1,5 @@
-dec.rs - source
1
+dec.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/jmp.rs.html b/src/juicebox_asm/insn/jmp.rs.html
index e0167e3..88f3066 100644
--- a/src/juicebox_asm/insn/jmp.rs.html
+++ b/src/juicebox_asm/insn/jmp.rs.html
@@ -1,4 +1,5 @@
-jmp.rs - source
1
+jmp.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/jnz.rs.html b/src/juicebox_asm/insn/jnz.rs.html
index be0062d..40ae96c 100644
--- a/src/juicebox_asm/insn/jnz.rs.html
+++ b/src/juicebox_asm/insn/jnz.rs.html
@@ -1,4 +1,5 @@
-jnz.rs - source
1
+jnz.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/jz.rs.html b/src/juicebox_asm/insn/jz.rs.html
index e4197af..9a44a21 100644
--- a/src/juicebox_asm/insn/jz.rs.html
+++ b/src/juicebox_asm/insn/jz.rs.html
@@ -1,4 +1,5 @@
-jz.rs - source
1
+jz.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/mov.rs.html b/src/juicebox_asm/insn/mov.rs.html
index 1e672a1..6d6e6e7 100644
--- a/src/juicebox_asm/insn/mov.rs.html
+++ b/src/juicebox_asm/insn/mov.rs.html
@@ -1,4 +1,5 @@
-mov.rs - source
1
+mov.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/nop.rs.html b/src/juicebox_asm/insn/nop.rs.html
index c3c264b..34afd35 100644
--- a/src/juicebox_asm/insn/nop.rs.html
+++ b/src/juicebox_asm/insn/nop.rs.html
@@ -1,4 +1,5 @@
-nop.rs - source
1
+nop.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/pop.rs.html b/src/juicebox_asm/insn/pop.rs.html
new file mode 100644
index 0000000..0852511
--- /dev/null
+++ b/src/juicebox_asm/insn/pop.rs.html
@@ -0,0 +1,30 @@
+pop.rs - source
+    
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+
use super::Pop;
+use crate::{Asm, Reg16, Reg64};
+
+impl Pop<Reg64> for Asm {
+    fn pop(&mut self, op1: Reg64) {
+        self.encode_r(0x8f, 0x0, op1);
+    }
+}
+
+impl Pop<Reg16> for Asm {
+    fn pop(&mut self, op1: Reg16) {
+        self.encode_r(0x8f, 0x0, op1);
+    }
+}
+
\ No newline at end of file diff --git a/src/juicebox_asm/insn/push.rs.html b/src/juicebox_asm/insn/push.rs.html new file mode 100644 index 0000000..e947e8b --- /dev/null +++ b/src/juicebox_asm/insn/push.rs.html @@ -0,0 +1,30 @@ +push.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+
use super::Push;
+use crate::{Asm, Reg16, Reg64};
+
+impl Push<Reg64> for Asm {
+    fn push(&mut self, op1: Reg64) {
+        self.encode_r(0xff, 0x6, op1);
+    }
+}
+
+impl Push<Reg16> for Asm {
+    fn push(&mut self, op1: Reg16) {
+        self.encode_r(0xff, 0x6, op1);
+    }
+}
+
\ No newline at end of file diff --git a/src/juicebox_asm/insn/ret.rs.html b/src/juicebox_asm/insn/ret.rs.html index 26e3a47..bc88856 100644 --- a/src/juicebox_asm/insn/ret.rs.html +++ b/src/juicebox_asm/insn/ret.rs.html @@ -1,4 +1,5 @@ -ret.rs - source
1
+ret.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/test.rs.html b/src/juicebox_asm/insn/test.rs.html
index 0f1d8da..6a0372d 100644
--- a/src/juicebox_asm/insn/test.rs.html
+++ b/src/juicebox_asm/insn/test.rs.html
@@ -1,4 +1,5 @@
-test.rs - source
1
+test.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/label.rs.html b/src/juicebox_asm/label.rs.html
index 29d236e..d986d64 100644
--- a/src/juicebox_asm/label.rs.html
+++ b/src/juicebox_asm/label.rs.html
@@ -1,4 +1,5 @@
-label.rs - source
1
+label.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/lib.rs.html b/src/juicebox_asm/lib.rs.html
index 7d1bc0c..d7d33f1 100644
--- a/src/juicebox_asm/lib.rs.html
+++ b/src/juicebox_asm/lib.rs.html
@@ -1,4 +1,5 @@
-lib.rs - source
1
+lib.rs - source
+    
1
 2
 3
 4
@@ -170,11 +171,11 @@
 //!
 //!     // Move code into executable page and get function pointer to it.
 //!     let mut rt = Runtime::new();
-//!     let fib = unsafe { rt.add_code::<extern "C" fn(u64) -> u64>(&asm.into_code()) };
+//!     let fib = unsafe { rt.add_code::<extern "C" fn(u64) -> u64>(&asm.into_code()) };
 //!
 //!     for n in 0..15 {
 //!         let fib_jit = fib(n);
-//!         println!("fib({}) = {}", n, fib_jit);
+//!         println!("fib({}) = {}", n, fib_jit);
 //!         assert_eq!(fib_jit, fib_rs(n));
 //!     }
 //! }
diff --git a/src/juicebox_asm/reg.rs.html b/src/juicebox_asm/reg.rs.html
index fe4b50c..f0612f6 100644
--- a/src/juicebox_asm/reg.rs.html
+++ b/src/juicebox_asm/reg.rs.html
@@ -1,4 +1,5 @@
-reg.rs - source
1
+reg.rs - source
+    
1
 2
 3
 4
@@ -353,7 +354,7 @@
 
         #[cfg(test)]
         impl $name {
-            fn iter() -> impl Iterator<Item = &'static $name> {
+            fn iter() -> impl Iterator<Item = &'static $name> {
                 use $name::*;
                 [$( $reg, )+].iter()
             }
diff --git a/src/juicebox_asm/rt.rs.html b/src/juicebox_asm/rt.rs.html
index efc55d3..d58d3e7 100644
--- a/src/juicebox_asm/rt.rs.html
+++ b/src/juicebox_asm/rt.rs.html
@@ -1,4 +1,5 @@
-rt.rs - source
1
+rt.rs - source
+    
1
 2
 3
 4
@@ -200,21 +201,125 @@
 200
 201
 202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
 
//! Simple `mmap`ed runtime.
 //!
 //! This runtime supports adding code to executable pages and turn the added code into user
 //! specified function pointer.
 
-use nix::sys::mman::{mmap, mprotect, munmap, MapFlags, ProtFlags};
+#[cfg(not(target_os = "linux"))]
+compile_error!("This runtime is only supported on linux");
 
-#[cfg(not(target_os = "linux"))]
-compile_error!("This runtime is only supported on linux");
+use nix::sys::mman::{mmap, mprotect, munmap, MapFlags, ProtFlags};
+
+mod perf {
+    use std::fs;
+    use std::io::Write;
+
+    /// Provide support for the simple [perf jit interface][perf-jit].
+    ///
+    /// This allows a simple (static) jit runtime to generate meta data describing the generated
+    /// functions, which is used during post-processing by `perf report` to symbolize addresses
+    /// captured while executing jitted code.
+    ///
+    /// By the nature of this format, this can not be used for dynamic jit runtimes, which reuses
+    /// memory which previously contained jitted code.
+    ///
+    /// [perf-jit]: https://elixir.bootlin.com/linux/v6.6.6/source/tools/perf/Documentation/jit-interface.txt
+    pub(super) struct PerfMap {
+        file: std::fs::File,
+    }
+
+    impl PerfMap {
+        /// Create an empty perf map file.
+        pub(super) fn new() -> Self {
+            let name = format!("/tmp/perf-{}.map", nix::unistd::getpid());
+            let file = fs::OpenOptions::new()
+                .truncate(true)
+                .create(true)
+                .write(true)
+                .open(&name)
+                .unwrap_or_else(|_| panic!("Failed to open perf map file {}", &name));
+
+            PerfMap { file }
+        }
+
+        /// Add an entry to the perf map file.
+        pub(super) fn add_entry(&mut self, start: usize, len: usize) {
+            // Each line has the following format, fields separated with spaces:
+            //   START SIZE NAME
+            //
+            // START and SIZE are hex numbers without 0x.
+            // NAME is the rest of the line, so it could contain special characters.
+            writeln!(self.file, "{:x} {:x} jitfn_{:x}", start, len, start)
+                .expect("Failed to write PerfMap entry");
+        }
+    }
+}
 
 /// A simple `mmap`ed runtime with executable pages.
 pub struct Runtime {
     buf: *mut u8,
     len: usize,
     idx: usize,
+    perf: Option<perf::PerfMap>,
 }
 
 impl Runtime {
@@ -225,7 +330,7 @@
     /// Panics if the `mmap` call fails.
     pub fn new() -> Runtime {
         // Allocate a single page.
-        let len = core::num::NonZeroUsize::new(4096).expect("Value is non zero");
+        let len = core::num::NonZeroUsize::new(4096).expect("Value is non zero");
         let buf = unsafe {
             mmap(
                 None,
@@ -235,16 +340,23 @@
                 0, /* fd */
                 0, /* off */
             )
-            .expect("Failed to mmap runtime code page") as *mut u8
+            .expect("Failed to mmap runtime code page") as *mut u8
         };
 
         Runtime {
             buf,
             len: len.get(),
             idx: 0,
+            perf: None,
         }
     }
 
+    pub fn with_profile() -> Runtime {
+        let mut rt = Runtime::new();
+        rt.perf = Some(perf::PerfMap::new());
+        rt
+    }
+
     /// Add the block of `code` to the runtime and a get function pointer of type `F`.
     ///
     /// # Panics
@@ -262,21 +374,21 @@
     /// let mut rt = juicebox_asm::Runtime::new();
     ///
     /// let code = [ 0x90 /* nop */, 0xc3 /* ret */ ];
-    /// let nop = unsafe { rt.add_code::<extern "C" fn()>(&code) };
+    /// let nop = unsafe { rt.add_code::<extern "C" fn()>(&code) };
     ///
     /// nop();
     /// ```
     pub unsafe fn add_code<F>(&mut self, code: impl AsRef<[u8]>) -> F {
         // Get pointer to start of next free byte.
-        assert!(self.idx < self.len, "Runtime code page full");
+        assert!(self.idx < self.len, "Runtime code page full");
         let fn_start = self.buf.add(self.idx);
 
         // Copy over code.
         let code = code.as_ref();
-        assert!(!code.is_empty(), "Adding empty code not supported");
+        assert!(!code.is_empty(), "Adding empty code not supported");
         assert!(
             code.len() <= (self.len - self.idx),
-            "Code does not fit on the runtime code page"
+            "Code does not fit on the runtime code page"
         );
         self.unprotect();
         unsafe { std::ptr::copy_nonoverlapping(code.as_ptr(), fn_start, code.len()) };
@@ -285,6 +397,11 @@
         // Increment index to next free byte.
         self.idx += code.len();
 
+        // Add perf map entry.
+        if let Some(map) = &mut self.perf {
+            map.add_entry(fn_start as usize, code.len());
+        }
+
         // Return function to newly added code.
         unsafe { Self::as_fn::<F>(fn_start) }
     }
@@ -304,7 +421,7 @@
     pub fn dump(&self) {
         assert!(self.idx <= self.len);
         let code = unsafe { core::slice::from_raw_parts(self.buf, self.idx) };
-        std::fs::write("jit.asm", code).expect("Failed to write file");
+        std::fs::write("jit.asm", code).expect("Failed to write file");
     }
 
     /// Reinterpret the block of code pointed to by `fn_start` as `F`.
@@ -326,7 +443,7 @@
                 self.len,
                 ProtFlags::PROT_READ | ProtFlags::PROT_EXEC,
             )
-            .expect("Failed to RX mprotect runtime code page");
+            .expect("Failed to RX mprotect runtime code page");
         }
     }
 
@@ -339,7 +456,7 @@
         unsafe {
             // Add write permissions to code page.
             mprotect(self.buf.cast(), self.len, ProtFlags::PROT_WRITE)
-                .expect("Failed to W mprotect runtime code page");
+                .expect("Failed to W mprotect runtime code page");
         }
     }
 }
@@ -349,7 +466,7 @@
     /// [`Runtime::add_code`].
     fn drop(&mut self) {
         unsafe {
-            munmap(self.buf.cast(), self.len).expect("Failed to munmap runtime");
+            munmap(self.buf.cast(), self.len).expect("Failed to munmap runtime");
         }
     }
 }
@@ -363,7 +480,7 @@
         let mut rt = Runtime::new();
         let code = [0u8; 4096];
         unsafe {
-            rt.add_code::<extern "C" fn()>(code);
+            rt.add_code::<extern "C" fn()>(code);
         }
     }
 
@@ -373,7 +490,7 @@
         let mut rt = Runtime::new();
         let code = [0u8; 4097];
         unsafe {
-            rt.add_code::<extern "C" fn()>(code);
+            rt.add_code::<extern "C" fn()>(code);
         }
     }
 
@@ -383,12 +500,12 @@
         let mut rt = Runtime::new();
         let code = [0u8; 4096];
         unsafe {
-            rt.add_code::<extern "C" fn()>(code);
+            rt.add_code::<extern "C" fn()>(code);
         }
 
         let code = [0u8; 1];
         unsafe {
-            rt.add_code::<extern "C" fn()>(code);
+            rt.add_code::<extern "C" fn()>(code);
         }
     }
 
@@ -398,7 +515,7 @@
         let mut rt = Runtime::new();
         let code = [0u8; 0];
         unsafe {
-            rt.add_code::<extern "C" fn()>(code);
+            rt.add_code::<extern "C" fn()>(code);
         }
     }
 }
-- 
cgit v1.2.3