lots of refactoring
This commit is contained in:
+52
-64
@@ -2,6 +2,7 @@ use std::collections::HashMap;
|
||||
|
||||
use super::*;
|
||||
use crate::backend::{LibImport, LinkedProgram, SymImport, SymTable, Symbol};
|
||||
use util::*;
|
||||
|
||||
pub struct Encoder<'a> {
|
||||
pub data: Vec<u8>,
|
||||
@@ -71,63 +72,42 @@ fn compile_instr(encoder: &mut Encoder, instr: &BInstr) -> Result<(), CompilerMs
|
||||
impl Encoder<'_> {
|
||||
// assembly
|
||||
|
||||
pub fn mov(&mut self, dst: RegMode, src: impl Into<RegImmMem>) -> Result<(), CompilerMsg> {
|
||||
let src = src.into();
|
||||
let width = dst.width;
|
||||
if width == BitWidth::B16 {
|
||||
pub fn movi(&mut self, dst: RegWH, imm: u64) -> Result<(), CompilerMsg> {
|
||||
if dst.widthh == WidthH::B16 {
|
||||
self.data.push(0x66);
|
||||
}
|
||||
let dst8 = dst.gt8();
|
||||
let b64 = width == BitWidth::B64;
|
||||
let b8 = width == BitWidth::B8;
|
||||
let src8 = if let RegImmMem::Reg(src) = src {
|
||||
src.gt8()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
// special 64-bit / register 4-7 indicator
|
||||
if dst8 || src8 || b64 || (dst.gt4() && !dst.high) {
|
||||
self.data
|
||||
.push(0x40 | dst8 as u8 | ((b64 as u8) << 3) | ((src8 as u8) << 2));
|
||||
if dst.requires_rex() {
|
||||
self.data.push(rex(dst.widthh, 0, 0, dst));
|
||||
}
|
||||
match src {
|
||||
RegImmMem::Reg(src) => {
|
||||
if dst.width != src.width {
|
||||
return Err("src and dst are not the same size".into());
|
||||
}
|
||||
self.data.push(0x88 | !b8 as u8);
|
||||
let modrm = 0b11_000_000 | (src.base() << 3) | dst.base();
|
||||
self.data.push(modrm);
|
||||
}
|
||||
RegImmMem::Imm(imm) => {
|
||||
if imm > width.max() {
|
||||
return Err("immediate cannot fit in register".into());
|
||||
}
|
||||
self.data.push(0xb0 | ((!b8 as u8) << 3) | dst.base());
|
||||
self.data.extend(&imm.to_le_bytes()[..width.bytes()]);
|
||||
}
|
||||
if imm > dst.widthh.max() {
|
||||
return Err("immediate cannot fit in register".into());
|
||||
}
|
||||
let opcode = 0xb0 | ((dst.widthh.gt8() as u8) << 3);
|
||||
self.data.push(opcode | dst.base());
|
||||
self.data.extend(&imm.to_le_bytes()[..dst.widthh.bytes()]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn mem_mov(&mut self, reg: RegMode, offset: u64, val: u64) {
|
||||
assert!(offset <= u8::MAX as u64);
|
||||
assert!(val <= u32::MAX as u64);
|
||||
self.data
|
||||
.extend([0x48 | ((reg.gt8() as u8) << 2), 0xc7, 0x40 | reg.base()]);
|
||||
if reg.reg == rsp.reg {
|
||||
self.data.push(0x24)
|
||||
pub fn movr(&mut self, dst: RegH, src: RegH, width: Width) {
|
||||
if width == Width::B16 {
|
||||
self.data.push(0x66);
|
||||
}
|
||||
self.data.push(offset as u8);
|
||||
self.data.extend((val as u32).to_le_bytes());
|
||||
if src.requires_rex(width) || dst.requires_rex(width) {
|
||||
self.data.push(rex(width, src, 0, dst));
|
||||
}
|
||||
self.data.push(0x88 | width.gt8() as u8);
|
||||
self.data.push(modrm_regs(src, dst));
|
||||
}
|
||||
|
||||
pub fn lea(&mut self, dst: RegMode, sym: Symbol) {
|
||||
self.data.extend([
|
||||
0x48 | ((dst.gt8() as u8) << 2),
|
||||
0x8d,
|
||||
0x05 | (dst.base() << 3),
|
||||
]);
|
||||
pub fn movm(&mut self, reg: RegWH, offset: u32, val: u32) {
|
||||
self.data.extend([rex(1, reg, 0, 0), 0xc7]);
|
||||
self.modrm_regdisp(reg, offset);
|
||||
self.data.extend(val.to_le_bytes());
|
||||
}
|
||||
|
||||
pub fn lea(&mut self, dst: RegWH, sym: Symbol) {
|
||||
self.data
|
||||
.extend([rex(1, dst, 0, 0), 0x8d, modrm_disp32(dst)]);
|
||||
self.sym_offset4(sym);
|
||||
}
|
||||
|
||||
@@ -144,7 +124,7 @@ impl Encoder<'_> {
|
||||
self.sym_offset4(sym);
|
||||
}
|
||||
|
||||
pub fn call_mem(&mut self, sym: Symbol) {
|
||||
pub fn callm(&mut self, sym: Symbol) {
|
||||
self.data.extend([0xff, 0x15]);
|
||||
self.sym_offset4(sym);
|
||||
}
|
||||
@@ -153,15 +133,15 @@ impl Encoder<'_> {
|
||||
self.data.push(0xc3);
|
||||
}
|
||||
|
||||
pub fn push(&mut self, reg: Reg) {
|
||||
pub fn pushr(&mut self, reg: Reg) {
|
||||
if reg.gt8() {
|
||||
self.data.push(0x41);
|
||||
}
|
||||
self.data.push(0x50 | reg.base());
|
||||
}
|
||||
|
||||
pub fn push_imm(&mut self, imm: u64) {
|
||||
const U8: u64 = 2 << 8;
|
||||
pub fn pushi(&mut self, imm: u32) {
|
||||
const U8: u32 = 2 << 8;
|
||||
if let 0..U8 = imm {
|
||||
self.data.push(0x6a);
|
||||
self.data.push(imm as u8);
|
||||
@@ -195,30 +175,38 @@ impl Encoder<'_> {
|
||||
|
||||
pub fn asm(&mut self, instr: Instr) -> Result<(), CompilerMsg> {
|
||||
match instr {
|
||||
Instr::Mov { dst, src } => self.mov(dst, src)?,
|
||||
Instr::MemMov { reg, offset, val } => self.mem_mov(reg, offset, val),
|
||||
Instr::Movr { dst, src, width } => self.movr(dst, src, width),
|
||||
Instr::Movi { dst, imm } => self.movi(dst, imm)?,
|
||||
Instr::Movm { reg, offset, val } => self.movm(reg, offset, val),
|
||||
Instr::Int(code) => self.int(code),
|
||||
Instr::Syscall => self.syscall(),
|
||||
Instr::Lea { dst, sym } => self.lea(dst, sym),
|
||||
Instr::Call(sym) => self.call(sym),
|
||||
Instr::Callm(sym) => self.callm(sym),
|
||||
Instr::Ret => self.ret(),
|
||||
Instr::Push(val) => match val {
|
||||
RegImm::Reg(reg) => self.push(reg),
|
||||
RegImm::Imm(imm) => self.push_imm(imm),
|
||||
},
|
||||
Instr::Pushr(reg) => self.pushr(reg),
|
||||
Instr::Pushi(imm) => self.pushi(imm),
|
||||
Instr::Pop(reg) => self.pop(reg),
|
||||
Instr::CallMem(sym) => self.call_mem(sym),
|
||||
Instr::Sub => self.data.extend([0x48, 0x83, 0xec, 0x28]),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// assumes the next instruction is directly after
|
||||
fn addr_offset(pos: usize, addr: u64) -> [u8; 4] {
|
||||
let pos = (pos + 4) as i32;
|
||||
let offset = addr as i32 - pos;
|
||||
offset.to_le_bytes()
|
||||
pub fn modrm_regdisp(&mut self, reg: impl Into<Reg>, disp: u32) {
|
||||
let reg = reg.into();
|
||||
let disp8 = disp < u8::MAX as u32;
|
||||
let mod_ = if disp8 { 0b01 } else { 0b10 };
|
||||
self.data.push(modrm(mod_, 0, reg.base()));
|
||||
if reg == rsp.reg {
|
||||
// SIB
|
||||
self.data.push(0x24);
|
||||
}
|
||||
if disp8 {
|
||||
self.data.push(disp as u8);
|
||||
} else {
|
||||
self.data.extend(disp.to_le_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Encoder<'a> {
|
||||
|
||||
Reference in New Issue
Block a user