risc0_binfmt/
addr.rs

1// Copyright 2025 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_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    /// Convert to a [WordAddr] if aligned
40    ///
41    /// 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`.
42    pub fn waddr_aligned(self) -> Option<WordAddr> {
43        self.is_aligned().then(|| self.waddr())
44    }
45
46    /// Reports if the address is aligned
47    ///
48    /// Returns `true` if the address is aligned to a word boundary, otherwise returns `false`
49    pub const fn is_aligned(&self) -> bool {
50        self.0 % WORD_SIZE as u32 == 0
51    }
52
53    /// Reports if the address is null
54    ///
55    /// The address `0x00000000` is null and will return `true`, for all others returns `false`.
56    pub const fn is_null(&self) -> bool {
57        self.0 == 0
58    }
59
60    /// Add an offset to an address
61    ///
62    /// This will wrap on overflow, e.g. `0xFFFFFFFF + 0x00000001` is `0x00000000`.
63    pub fn wrapping_add(self, rhs: u32) -> Self {
64        Self(self.0.wrapping_add(rhs))
65    }
66
67    /// The subaddress of this address relative to its containing word
68    ///
69    /// 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`.
70    pub fn subaddr(&self) -> u32 {
71        self.0 % WORD_SIZE as u32
72    }
73}
74
75impl WordAddr {
76    /// Convert to a [ByteAddr]
77    pub const fn baddr(self) -> ByteAddr {
78        ByteAddr(self.0 * WORD_SIZE as u32)
79    }
80
81    /// Gives the [crate::image::Page] containing this memory address
82    pub fn page_idx(&self) -> u32 {
83        self.0 / PAGE_WORDS as u32
84    }
85
86    /// The subaddress of this address relative to its containing [crate::image::Page]
87    ///
88    /// The number of words this address is beyond the first word of the page which contains it.
89    pub fn page_subaddr(&self) -> WordAddr {
90        Self(self.0 % PAGE_WORDS as u32)
91    }
92
93    /// Increments this address to the next word
94    ///
95    /// This increments the address without returning any value.
96    pub fn inc(&mut self) {
97        self.0 += 1;
98    }
99
100    /// Increments this address to the next word and returns its previous value
101    ///
102    /// This is a postfixing increment, analogous to `addr++` in C; the value this evaluates to is the value prior to the increment.
103    pub fn postfix_inc(&mut self) -> Self {
104        let cur = *self;
105        self.0 += 1;
106        cur
107    }
108
109    /// Reports if the address is null
110    ///
111    /// The address `0x00000000` is null and will return `true`, for all others returns `false`.
112    pub const fn is_null(&self) -> bool {
113        self.0 == 0
114    }
115}
116
117impl core::ops::Add<usize> for WordAddr {
118    type Output = WordAddr;
119
120    fn add(self, rhs: usize) -> Self::Output {
121        Self(self.0 + rhs as u32)
122    }
123}
124
125impl core::ops::Add<u32> for WordAddr {
126    type Output = WordAddr;
127
128    fn add(self, rhs: u32) -> Self::Output {
129        Self(self.0 + rhs)
130    }
131}
132
133impl core::ops::Add<i32> for WordAddr {
134    type Output = WordAddr;
135
136    fn add(self, rhs: i32) -> Self::Output {
137        Self(self.0.checked_add_signed(rhs).unwrap())
138    }
139}
140
141impl core::ops::Sub<u32> for WordAddr {
142    type Output = WordAddr;
143
144    fn sub(self, rhs: u32) -> Self::Output {
145        Self(self.0 - rhs)
146    }
147}
148
149impl core::ops::AddAssign<usize> for WordAddr {
150    fn add_assign(&mut self, rhs: usize) {
151        self.0 += rhs as u32;
152    }
153}
154
155impl core::ops::AddAssign<u32> for WordAddr {
156    fn add_assign(&mut self, rhs: u32) {
157        self.0 += rhs;
158    }
159}
160
161impl core::ops::Add<usize> for ByteAddr {
162    type Output = ByteAddr;
163
164    fn add(self, rhs: usize) -> Self::Output {
165        Self(self.0 + rhs as u32)
166    }
167}
168
169impl core::ops::Add<u32> for ByteAddr {
170    type Output = ByteAddr;
171
172    fn add(self, rhs: u32) -> Self::Output {
173        Self(self.0 + rhs)
174    }
175}
176
177impl core::ops::Add<i32> for ByteAddr {
178    type Output = ByteAddr;
179
180    fn add(self, rhs: i32) -> Self::Output {
181        Self(self.0.checked_add_signed(rhs).unwrap())
182    }
183}
184
185impl core::ops::AddAssign<usize> for ByteAddr {
186    fn add_assign(&mut self, rhs: usize) {
187        self.0 += rhs as u32;
188    }
189}
190
191impl core::ops::AddAssign<u32> for ByteAddr {
192    fn add_assign(&mut self, rhs: u32) {
193        self.0 += rhs;
194    }
195}
196
197impl From<ByteAddr> for WordAddr {
198    fn from(addr: ByteAddr) -> Self {
199        addr.waddr()
200    }
201}
202
203impl From<WordAddr> for ByteAddr {
204    fn from(addr: WordAddr) -> Self {
205        addr.baddr()
206    }
207}