push and pop
This commit is contained in:
+29
-13
@@ -1,4 +1,7 @@
|
|||||||
use crate::{arch::x86_64::RegMode, backend::Symbol};
|
use crate::{
|
||||||
|
arch::x86_64::{BitWidth, Reg, RegMode},
|
||||||
|
backend::Symbol,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct Asm {
|
pub struct Asm {
|
||||||
pub instrs: Vec<Instr>,
|
pub instrs: Vec<Instr>,
|
||||||
@@ -7,11 +10,13 @@ pub struct Asm {
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum Instr {
|
pub enum Instr {
|
||||||
Mov { dst: RegMode, src: RegImm },
|
Mov { dst: RegMode, src: RegImm },
|
||||||
Int { code: u8 },
|
Int(u8),
|
||||||
Call(Symbol),
|
Call(Symbol),
|
||||||
Ret,
|
Ret,
|
||||||
Syscall,
|
Syscall,
|
||||||
Lea { dst: RegMode, sym: Symbol },
|
Lea { dst: RegMode, sym: Symbol },
|
||||||
|
Push(Reg),
|
||||||
|
Pop(Reg),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@@ -32,17 +37,28 @@ impl From<u64> for RegImm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mov(dst: RegMode, src: impl Into<RegImm>) -> Instr {
|
mod fns {
|
||||||
Instr::Mov {
|
use super::*;
|
||||||
dst,
|
pub fn mov(dst: RegMode, src: impl Into<RegImm>) -> Instr {
|
||||||
src: src.into(),
|
Instr::Mov {
|
||||||
|
dst,
|
||||||
|
src: src.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lea(dst: RegMode, sym: Symbol) -> Instr {
|
||||||
|
Instr::Lea { dst, sym }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(reg: RegMode) -> Instr {
|
||||||
|
assert!(reg.width == BitWidth::B64);
|
||||||
|
Instr::Push(reg.reg)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop(reg: RegMode) -> Instr {
|
||||||
|
assert!(reg.width == BitWidth::B64);
|
||||||
|
Instr::Pop(reg.reg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lea(dst: RegMode, sym: Symbol) -> Instr {
|
pub use fns::*;
|
||||||
Instr::Lea { dst, sym }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn int(code: u8) -> Instr {
|
|
||||||
Instr::Int { code }
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -115,6 +115,20 @@ impl Encoder {
|
|||||||
self.data.push(0xc3);
|
self.data.push(0xc3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, reg: Reg) {
|
||||||
|
if reg.gt8() {
|
||||||
|
self.data.push(0x41);
|
||||||
|
}
|
||||||
|
self.data.push(0x50 | reg.base());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop(&mut self, reg: Reg) {
|
||||||
|
if reg.gt8() {
|
||||||
|
self.data.push(0x41);
|
||||||
|
}
|
||||||
|
self.data.push(0x58 | reg.base());
|
||||||
|
}
|
||||||
|
|
||||||
/// inserts a 32 bit offset from a symbol
|
/// inserts a 32 bit offset from a symbol
|
||||||
pub fn sym_offset4(&mut self, sym: Symbol) {
|
pub fn sym_offset4(&mut self, sym: Symbol) {
|
||||||
let Some(addr) = self.sym_tab.get(sym) else {
|
let Some(addr) = self.sym_tab.get(sym) else {
|
||||||
@@ -129,11 +143,13 @@ impl Encoder {
|
|||||||
pub fn asm(&mut self, instr: Instr) -> Result<(), CompilerMsg> {
|
pub fn asm(&mut self, instr: Instr) -> Result<(), CompilerMsg> {
|
||||||
match instr {
|
match instr {
|
||||||
Instr::Mov { dst, src } => self.mov(dst, src)?,
|
Instr::Mov { dst, src } => self.mov(dst, src)?,
|
||||||
Instr::Int { code } => self.int(code),
|
Instr::Int(code) => self.int(code),
|
||||||
Instr::Syscall => self.syscall(),
|
Instr::Syscall => self.syscall(),
|
||||||
Instr::Lea { dst, sym } => self.lea(dst, sym),
|
Instr::Lea { dst, sym } => self.lea(dst, sym),
|
||||||
Instr::Call(sym) => self.call(sym),
|
Instr::Call(sym) => self.call(sym),
|
||||||
Instr::Ret => self.ret(),
|
Instr::Ret => self.ret(),
|
||||||
|
Instr::Push(reg) => self.push(reg),
|
||||||
|
Instr::Pop(reg) => self.pop(reg),
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-4
@@ -16,16 +16,29 @@ pub enum BitWidth {
|
|||||||
B8,
|
B8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegMode {
|
impl Reg {
|
||||||
pub fn base(&self) -> u8 {
|
pub fn base(&self) -> u8 {
|
||||||
self.reg.0 & 0b111
|
self.0 & 0b111
|
||||||
}
|
}
|
||||||
/// checks if register is not one of the first 8 (0-7)
|
/// checks if register is not one of the first 8 (0-7)
|
||||||
pub fn gt8(&self) -> bool {
|
pub fn gt8(&self) -> bool {
|
||||||
self.reg.0 >= 0b1000
|
self.0 >= 0b1000
|
||||||
}
|
}
|
||||||
pub fn gt4(&self) -> bool {
|
pub fn gt4(&self) -> bool {
|
||||||
self.reg.0 >= 0b0100
|
self.0 >= 0b0100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RegMode {
|
||||||
|
pub fn base(&self) -> u8 {
|
||||||
|
self.reg.base()
|
||||||
|
}
|
||||||
|
/// checks if register is not one of the first 8 (0-7)
|
||||||
|
pub fn gt8(&self) -> bool {
|
||||||
|
self.reg.gt8()
|
||||||
|
}
|
||||||
|
pub fn gt4(&self) -> bool {
|
||||||
|
self.reg.gt4()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ pub fn run() {
|
|||||||
})]);
|
})]);
|
||||||
let entry = program.func([BInstr::Asm(Asm {
|
let entry = program.func([BInstr::Asm(Asm {
|
||||||
instrs: vec![
|
instrs: vec![
|
||||||
|
mov(di, 39),
|
||||||
|
push(rdi),
|
||||||
mov(ax, 1),
|
mov(ax, 1),
|
||||||
mov(di, 1),
|
mov(di, 1),
|
||||||
lea(rsi, text_sym),
|
lea(rsi, text_sym),
|
||||||
@@ -29,7 +31,7 @@ pub fn run() {
|
|||||||
Instr::Syscall,
|
Instr::Syscall,
|
||||||
Instr::Call(hello2),
|
Instr::Call(hello2),
|
||||||
mov(ax, 0x3c),
|
mov(ax, 0x3c),
|
||||||
mov(di, 39),
|
pop(rdi),
|
||||||
Instr::Syscall,
|
Instr::Syscall,
|
||||||
],
|
],
|
||||||
})]);
|
})]);
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ impl Node for Asm {
|
|||||||
let code = parse_imm(&num, ctx.span)?
|
let code = parse_imm(&num, ctx.span)?
|
||||||
.try_into()
|
.try_into()
|
||||||
.map_err(|_| CompilerMsg::from("Immediate must be a u8"))?;
|
.map_err(|_| CompilerMsg::from("Immediate must be a u8"))?;
|
||||||
instrs.push(Instr::Int { code });
|
instrs.push(Instr::Int(code));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let msg = format!("Unknown instruction {next}");
|
let msg = format!("Unknown instruction {next}");
|
||||||
|
|||||||
BIN
Binary file not shown.
Reference in New Issue
Block a user