1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
//! Definition of the lable type which can be used as jump target and can be bound to a location in
//! the emitted code.
use std::collections::HashSet;
/// A label which is used as target for jump instructions.
///
/// ```rust
/// use juicebox_asm::{Asm, Label, Reg64};
/// use juicebox_asm::insn::{Mov, Jmp};
///
/// 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<usize>,
/// Offsets that must be patched with the label location.
offsets: HashSet<usize>,
}
impl Label {
/// Create a new `unbound` [Label].
pub fn new() -> Label {
Label {
location: None,
offsets: HashSet::new(),
}
}
/// Bind the label to the `location`, can only be bound once.
///
/// # Panics
///
/// Panics if the lable is already bound.
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);
}
/// Get the location of the lable if already bound, `None` else.
pub(crate) fn location(&self) -> Option<usize> {
self.location
}
/// Get the offsets which refer to the label. These are used to patch the jump instructions to
/// the label location.
pub(crate) fn offsets_mut(&mut self) -> &mut HashSet<usize> {
&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());
}
}
|