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