use std::collections::HashMap;
use super::instruction::*;
use crate::error::Result;
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;
for element in block.instructions.iter_mut() {
match element {
InstructionBlockElement::Label(label) => {
if labels.insert(*label, pc).is_some() {
todo!()
}
}
InstructionBlockElement::Instruction(instruction) => {
instruction.pc = pc;
pc += instruction.size as u64;
}
}
}
}
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: u64,
pub data: Vec<u8>,
}
#[cfg(test)]
mod test {
use crate::core::a64::config::*;
use crate::core::a64::consts::*;
use crate::core::a64::formatter::*;
use crate::core::a64::operand::*;
use super::*;
use rhexdump::rhexdump;
#[test]
pub fn blocks() {
let instructions: Vec<InstructionBlockElement> = vec![
Instruction::with_4(
Code::ADD_64_addsub_imm,
Register::X0,
Register::X1,
16u32,
Extension::Lsl(12),
)
.unwrap()
.into(),
1.into(),
Instruction::with_4(
Code::ADD_64_addsub_imm,
Register::X0,
Register::X1,
16u32,
Extension::Lsl(12),
)
.unwrap()
.into(),
Instruction::with_4(
Code::ADD_64_addsub_imm,
Register::X0,
Register::X1,
16u32,
Extension::Lsl(12),
)
.unwrap()
.into(),
Instruction::with_4(
Code::ADD_64_addsub_imm,
Register::X0,
Register::X1,
16u32,
Extension::Lsl(12),
)
.unwrap()
.into(),
Instruction::with_2(Code::ADR_only_pcreladdr, Register::X0, Label::LabelName(3))
.unwrap()
.into(),
Instruction::with_2(Code::ADR_only_pcreladdr, Register::X0, Label::LabelName(4))
.unwrap()
.into(),
2.into(),
];
let instructions2: Vec<InstructionBlockElement> = vec![
Instruction::with_4(
Code::ADD_64_addsub_imm,
Register::X0,
Register::X1,
16u32,
Extension::Lsl(12),
)
.unwrap()
.into(),
3.into(),
Instruction::with_4(
Code::ADD_64_addsub_imm,
Register::X0,
Register::X1,
16u32,
Extension::Lsl(12),
)
.unwrap()
.into(),
Instruction::with_4(
Code::ADD_64_addsub_imm,
Register::X0,
Register::X1,
16u32,
Extension::Lsl(12),
)
.unwrap()
.into(),
Instruction::with_4(
Code::ADD_64_addsub_imm,
Register::X0,
Register::X1,
16u32,
Extension::Lsl(12),
)
.unwrap()
.into(),
Instruction::with_2(Code::ADR_only_pcreladdr, Register::X0, Label::LabelName(1))
.unwrap()
.into(),
Instruction::with_2(Code::ADR_only_pcreladdr, Register::X0, Label::LabelName(2))
.unwrap()
.into(),
4.into(),
];
let block = InstructionBlock::with_instructions(0xdead0000, instructions);
let block2 = InstructionBlock::with_instructions(0xdeaf0000, instructions2);
let encoder_block = EncoderBlock::new(vec![block, block2]);
let block = encoder_block.encode().unwrap();
rhexdump!(&block[0].data, 0xdead0001);
rhexdump!(&block[1].data, 0xdeaf0002);
let config = ConfigLLVM::new();
let mut insn =
Instruction::with_2(Code::ADR_only_pcreladdr, Register::X0, Label::Label(24)).unwrap();
let mut formatter = Fmt {};
let mut output = String::new();
insn.pc = 0xdead0000;
formatter.format(&mut output, &config, &insn).unwrap();
println!("{}", output);
}
}