1use crate::bit_misc::BitRange;
2use anyhow::Result;
3use object::LittleEndian;
4use object::read::elf::ProgramHeader as _;
5use object::read::elf::SectionHeader;
6use std::borrow::Cow;
7use std::fmt;
8
9macro_rules! const_name_by_value {
10 ($needle: expr, $( $const:ident ),* $(,)?) => {
11 match $needle {
12 $(object::elf::$const => Some(stringify!($const)),)*
13 _ => None
14 }
15 };
16}
17
18macro_rules! const_or_literal {
19 ($prefix:ident $const:ident = $value:expr) => {
20 $value
21 };
22 ($prefix:ident $const:ident) => {
23 ::paste::paste! {
24 ::object::elf::[<$prefix _ $const>]
25 }
26 };
27}
28
29macro_rules! elf_constant_newtype {
33 (
34 $name:ident,
35 $inner_type:ident,
36 $constants_module:ident,
37 $prefix:ident,
38 $(
39 $const:ident $(= $value:expr)?
40 ),* $(,)?
41 ) => {
42 #[derive(Clone, Copy, derive_more::Debug, PartialEq, Eq, PartialOrd, Ord)]
43 #[debug("{}", self.as_str())]
44 pub struct $name($inner_type);
45
46 impl $name {
47 #[must_use]
48 pub fn raw(&self) -> $inner_type {
49 self.0
50 }
51
52 #[allow(unreachable_patterns)] #[must_use]
54 pub fn as_str(&self) -> Cow<'static, str> {
55 match self.0 {
56 $(
57 const_or_literal!($prefix $const $(= $value )?)
58 => ::std::borrow::Cow::Borrowed(stringify!($const)),
59 )*
60 r => Cow::Owned(format!("Unknown({r})")),
61 }
62 }
63
64 ::paste::paste! {
65 #[must_use]
66 pub const fn [<from_ $inner_type>](value: $inner_type) -> Self {
67 Self(value)
68 }
69 }
70 }
71
72 impl From < $inner_type > for $name {
73 fn from(value: $inner_type) -> Self {
74 Self(value)
75 }
76 }
77
78 impl std::fmt::Display for $name {
79 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 write!(f, "{}", self.as_str())
81 }
82 }
83
84 pub mod $constants_module {
85 #![allow(non_upper_case_globals)]
86 use super::$name;
87
88 $(pub const $const: $name = $name(const_or_literal!($prefix $const $(= $value)?));)*
89 }
90 };
91}
92
93elf_constant_newtype!(
94 SegmentType,
95 u32,
96 pt,
97 PT,
98 NULL,
99 LOAD,
100 DYNAMIC,
101 INTERP,
102 NOTE,
103 SHLIB,
104 PHDR,
105 TLS,
106 GNU_EH_FRAME,
107 GNU_STACK,
108 GNU_RELRO,
109 GNU_PROPERTY,
110 GNU_SFRAME,
111 RISCV_ATTRIBUTES,
112);
113
114impl SegmentType {
115 #[must_use]
116 pub fn from_header(header: &object::elf::ProgramHeader64<LittleEndian>) -> Self {
117 Self(header.p_type(LittleEndian))
118 }
119}
120
121elf_constant_newtype!(
122 SectionType,
123 u32,
124 sht,
125 SHT,
126 NULL,
127 PROGBITS,
128 SYMTAB,
129 STRTAB,
130 RELA,
131 HASH,
132 DYNAMIC,
133 NOTE,
134 NOBITS,
135 REL,
136 SHLIB,
137 DYNSYM,
138 INIT_ARRAY,
139 FINI_ARRAY,
140 PREINIT_ARRAY,
141 GROUP,
142 SYMTAB_SHNDX,
143 LOOS,
144 GNU_SFRAME,
145 GNU_ATTRIBUTES,
146 GNU_HASH,
147 GNU_LIBLIST,
148 CHECKSUM,
149 LOSUNW,
150 SUNW_COMDAT,
151 SUNW_syminfo,
152 GNU_VERDEF,
153 GNU_VERNEED,
154 GNU_VERSYM,
155 HISUNW,
156 HIOS,
157 LOPROC,
158 HIPROC,
159 LOUSER,
160 HIUSER,
161 RISCV_ATTRIBUTES,
162);
163
164impl SectionType {
165 #[must_use]
166 pub fn from_header(header: &object::elf::SectionHeader64<LittleEndian>) -> Self {
167 Self(header.sh_type(LittleEndian))
168 }
169}
170
171elf_constant_newtype!(SymbolType, u8, stt, STT, NOTYPE, TLS);
172
173#[must_use]
174pub fn x86_64_rel_type_to_string(r_type: u32) -> Cow<'static, str> {
175 if let Some(name) = const_name_by_value![
176 r_type,
177 R_X86_64_NONE,
178 R_X86_64_64,
179 R_X86_64_PC32,
180 R_X86_64_GOT32,
181 R_X86_64_PLT32,
182 R_X86_64_COPY,
183 R_X86_64_GLOB_DAT,
184 R_X86_64_JUMP_SLOT,
185 R_X86_64_RELATIVE,
186 R_X86_64_GOTPCREL,
187 R_X86_64_32,
188 R_X86_64_32S,
189 R_X86_64_16,
190 R_X86_64_PC16,
191 R_X86_64_8,
192 R_X86_64_PC8,
193 R_X86_64_DTPMOD64,
194 R_X86_64_DTPOFF64,
195 R_X86_64_TPOFF64,
196 R_X86_64_TLSGD,
197 R_X86_64_TLSLD,
198 R_X86_64_DTPOFF32,
199 R_X86_64_GOTTPOFF,
200 R_X86_64_TPOFF32,
201 R_X86_64_PC64,
202 R_X86_64_GOTOFF64,
203 R_X86_64_GOTPC32,
204 R_X86_64_GOT64,
205 R_X86_64_GOTPCREL64,
206 R_X86_64_GOTPC64,
207 R_X86_64_GOTPLT64,
208 R_X86_64_PLTOFF64,
209 R_X86_64_SIZE32,
210 R_X86_64_SIZE64,
211 R_X86_64_GOTPC32_TLSDESC,
212 R_X86_64_TLSDESC_CALL,
213 R_X86_64_TLSDESC,
214 R_X86_64_IRELATIVE,
215 R_X86_64_RELATIVE64,
216 R_X86_64_GOTPCRELX,
217 R_X86_64_REX_GOTPCRELX,
218 ] {
219 Cow::Borrowed(name)
220 } else {
221 Cow::Owned(format!("Unknown x86_64 relocation type 0x{r_type:x}"))
222 }
223}
224
225#[must_use]
226pub fn aarch64_rel_type_to_string(r_type: u32) -> Cow<'static, str> {
227 if let Some(name) = const_name_by_value![
228 r_type,
229 R_AARCH64_NONE,
230 R_AARCH64_P32_ABS32,
231 R_AARCH64_P32_COPY,
232 R_AARCH64_P32_GLOB_DAT,
233 R_AARCH64_P32_JUMP_SLOT,
234 R_AARCH64_P32_RELATIVE,
235 R_AARCH64_P32_TLS_DTPMOD,
236 R_AARCH64_P32_TLS_DTPREL,
237 R_AARCH64_P32_TLS_TPREL,
238 R_AARCH64_P32_TLSDESC,
239 R_AARCH64_P32_IRELATIVE,
240 R_AARCH64_ABS64,
241 R_AARCH64_ABS32,
242 R_AARCH64_ABS16,
243 R_AARCH64_PREL64,
244 R_AARCH64_PREL32,
245 R_AARCH64_PREL16,
246 R_AARCH64_MOVW_UABS_G0,
247 R_AARCH64_MOVW_UABS_G0_NC,
248 R_AARCH64_MOVW_UABS_G1,
249 R_AARCH64_MOVW_UABS_G1_NC,
250 R_AARCH64_MOVW_UABS_G2,
251 R_AARCH64_MOVW_UABS_G2_NC,
252 R_AARCH64_MOVW_UABS_G3,
253 R_AARCH64_MOVW_SABS_G0,
254 R_AARCH64_MOVW_SABS_G1,
255 R_AARCH64_MOVW_SABS_G2,
256 R_AARCH64_LD_PREL_LO19,
257 R_AARCH64_ADR_PREL_LO21,
258 R_AARCH64_ADR_PREL_PG_HI21,
259 R_AARCH64_ADR_PREL_PG_HI21_NC,
260 R_AARCH64_ADD_ABS_LO12_NC,
261 R_AARCH64_LDST8_ABS_LO12_NC,
262 R_AARCH64_TSTBR14,
263 R_AARCH64_CONDBR19,
264 R_AARCH64_JUMP26,
265 R_AARCH64_CALL26,
266 R_AARCH64_LDST16_ABS_LO12_NC,
267 R_AARCH64_LDST32_ABS_LO12_NC,
268 R_AARCH64_LDST64_ABS_LO12_NC,
269 R_AARCH64_MOVW_PREL_G0,
270 R_AARCH64_MOVW_PREL_G0_NC,
271 R_AARCH64_MOVW_PREL_G1,
272 R_AARCH64_MOVW_PREL_G1_NC,
273 R_AARCH64_MOVW_PREL_G2,
274 R_AARCH64_MOVW_PREL_G2_NC,
275 R_AARCH64_MOVW_PREL_G3,
276 R_AARCH64_LDST128_ABS_LO12_NC,
277 R_AARCH64_MOVW_GOTOFF_G0,
278 R_AARCH64_MOVW_GOTOFF_G0_NC,
279 R_AARCH64_MOVW_GOTOFF_G1,
280 R_AARCH64_MOVW_GOTOFF_G1_NC,
281 R_AARCH64_MOVW_GOTOFF_G2,
282 R_AARCH64_MOVW_GOTOFF_G2_NC,
283 R_AARCH64_MOVW_GOTOFF_G3,
284 R_AARCH64_GOTREL64,
285 R_AARCH64_GOTREL32,
286 R_AARCH64_GOT_LD_PREL19,
287 R_AARCH64_LD64_GOTOFF_LO15,
288 R_AARCH64_ADR_GOT_PAGE,
289 R_AARCH64_LD64_GOT_LO12_NC,
290 R_AARCH64_LD64_GOTPAGE_LO15,
291 R_AARCH64_TLSGD_ADR_PREL21,
292 R_AARCH64_TLSGD_ADR_PAGE21,
293 R_AARCH64_TLSGD_ADD_LO12_NC,
294 R_AARCH64_TLSGD_MOVW_G1,
295 R_AARCH64_TLSGD_MOVW_G0_NC,
296 R_AARCH64_TLSLD_ADR_PREL21,
297 R_AARCH64_TLSLD_ADR_PAGE21,
298 R_AARCH64_TLSLD_ADD_LO12_NC,
299 R_AARCH64_TLSLD_MOVW_G1,
300 R_AARCH64_TLSLD_MOVW_G0_NC,
301 R_AARCH64_TLSLD_LD_PREL19,
302 R_AARCH64_TLSLD_MOVW_DTPREL_G2,
303 R_AARCH64_TLSLD_MOVW_DTPREL_G1,
304 R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC,
305 R_AARCH64_TLSLD_MOVW_DTPREL_G0,
306 R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC,
307 R_AARCH64_TLSLD_ADD_DTPREL_HI12,
308 R_AARCH64_TLSLD_ADD_DTPREL_LO12,
309 R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC,
310 R_AARCH64_TLSLD_LDST8_DTPREL_LO12,
311 R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC,
312 R_AARCH64_TLSLD_LDST16_DTPREL_LO12,
313 R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC,
314 R_AARCH64_TLSLD_LDST32_DTPREL_LO12,
315 R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC,
316 R_AARCH64_TLSLD_LDST64_DTPREL_LO12,
317 R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC,
318 R_AARCH64_TLSIE_MOVW_GOTTPREL_G1,
319 R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC,
320 R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21,
321 R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC,
322 R_AARCH64_TLSIE_LD_GOTTPREL_PREL19,
323 R_AARCH64_TLSLE_MOVW_TPREL_G2,
324 R_AARCH64_TLSLE_MOVW_TPREL_G1,
325 R_AARCH64_TLSLE_MOVW_TPREL_G1_NC,
326 R_AARCH64_TLSLE_MOVW_TPREL_G0,
327 R_AARCH64_TLSLE_MOVW_TPREL_G0_NC,
328 R_AARCH64_TLSLE_ADD_TPREL_HI12,
329 R_AARCH64_TLSLE_ADD_TPREL_LO12,
330 R_AARCH64_TLSLE_ADD_TPREL_LO12_NC,
331 R_AARCH64_TLSLE_LDST8_TPREL_LO12,
332 R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC,
333 R_AARCH64_TLSLE_LDST16_TPREL_LO12,
334 R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC,
335 R_AARCH64_TLSLE_LDST32_TPREL_LO12,
336 R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC,
337 R_AARCH64_TLSLE_LDST64_TPREL_LO12,
338 R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC,
339 R_AARCH64_TLSDESC_LD_PREL19,
340 R_AARCH64_TLSDESC_ADR_PREL21,
341 R_AARCH64_TLSDESC_ADR_PAGE21,
342 R_AARCH64_TLSDESC_LD64_LO12,
343 R_AARCH64_TLSDESC_ADD_LO12,
344 R_AARCH64_TLSDESC_OFF_G1,
345 R_AARCH64_TLSDESC_OFF_G0_NC,
346 R_AARCH64_TLSDESC_LDR,
347 R_AARCH64_TLSDESC_ADD,
348 R_AARCH64_TLSDESC_CALL,
349 R_AARCH64_TLSLE_LDST128_TPREL_LO12,
350 R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC,
351 R_AARCH64_TLSLD_LDST128_DTPREL_LO12,
352 R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC,
353 R_AARCH64_COPY,
354 R_AARCH64_GLOB_DAT,
355 R_AARCH64_JUMP_SLOT,
356 R_AARCH64_RELATIVE,
357 R_AARCH64_TLS_DTPMOD,
358 R_AARCH64_TLS_DTPREL,
359 R_AARCH64_TLS_TPREL,
360 R_AARCH64_TLSDESC,
361 R_AARCH64_IRELATIVE,
362 ] {
363 Cow::Borrowed(name)
364 } else {
365 Cow::Owned(format!("Unknown aarch64 relocation type 0x{r_type:x}"))
366 }
367}
368
369#[must_use]
370pub fn riscv64_rel_type_to_string(r_type: u32) -> Cow<'static, str> {
371 if let Some(name) = const_name_by_value![
372 r_type,
373 R_RISCV_NONE,
374 R_RISCV_32,
375 R_RISCV_64,
376 R_RISCV_RELATIVE,
377 R_RISCV_COPY,
378 R_RISCV_JUMP_SLOT,
379 R_RISCV_TLS_DTPMOD32,
380 R_RISCV_TLS_DTPMOD64,
381 R_RISCV_TLS_DTPREL32,
382 R_RISCV_TLS_DTPREL64,
383 R_RISCV_TLS_TPREL32,
384 R_RISCV_TLS_TPREL64,
385 R_RISCV_TLSDESC,
386 R_RISCV_BRANCH,
387 R_RISCV_JAL,
388 R_RISCV_CALL,
389 R_RISCV_CALL_PLT,
390 R_RISCV_GOT_HI20,
391 R_RISCV_TLS_GOT_HI20,
392 R_RISCV_TLS_GD_HI20,
393 R_RISCV_PCREL_HI20,
394 R_RISCV_PCREL_LO12_I,
395 R_RISCV_PCREL_LO12_S,
396 R_RISCV_HI20,
397 R_RISCV_LO12_I,
398 R_RISCV_LO12_S,
399 R_RISCV_TPREL_HI20,
400 R_RISCV_TPREL_LO12_I,
401 R_RISCV_TPREL_LO12_S,
402 R_RISCV_TPREL_ADD,
403 R_RISCV_ADD8,
404 R_RISCV_ADD16,
405 R_RISCV_ADD32,
406 R_RISCV_ADD64,
407 R_RISCV_SUB8,
408 R_RISCV_SUB16,
409 R_RISCV_SUB32,
410 R_RISCV_SUB64,
411 R_RISCV_GOT32_PCREL,
412 R_RISCV_ALIGN,
413 R_RISCV_RVC_BRANCH,
414 R_RISCV_RVC_JUMP,
415 R_RISCV_RVC_LUI,
416 R_RISCV_GPREL_I,
417 R_RISCV_GPREL_S,
418 R_RISCV_TPREL_I,
419 R_RISCV_TPREL_S,
420 R_RISCV_RELAX,
421 R_RISCV_SUB6,
422 R_RISCV_SET6,
423 R_RISCV_SET8,
424 R_RISCV_SET16,
425 R_RISCV_SET32,
426 R_RISCV_32_PCREL,
427 R_RISCV_IRELATIVE,
428 R_RISCV_PLT32,
429 R_RISCV_SET_ULEB128,
430 R_RISCV_SUB_ULEB128,
431 R_RISCV_TLSDESC_HI20,
432 R_RISCV_TLSDESC_LOAD_LO12,
433 R_RISCV_TLSDESC_ADD_LO12,
434 R_RISCV_TLSDESC_CALL,
435 ] {
436 Cow::Borrowed(name)
437 } else {
438 Cow::Owned(format!("Unknown riscv64 relocation type 0x{r_type:x}"))
439 }
440}
441
442#[must_use]
443pub fn loongarch64_rel_type_to_string(r_type: u32) -> Cow<'static, str> {
444 if let Some(name) = const_name_by_value![
445 r_type,
446 R_LARCH_32,
447 R_LARCH_64,
448 R_LARCH_B16,
449 R_LARCH_CFA,
450 R_LARCH_B21,
451 R_LARCH_B26,
452 R_LARCH_NONE,
453 R_LARCH_ADD6,
454 R_LARCH_SUB8,
455 R_LARCH_COPY,
456 R_LARCH_ADD8,
457 R_LARCH_SUB6,
458 R_LARCH_ADD16,
459 R_LARCH_ADD64,
460 R_LARCH_SUB32,
461 R_LARCH_ADD24,
462 R_LARCH_ADD32,
463 R_LARCH_SUB16,
464 R_LARCH_SUB24,
465 R_LARCH_SOP_SL,
466 R_LARCH_SOP_SR,
467 R_LARCH_SUB64,
468 R_LARCH_RELAX,
469 R_LARCH_ALIGN,
470 R_LARCH_SOP_SUB,
471 R_LARCH_SOP_ADD,
472 R_LARCH_SOP_AND,
473 R_LARCH_MARK_LA,
474 R_LARCH_CALL36,
475 R_LARCH_SOP_NOT,
476 R_LARCH_DELETE,
477 R_LARCH_GOT_HI20,
478 R_LARCH_GOT_LO12,
479 R_LARCH_32_PCREL,
480 R_LARCH_64_PCREL,
481 R_LARCH_ABS_HI20,
482 R_LARCH_ABS_LO12,
483 R_LARCH_JUMP_SLOT,
484 R_LARCH_RELATIVE,
485 R_LARCH_PCREL20_S2,
486 R_LARCH_ABS64_HI12,
487 R_LARCH_ABS64_LO20,
488 R_LARCH_TLS_LD_HI20,
489 R_LARCH_GOT64_HI12,
490 R_LARCH_GOT64_LO20,
491 R_LARCH_TLS_LE_LO12,
492 R_LARCH_GOT_PC_LO12,
493 R_LARCH_TLS_LE_ADD_R,
494 R_LARCH_SOP_POP_32_U,
495 R_LARCH_SOP_IF_ELSE,
496 R_LARCH_TLS_DESC_LD,
497 R_LARCH_SOP_ASSERT,
498 R_LARCH_MARK_PCREL,
499 R_LARCH_PCALA_HI20,
500 R_LARCH_PCALA_LO12,
501 R_LARCH_GOT_PC_HI20,
502 R_LARCH_TLS_LE_HI20,
503 R_LARCH_IRELATIVE,
504 R_LARCH_TLS_GD_HI20,
505 R_LARCH_TLS_IE_HI20,
506 R_LARCH_TLS_IE_LO12,
507 R_LARCH_SOP_PUSH_DUP,
508 R_LARCH_TLS_TPREL32,
509 R_LARCH_TLS_LE_LO12_R,
510 R_LARCH_TLS_TPREL64,
511 R_LARCH_TLS_LE_HI20_R,
512 R_LARCH_GNU_VTENTRY,
513 R_LARCH_SUB_ULEB128,
514 R_LARCH_ADD_ULEB128,
515 R_LARCH_TLS_DTPREL32,
516 R_LARCH_GOT64_PC_HI12,
517 R_LARCH_TLS_GD_PC_HI20,
518 R_LARCH_TLS_IE64_LO20,
519 R_LARCH_TLS_DESC_CALL,
520 R_LARCH_TLS_LE64_LO20,
521 R_LARCH_TLS_DTPMOD32,
522 R_LARCH_PCALA64_LO20,
523 R_LARCH_TLS_DTPMOD64,
524 R_LARCH_TLS_IE64_HI12,
525 R_LARCH_TLS_DTPREL64,
526 R_LARCH_TLS_DESC_HI20,
527 R_LARCH_GOT64_PC_LO20,
528 R_LARCH_TLS_IE_PC_HI20,
529 R_LARCH_TLS_IE_PC_LO12,
530 R_LARCH_TLS_DESC_LO12,
531 R_LARCH_TLS_LE64_HI12,
532 R_LARCH_TLS_LD_PC_HI20,
533 R_LARCH_PCALA64_HI12,
534 R_LARCH_SOP_POP_32_S_10_5,
535 R_LARCH_SOP_PUSH_PCREL,
536 R_LARCH_SOP_POP_32_S_5_20,
537 R_LARCH_SOP_PUSH_GPREL,
538 R_LARCH_SOP_PUSH_TLS_GD,
539 R_LARCH_GNU_VTINHERIT,
540 R_LARCH_TLS_IE64_PC_LO20,
541 R_LARCH_SOP_POP_32_S_10_12,
542 R_LARCH_TLS_DESC_PC_HI20,
543 R_LARCH_TLS_DESC_PC_LO12,
544 R_LARCH_SOP_POP_32_S_10_16,
545 R_LARCH_SOP_POP_32_U_10_12,
546 R_LARCH_TLS_DESC64_HI12,
547 R_LARCH_SOP_PUSH_TLS_GOT,
548 R_LARCH_TLS_IE64_PC_HI12,
549 R_LARCH_TLS_DESC64_LO20,
550 R_LARCH_TLS_LD_PCREL20_S2,
551 R_LARCH_TLS_GD_PCREL20_S2,
552 R_LARCH_TLS_DESC64_PC_HI12,
553 R_LARCH_SOP_PUSH_ABSOLUTE,
554 R_LARCH_TLS_DESC64_PC_LO20,
555 R_LARCH_SOP_PUSH_PLT_PCREL,
556 R_LARCH_SOP_PUSH_TLS_TPREL,
557 R_LARCH_SOP_POP_32_S_10_16_S2,
558 R_LARCH_TLS_DESC_PCREL20_S2,
559 R_LARCH_SOP_POP_32_S_0_5_10_16_S2,
560 R_LARCH_SOP_POP_32_S_0_10_10_16_S2,
561 ] {
562 Cow::Borrowed(name)
563 } else {
564 Cow::Owned(format!("Unknown loongarch relocation type 0x{r_type:x}"))
565 }
566}
567
568pub mod shf {
570 use super::SectionFlags;
571
572 pub const WRITE: SectionFlags = SectionFlags::from_u32(object::elf::SHF_WRITE);
573 pub const ALLOC: SectionFlags = SectionFlags::from_u32(object::elf::SHF_ALLOC);
574 pub const EXECINSTR: SectionFlags = SectionFlags::from_u32(object::elf::SHF_EXECINSTR);
575 pub const MERGE: SectionFlags = SectionFlags::from_u32(object::elf::SHF_MERGE);
576 pub const STRINGS: SectionFlags = SectionFlags::from_u32(object::elf::SHF_STRINGS);
577 pub const INFO_LINK: SectionFlags = SectionFlags::from_u32(object::elf::SHF_INFO_LINK);
578 pub const LINK_ORDER: SectionFlags = SectionFlags::from_u32(object::elf::SHF_LINK_ORDER);
579 pub const OS_NONCONFORMING: SectionFlags =
580 SectionFlags::from_u32(object::elf::SHF_OS_NONCONFORMING);
581 pub const GROUP: SectionFlags = SectionFlags::from_u32(object::elf::SHF_GROUP);
582 pub const TLS: SectionFlags = SectionFlags::from_u32(object::elf::SHF_TLS);
583 pub const COMPRESSED: SectionFlags = SectionFlags::from_u32(object::elf::SHF_COMPRESSED);
584 pub const GNU_RETAIN: SectionFlags = SectionFlags::from_u32(object::elf::SHF_GNU_RETAIN);
585 pub const EXCLUDE: SectionFlags = SectionFlags::from_u32(object::elf::SHF_EXCLUDE);
586}
587
588#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
589pub struct SectionFlags(u32);
590
591impl SectionFlags {
592 #[must_use]
593 pub const fn empty() -> Self {
594 Self(0)
595 }
596
597 #[must_use]
598 pub fn from_header(header: &object::elf::SectionHeader64<LittleEndian>) -> Self {
599 Self(header.sh_flags(LittleEndian) as u32)
600 }
601
602 #[must_use]
603 pub fn contains(self, flag: SectionFlags) -> bool {
604 self.0 & flag.0 != 0
605 }
606
607 #[must_use]
608 pub const fn from_u32(raw: u32) -> SectionFlags {
609 SectionFlags(raw)
610 }
611
612 #[must_use]
614 pub const fn with(self, flags: SectionFlags) -> SectionFlags {
615 SectionFlags(self.0 | flags.0)
616 }
617
618 #[must_use]
620 pub const fn without(self, flags: SectionFlags) -> SectionFlags {
621 SectionFlags(self.0 & !flags.0)
622 }
623
624 #[must_use]
625 pub const fn raw(self) -> u64 {
626 self.0 as u64
627 }
628
629 #[must_use]
630 pub fn should_retain(&self) -> bool {
631 self.contains(shf::GNU_RETAIN)
632 }
633
634 #[must_use]
635 pub fn should_exclude(&self) -> bool {
636 self.contains(shf::EXCLUDE)
637 }
638}
639
640impl From<u64> for SectionFlags {
641 fn from(value: u64) -> Self {
642 Self(value as u32)
643 }
644}
645
646impl std::fmt::Display for SectionFlags {
647 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
648 for (flag, ch) in [
649 (shf::WRITE, "W"),
650 (shf::ALLOC, "A"),
651 (shf::EXECINSTR, "X"),
652 (shf::MERGE, "M"),
653 (shf::STRINGS, "S"),
654 (shf::INFO_LINK, "I"),
655 (shf::LINK_ORDER, "L"),
656 (shf::OS_NONCONFORMING, "O"),
657 (shf::GROUP, "G"),
658 (shf::TLS, "T"),
659 (shf::COMPRESSED, "C"),
660 (shf::EXCLUDE, "E"),
661 ] {
664 if self.contains(flag) {
665 f.write_str(ch)?;
666 }
667 }
668 Ok(())
669 }
670}
671
672impl std::fmt::Debug for SectionFlags {
673 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
674 std::fmt::Display::fmt(&self, f)
675 }
676}
677
678impl std::ops::BitOrAssign for SectionFlags {
679 fn bitor_assign(&mut self, rhs: Self) {
680 self.0 |= rhs.0;
681 }
682}
683
684impl std::ops::BitAnd for SectionFlags {
685 type Output = SectionFlags;
686
687 fn bitand(self, rhs: Self) -> Self::Output {
688 Self(self.0 & rhs.0)
689 }
690}
691
692pub mod secnames {
693 pub const FILEHEADER_SECTION_NAME_STR: &str = "";
694 pub const FILEHEADER_SECTION_NAME: &[u8] = FILEHEADER_SECTION_NAME_STR.as_bytes();
695 pub const RODATA_SECTION_NAME_STR: &str = ".rodata";
696 pub const RODATA_SECTION_NAME: &[u8] = RODATA_SECTION_NAME_STR.as_bytes();
697 pub const TEXT_SECTION_NAME_STR: &str = ".text";
698 pub const TEXT_SECTION_NAME: &[u8] = TEXT_SECTION_NAME_STR.as_bytes();
699 pub const INIT_ARRAY_SECTION_NAME_STR: &str = ".init_array";
700 pub const INIT_ARRAY_SECTION_NAME: &[u8] = INIT_ARRAY_SECTION_NAME_STR.as_bytes();
701 pub const FINI_ARRAY_SECTION_NAME_STR: &str = ".fini_array";
702 pub const FINI_ARRAY_SECTION_NAME: &[u8] = FINI_ARRAY_SECTION_NAME_STR.as_bytes();
703 pub const PREINIT_ARRAY_SECTION_NAME_STR: &str = ".preinit_array";
704 pub const PREINIT_ARRAY_SECTION_NAME: &[u8] = PREINIT_ARRAY_SECTION_NAME_STR.as_bytes();
705 pub const DATA_SECTION_NAME_STR: &str = ".data";
706 pub const DATA_SECTION_NAME: &[u8] = DATA_SECTION_NAME_STR.as_bytes();
707 pub const EH_FRAME_SECTION_NAME_STR: &str = ".eh_frame";
708 pub const EH_FRAME_SECTION_NAME: &[u8] = EH_FRAME_SECTION_NAME_STR.as_bytes();
709 pub const EH_FRAME_HDR_SECTION_NAME_STR: &str = ".eh_frame_hdr";
710 pub const EH_FRAME_HDR_SECTION_NAME: &[u8] = EH_FRAME_HDR_SECTION_NAME_STR.as_bytes();
711 pub const SFRAME_SECTION_NAME_STR: &str = ".sframe";
712 pub const SFRAME_SECTION_NAME: &[u8] = SFRAME_SECTION_NAME_STR.as_bytes();
713 pub const SHSTRTAB_SECTION_NAME_STR: &str = ".shstrtab";
714 pub const SHSTRTAB_SECTION_NAME: &[u8] = SHSTRTAB_SECTION_NAME_STR.as_bytes();
715 pub const SYMTAB_SECTION_NAME_STR: &str = ".symtab";
716 pub const SYMTAB_SECTION_NAME: &[u8] = SYMTAB_SECTION_NAME_STR.as_bytes();
717 pub const STRTAB_SECTION_NAME_STR: &str = ".strtab";
718 pub const STRTAB_SECTION_NAME: &[u8] = STRTAB_SECTION_NAME_STR.as_bytes();
719 pub const TDATA_SECTION_NAME_STR: &str = ".tdata";
720 pub const TDATA_SECTION_NAME: &[u8] = TDATA_SECTION_NAME_STR.as_bytes();
721 pub const TBSS_SECTION_NAME_STR: &str = ".tbss";
722 pub const TBSS_SECTION_NAME: &[u8] = TBSS_SECTION_NAME_STR.as_bytes();
723 pub const BSS_SECTION_NAME_STR: &str = ".bss";
724 pub const BSS_SECTION_NAME: &[u8] = BSS_SECTION_NAME_STR.as_bytes();
725 pub const GOT_SECTION_NAME_STR: &str = ".got";
726 pub const GOT_SECTION_NAME: &[u8] = GOT_SECTION_NAME_STR.as_bytes();
727 pub const INIT_SECTION_NAME_STR: &str = ".init";
728 pub const INIT_SECTION_NAME: &[u8] = INIT_SECTION_NAME_STR.as_bytes();
729 pub const FINI_SECTION_NAME_STR: &str = ".fini";
730 pub const FINI_SECTION_NAME: &[u8] = FINI_SECTION_NAME_STR.as_bytes();
731 pub const RELA_PLT_SECTION_NAME_STR: &str = ".rela.plt";
732 pub const RELA_PLT_SECTION_NAME: &[u8] = RELA_PLT_SECTION_NAME_STR.as_bytes();
733 pub const COMMENT_SECTION_NAME_STR: &str = ".comment";
734 pub const COMMENT_SECTION_NAME: &[u8] = COMMENT_SECTION_NAME_STR.as_bytes();
735 pub const DYNAMIC_SECTION_NAME_STR: &str = ".dynamic";
736 pub const DYNAMIC_SECTION_NAME: &[u8] = DYNAMIC_SECTION_NAME_STR.as_bytes();
737 pub const DYNSYM_SECTION_NAME_STR: &str = ".dynsym";
738 pub const DYNSYM_SECTION_NAME: &[u8] = DYNSYM_SECTION_NAME_STR.as_bytes();
739 pub const DYNSTR_SECTION_NAME_STR: &str = ".dynstr";
740 pub const DYNSTR_SECTION_NAME: &[u8] = DYNSTR_SECTION_NAME_STR.as_bytes();
741 pub const RELA_DYN_SECTION_NAME_STR: &str = ".rela.dyn";
742 pub const RELA_DYN_SECTION_NAME: &[u8] = RELA_DYN_SECTION_NAME_STR.as_bytes();
743 pub const GCC_EXCEPT_TABLE_SECTION_NAME_STR: &str = ".gcc_except_table";
744 pub const GCC_EXCEPT_TABLE_SECTION_NAME: &[u8] = GCC_EXCEPT_TABLE_SECTION_NAME_STR.as_bytes();
745 pub const INTERP_SECTION_NAME_STR: &str = ".interp";
746 pub const INTERP_SECTION_NAME: &[u8] = INTERP_SECTION_NAME_STR.as_bytes();
747 pub const GNU_VERSION_SECTION_NAME_STR: &str = ".gnu.version";
748 pub const GNU_VERSION_SECTION_NAME: &[u8] = GNU_VERSION_SECTION_NAME_STR.as_bytes();
749 pub const GNU_VERSION_D_SECTION_NAME_STR: &str = ".gnu.version_d";
750 pub const GNU_VERSION_D_SECTION_NAME: &[u8] = GNU_VERSION_D_SECTION_NAME_STR.as_bytes();
751 pub const GNU_VERSION_R_SECTION_NAME_STR: &str = ".gnu.version_r";
752 pub const GNU_VERSION_R_SECTION_NAME: &[u8] = GNU_VERSION_R_SECTION_NAME_STR.as_bytes();
753 pub const HASH_SECTION_NAME_STR: &str = ".hash";
754 pub const HASH_SECTION_NAME: &[u8] = HASH_SECTION_NAME_STR.as_bytes();
755 pub const PROGRAM_HEADERS_SECTION_NAME_STR: &str = ".phdr";
756 pub const PROGRAM_HEADERS_SECTION_NAME: &[u8] = PROGRAM_HEADERS_SECTION_NAME_STR.as_bytes();
757 pub const SECTION_HEADERS_SECTION_NAME_STR: &str = ".shdr";
758 pub const SECTION_HEADERS_SECTION_NAME: &[u8] = SECTION_HEADERS_SECTION_NAME_STR.as_bytes();
759 pub const GNU_HASH_SECTION_NAME_STR: &str = ".gnu.hash";
760 pub const GNU_HASH_SECTION_NAME: &[u8] = GNU_HASH_SECTION_NAME_STR.as_bytes();
761 pub const PLT_SECTION_NAME_STR: &str = ".plt";
762 pub const PLT_SECTION_NAME: &[u8] = PLT_SECTION_NAME_STR.as_bytes();
763 pub const IPLT_SECTION_NAME_STR: &str = ".iplt";
764 pub const IPLT_SECTION_NAME: &[u8] = IPLT_SECTION_NAME_STR.as_bytes();
765 pub const PLT_GOT_SECTION_NAME_STR: &str = ".plt.got";
766 pub const PLT_GOT_SECTION_NAME: &[u8] = PLT_GOT_SECTION_NAME_STR.as_bytes();
767 pub const GOT_PLT_SECTION_NAME_STR: &str = ".got.plt";
768 pub const GOT_PLT_SECTION_NAME: &[u8] = GOT_PLT_SECTION_NAME_STR.as_bytes();
769 pub const PLT_SEC_SECTION_NAME_STR: &str = ".plt.sec";
770 pub const PLT_SEC_SECTION_NAME: &[u8] = PLT_SEC_SECTION_NAME_STR.as_bytes();
771 pub const NOTE_ABI_TAG_SECTION_NAME_STR: &str = ".note.ABI-tag";
772 pub const NOTE_ABI_TAG_SECTION_NAME: &[u8] = NOTE_ABI_TAG_SECTION_NAME_STR.as_bytes();
773 pub const NOTE_GNU_PROPERTY_SECTION_NAME_STR: &str = ".note.gnu.property";
774 pub const NOTE_GNU_PROPERTY_SECTION_NAME: &[u8] = NOTE_GNU_PROPERTY_SECTION_NAME_STR.as_bytes();
775 pub const NOTE_GNU_BUILD_ID_SECTION_NAME_STR: &str = ".note.gnu.build-id";
776 pub const NOTE_GNU_BUILD_ID_SECTION_NAME: &[u8] = NOTE_GNU_BUILD_ID_SECTION_NAME_STR.as_bytes();
777 pub const DEBUG_LOC_SECTION_NAME_STR: &str = ".debug_loc";
778 pub const DEBUG_LOC_SECTION_NAME: &[u8] = DEBUG_LOC_SECTION_NAME_STR.as_bytes();
779 pub const DEBUG_RANGES_SECTION_NAME_STR: &str = ".debug_ranges";
780 pub const DEBUG_RANGES_SECTION_NAME: &[u8] = DEBUG_RANGES_SECTION_NAME_STR.as_bytes();
781 pub const GROUP_SECTION_NAME_STR: &str = ".group";
782 pub const GROUP_SECTION_NAME: &[u8] = GROUP_SECTION_NAME_STR.as_bytes();
783 pub const DATA_REL_RO_SECTION_NAME_STR: &str = ".data.rel.ro";
784 pub const DATA_REL_RO_SECTION_NAME: &[u8] = DATA_REL_RO_SECTION_NAME_STR.as_bytes();
785 pub const RISCV_ATTRIBUTES_SECTION_NAME_STR: &str = ".riscv.attributes";
786 pub const RISCV_ATTRIBUTES_SECTION_NAME: &[u8] = RISCV_ATTRIBUTES_SECTION_NAME_STR.as_bytes();
787
788 pub const GNU_LTO_SYMTAB_PREFIX: &str = ".gnu.lto_.symtab";
789}
790
791#[derive(Clone, Copy, PartialEq, Eq)]
792pub struct SegmentFlags(u32);
793
794impl SegmentFlags {
795 #[must_use]
796 pub const fn empty() -> Self {
797 Self(0)
798 }
799
800 #[must_use]
801 pub fn from_header(header: &object::elf::ProgramHeader64<LittleEndian>) -> Self {
802 Self(header.p_flags(LittleEndian))
803 }
804
805 #[must_use]
806 pub fn contains(self, flag: SegmentFlags) -> bool {
807 self.0 & flag.0 != 0
808 }
809
810 #[must_use]
811 pub const fn from_u32(raw: u32) -> SegmentFlags {
812 SegmentFlags(raw)
813 }
814
815 #[must_use]
817 pub const fn with(self, flags: SegmentFlags) -> SegmentFlags {
818 SegmentFlags(self.0 | flags.0)
819 }
820
821 #[must_use]
823 pub const fn without(self, flags: SegmentFlags) -> SegmentFlags {
824 SegmentFlags(self.0 & !flags.0)
825 }
826
827 #[must_use]
828 pub const fn raw(self) -> u32 {
829 self.0
830 }
831}
832
833pub mod pf {
834 use super::SegmentFlags;
835
836 pub const EXECUTABLE: SegmentFlags = SegmentFlags::from_u32(object::elf::PF_X);
837 pub const WRITABLE: SegmentFlags = SegmentFlags::from_u32(object::elf::PF_W);
838 pub const READABLE: SegmentFlags = SegmentFlags::from_u32(object::elf::PF_R);
839}
840
841impl std::fmt::Display for SegmentFlags {
842 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
843 if self.contains(pf::WRITABLE) {
844 f.write_str("W")?;
845 }
846 if self.contains(pf::READABLE) {
847 f.write_str("R")?;
848 }
849 if self.contains(pf::EXECUTABLE) {
850 f.write_str("X")?;
851 }
852 Ok(())
853 }
854}
855
856impl std::fmt::Debug for SegmentFlags {
857 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
858 std::fmt::Display::fmt(&self, f)
859 }
860}
861
862impl std::ops::BitOrAssign for SegmentFlags {
863 fn bitor_assign(&mut self, rhs: Self) {
864 self.0 |= rhs.0;
865 }
866}
867
868impl std::ops::BitAnd for SegmentFlags {
869 type Output = SegmentFlags;
870
871 fn bitand(self, rhs: Self) -> Self::Output {
872 Self(self.0 & rhs.0)
873 }
874}
875
876pub const RISCV_TLS_DTV_OFFSET: u64 = 0x800;
880
881pub const RISCV_ATTRIBUTE_VENDOR_NAME: &str = "riscv";
882
883pub mod riscvattr {
885 pub const TAG_RISCV_WHOLE_FILE: u64 = 1;
887 pub const TAG_RISCV_STACK_ALIGN: u64 = 4;
889 pub const TAG_RISCV_ARCH: u64 = 5;
891 pub const TAG_RISCV_UNALIGNED_ACCESS: u64 = 6;
893 pub const TAG_RISCV_PRIV_SPEC: u64 = 8;
895 pub const TAG_RISCV_PRIV_SPEC_MINOR: u64 = 10;
897 pub const TAG_RISCV_PRIV_SPEC_REVISION: u64 = 12;
899 pub const TAG_RISCV_ATOMIC_ABI: u64 = 14;
901 pub const TAG_RISCV_X3_REG_USAGE: u64 = 16;
903}
904
905#[derive(Clone, Copy, Debug, PartialEq, Eq)]
906pub enum Sign {
907 Signed,
908 Unsigned,
909}
910
911#[derive(Clone, Copy, Debug, PartialEq, Eq)]
915pub enum RelocationKind {
916 Absolute,
918
919 AbsoluteSet,
921
922 AbsoluteSetWord6,
924
925 AbsoluteAddition,
928
929 AbsoluteAdditionWord6,
932
933 AbsoluteSubtraction,
936
937 AbsoluteSubtractionWord6,
940
941 AbsoluteLowPart,
945
946 PairSubtractionULEB128(u32),
953
954 Relative,
956
957 RelativeLoongArchHigh,
960
961 RelativeRiscVLow12,
965
966 SymRelGotBase,
968
969 GotRelGotBase,
971
972 Got,
974
975 PltRelGotBase,
977
978 PltRelative,
980
981 GotRelative,
983
984 GotRelativeLoongArch64,
987
988 TlsGd,
992
993 TlsGdGot,
995
996 TlsGdGotBase,
998
999 TlsLd,
1003
1004 TlsLdGot,
1006
1007 TlsLdGotBase,
1010
1011 DtpOff,
1013
1014 GotTpOff,
1017
1018 GotTpOffLoongArch64,
1022
1023 GotTpOffGot,
1026
1027 GotTpOffGotBase,
1030
1031 TpOff,
1033
1034 TlsDesc,
1036
1037 TlsDescLoongArch64,
1040
1041 TlsDescGot,
1043
1044 TlsDescGotBase,
1046
1047 TlsDescCall,
1050
1051 None,
1054
1055 Alignment,
1057}
1058
1059impl RelocationKind {
1060 #[must_use]
1061 pub fn is_tls(self) -> bool {
1062 matches!(
1063 self,
1064 Self::DtpOff
1065 | Self::GotTpOff
1066 | Self::GotTpOffGotBase
1067 | Self::TlsDesc
1068 | Self::TlsDescCall
1069 | Self::TlsDescGot
1070 | Self::TlsDescGotBase
1071 | Self::TlsGd
1072 | Self::TlsGdGot
1073 | Self::TlsGdGotBase
1074 | Self::TlsLd
1075 | Self::TlsLdGot
1076 | Self::TlsLdGotBase
1077 | Self::TpOff
1078 )
1079 }
1080}
1081
1082#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1083pub enum DynamicRelocationKind {
1084 Copy,
1085 Irelative,
1086 DtpMod,
1087 DtpOff,
1088 TlsDesc,
1089 TpOff,
1090 Relative,
1091 Absolute,
1092 GotEntry,
1093 JumpSlot,
1094}
1095
1096impl DynamicRelocationKind {
1097 #[must_use]
1098 pub fn from_x86_64_r_type(r_type: u32) -> Option<Self> {
1099 let kind = match r_type {
1100 object::elf::R_X86_64_COPY => DynamicRelocationKind::Copy,
1101 object::elf::R_X86_64_IRELATIVE => DynamicRelocationKind::Irelative,
1102 object::elf::R_X86_64_DTPMOD64 => DynamicRelocationKind::DtpMod,
1103 object::elf::R_X86_64_DTPOFF64 => DynamicRelocationKind::DtpOff,
1104 object::elf::R_X86_64_TPOFF64 => DynamicRelocationKind::TpOff,
1105 object::elf::R_X86_64_RELATIVE => DynamicRelocationKind::Relative,
1106 object::elf::R_X86_64_GLOB_DAT => DynamicRelocationKind::GotEntry,
1107 object::elf::R_X86_64_64 => DynamicRelocationKind::Absolute,
1108 object::elf::R_X86_64_TLSDESC => DynamicRelocationKind::TlsDesc,
1109 object::elf::R_X86_64_JUMP_SLOT => DynamicRelocationKind::JumpSlot,
1110 _ => return None,
1111 };
1112
1113 Some(kind)
1114 }
1115
1116 #[must_use]
1117 pub fn x86_64_r_type(self) -> u32 {
1118 match self {
1119 DynamicRelocationKind::Copy => object::elf::R_X86_64_COPY,
1120 DynamicRelocationKind::Irelative => object::elf::R_X86_64_IRELATIVE,
1121 DynamicRelocationKind::DtpMod => object::elf::R_X86_64_DTPMOD64,
1122 DynamicRelocationKind::DtpOff => object::elf::R_X86_64_DTPOFF64,
1123 DynamicRelocationKind::TpOff => object::elf::R_X86_64_TPOFF64,
1124 DynamicRelocationKind::Relative => object::elf::R_X86_64_RELATIVE,
1125 DynamicRelocationKind::Absolute => object::elf::R_X86_64_64,
1126 DynamicRelocationKind::GotEntry => object::elf::R_X86_64_GLOB_DAT,
1127 DynamicRelocationKind::TlsDesc => object::elf::R_X86_64_TLSDESC,
1128 DynamicRelocationKind::JumpSlot => object::elf::R_X86_64_JUMP_SLOT,
1129 }
1130 }
1131
1132 #[must_use]
1133 pub fn from_aarch64_r_type(r_type: u32) -> Option<Self> {
1134 let kind = match r_type {
1135 object::elf::R_AARCH64_COPY => DynamicRelocationKind::Copy,
1136 object::elf::R_AARCH64_IRELATIVE => DynamicRelocationKind::Irelative,
1137 object::elf::R_AARCH64_TLS_DTPMOD => DynamicRelocationKind::DtpMod,
1138 object::elf::R_AARCH64_TLS_DTPREL => DynamicRelocationKind::DtpOff,
1139 object::elf::R_AARCH64_TLS_TPREL => DynamicRelocationKind::TpOff,
1140 object::elf::R_AARCH64_RELATIVE => DynamicRelocationKind::Relative,
1141 object::elf::R_AARCH64_ABS64 => DynamicRelocationKind::Absolute,
1142 object::elf::R_AARCH64_GLOB_DAT => DynamicRelocationKind::GotEntry,
1143 object::elf::R_AARCH64_TLSDESC => DynamicRelocationKind::TlsDesc,
1144 object::elf::R_AARCH64_JUMP_SLOT => DynamicRelocationKind::JumpSlot,
1145 _ => return None,
1146 };
1147
1148 Some(kind)
1149 }
1150
1151 #[must_use]
1152 pub fn aarch64_r_type(&self) -> u32 {
1153 match self {
1154 DynamicRelocationKind::Copy => object::elf::R_AARCH64_COPY,
1155 DynamicRelocationKind::Irelative => object::elf::R_AARCH64_IRELATIVE,
1156 DynamicRelocationKind::DtpMod => object::elf::R_AARCH64_TLS_DTPMOD,
1157 DynamicRelocationKind::DtpOff => object::elf::R_AARCH64_TLS_DTPREL,
1158 DynamicRelocationKind::TpOff => object::elf::R_AARCH64_TLS_TPREL,
1159 DynamicRelocationKind::Relative => object::elf::R_AARCH64_RELATIVE,
1160 DynamicRelocationKind::Absolute => object::elf::R_AARCH64_ABS64,
1161 DynamicRelocationKind::GotEntry => object::elf::R_AARCH64_GLOB_DAT,
1162 DynamicRelocationKind::TlsDesc => object::elf::R_AARCH64_TLSDESC,
1163 DynamicRelocationKind::JumpSlot => object::elf::R_AARCH64_JUMP_SLOT,
1164 }
1165 }
1166
1167 #[must_use]
1168 pub fn from_riscv64_r_type(r_type: u32) -> Option<Self> {
1169 let kind = match r_type {
1170 object::elf::R_RISCV_COPY => DynamicRelocationKind::Copy,
1171 object::elf::R_RISCV_IRELATIVE => DynamicRelocationKind::Irelative,
1172 object::elf::R_RISCV_TLS_DTPMOD64 => DynamicRelocationKind::DtpMod,
1173 object::elf::R_RISCV_TLS_DTPREL64 => DynamicRelocationKind::DtpOff,
1174 object::elf::R_RISCV_TLS_TPREL64 => DynamicRelocationKind::TpOff,
1175 object::elf::R_RISCV_RELATIVE => DynamicRelocationKind::Relative,
1176 object::elf::R_RISCV_64 => DynamicRelocationKind::Absolute,
1177 object::elf::R_RISCV_TLSDESC => DynamicRelocationKind::TlsDesc,
1178 object::elf::R_RISCV_JUMP_SLOT => DynamicRelocationKind::JumpSlot,
1179 _ => return None,
1180 };
1181 Some(kind)
1182 }
1183
1184 #[must_use]
1185 pub fn riscv64_r_type(&self) -> u32 {
1186 match self {
1187 DynamicRelocationKind::Copy => object::elf::R_RISCV_COPY,
1188 DynamicRelocationKind::Irelative => object::elf::R_RISCV_IRELATIVE,
1189 DynamicRelocationKind::DtpMod => object::elf::R_RISCV_TLS_DTPMOD64,
1190 DynamicRelocationKind::DtpOff => object::elf::R_RISCV_TLS_DTPREL64,
1191 DynamicRelocationKind::TpOff => object::elf::R_RISCV_TLS_TPREL64,
1192 DynamicRelocationKind::Relative => object::elf::R_RISCV_RELATIVE,
1193 DynamicRelocationKind::Absolute => object::elf::R_RISCV_64,
1194 DynamicRelocationKind::GotEntry => object::elf::R_RISCV_64,
1195 DynamicRelocationKind::TlsDesc => object::elf::R_RISCV_TLSDESC,
1196 DynamicRelocationKind::JumpSlot => object::elf::R_RISCV_JUMP_SLOT,
1197 }
1198 }
1199
1200 #[must_use]
1201 pub fn from_loongarch64_r_type(r_type: u32) -> Option<Self> {
1202 let kind = match r_type {
1203 object::elf::R_LARCH_COPY => DynamicRelocationKind::Copy,
1204 object::elf::R_LARCH_IRELATIVE => DynamicRelocationKind::Irelative,
1205 object::elf::R_LARCH_TLS_DTPMOD64 => DynamicRelocationKind::DtpMod,
1206 object::elf::R_LARCH_TLS_DTPREL64 => DynamicRelocationKind::DtpOff,
1207 object::elf::R_LARCH_TLS_TPREL64 => DynamicRelocationKind::TpOff,
1208 object::elf::R_LARCH_RELATIVE => DynamicRelocationKind::Relative,
1209 object::elf::R_LARCH_64 => DynamicRelocationKind::Absolute,
1210 object::elf::R_LARCH_TLS_DESC64 => DynamicRelocationKind::TlsDesc,
1211 object::elf::R_LARCH_JUMP_SLOT => DynamicRelocationKind::JumpSlot,
1212 _ => return None,
1213 };
1214 Some(kind)
1215 }
1216
1217 #[must_use]
1218 pub fn loongarch64_r_type(&self) -> u32 {
1219 match self {
1220 DynamicRelocationKind::Copy => object::elf::R_LARCH_COPY,
1221 DynamicRelocationKind::Irelative => object::elf::R_LARCH_IRELATIVE,
1222 DynamicRelocationKind::DtpMod => object::elf::R_LARCH_TLS_DTPMOD64,
1223 DynamicRelocationKind::DtpOff => object::elf::R_LARCH_TLS_DTPREL64,
1224 DynamicRelocationKind::TpOff => object::elf::R_LARCH_TLS_TPREL64,
1225 DynamicRelocationKind::Relative => object::elf::R_LARCH_RELATIVE,
1226 DynamicRelocationKind::Absolute => object::elf::R_LARCH_64,
1227 DynamicRelocationKind::GotEntry => object::elf::R_LARCH_64,
1228 DynamicRelocationKind::TlsDesc => object::elf::R_LARCH_TLS_DESC64,
1229 DynamicRelocationKind::JumpSlot => object::elf::R_LARCH_JUMP_SLOT,
1230 }
1231 }
1232}
1233
1234#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1235pub enum AArch64Instruction {
1236 Adr,
1237 Movkz,
1238 Movnz,
1239 Ldr,
1240 LdrRegister,
1241 Add,
1242 LdSt,
1243 TstBr,
1244 Bcond,
1245 JumpCall,
1246}
1247
1248#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1249pub enum RiscVInstruction {
1250 UiType,
1257
1258 UType,
1260
1261 IType,
1263
1264 SType,
1266
1267 BType,
1272
1273 JType,
1275
1276 CbType,
1279
1280 CjType,
1282}
1283
1284#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1285pub enum LoongArch64Instruction {
1286 Shift5,
1287 Shift10,
1288 Branch21or26,
1289 Call30,
1290 Call36,
1291}
1292
1293#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1294pub enum RelocationInstruction {
1295 AArch64(AArch64Instruction),
1296 RiscV(RiscVInstruction),
1297 LoongArch64(LoongArch64Instruction),
1298}
1299
1300impl RelocationInstruction {
1301 #[must_use]
1302 pub fn bit_mask(&self, range: BitRange) -> [u8; 4] {
1303 let mut mask = [0; 4];
1304
1305 let all_ones = (1 << (range.end - range.start)) - 1;
1308 self.write_to_value(all_ones, false, &mut mask);
1309
1310 for b in &mut mask {
1312 *b = !*b;
1313 }
1314
1315 mask
1316 }
1317
1318 pub fn write_to_value(self, extracted_value: u64, negative: bool, dest: &mut [u8]) {
1319 match self {
1320 Self::AArch64(insn) => insn.write_to_value(extracted_value, negative, dest),
1321 Self::RiscV(insn) => insn.write_to_value(extracted_value, negative, dest),
1322 Self::LoongArch64(insn) => insn.write_to_value(extracted_value, negative, dest),
1323 }
1324 }
1325
1326 #[must_use]
1329 pub fn read_value(self, bytes: &[u8]) -> (u64, bool) {
1330 match self {
1331 Self::AArch64(insn) => insn.read_value(bytes),
1332 Self::RiscV(insn) => insn.read_value(bytes),
1333 Self::LoongArch64(insn) => insn.read_value(bytes),
1334 }
1335 }
1336
1337 #[must_use]
1339 pub fn write_windows_size(self) -> usize {
1340 match self {
1341 Self::AArch64(..) => 4,
1342 Self::RiscV(..) => 4,
1343 Self::LoongArch64(..) => 4,
1344 }
1345 }
1346}
1347
1348#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1349pub enum RelocationSize {
1350 ByteSize(usize),
1351 BitMasking(BitMask),
1352}
1353
1354impl fmt::Display for RelocationSize {
1355 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1356 match self {
1357 Self::ByteSize(bytes) => f.write_fmt(format_args!("{bytes}B")),
1358 Self::BitMasking(mask) => {
1359 f.write_fmt(format_args!("{}..{}", mask.range.start, mask.range.end))
1360 }
1361 }
1362 }
1363}
1364
1365impl RelocationSize {
1366 pub(crate) const fn bit_mask_aarch64(
1367 bit_start: u32,
1368 bit_end: u32,
1369 instruction: AArch64Instruction,
1370 ) -> RelocationSize {
1371 Self::BitMasking(BitMask::new(
1372 RelocationInstruction::AArch64(instruction),
1373 bit_start,
1374 bit_end,
1375 ))
1376 }
1377
1378 pub(crate) const fn bit_mask_riscv(
1379 bit_start: u32,
1380 bit_end: u32,
1381 instruction: RiscVInstruction,
1382 ) -> RelocationSize {
1383 Self::BitMasking(BitMask::new(
1384 RelocationInstruction::RiscV(instruction),
1385 bit_start,
1386 bit_end,
1387 ))
1388 }
1389
1390 pub(crate) const fn bit_mask_loongarch64(
1391 bit_start: u32,
1392 bit_end: u32,
1393 instruction: LoongArch64Instruction,
1394 ) -> RelocationSize {
1395 Self::BitMasking(BitMask::new(
1396 RelocationInstruction::LoongArch64(instruction),
1397 bit_start,
1398 bit_end,
1399 ))
1400 }
1401}
1402
1403#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1404pub struct BitMask {
1405 pub instruction: RelocationInstruction,
1406 pub range: BitRange,
1407}
1408
1409pub const SIZE_2KB: u64 = 1 << 11;
1410pub const SIZE_4KB: u64 = 1 << 12;
1411pub const SIZE_2GB: u64 = 1 << 31;
1412pub const SIZE_4GB: u64 = 1 << 32;
1413
1414pub const PAGE_MASK_4KB: u64 = SIZE_4KB - 1;
1415pub const PAGE_MASK_4GB: u64 = SIZE_4GB - 1;
1416
1417#[derive(Debug, Clone, Copy)]
1418pub enum PageMask {
1419 SymbolPlusAddendAndPosition(u64),
1420 GotEntryAndPosition(u64),
1421 GotBase(u64),
1422 Position(u64),
1423}
1424
1425#[derive(Clone, Debug, Copy, PartialEq)]
1427pub struct AllowedRange {
1428 pub min: i64,
1429 pub max: i64,
1430}
1431
1432impl AllowedRange {
1433 #[must_use]
1434 pub const fn new(min: i64, max: i64) -> Self {
1435 Self { min, max }
1436 }
1437
1438 #[must_use]
1439 pub const fn no_check() -> Self {
1440 Self::new(i64::MIN, i64::MAX)
1441 }
1442
1443 #[must_use]
1444 pub const fn from_byte_size(n_bytes: usize, sign: Sign) -> Self {
1447 match n_bytes {
1448 0 | 8 => Self::no_check(),
1449 1..=7 => {
1450 let bits = n_bytes * 8;
1451 let half_range = 1i64 << (bits - 1);
1452 match sign {
1453 Sign::Unsigned => Self::new(0, half_range * 2 - 1),
1454 Sign::Signed => Self::new(-half_range, half_range - 1),
1455 }
1456 }
1457 _ => panic!("Only sizes up to 8 bytes are supported"),
1458 }
1459 }
1460}
1461
1462#[derive(Clone, Debug, Copy)]
1463pub struct RelocationKindInfo {
1464 pub kind: RelocationKind,
1465 pub size: RelocationSize,
1466 pub mask: Option<PageMask>,
1467 pub range: AllowedRange,
1468 pub alignment: usize,
1469 pub bias: u64,
1470}
1471
1472impl RelocationKindInfo {
1473 #[inline(always)]
1474 pub fn verify(&self, value: i64) -> Result<()> {
1475 anyhow::ensure!(
1476 (value as usize) & (self.alignment - 1) == 0,
1477 "Relocation {value} not aligned to {} bytes",
1478 self.alignment
1479 );
1480 anyhow::ensure!(
1481 self.range.min <= value && value < self.range.max,
1482 format!(
1483 "Relocation {value} outside of bounds [{}, {})",
1484 self.range.min, self.range.max
1485 )
1486 );
1487 Ok(())
1488 }
1489}
1490
1491impl BitMask {
1492 #[must_use]
1493 pub const fn new(instruction: RelocationInstruction, bit_start: u32, bit_end: u32) -> Self {
1494 Self {
1495 instruction,
1496 range: BitRange {
1497 start: bit_start,
1498 end: bit_end,
1499 },
1500 }
1501 }
1502}
1503
1504#[cfg(test)]
1505mod tests {
1506 use super::*;
1507 use object::elf::*;
1508
1509 #[test]
1510 fn test_rel_type_to_string() {
1511 assert_eq!(
1512 &x86_64_rel_type_to_string(R_X86_64_32),
1513 stringify!(R_X86_64_32)
1514 );
1515 assert_eq!(
1516 &x86_64_rel_type_to_string(R_X86_64_GOTPC32_TLSDESC),
1517 stringify!(R_X86_64_GOTPC32_TLSDESC)
1518 );
1519 assert_eq!(
1520 &x86_64_rel_type_to_string(64),
1521 "Unknown x86_64 relocation type 0x40"
1522 );
1523
1524 assert_eq!(
1525 &aarch64_rel_type_to_string(64),
1526 "Unknown aarch64 relocation type 0x40"
1527 );
1528 }
1529
1530 #[test]
1531 fn test_range_from_byte_size() {
1532 assert_eq!(
1533 AllowedRange::from_byte_size(0, Sign::Signed),
1534 AllowedRange::no_check(),
1535 );
1536 assert_eq!(
1537 AllowedRange::from_byte_size(0, Sign::Unsigned),
1538 AllowedRange::no_check(),
1539 );
1540 assert_eq!(
1541 AllowedRange::from_byte_size(1, Sign::Signed),
1542 AllowedRange::new(-128, 127)
1543 );
1544 assert_eq!(
1545 AllowedRange::from_byte_size(1, Sign::Unsigned),
1546 AllowedRange::new(0, 255)
1547 );
1548 assert_eq!(
1549 AllowedRange::from_byte_size(4, Sign::Signed),
1550 AllowedRange::new(i32::MIN.into(), i32::MAX.into())
1551 );
1552 assert_eq!(
1553 AllowedRange::from_byte_size(4, Sign::Unsigned),
1554 AllowedRange::new(u32::MIN.into(), u32::MAX.into())
1555 );
1556 assert_eq!(
1557 AllowedRange::from_byte_size(8, Sign::Signed),
1558 AllowedRange::no_check()
1559 );
1560 assert_eq!(
1562 AllowedRange::from_byte_size(8, Sign::Unsigned),
1563 AllowedRange::no_check()
1564 );
1565 }
1566}