use super::instruction::*;
use crate::error::Result;
use std::collections::HashMap;
pub(crate) mod encoder;
#[derive(Clone, Debug)]
pub struct Encoder {
data: Vec<u8>,
}
impl Encoder {
pub fn new() -> Self {
Self { data: vec![] }
}
pub fn encode(&mut self, instr: &Instruction) -> Result<usize> {
encoder::encode(instr, &mut self.data)
}
pub(crate) fn encode_block(
&mut self,
instr: &mut Instruction,
labels: &HashMap<u64, u64>,
) -> Result<usize> {
encoder::encode_block(instr, &mut self.data, labels)
}
pub fn take(self) -> Vec<u8> {
self.data
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub struct EncoderBlock {
blocks: Vec<InstructionBlock>,
}
impl EncoderBlock {
pub fn new(instr_blocks: Vec<InstructionBlock>) -> Self {
Self {
blocks: instr_blocks,
}
}
pub fn encode(mut self) -> Result<Vec<EncoderBlockResult>> {
let mut labels = HashMap::new();
for block in self.blocks.iter_mut() {
let mut pc = block.pc as u32;
for element in block.instructions.iter_mut() {
match element {
InstructionBlockElement::Label(label) => {
if labels.insert(*label, pc as u64).is_some() {
todo!()
}
}
InstructionBlockElement::Instruction(instruction) => {
instruction.pc = pc;
pc += instruction.size as u32;
}
}
}
}
self.blocks
.into_iter()
.map(|block| -> Result<EncoderBlockResult> {
let mut encoder = Encoder::new();
for element in block.instructions.into_iter() {
if let InstructionBlockElement::Instruction(mut instruction) = element {
let _ = encoder.encode_block(&mut instruction, &labels)?;
}
}
Ok(EncoderBlockResult {
pc: block.pc,
data: encoder.take(),
})
})
.collect()
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub struct EncoderBlockResult {
pub pc: u32,
pub data: Vec<u8>,
}
#[cfg(test)]
mod test {
use crate::core::a32::config::*;
use crate::core::a32::consts::*;
use crate::core::a32::formatter::*;
use crate::core::a32::operand::*;
use super::*;
use rhexdump::rhexdump;
#[test]
pub fn blocks() {
let instructions: Vec<InstructionBlockElement> = vec![
1.into(),
Instruction::with_4(
Code::AND_r_A1,
MnemonicCondition::Eq,
Register::R0,
Register::R1,
Register::R2,
)
.unwrap()
.into(),
Instruction::with_3(
Code::ADR_A2,
MnemonicCondition::Al,
Register::R0,
Label::LabelName(1),
)
.unwrap()
.into(),
Instruction::with_3(
Code::ADR_A1,
MnemonicCondition::Al,
Register::R0,
Label::LabelName(3),
)
.unwrap()
.into(),
2.into(),
];
let instructions2: Vec<InstructionBlockElement> = vec![
3.into(),
Instruction::with_4(
Code::AND_r_A1,
MnemonicCondition::Eq,
Register::R0,
Register::R1,
Register::R2,
)
.unwrap()
.into(),
Instruction::with_3(
Code::ADR_A2,
MnemonicCondition::Al,
Register::R0,
Label::LabelName(1),
)
.unwrap()
.into(),
Instruction::with_3(
Code::ADR_A1,
MnemonicCondition::Al,
Register::R0,
Label::LabelName(4),
)
.unwrap()
.into(),
Instruction::with_3(
Code::ADR_A2,
MnemonicCondition::Al,
Register::R0,
Label::LabelName(3),
)
.unwrap()
.into(),
4.into(),
];
let block = InstructionBlock::with_instructions(0xdead0000, instructions);
let block2 = InstructionBlock::with_instructions(0xdead0200, instructions2);
let encoder_block = EncoderBlock::new(vec![block, block2]);
let block = encoder_block.encode().unwrap();
rhexdump!(&block[0].data, 0xdead0000);
rhexdump!(&block[1].data, 0xdead0200);
let config = ConfigLLVM::new();
let mut insn = Instruction::with_3(
Code::ADR_A2,
MnemonicCondition::Al,
Register::R0,
Label::decode(-24, true),
)
.unwrap();
let mut formatter = Fmt {};
let mut output = String::new();
insn.pc = 0xdead0000;
formatter.format(&mut output, &config, &insn).unwrap();
println!("{}", output);
}
}