use crate::cursor::Cursor;
use crate::diag::DiagBag;
use crate::expr::{ExprArena, ExprParser};
use crate::intern::{Interner, Name};
use crate::lexer::{LitPool, Token};
use crate::section::Variant;
use crate::source::Span;
use crate::symbol::SymbolTable;
#[cfg(feature = "x86")]
pub mod x86;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Endian {
Little,
Big,
}
impl Endian {
pub fn write(self, out: &mut [u8], value: u64) {
let n = out.len();
for (i, slot) in out.iter_mut().enumerate() {
let shift = match self {
Endian::Little => i,
Endian::Big => n - 1 - i,
};
*slot = (value >> (shift * 8)) as u8;
}
}
pub fn bytes(self, value: u64, n: usize) -> Vec<u8> {
let mut v = vec![0u8; n];
self.write(&mut v, value);
v
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Syntax {
Att,
Intel,
}
#[derive(Clone, Debug)]
pub struct ArchState {
pub bits: u8,
pub syntax: Syntax,
pub features: u64,
pub intel_register_prefix: bool,
}
pub struct InsnRequest<'t> {
pub mnemonic: Name,
pub mnemonic_span: Span,
pub operands: &'t [Token],
pub span: Span,
}
impl InsnRequest<'_> {
pub fn cursor(&self) -> Cursor<'_> {
Cursor::new(self.operands)
}
}
pub struct AsmCtx<'a> {
pub interner: &'a mut Interner,
pub exprs: &'a mut ExprArena,
pub diags: &'a mut DiagBag,
pub pool: &'a LitPool,
pub symbols: &'a SymbolTable,
pub state: &'a mut ArchState,
}
impl AsmCtx<'_> {
pub fn expr_parser(&mut self) -> ExprParser<'_> {
ExprParser {
arena: self.exprs,
interner: self.interner,
diags: self.diags,
dollar_is_here: false,
}
}
pub fn name(&self, n: Name) -> &str {
self.interner.get(n)
}
pub fn constant(&self, e: crate::expr::ExprRef) -> Option<i64> {
crate::expr::SymbolEnv::new(self.exprs, self.symbols).constant(e)
}
pub fn error(&mut self, span: Span, msg: impl Into<String>) {
self.diags.error(span, msg);
}
}
pub trait Architecture {
fn name(&self) -> &'static str;
fn aliases(&self) -> &'static [&'static str] {
&[]
}
fn endian(&self) -> Endian;
fn pointer_bytes(&self, state: &ArchState) -> u8;
fn initial_state(&self) -> ArchState;
fn supports_syntax(&self, syntax: Syntax) -> bool;
fn elf_machine(&self) -> u16;
fn data_reloc(&self, size: u8, pcrel: bool) -> Option<u32>;
fn modifier_reloc(&self, _name: &str, _size: u8, _pcrel: bool) -> Option<u32> {
None
}
fn nop_fill(&self, state: &ArchState, len: u64) -> Vec<u8>;
fn assemble(&self, cx: &mut AsmCtx<'_>, insn: &InsnRequest<'_>) -> Option<Vec<Variant>>;
fn directive(&self, _cx: &mut AsmCtx<'_>, _name: &str, _cur: &mut Cursor<'_>) -> bool {
false
}
}
pub fn lookup(name: &str) -> Option<Box<dyn Architecture>> {
let lower = name.to_ascii_lowercase();
#[cfg(feature = "x86")]
if let Some(a) = x86::lookup(&lower) {
return Some(a);
}
let _ = lower;
None
}
pub fn available() -> Vec<&'static str> {
#[allow(unused_mut)]
let mut v = Vec::new();
#[cfg(feature = "x86")]
v.extend_from_slice(x86::NAMES);
v
}
pub fn default_arch() -> Option<Box<dyn Architecture>> {
#[cfg(all(feature = "x86", target_arch = "x86_64"))]
if let Some(a) = lookup("x86-64") {
return Some(a);
}
available().first().and_then(|n| lookup(n))
}