From fed6ae454f659f4d2b36520474d1998b526a27dd Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Mon, 27 Feb 2023 22:00:11 +0100 Subject: Add JMP, JZ, and Label --- src/label.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/label.rs (limited to 'src/label.rs') diff --git a/src/label.rs b/src/label.rs new file mode 100644 index 0000000..b1f1133 --- /dev/null +++ b/src/label.rs @@ -0,0 +1,72 @@ +use std::collections::HashSet; + +/// A label which is used as target for jump instructions. +/// +/// ```rust +/// use juicebox_asm::prelude::*; +/// +/// let mut lbl = Label::new(); +/// let mut asm = Asm::new(); +/// +/// // Skip the mov instruction. +/// asm.jmp(&mut lbl); +/// asm.mov(Reg64::rax, Reg64::rax); +/// asm.bind(&mut lbl); +/// ``` +/// +/// # Panics +/// +/// Panics if the label is dropped while not yet bound, or having unresolved relocations. +/// This is mainly a safety-guard to detect wrong usage. +pub struct Label { + /// Location of the label. Will be set after the label is bound, else None. + location: Option, + + /// Offsets that must be patched with the label location. + offsets: HashSet, +} + +impl Label { + /// Create a new `unbound` [Label]. + pub fn new() -> Label { + Label { + location: None, + offsets: HashSet::new(), + } + } + + /// Bind the label to the `location`. + pub(crate) fn bind(&mut self, loc: usize) { + // A label can only be bound once! + assert!(!self.is_bound()); + + self.location = Some(loc); + } + + /// Record an offset that must be patched with the label location. + pub(crate) fn record_offset(&mut self, off: usize) { + self.offsets.insert(off); + } + + pub(crate) fn location(&self) -> Option { + self.location + } + + pub(crate) fn offsets_mut(&mut self) -> &mut HashSet { + &mut self.offsets + } + + /// Check whether the label is bound to a location. + const fn is_bound(&self) -> bool { + self.location.is_some() + } +} + +impl Drop for Label { + fn drop(&mut self) { + // Ensure the label was bound when it is dropped. + assert!(self.is_bound()); + // Ensure all offsets have been patched when the label is dropped. + assert!(self.offsets.is_empty()); + } +} -- cgit v1.2.3