linker_utils/
relaxation.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2pub enum RelocationModifier {
3 Normal,
4 SkipNextRelocation,
5}
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub struct RelaxDelta {
10 pub input_offset: u64,
12 pub cumulative_deleted: u64,
14 pub bytes_deleted: u32,
16}
17
18#[derive(Debug, Clone, Default)]
20pub struct SectionRelaxDeltas {
21 deltas: Vec<RelaxDelta>,
24}
25
26impl SectionRelaxDeltas {
27 #[must_use]
28 pub fn new(raw: Vec<(u64, u32)>) -> Self {
29 debug_assert!(
30 raw.windows(2).all(|w| w[0].0 < w[1].0),
31 "entries must be sorted by input_offset in strictly ascending order"
32 );
33
34 let mut deltas = Vec::with_capacity(raw.len());
35 let mut running = 0u64;
36 for (input_offset, bytes_deleted) in raw {
37 running += u64::from(bytes_deleted);
38 deltas.push(RelaxDelta {
39 input_offset,
40 cumulative_deleted: running,
41 bytes_deleted,
42 });
43 }
44
45 SectionRelaxDeltas { deltas }
46 }
47
48 #[must_use]
49 pub fn deltas(&self) -> &[RelaxDelta] {
50 &self.deltas
51 }
52
53 #[must_use]
54 pub fn is_empty(&self) -> bool {
55 self.deltas.is_empty()
56 }
57
58 #[must_use]
59 pub fn total_deleted(&self) -> u64 {
60 self.deltas.last().map_or(0, |d| d.cumulative_deleted)
61 }
62
63 pub fn merge_additional(&mut self, additional: Vec<(u64, u32)>) {
67 if additional.is_empty() {
68 return;
69 }
70 let mut raw: Vec<(u64, u32)> = self
71 .deltas
72 .iter()
73 .map(|d| (d.input_offset, d.bytes_deleted))
74 .chain(additional)
75 .collect();
76 raw.sort_by_key(|(offset, _)| *offset);
77 debug_assert!(
78 raw.windows(2).all(|w| w[0].0 < w[1].0),
79 "merge_additional: duplicate or overlapping offsets"
80 );
81 *self = SectionRelaxDeltas::new(raw);
82 }
83
84 #[must_use]
85 pub fn has_delta_at(&self, offset: u64) -> bool {
86 self.deltas
87 .binary_search_by_key(&offset, |d| d.input_offset)
88 .is_ok()
89 }
90
91 #[must_use]
93 pub fn delta_bytes_at(&self, offset: u64) -> u32 {
94 self.deltas
95 .binary_search_by_key(&offset, |d| d.input_offset)
96 .map_or(0, |i| self.deltas[i].bytes_deleted)
97 }
98
99 #[must_use]
102 pub fn input_to_output_offset(&self, input_offset: u64) -> u64 {
103 if self.deltas.is_empty() {
104 return input_offset;
105 }
106
107 let idx = self
110 .deltas
111 .partition_point(|d| d.input_offset < input_offset);
112
113 if idx == 0 {
114 input_offset
115 } else {
116 input_offset - self.deltas[idx - 1].cumulative_deleted
117 }
118 }
119
120 #[must_use]
122 pub fn output_to_input_offset(&self, output_offset: u64) -> u64 {
123 if self.deltas.is_empty() {
124 return output_offset;
125 }
126
127 let lo = self.deltas.partition_point(|d| {
128 d.input_offset + u64::from(d.bytes_deleted) - d.cumulative_deleted <= output_offset
129 });
130
131 if lo == 0 {
132 output_offset
133 } else {
134 output_offset + self.deltas[lo - 1].cumulative_deleted
135 }
136 }
137
138 #[must_use]
139 pub fn cursor(&self) -> RelaxCursor<'_> {
140 RelaxCursor {
141 deltas: &self.deltas,
142 index: 0,
143 current_cumulative: 0,
144 }
145 }
146}
147
148pub struct RelaxCursor<'a> {
149 deltas: &'a [RelaxDelta],
150 index: usize,
152 current_cumulative: u64,
154}
155
156impl RelaxCursor<'_> {
157 #[inline]
159 pub fn translate(&mut self, input_offset: u64) -> u64 {
160 while self.index < self.deltas.len() && self.deltas[self.index].input_offset < input_offset
162 {
163 self.current_cumulative = self.deltas[self.index].cumulative_deleted;
164 self.index += 1;
165 }
166 input_offset - self.current_cumulative
167 }
168}
169
170#[inline]
172#[must_use]
173pub fn opt_input_to_output(deltas: Option<&SectionRelaxDeltas>, input_offset: u64) -> u64 {
174 match deltas {
175 Some(d) => d.input_to_output_offset(input_offset),
176 None => input_offset,
177 }
178}
179
180#[derive(Debug, Clone, Default)]
182pub struct RelaxDeltaMap {
183 entries: Vec<(usize, SectionRelaxDeltas)>,
185}
186
187impl RelaxDeltaMap {
188 #[must_use]
189 pub fn new() -> Self {
190 Self {
191 entries: Vec::new(),
192 }
193 }
194
195 pub fn insert(&mut self, section_index: usize, deltas: SectionRelaxDeltas) {
196 debug_assert!(
197 self.entries
198 .last()
199 .is_none_or(|(idx, _)| *idx < section_index),
200 "entries must be inserted in ascending section index order"
201 );
202 self.entries.push((section_index, deltas));
203 }
204
205 #[must_use]
206 pub fn get(&self, section_index: usize) -> Option<&SectionRelaxDeltas> {
207 self.entries
208 .binary_search_by_key(§ion_index, |(idx, _)| *idx)
209 .ok()
210 .map(|i| &self.entries[i].1)
211 }
212
213 #[must_use]
214 pub fn get_mut(&mut self, section_index: usize) -> Option<&mut SectionRelaxDeltas> {
215 self.entries
216 .binary_search_by_key(§ion_index, |(idx, _)| *idx)
217 .ok()
218 .map(|i| &mut self.entries[i].1)
219 }
220
221 pub fn insert_sorted(&mut self, section_index: usize, deltas: SectionRelaxDeltas) {
222 let pos = self
223 .entries
224 .partition_point(|(idx, _)| *idx < section_index);
225 debug_assert!(
226 pos >= self.entries.len() || self.entries[pos].0 != section_index,
227 "insert_sorted: duplicate section_index {section_index}"
228 );
229 self.entries.insert(pos, (section_index, deltas));
230 }
231
232 #[must_use]
233 pub fn is_empty(&self) -> bool {
234 self.entries.is_empty()
235 }
236}