dynasm/
directive.rs

1use std::collections::hash_map::Entry;
2
3use crate::common::{Const, Expr, NumericRepr, Stmt, Size, Value};
4use crate::arch;
5use crate::DynasmData;
6
7pub enum Directive {
8    /// Set the architcture.
9    Arch(String),
10    /// Activate an architecture feature, or none to remove all.
11    Feature(Vec<String>),
12    /// Directly add some inline data words.
13    Data(Size, Vec<Const>),
14    /// Add some byte directly to the assembled data.
15    Byte(Expr),
16    /// Perform an alignment.
17    Align {
18        value: Expr,
19        with: Option<Expr>,
20    },
21    Alias {
22        /// The alias to use.
23        alias: String,
24        /// The target register which is given an alias.
25        reg: String,
26    },
27    /// A direct expression to add as bytes to the output.
28    Expr(Expr),
29}
30
31pub enum MalformedDirectiveError {
32    /// The architecture that was set was not recognized.
33    UnknownArchitecture(String),
34
35    /// The feature at the index was unknown.
36    UnknownFeature {
37        /// The index, to match to an input span for example.
38        idx: usize,
39        /// The bad feature.
40        what: String,
41    },
42
43    DuplicateAlias {
44        /// The name that has already been aliased.
45        reused: String,
46    },
47
48    /// Not a recognized directive.
49    UnknownDirective,
50}
51
52pub(crate) fn evaluate_directive(file_data: &mut DynasmData, stmts: &mut Vec<Stmt>, directive: &Directive)
53    -> Result<(), MalformedDirectiveError>
54{
55    match directive {
56        // TODO: oword, qword, float, double, long double
57        Directive::Arch(arch) => {
58            // ; .arch ident
59            if let Some(a) = arch::from_str(&arch) {
60                file_data.current_arch = a;
61            } else {
62                return Err(MalformedDirectiveError::UnknownArchitecture(arch.to_string()));
63            }
64        },
65        Directive::Feature(features) => {
66            // ;.feature none  cancels all features
67            if features.len() == 1 && features[0] == "none" {
68                file_data.current_arch.set_features(&[]);
69            } else {
70                file_data.current_arch.set_features(features);
71            }
72        },
73        // ; .byte (expr ("," expr)*)?
74        Directive::Data(size, consts) => {
75            directive_const(file_data, stmts, &consts, *size);
76        },
77        Directive::Byte(expr) => {
78            // ; .bytes expr
79            stmts.push(Stmt::ExprExtend(expr.into()));
80        },
81        Directive::Align { value, with } => {
82            // ; .align expr ("," expr)
83            let with = if let Some(with) = with {
84                Value::Expr(*with)
85            } else {
86                let with = file_data.current_arch.default_align();
87                Value::Byte(with)
88            };
89
90            stmts.push(Stmt::Align(*value, with));
91        },
92        Directive::Alias { alias, reg, } => {
93            // ; .alias ident, ident
94            match file_data.aliases.entry(alias.clone()) {
95                Entry::Occupied(_) => {
96                    return Err(MalformedDirectiveError::DuplicateAlias {
97                        reused: alias.clone(),
98                    });
99                },
100                Entry::Vacant(v) => {
101                    v.insert(reg.clone());
102                }
103            }
104        },
105        d => {
106            // unknown directive. skip ahead until we hit a ; so the parser can recover
107            return Err(MalformedDirectiveError::UnknownDirective);
108        }
109    }
110
111    Ok(())
112}
113
114fn directive_const(file_data: &mut DynasmData, stmts: &mut Vec<Stmt>, values: &[Const], size: Size) {
115    for value in values {
116        match value {
117            Const::Relocate(jump) => {
118                file_data.current_arch.handle_static_reloc(stmts, jump.clone(), size);
119            },
120            Const::Value(mut expr) => {
121                expr.repr = NumericRepr::signed(size);
122                stmts.push(Stmt::Const(expr.into()));
123            },
124        }
125    }
126}