Skip to main content

risc0_binfmt/
addr.rs

1// Copyright 2026 RISC Zero, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use derive_more::{Add, AddAssign, Debug, Sub};
16
17use crate::{PAGE_BYTES, PAGE_WORDS, WORD_SIZE};
18
19/// A memory address expressed in bytes
20#[derive(Add, AddAssign, Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Sub)]
21#[debug("{_0:#010x}")]
22pub struct ByteAddr(pub u32);
23
24/// A memory address expressed in words
25///
26/// Only capable of representing aligned addresses, as adjacent [WordAddr]s are a word apart.
27#[derive(Add, AddAssign, Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Sub)]
28#[debug("${_0:#010x}")]
29pub struct WordAddr(pub u32);
30
31impl ByteAddr {
32    /// Convert to a [WordAddr]
33    ///
34    /// If the address is not aligned to a word boundary, this will return the highest aligned address smaller than the input address.
35    pub const fn waddr(self) -> WordAddr {
36        WordAddr(self.0 / WORD_SIZE as u32)
37    }
38
39    /// Gives the [Page][crate::image::Page] containing this memory address
40    pub const fn page_idx(&self) -> u32 {
41        self.0 / PAGE_BYTES as u32
42    }
43
44    /// The subaddress of this address relative to its containing
45    /// [Page][crate::image::Page]
46    ///
47    /// The number of bytes this address is beyond the first byte of the page which contains it.
48    pub const fn page_subaddr(&self) -> ByteAddr {
49        Self(self.0 % PAGE_BYTES as u32)
50    }
51
52    /// Convert to a [WordAddr] if aligned
53    ///
54    /// If the address is aligned to a word boundary, this will return the [WordAddr] for this memory location. If it is not aligned, it returns `None`.
55    pub fn waddr_aligned(self) -> Option<WordAddr> {
56        self.is_aligned().then(|| self.waddr())
57    }
58
59    /// Reports if the address is aligned
60    ///
61    /// Returns `true` if the address is aligned to a word boundary, otherwise returns `false`
62    pub const fn is_aligned(&self) -> bool {
63        self.0.is_multiple_of(WORD_SIZE as u32)
64    }
65
66    /// Reports if the address is null
67    ///
68    /// The address `0x00000000` is null and will return `true`, for all others returns `false`.
69    pub const fn is_null(&self) -> bool {
70        self.0 == 0
71    }
72
73    /// Add an offset to an address, returning `None` on overflow.
74    pub const fn checked_add(self, rhs: u32) -> Option<Self> {
75        match self.0.checked_add(rhs) {
76            None => None,
77            Some(x) => Some(Self(x)),
78        }
79    }
80
81    /// Add an offset to an address, saturating on overflow.
82    pub const fn saturating_add(self, rhs: u32) -> Self {
83        Self(self.0.saturating_add(rhs))
84    }
85
86    /// Add an offset to an address
87    ///
88    /// This will wrap on overflow, e.g. `0xFFFFFFFF + 0x00000001` is `0x00000000`.
89    pub const fn wrapping_add(self, rhs: u32) -> Self {
90        Self(self.0.wrapping_add(rhs))
91    }
92
93    /// The subaddress of this address relative to its containing word
94    ///
95    /// The number of bytes this address is beyond the previous aligned address. So for example an aligned address will have a subaddress of `0`, while the address `0x00003001` will have subaddress `1`.
96    pub const fn subaddr(&self) -> u32 {
97        self.0 % WORD_SIZE as u32
98    }
99}
100
101impl WordAddr {
102    /// Convert to a [ByteAddr]
103    pub const fn baddr(self) -> ByteAddr {
104        ByteAddr(self.0 * WORD_SIZE as u32)
105    }
106
107    /// Gives the [crate::image::Page] containing this memory address
108    pub const fn page_idx(&self) -> u32 {
109        self.0 / PAGE_WORDS as u32
110    }
111
112    /// The subaddress of this address relative to its containing [crate::image::Page]
113    ///
114    /// The number of words this address is beyond the first word of the page which contains it.
115    pub const fn page_subaddr(&self) -> WordAddr {
116        Self(self.0 % PAGE_WORDS as u32)
117    }
118
119    /// Increments this address to the next word
120    ///
121    /// This increments the address without returning any value.
122    pub const fn inc(&mut self) {
123        self.0 += 1;
124    }
125
126    /// Increments this address to the next word and returns its previous value
127    ///
128    /// This is a postfixing increment, analogous to `addr++` in C; the value this evaluates to is the value prior to the increment.
129    pub const fn postfix_inc(&mut self) -> Self {
130        let cur = *self;
131        self.0 += 1;
132        cur
133    }
134
135    /// Reports if the address is null
136    ///
137    /// The address `0x00000000` is null and will return `true`, for all others returns `false`.
138    pub const fn is_null(&self) -> bool {
139        self.0 == 0
140    }
141}
142
143impl core::ops::Add<usize> for WordAddr {
144    type Output = WordAddr;
145
146    fn add(self, rhs: usize) -> Self::Output {
147        Self(self.0 + rhs as u32)
148    }
149}
150
151impl core::ops::Add<u32> for WordAddr {
152    type Output = WordAddr;
153
154    fn add(self, rhs: u32) -> Self::Output {
155        Self(self.0 + rhs)
156    }
157}
158
159impl core::ops::Add<i32> for WordAddr {
160    type Output = WordAddr;
161
162    fn add(self, rhs: i32) -> Self::Output {
163        Self(self.0.checked_add_signed(rhs).unwrap())
164    }
165}
166
167impl core::ops::Sub<u32> for WordAddr {
168    type Output = WordAddr;
169
170    fn sub(self, rhs: u32) -> Self::Output {
171        Self(self.0 - rhs)
172    }
173}
174
175impl core::ops::AddAssign<usize> for WordAddr {
176    fn add_assign(&mut self, rhs: usize) {
177        self.0 += rhs as u32;
178    }
179}
180
181impl core::ops::AddAssign<u32> for WordAddr {
182    fn add_assign(&mut self, rhs: u32) {
183        self.0 += rhs;
184    }
185}
186
187impl core::ops::Add<usize> for ByteAddr {
188    type Output = ByteAddr;
189
190    fn add(self, rhs: usize) -> Self::Output {
191        Self(self.0 + rhs as u32)
192    }
193}
194
195impl core::ops::Add<u32> for ByteAddr {
196    type Output = ByteAddr;
197
198    fn add(self, rhs: u32) -> Self::Output {
199        Self(self.0 + rhs)
200    }
201}
202
203impl core::ops::Add<i32> for ByteAddr {
204    type Output = ByteAddr;
205
206    fn add(self, rhs: i32) -> Self::Output {
207        Self(self.0.checked_add_signed(rhs).unwrap())
208    }
209}
210
211impl core::ops::AddAssign<usize> for ByteAddr {
212    fn add_assign(&mut self, rhs: usize) {
213        self.0 += rhs as u32;
214    }
215}
216
217impl core::ops::AddAssign<u32> for ByteAddr {
218    fn add_assign(&mut self, rhs: u32) {
219        self.0 += rhs;
220    }
221}
222
223impl From<ByteAddr> for WordAddr {
224    fn from(addr: ByteAddr) -> Self {
225        addr.waddr()
226    }
227}
228
229impl From<WordAddr> for ByteAddr {
230    fn from(addr: WordAddr) -> Self {
231        addr.baddr()
232    }
233}