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