aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2021-03-13 14:19:55 -0800
committeriximeow <me@iximeow.net>2021-03-13 14:54:47 -0800
commit93c53657c2289e979672ee6c4612af7e9eac109c (patch)
treea0acdc143595f64a796827bc849a122dd49cc4e3
parent6232e8b1daf7067cb2e8065687530d5f88ecb46d (diff)
split ffi crate to support distinct 16, 32, and 64-bit builds
initial work to optionally discard any instruction printing support when using `-Z build-std` to fully remove .eh_frame, a stripped long_mode_no_fmt .so is 61kb!
-rw-r--r--Cargo.toml5
-rw-r--r--ffi/.cargo/config5
-rw-r--r--ffi/Cargo.toml26
-rw-r--r--ffi/README.md8
-rw-r--r--ffi/long_mode/Cargo.toml19
-rw-r--r--ffi/long_mode/src/lib.rs11
-rw-r--r--ffi/multiarch/Cargo.toml14
-rw-r--r--ffi/multiarch/src/lib.rs0
-rw-r--r--ffi/multiarch/src/long_mode.rs (renamed from ffi/src/lib.rs)38
-rw-r--r--ffi/protected_mode/Cargo.toml14
-rw-r--r--ffi/protected_mode/src/lib.rs0
-rw-r--r--ffi/real_mode/Cargo.toml14
-rw-r--r--ffi/real_mode/src/lib.rs0
-rw-r--r--ffi/src/long_mode.rs37
-rw-r--r--ffi/src/protected_mode.rs35
-rw-r--r--ffi/src/real_mode.rs35
-rw-r--r--ffi/src/write_sink.rs20
-rw-r--r--src/long_mode/display.rs15
-rw-r--r--src/long_mode/mod.rs16
19 files changed, 257 insertions, 55 deletions
diff --git a/Cargo.toml b/Cargo.toml
index e1a952c..43ff777 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -33,11 +33,14 @@ opt-level = 3
lto = true
[features]
-default = ["std", "colors", "use-serde"]
+default = ["std", "colors", "use-serde", "fmt"]
# opt-in for some apis that are really much nicer with String
std = []
+# feature for formatting instructions and their components
+fmt = []
+
use-serde = ["yaxpeax-arch/use-serde", "serde", "serde_derive"]
colors = ["yaxpeax-arch/colors"]
diff --git a/ffi/.cargo/config b/ffi/.cargo/config
new file mode 100644
index 0000000..3a8d01c
--- /dev/null
+++ b/ffi/.cargo/config
@@ -0,0 +1,5 @@
+[build]
+rustflags = [
+ "-C",
+ "link-args=-nostdlib",
+]
diff --git a/ffi/Cargo.toml b/ffi/Cargo.toml
index e009a38..6914779 100644
--- a/ffi/Cargo.toml
+++ b/ffi/Cargo.toml
@@ -1,19 +1,15 @@
-[package]
-name = "yaxpeax_x86_ffi"
-version = "0.0.2"
-authors = ["iximeow <me@iximeow.net>"]
-edition = "2018"
-
-[dependencies]
-yaxpeax-x86 = { path = "../", default-features = false }
-yaxpeax-arch = { version = "0.0.4", default-features = false, features = [] }
-
-[lib]
-name = "yaxpeax_x86_ffi"
-path = "src/lib.rs"
-crate-type = ["staticlib"]
+[profile.dev]
+lto = "fat"
+panic = "abort"
[profile.release]
-opt-level = 3
lto = "fat"
panic = "abort"
+
+[workspace]
+members = [
+ "multiarch",
+ "long_mode",
+ "protected_mode",
+ "real_mode",
+]
diff --git a/ffi/README.md b/ffi/README.md
new file mode 100644
index 0000000..02a20e3
--- /dev/null
+++ b/ffi/README.md
@@ -0,0 +1,8 @@
+# building
+for maximum small, ffi crates' `rustflags` includes `-C link-args=-nostdlib`. to avoid conflicts with the native toolchain, this motivates cross-compiling for the native target with `--target x86_64-unknown-linux-gnu`.
+
+then, to remove extra `eh_frame` information from core, rebuild core with panic=abort by `-Z build-std` to cargo. in total, a build command for `yaxpeax_x86_ffi*` looks like:
+
+```
+cargo build -Z build-std --release --no-default-features --verbose --target x86_64-unknown-linux-gnu
+``
diff --git a/ffi/long_mode/Cargo.toml b/ffi/long_mode/Cargo.toml
new file mode 100644
index 0000000..c4b9282
--- /dev/null
+++ b/ffi/long_mode/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "yaxpeax_x86_ffi_long_mode"
+version = "0.0.2"
+authors = ["iximeow <me@iximeow.net>"]
+edition = "2018"
+
+[dependencies]
+yaxpeax-x86 = { path = "../../", default-features = false }
+yaxpeax-arch = { version = "0.0.4", default-features = false }
+
+[lib]
+name = "yaxpeax_x86_ffi_long_mode"
+path = "src/lib.rs"
+crate-type = ["staticlib", "cdylib"]
+
+[features]
+default = ["fmt"]
+
+fmt = ["yaxpeax-x86/fmt"]
diff --git a/ffi/long_mode/src/lib.rs b/ffi/long_mode/src/lib.rs
new file mode 100644
index 0000000..368f8a9
--- /dev/null
+++ b/ffi/long_mode/src/lib.rs
@@ -0,0 +1,11 @@
+#![no_std]
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+ loop {}
+}
+
+#[path = "../../src/long_mode.rs"]
+mod long_mode;
+
+pub use long_mode::*;
diff --git a/ffi/multiarch/Cargo.toml b/ffi/multiarch/Cargo.toml
new file mode 100644
index 0000000..c6609d2
--- /dev/null
+++ b/ffi/multiarch/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "yaxpeax_x86_ffi_multiarch"
+version = "0.0.2"
+authors = ["iximeow <me@iximeow.net>"]
+edition = "2018"
+
+[dependencies]
+yaxpeax-x86 = { path = "../../", default-features = false }
+yaxpeax-arch = { version = "0.0.4", default-features = false }
+
+[lib]
+name = "yaxpeax_x86_ffi_multiarch"
+path = "src/lib.rs"
+crate-type = ["staticlib"]
diff --git a/ffi/multiarch/src/lib.rs b/ffi/multiarch/src/lib.rs
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ffi/multiarch/src/lib.rs
diff --git a/ffi/src/lib.rs b/ffi/multiarch/src/long_mode.rs
index ca0bf5c..c0d422b 100644
--- a/ffi/src/lib.rs
+++ b/ffi/multiarch/src/long_mode.rs
@@ -12,8 +12,6 @@ fn panic(_panic: &core::panic::PanicInfo) -> ! {
use yaxpeax_arch::{Arch, Decoder, LengthedInstruction, AddressBase};
use yaxpeax_x86::long_mode as amd64;
-use core::fmt::Write;
-
#[no_mangle]
pub unsafe extern "C" fn yaxpeax_decode_x86_64_optimistic(data: *const u8, length: u64, inst: *mut amd64::Instruction) -> bool {
let inst: &mut amd64::Instruction = core::mem::transmute(inst);
@@ -26,30 +24,20 @@ pub unsafe extern "C" fn yaxpeax_instr_length_x86_64(inst: *mut amd64::Instructi
0.wrapping_offset(inst.len()).to_linear()
}
-struct InstructionSink<'buf> {
- buf: &'buf mut [u8],
- offs: usize,
-}
+#[cfg(fmt)]
+mod write_sink;
-impl<'a> core::fmt::Write for InstructionSink<'a> {
- fn write_str(&mut self, s: &str) -> core::fmt::Result {
- for b in s.bytes() {
- if self.offs < self.buf.len() {
- self.buf[self.offs] = b;
- self.offs += 1;
- } else {
- break;
- }
- }
-
- Ok(())
- }
-}
+#[cfg(fmt)]
+mod fmt {
+ use write_sink::InstructionSink;
-#[no_mangle]
-pub unsafe extern "C" fn yaxpeax_instr_fmt(inst: *mut amd64::Instruction, text: *mut u8, len: usize) {
- let inst: &mut amd64::Instruction = core::mem::transmute(inst);
- let res = core::slice::from_raw_parts_mut(text, len);
+ use core::fmt::Write;
- write!(InstructionSink { buf: res, offs: 0 }, "{}", inst).unwrap();
+ #[no_mangle]
+ pub unsafe extern "C" fn yaxpeax_instr_fmt(inst: *mut amd64::Instruction, text: *mut u8, len: usize) {
+ let inst: &mut amd64::Instruction = core::mem::transmute(inst);
+ let res = core::slice::from_raw_parts_mut(text, len);
+
+ write!(InstructionSink { buf: res, offs: 0 }, "{}", inst).unwrap();
+ }
}
diff --git a/ffi/protected_mode/Cargo.toml b/ffi/protected_mode/Cargo.toml
new file mode 100644
index 0000000..9c0e03a
--- /dev/null
+++ b/ffi/protected_mode/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "yaxpeax_x86_ffi_protected_mode"
+version = "0.0.2"
+authors = ["iximeow <me@iximeow.net>"]
+edition = "2018"
+
+[dependencies]
+yaxpeax-x86 = { path = "../../", default-features = false }
+yaxpeax-arch = { version = "0.0.4", default-features = false }
+
+[lib]
+name = "yaxpeax_x86_ffi_protected_mode"
+path = "src/lib.rs"
+crate-type = ["staticlib"]
diff --git a/ffi/protected_mode/src/lib.rs b/ffi/protected_mode/src/lib.rs
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ffi/protected_mode/src/lib.rs
diff --git a/ffi/real_mode/Cargo.toml b/ffi/real_mode/Cargo.toml
new file mode 100644
index 0000000..f24f8a4
--- /dev/null
+++ b/ffi/real_mode/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "yaxpeax_x86_ffi_real_mode"
+version = "0.0.2"
+authors = ["iximeow <me@iximeow.net>"]
+edition = "2018"
+
+[dependencies]
+yaxpeax-x86 = { path = "../../", default-features = false }
+yaxpeax-arch = { version = "0.0.4", default-features = false }
+
+[lib]
+name = "yaxpeax_x86_ffi_real_mode"
+path = "src/lib.rs"
+crate-type = ["staticlib"]
diff --git a/ffi/real_mode/src/lib.rs b/ffi/real_mode/src/lib.rs
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ffi/real_mode/src/lib.rs
diff --git a/ffi/src/long_mode.rs b/ffi/src/long_mode.rs
new file mode 100644
index 0000000..a3fd784
--- /dev/null
+++ b/ffi/src/long_mode.rs
@@ -0,0 +1,37 @@
+use yaxpeax_arch::{Arch, Decoder, LengthedInstruction, AddressBase};
+use yaxpeax_x86::long_mode;
+
+#[no_mangle]
+pub unsafe extern "C" fn yaxpeax_x86_64_decode_optimistic(data: *const u8, length: u64, inst: *mut long_mode::Instruction) -> bool {
+ let inst: &mut long_mode::Instruction = core::mem::transmute(inst);
+ <long_mode::Arch as Arch>::Decoder::default().decode_into(inst, core::slice::from_raw_parts(data as *const u8, length as usize).iter().cloned()).is_err()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn yaxpeax_x86_64_instr_length(inst: *mut long_mode::Instruction) -> usize {
+ let inst: &mut long_mode::Instruction = core::mem::transmute(inst);
+ 0.wrapping_offset(inst.len()).to_linear()
+}
+
+#[cfg(feature = "fmt")]
+mod write_sink;
+
+#[cfg(feature = "fmt")]
+mod fmt {
+ use super::write_sink::InstructionSink;
+
+ use core::fmt::Write;
+
+ use yaxpeax_x86::long_mode;
+
+ #[no_mangle]
+ pub unsafe extern "C" fn yaxpeax_x86_64_fmt(inst: *mut long_mode::Instruction, text: *mut u8, len: usize) {
+ let inst: &mut long_mode::Instruction = core::mem::transmute(inst);
+ let res = core::slice::from_raw_parts_mut(text, len);
+
+ write!(InstructionSink { buf: res, offs: 0 }, "{}", inst).unwrap();
+ }
+}
+
+#[cfg(feature = "fmt")]
+pub use fmt::yaxpeax_x86_64_fmt;
diff --git a/ffi/src/protected_mode.rs b/ffi/src/protected_mode.rs
new file mode 100644
index 0000000..fc0c6a9
--- /dev/null
+++ b/ffi/src/protected_mode.rs
@@ -0,0 +1,35 @@
+use yaxpeax_arch::{Arch, Decoder, LengthedInstruction, AddressBase};
+use yaxpeax_x86::protected_mode;
+
+#[no_mangle]
+pub unsafe extern "C" fn yaxpeax_x86_32_decode_optimistic(data: *const u8, length: u64, inst: *mut protected_mode::Instruction) -> bool {
+ let inst: &mut protected_mode::Instruction = core::mem::transmute(inst);
+ <protected_mode::Arch as Arch>::Decoder::default().decode_into(inst, core::slice::from_raw_parts(data as *const u8, length as usize).iter().cloned()).is_err()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn yaxpeax_x86_32_instr_length(inst: *mut protected_mode::Instruction) -> usize {
+ let inst: &mut protected_mode::Instruction = core::mem::transmute(inst);
+ 0.wrapping_offset(inst.len()).to_linear()
+}
+
+#[cfg(fmt)]
+mod write_sink;
+
+#[cfg(fmt)]
+mod fmt {
+ use write_sink::InstructionSink;
+
+ use core::fmt::Write;
+
+ #[no_mangle]
+ pub unsafe extern "C" fn yaxpeax_x86_32_fmt(inst: *mut protected_mode::Instruction, text: *mut u8, len: usize) {
+ let inst: &mut protected_mode::Instruction = core::mem::transmute(inst);
+ let res = core::slice::from_raw_parts_mut(text, len);
+
+ write!(InstructionSink { buf: res, offs: 0 }, "{}", inst).unwrap();
+ }
+}
+
+#[cfg(fmt)]
+pub use fmt::yaxpeax_x86_32_fmt;
diff --git a/ffi/src/real_mode.rs b/ffi/src/real_mode.rs
new file mode 100644
index 0000000..6a5f866
--- /dev/null
+++ b/ffi/src/real_mode.rs
@@ -0,0 +1,35 @@
+use yaxpeax_arch::{Arch, Decoder, LengthedInstruction, AddressBase};
+use yaxpeax_x86::real_mode;
+
+#[no_mangle]
+pub unsafe extern "C" fn yaxpeax_x86_16_decode_optimistic(data: *const u8, length: u64, inst: *mut real_mode::Instruction) -> bool {
+ let inst: &mut real_mode::Instruction = core::mem::transmute(inst);
+ <real_mode::Arch as Arch>::Decoder::default().decode_into(inst, core::slice::from_raw_parts(data as *const u8, length as usize).iter().cloned()).is_err()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn yaxpeax_x86_16_instr_length(inst: *mut real_mode::Instruction) -> usize {
+ let inst: &mut real_mode::Instruction = core::mem::transmute(inst);
+ 0.wrapping_offset(inst.len()).to_linear()
+}
+
+#[cfg(fmt)]
+mod write_sink;
+
+#[cfg(fmt)]
+mod fmt {
+ use write_sink::InstructionSink;
+
+ use core::fmt::Write;
+
+ #[no_mangle]
+ pub unsafe extern "C" fn yaxpeax_x86_16_fmt(inst: *mut real_mode::Instruction, text: *mut u8, len: usize) {
+ let inst: &mut real_mode::Instruction = core::mem::transmute(inst);
+ let res = core::slice::from_raw_parts_mut(text, len);
+
+ write!(InstructionSink { buf: res, offs: 0 }, "{}", inst).unwrap();
+ }
+}
+
+#[cfg(fmt)]
+pub use fmt::yaxpeax_x86_16_fmt;
diff --git a/ffi/src/write_sink.rs b/ffi/src/write_sink.rs
new file mode 100644
index 0000000..b188498
--- /dev/null
+++ b/ffi/src/write_sink.rs
@@ -0,0 +1,20 @@
+pub struct InstructionSink<'buf> {
+ pub buf: &'buf mut [u8],
+ pub offs: usize,
+}
+
+impl<'a> core::fmt::Write for InstructionSink<'a> {
+ fn write_str(&mut self, s: &str) -> core::fmt::Result {
+ for b in s.bytes() {
+ if self.offs < self.buf.len() {
+ self.buf[self.offs] = b;
+ self.offs += 1;
+ } else {
+ break;
+ }
+ }
+
+ Ok(())
+ }
+}
+
diff --git a/src/long_mode/display.rs b/src/long_mode/display.rs
index c3f4413..1be4a32 100644
--- a/src/long_mode/display.rs
+++ b/src/long_mode/display.rs
@@ -5,20 +5,7 @@ use core::fmt;
use yaxpeax_arch::{Colorize, ShowContextual, NoColors, YaxColors};
use yaxpeax_arch::display::*;
-use crate::long_mode::{RegSpec, Opcode, Operand, InstDecoder, Instruction, Segment, PrefixRex, OperandSpec, DecodeError};
-
-impl fmt::Display for DecodeError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- DecodeError::ExhaustedInput => { write!(f, "exhausted input") },
- DecodeError::InvalidOpcode => { write!(f, "invalid opcode") },
- DecodeError::InvalidOperand => { write!(f, "invalid operand") },
- DecodeError::InvalidPrefixes => { write!(f, "invalid prefixes") },
- DecodeError::TooLong => { write!(f, "too long") },
- DecodeError::IncompleteDecoder => { write!(f, "the decoder is incomplete") },
- }
- }
-}
+use crate::long_mode::{RegSpec, Opcode, Operand, InstDecoder, Instruction, Segment, PrefixRex, OperandSpec};
impl fmt::Display for InstDecoder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs
index 909157b..ff5e43b 100644
--- a/src/long_mode/mod.rs
+++ b/src/long_mode/mod.rs
@@ -1,4 +1,5 @@
mod vex;
+#[cfg(feature = "fmt")]
mod display;
pub mod uarch;
@@ -6,6 +7,20 @@ use core::hint::unreachable_unchecked;
use yaxpeax_arch::{AddressDiff, Decoder, LengthedInstruction};
+use core::fmt;
+impl fmt::Display for DecodeError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ DecodeError::ExhaustedInput => { write!(f, "exhausted input") },
+ DecodeError::InvalidOpcode => { write!(f, "invalid opcode") },
+ DecodeError::InvalidOperand => { write!(f, "invalid operand") },
+ DecodeError::InvalidPrefixes => { write!(f, "invalid prefixes") },
+ DecodeError::TooLong => { write!(f, "too long") },
+ DecodeError::IncompleteDecoder => { write!(f, "the decoder is incomplete") },
+ }
+ }
+}
+
#[cfg(feature="use-serde")]
#[derive(Copy, Clone, Debug, PartialOrd, Ord, Eq, PartialEq, Serialize, Deserialize)]
pub struct RegSpec {
@@ -71,6 +86,7 @@ impl RegSpec {
RegisterClass { kind: self.bank }
}
+ #[cfg(feature = "fmt")]
/// return a human-friendly name for this register. the returned name is the same as would be
/// used to render this register in an instruction.
pub fn name(&self) -> &'static str {