dynasm\arch/
mod.rs

1use syn::parse;
2use proc_macro_error2::emit_error;
3
4use crate::common::{Size, Stmt, Jump};
5use crate::State;
6
7use std::fmt::Debug;
8
9pub mod x64;
10pub mod aarch64;
11pub mod riscv;
12
13pub(crate) trait Arch : Debug + Send {
14    /// When the .features directive is used for an architecture, this architecture method will be
15    /// called with the list of features as argument
16    fn set_features(&mut self, features: &[syn::Ident]);
17    /// When a data directive (.u32, .i64) is used with a jump in it, this needs to be emitted
18    /// in a way that the target runtime understands it. This architecture method handles this.
19    fn handle_static_reloc(&self, stmts: &mut Vec<Stmt>, reloc: Jump, size: Size);
20    /// The default byte to pad with for alignment for this architecture.
21    fn default_align(&self) -> u8;
22    /// The core of the architecture. This function parses a single instruction, storing the to be
23    /// emitted code in the passed `state` parameter. 
24    fn compile_instruction(&self, state: &mut State, input: parse::ParseStream) -> parse::Result<()>;
25}
26
27#[derive(Clone, Debug)]
28pub struct DummyArch {}
29
30impl DummyArch {
31    fn new() -> DummyArch {
32        DummyArch{}
33    }
34}
35
36impl Arch for DummyArch {
37    fn set_features(&mut self, features: &[syn::Ident]) {
38        if let Some(feature) = features.first() {
39            emit_error!(feature, "Cannot set features when the assembling architecture is undefined. Define it using a .arch directive");
40        }
41    }
42
43    fn handle_static_reloc(&self, _stmts: &mut Vec<Stmt>, reloc: Jump, _size: Size) {
44        let span = reloc.span();
45        emit_error!(span, "Current assembling architecture is undefined. Define it using a .arch directive");
46    }
47
48    fn default_align(&self) -> u8 {
49        0
50    }
51
52    fn compile_instruction(&self, _state: &mut State, input: parse::ParseStream) -> parse::Result<()> {
53        emit_error!(input.cursor().span(), "Current assembling architecture is undefined. Define it using a .arch directive");
54        Ok(())
55    }
56}
57
58pub(crate) fn from_str(s: &str) -> Option<Box<dyn Arch>> {
59    match s {
60        "x64" => Some(Box::new(x64::Archx64::default())),
61        "x86" => Some(Box::new(x64::Archx86::default())),
62        "aarch64" => Some(Box::new(aarch64::ArchAarch64::default())),
63        "riscv64i" | "riscv64" => Some(Box::new(riscv::ArchRiscV64I::default())),
64        "riscv64e" => Some(Box::new(riscv::ArchRiscV64E::default())),
65        "riscv32i" | "riscv32" => Some(Box::new(riscv::ArchRiscV32I::default())),
66        "riscv32e" => Some(Box::new(riscv::ArchRiscV32E::default())),
67        "unknown" => Some(Box::new(DummyArch::new())),
68        _ => None
69    }
70}
71
72#[cfg(target_arch="x86_64")]
73pub const CURRENT_ARCH: &str = "x64";
74#[cfg(target_arch="x86")]
75pub const CURRENT_ARCH: &str = "x86";
76#[cfg(target_arch="aarch64")]
77pub const CURRENT_ARCH: &str = "aarch64";
78// TODO: there seems to be no good way to detect riscv64i from riscv64e. You're probably not running
79// rustc on an embedded targets so assume the i variant.
80#[cfg(target_arch="riscv64")]
81pub const CURRENT_ARCH: &str = "riscv64i";
82#[cfg(target_arch="riscv32")]
83pub const CURRENT_ARCH: &str = "riscv32i";
84#[cfg(not(any(
85    target_arch="x86",
86    target_arch="x86_64",
87    target_arch="aarch64",
88    target_arch="riscv64",
89    target_arch="riscv32"
90)))]
91pub const CURRENT_ARCH: &str = "unknown";