Skip to main content

gen_elf/arch/
mod.rs

1use crate::common::RelocType;
2use object::Architecture;
3use object::elf::*;
4
5pub mod aarch64;
6pub mod arm;
7pub mod loongarch64;
8pub mod riscv32;
9pub mod riscv64;
10pub mod x86;
11pub mod x86_64;
12
13/// Supported CPU architectures for ELF generation.
14#[derive(Clone, Copy, Debug, PartialEq)]
15pub enum Arch {
16    X86_64,
17    X86,
18    Aarch64,
19    Riscv64,
20    Riscv32,
21    Arm,
22    Loongarch64,
23}
24
25impl Arch {
26    /// Returns the architecture of the current host.
27    pub fn current() -> Self {
28        #[cfg(target_arch = "x86_64")]
29        return Arch::X86_64;
30        #[cfg(target_arch = "x86")]
31        return Arch::X86;
32        #[cfg(target_arch = "aarch64")]
33        return Arch::Aarch64;
34        #[cfg(target_arch = "riscv64")]
35        return Arch::Riscv64;
36        #[cfg(target_arch = "riscv32")]
37        return Arch::Riscv32;
38        #[cfg(target_arch = "arm")]
39        return Arch::Arm;
40        #[cfg(target_arch = "loongarch64")]
41        return Arch::Loongarch64;
42        #[cfg(not(any(
43            target_arch = "x86_64",
44            target_arch = "x86",
45            target_arch = "aarch64",
46            target_arch = "riscv64",
47            target_arch = "riscv32",
48            target_arch = "arm",
49            target_arch = "loongarch64"
50        )))]
51        panic!("Unsupported architecture");
52    }
53
54    /// Returns true if the architecture is 64-bit.
55    pub fn is_64(&self) -> bool {
56        match self {
57            Arch::X86_64 | Arch::Aarch64 | Arch::Riscv64 | Arch::Loongarch64 => true,
58            Arch::X86 | Arch::Riscv32 | Arch::Arm => false,
59        }
60    }
61
62    /// Returns true if the architecture uses RELA (with addend) relocations.
63    pub fn is_rela(&self) -> bool {
64        match self {
65            Arch::X86_64 | Arch::Aarch64 | Arch::Riscv64 | Arch::Riscv32 | Arch::Loongarch64 => {
66                true
67            }
68            Arch::X86 | Arch::Arm => false,
69        }
70    }
71
72    /// Returns the architecture-specific JUMP_SLOT relocation type.
73    pub fn jump_slot_reloc(&self) -> u32 {
74        match self {
75            Arch::X86_64 => R_X86_64_JUMP_SLOT,
76            Arch::X86 => R_386_JMP_SLOT,
77            Arch::Aarch64 => R_AARCH64_JUMP_SLOT,
78            Arch::Arm => R_ARM_JUMP_SLOT,
79            Arch::Riscv64 | Arch::Riscv32 => R_RISCV_JUMP_SLOT,
80            Arch::Loongarch64 => R_LARCH_JUMP_SLOT,
81        }
82    }
83
84    /// Returns the architecture-specific GLOB_DAT relocation type.
85    pub fn glob_dat_reloc(&self) -> u32 {
86        match self {
87            Arch::X86_64 => R_X86_64_GLOB_DAT,
88            Arch::X86 => R_386_GLOB_DAT,
89            Arch::Aarch64 => R_AARCH64_GLOB_DAT,
90            Arch::Arm => R_ARM_GLOB_DAT,
91            Arch::Riscv64 => R_RISCV_64,
92            Arch::Riscv32 => R_RISCV_32,
93            Arch::Loongarch64 => R_LARCH_64,
94        }
95    }
96
97    /// Returns the architecture-specific RELATIVE relocation type.
98    pub fn relative_reloc(&self) -> u32 {
99        match self {
100            Arch::X86_64 => R_X86_64_RELATIVE,
101            Arch::X86 => R_386_RELATIVE,
102            Arch::Aarch64 => R_AARCH64_RELATIVE,
103            Arch::Riscv64 | Arch::Riscv32 => R_RISCV_RELATIVE,
104            Arch::Arm => R_ARM_RELATIVE,
105            Arch::Loongarch64 => R_LARCH_RELATIVE,
106        }
107    }
108
109    pub fn irelative_reloc(&self) -> u32 {
110        match self {
111            Arch::X86_64 => R_X86_64_IRELATIVE,
112            Arch::X86 => R_386_IRELATIVE,
113            Arch::Aarch64 => R_AARCH64_IRELATIVE,
114            Arch::Arm => R_ARM_IRELATIVE,
115            Arch::Riscv64 | Arch::Riscv32 => R_RISCV_IRELATIVE,
116            Arch::Loongarch64 => R_LARCH_IRELATIVE,
117        }
118    }
119
120    pub fn abs_reloc(&self) -> u32 {
121        match self {
122            Arch::X86_64 => R_X86_64_64,
123            Arch::X86 => R_386_32,
124            Arch::Aarch64 => R_AARCH64_ABS64,
125            Arch::Riscv64 => R_RISCV_64,
126            Arch::Riscv32 => R_RISCV_32,
127            Arch::Arm => R_ARM_ABS32,
128            Arch::Loongarch64 => R_LARCH_64,
129        }
130    }
131
132    pub fn copy_reloc(&self) -> u32 {
133        match self {
134            Arch::X86_64 => R_X86_64_COPY,
135            Arch::X86 => R_386_COPY,
136            Arch::Aarch64 => R_AARCH64_COPY,
137            Arch::Arm => R_ARM_COPY,
138            Arch::Riscv64 | Arch::Riscv32 => R_RISCV_COPY,
139            Arch::Loongarch64 => R_LARCH_COPY,
140        }
141    }
142
143    pub fn dtpmod_reloc(&self) -> u32 {
144        match self {
145            Arch::X86_64 => R_X86_64_DTPMOD64,
146            Arch::X86 => R_386_TLS_DTPMOD32,
147            Arch::Aarch64 => R_AARCH64_TLS_DTPMOD,
148            Arch::Arm => R_ARM_TLS_DTPMOD32,
149            Arch::Riscv64 => R_RISCV_TLS_DTPMOD64,
150            Arch::Riscv32 => R_RISCV_TLS_DTPMOD32,
151            Arch::Loongarch64 => R_LARCH_TLS_DTPMOD64,
152        }
153    }
154
155    pub fn dtpoff_reloc(&self) -> u32 {
156        match self {
157            Arch::X86_64 => R_X86_64_DTPOFF64,
158            Arch::X86 => R_386_TLS_DTPOFF32,
159            Arch::Aarch64 => R_AARCH64_TLS_DTPREL,
160            Arch::Arm => R_ARM_TLS_DTPOFF32,
161            Arch::Riscv64 => R_RISCV_TLS_DTPREL64,
162            Arch::Riscv32 => R_RISCV_TLS_DTPREL32,
163            Arch::Loongarch64 => R_LARCH_TLS_DTPREL64,
164        }
165    }
166}
167
168impl From<Arch> for Architecture {
169    fn from(arch: Arch) -> Self {
170        match arch {
171            Arch::X86_64 => Architecture::X86_64,
172            Arch::X86 => Architecture::I386,
173            Arch::Aarch64 => Architecture::Aarch64,
174            Arch::Riscv64 => Architecture::Riscv64,
175            Arch::Riscv32 => Architecture::Riscv32,
176            Arch::Arm => Architecture::Arm,
177            Arch::Loongarch64 => Architecture::LoongArch64,
178        }
179    }
180}
181
182impl RelocType {
183    /// Check if a relocation is a PLT-related type for the given architecture
184    pub(crate) fn is_plt_reloc(&self, arch: Arch) -> bool {
185        let r_type = self.as_u32();
186        match arch {
187            Arch::X86_64 => r_type == R_X86_64_JUMP_SLOT,
188            Arch::X86 => r_type == R_386_JMP_SLOT,
189            Arch::Aarch64 => r_type == R_AARCH64_JUMP_SLOT,
190            Arch::Arm => r_type == R_ARM_JUMP_SLOT,
191            Arch::Riscv64 => r_type == R_RISCV_JUMP_SLOT,
192            Arch::Riscv32 => r_type == R_RISCV_JUMP_SLOT,
193            Arch::Loongarch64 => r_type == R_LARCH_JUMP_SLOT,
194        }
195    }
196
197    pub(crate) fn is_irelative_reloc(&self, arch: Arch) -> bool {
198        let r_type = self.as_u32();
199        match arch {
200            Arch::X86_64 => r_type == R_X86_64_IRELATIVE,
201            Arch::X86 => r_type == R_386_IRELATIVE,
202            Arch::Aarch64 => r_type == R_AARCH64_IRELATIVE,
203            Arch::Arm => r_type == R_ARM_IRELATIVE,
204            Arch::Riscv64 => r_type == R_RISCV_IRELATIVE,
205            Arch::Riscv32 => r_type == R_RISCV_IRELATIVE,
206            Arch::Loongarch64 => r_type == R_LARCH_IRELATIVE,
207        }
208    }
209
210    /// Check if a relocation is RELATIVE type (doesn't depend on symbols)
211    pub(crate) fn is_relative_reloc(&self, arch: Arch) -> bool {
212        let r_type = self.as_u32();
213        match arch {
214            Arch::X86_64 => r_type == R_X86_64_RELATIVE,
215            Arch::X86 => r_type == R_386_RELATIVE,
216            Arch::Aarch64 => r_type == R_AARCH64_RELATIVE,
217            Arch::Riscv64 | Arch::Riscv32 => r_type == R_RISCV_RELATIVE,
218            Arch::Arm => r_type == R_ARM_RELATIVE,
219            Arch::Loongarch64 => r_type == R_LARCH_RELATIVE,
220        }
221    }
222
223    pub(crate) fn is_abs_reloc(&self, arch: Arch) -> bool {
224        let r_type = self.as_u32();
225        match arch {
226            Arch::X86_64 => r_type == R_X86_64_64,
227            Arch::X86 => r_type == R_386_32,
228            Arch::Aarch64 => r_type == R_AARCH64_ABS64,
229            Arch::Riscv64 => r_type == R_RISCV_64,
230            Arch::Riscv32 => r_type == R_RISCV_32,
231            Arch::Arm => r_type == R_ARM_ABS32,
232            Arch::Loongarch64 => r_type == R_LARCH_64,
233        }
234    }
235
236    pub(crate) fn is_glob_dat_reloc(&self, arch: Arch) -> bool {
237        let r_type = self.as_u32();
238        match arch {
239            Arch::X86_64 => r_type == R_X86_64_GLOB_DAT,
240            Arch::X86 => r_type == R_386_GLOB_DAT,
241            Arch::Aarch64 => r_type == R_AARCH64_GLOB_DAT,
242            Arch::Arm => r_type == R_ARM_GLOB_DAT,
243            Arch::Riscv64 => r_type == R_RISCV_64,
244            Arch::Riscv32 => r_type == R_RISCV_32,
245            Arch::Loongarch64 => r_type == R_LARCH_64,
246        }
247    }
248
249    pub(crate) fn is_copy_reloc(&self, arch: Arch) -> bool {
250        let r_type = self.as_u32();
251        match arch {
252            Arch::X86_64 => r_type == R_X86_64_COPY,
253            Arch::X86 => r_type == R_386_COPY,
254            Arch::Aarch64 => r_type == R_AARCH64_COPY,
255            Arch::Arm => r_type == R_ARM_COPY,
256            Arch::Riscv64 | Arch::Riscv32 => r_type == R_RISCV_COPY,
257            Arch::Loongarch64 => r_type == R_LARCH_COPY,
258        }
259    }
260
261    pub(crate) fn is_tls_reloc(&self, arch: Arch) -> bool {
262        let r_type = self.as_u32();
263        match arch {
264            Arch::X86_64 => {
265                r_type == R_X86_64_DTPMOD64
266                    || r_type == R_X86_64_DTPOFF64
267                    || r_type == R_X86_64_TPOFF64
268            }
269            Arch::X86 => {
270                r_type == R_386_TLS_DTPMOD32
271                    || r_type == R_386_TLS_DTPOFF32
272                    || r_type == R_386_TLS_TPOFF
273            }
274            Arch::Aarch64 => {
275                r_type == R_AARCH64_TLS_DTPMOD
276                    || r_type == R_AARCH64_TLS_DTPREL
277                    || r_type == R_AARCH64_TLS_TPREL
278            }
279            Arch::Arm => {
280                r_type == R_ARM_TLS_DTPMOD32
281                    || r_type == R_ARM_TLS_DTPOFF32
282                    || r_type == R_ARM_TLS_TPOFF32
283            }
284            Arch::Riscv64 => {
285                r_type == R_RISCV_TLS_DTPMOD64
286                    || r_type == R_RISCV_TLS_DTPREL64
287                    || r_type == R_RISCV_TLS_TPREL64
288            }
289            Arch::Riscv32 => {
290                r_type == R_RISCV_TLS_DTPMOD32
291                    || r_type == R_RISCV_TLS_DTPREL32
292                    || r_type == R_RISCV_TLS_TPREL32
293            }
294            Arch::Loongarch64 => {
295                r_type == R_LARCH_TLS_DTPMOD64
296                    || r_type == R_LARCH_TLS_DTPREL64
297                    || r_type == R_LARCH_TLS_TPREL64
298            }
299        }
300    }
301}
302
303/// Calculate addend value for a relocation based on type and section virtual addresses
304pub(crate) fn calculate_addend(
305    arch: Arch,
306    r_type: RelocType,
307    reloc_offset: u64,
308    data_vaddr: u64,
309    sym_value: u64,
310) -> i64 {
311    if r_type.is_glob_dat_reloc(arch) {
312        0
313    } else if r_type.is_abs_reloc(arch) {
314        (sym_value + 0x10) as i64
315    } else if r_type.is_plt_reloc(arch) || r_type.is_copy_reloc(arch) || r_type.is_tls_reloc(arch) {
316        0
317    } else if r_type.is_relative_reloc(arch) {
318        if sym_value != 0 {
319            sym_value as i64
320        } else {
321            data_vaddr as i64
322        }
323    } else {
324        reloc_offset as i64
325    }
326}
327
328pub fn generate_helper_code(arch: Arch) -> Vec<u8> {
329    match arch {
330        Arch::X86_64 => x86_64::generate_helper_code(),
331        Arch::X86 => x86::generate_helper_code(),
332        Arch::Aarch64 => aarch64::generate_helper_code(),
333        Arch::Arm => arm::generate_helper_code(),
334        Arch::Riscv64 => riscv64::generate_helper_code(),
335        Arch::Riscv32 => riscv32::generate_helper_code(),
336        Arch::Loongarch64 => loongarch64::generate_helper_code(),
337    }
338}
339
340pub fn generate_tls_helper_code(arch: Arch) -> Vec<u8> {
341    match arch {
342        Arch::X86_64 => x86_64::generate_tls_helper_code(),
343        Arch::X86 => x86::generate_tls_helper_code(),
344        Arch::Aarch64 => aarch64::generate_tls_helper_code(),
345        Arch::Arm => arm::generate_tls_helper_code(),
346        Arch::Riscv64 => riscv64::generate_tls_helper_code(),
347        Arch::Riscv32 => riscv32::generate_tls_helper_code(),
348        Arch::Loongarch64 => loongarch64::generate_tls_helper_code(),
349    }
350}
351
352pub fn patch_plt_testers(
353    arch: Arch,
354    text_data: &mut [u8],
355    helper_text_off: usize,
356    helper_vaddr: u64,
357    target_plt_vaddr: u64,
358    got_vaddr: u64,
359) {
360    match arch {
361        Arch::X86_64 => {
362            x86_64::patch_helper(text_data, helper_text_off, helper_vaddr, target_plt_vaddr)
363        }
364        Arch::X86 => x86::patch_helper(
365            text_data,
366            helper_text_off,
367            helper_vaddr,
368            target_plt_vaddr,
369            got_vaddr,
370        ),
371        Arch::Aarch64 => {
372            aarch64::patch_helper(text_data, helper_text_off, helper_vaddr, target_plt_vaddr)
373        }
374        Arch::Arm => arm::patch_helper(text_data, helper_text_off, helper_vaddr, target_plt_vaddr),
375        Arch::Riscv64 => {
376            riscv64::patch_helper(text_data, helper_text_off, helper_vaddr, target_plt_vaddr)
377        }
378        Arch::Riscv32 => {
379            riscv32::patch_helper(text_data, helper_text_off, helper_vaddr, target_plt_vaddr)
380        }
381        Arch::Loongarch64 => {
382            loongarch64::patch_helper(text_data, helper_text_off, helper_vaddr, target_plt_vaddr)
383        }
384    }
385}
386
387pub fn patch_tls_tester(
388    arch: Arch,
389    text_data: &mut [u8],
390    helper_text_off: usize,
391    helper_vaddr: u64,
392    reloc_vaddr: u64,
393    tls_get_addr_vaddr: u64,
394    got_vaddr: u64,
395) {
396    match arch {
397        Arch::X86_64 => x86_64::patch_tls_tester(
398            text_data,
399            helper_text_off,
400            helper_vaddr,
401            reloc_vaddr,
402            tls_get_addr_vaddr,
403        ),
404        Arch::X86 => x86::patch_tls_tester(
405            text_data,
406            helper_text_off,
407            helper_vaddr,
408            reloc_vaddr,
409            tls_get_addr_vaddr,
410            got_vaddr,
411        ),
412        Arch::Aarch64 => aarch64::patch_tls_tester(
413            text_data,
414            helper_text_off,
415            helper_vaddr,
416            reloc_vaddr,
417            tls_get_addr_vaddr,
418        ),
419        Arch::Arm => arm::patch_tls_tester(
420            text_data,
421            helper_text_off,
422            helper_vaddr,
423            reloc_vaddr,
424            tls_get_addr_vaddr,
425        ),
426        Arch::Riscv64 => riscv64::patch_tls_tester(
427            text_data,
428            helper_text_off,
429            helper_vaddr,
430            reloc_vaddr,
431            tls_get_addr_vaddr,
432        ),
433        Arch::Riscv32 => riscv32::patch_tls_tester(
434            text_data,
435            helper_text_off,
436            helper_vaddr,
437            reloc_vaddr,
438            tls_get_addr_vaddr,
439        ),
440        Arch::Loongarch64 => loongarch64::patch_tls_tester(
441            text_data,
442            helper_text_off,
443            helper_vaddr,
444            reloc_vaddr,
445            tls_get_addr_vaddr,
446        ),
447    }
448}
449
450pub fn get_ifunc_resolver_code(arch: Arch) -> Vec<u8> {
451    match arch {
452        Arch::X86_64 => x86_64::get_ifunc_resolver_code(),
453        Arch::X86 => x86::get_ifunc_resolver_code(),
454        Arch::Aarch64 => aarch64::get_ifunc_resolver_code(),
455        Arch::Arm => arm::get_ifunc_resolver_code(),
456        Arch::Riscv64 => riscv64::get_ifunc_resolver_code(),
457        Arch::Riscv32 => riscv32::get_ifunc_resolver_code(),
458        Arch::Loongarch64 => loongarch64::get_ifunc_resolver_code(),
459    }
460}
461
462pub fn patch_ifunc_resolver(
463    arch: Arch,
464    text_data: &mut [u8],
465    offset: usize,
466    resolver_vaddr: u64,
467    target_vaddr: u64,
468) {
469    match arch {
470        Arch::X86_64 => {
471            x86_64::patch_ifunc_resolver(text_data, offset, resolver_vaddr, target_vaddr)
472        }
473        Arch::X86 => x86::patch_ifunc_resolver(text_data, offset, resolver_vaddr, target_vaddr),
474        Arch::Aarch64 => {
475            aarch64::patch_ifunc_resolver(text_data, offset, resolver_vaddr, target_vaddr)
476        }
477        Arch::Arm => arm::patch_ifunc_resolver(text_data, offset, resolver_vaddr, target_vaddr),
478        Arch::Riscv64 => {
479            riscv64::patch_ifunc_resolver(text_data, offset, resolver_vaddr, target_vaddr)
480        }
481        Arch::Riscv32 => {
482            riscv32::patch_ifunc_resolver(text_data, offset, resolver_vaddr, target_vaddr)
483        }
484        Arch::Loongarch64 => {
485            loongarch64::patch_ifunc_resolver(text_data, offset, resolver_vaddr, target_vaddr)
486        }
487    }
488}
489
490pub fn generate_plt0_code(arch: Arch) -> Vec<u8> {
491    match arch {
492        Arch::X86_64 => x86_64::generate_plt0_code(),
493        Arch::X86 => x86::generate_plt0_code(),
494        Arch::Aarch64 => aarch64::generate_plt0_code(),
495        Arch::Arm => arm::generate_plt0_code(),
496        Arch::Riscv64 => riscv64::generate_plt0_code(),
497        Arch::Riscv32 => riscv32::generate_plt0_code(),
498        Arch::Loongarch64 => loongarch64::generate_plt0_code(),
499    }
500}
501
502pub fn generate_plt_entry_code(arch: Arch, reloc_idx: u32, plt_entry_offset: u64) -> Vec<u8> {
503    match arch {
504        Arch::X86_64 => x86_64::generate_plt_entry_code(reloc_idx, plt_entry_offset),
505        Arch::X86 => x86::generate_plt_entry_code(reloc_idx, plt_entry_offset),
506        Arch::Aarch64 => aarch64::generate_plt_entry_code(),
507        Arch::Arm => arm::generate_plt_entry_code(),
508        Arch::Riscv64 => riscv64::generate_plt_entry_code(),
509        Arch::Riscv32 => riscv32::generate_plt_entry_code(reloc_idx, plt_entry_offset),
510        Arch::Loongarch64 => loongarch64::generate_plt_entry_code(reloc_idx, plt_entry_offset),
511    }
512}
513
514pub fn patch_plt0(
515    arch: Arch,
516    plt_data: &mut [u8],
517    plt0_off: usize,
518    plt0_vaddr: u64,
519    got_plt_vaddr: u64,
520) {
521    match arch {
522        Arch::X86_64 => x86_64::patch_plt0(plt_data, plt0_off, plt0_vaddr, got_plt_vaddr),
523        Arch::X86 => {}
524        Arch::Aarch64 => aarch64::patch_plt0(plt_data, plt0_off, plt0_vaddr, got_plt_vaddr),
525        Arch::Arm => arm::patch_plt0(plt_data, plt0_off, plt0_vaddr, got_plt_vaddr),
526        Arch::Riscv64 => riscv64::patch_plt0(plt_data, plt0_off, plt0_vaddr, got_plt_vaddr),
527        Arch::Riscv32 => riscv32::patch_plt0(plt_data, plt0_off, plt0_vaddr, got_plt_vaddr),
528        Arch::Loongarch64 => loongarch64::patch_plt0(plt_data, plt0_off, plt0_vaddr, got_plt_vaddr),
529    }
530}
531
532pub fn patch_plt_entry(
533    arch: Arch,
534    plt_data: &mut [u8],
535    plt_entry_off: usize,
536    plt_entry_vaddr: u64,
537    target_got_vaddr: u64,
538    got_vaddr: u64,
539) {
540    match arch {
541        Arch::X86_64 => {
542            x86_64::patch_plt_entry(plt_data, plt_entry_off, plt_entry_vaddr, target_got_vaddr)
543        }
544        Arch::X86 => x86::patch_plt_entry(plt_data, plt_entry_off, target_got_vaddr, got_vaddr),
545        Arch::Aarch64 => {
546            aarch64::patch_plt_entry(plt_data, plt_entry_off, plt_entry_vaddr, target_got_vaddr)
547        }
548        Arch::Arm => {
549            arm::patch_plt_entry(plt_data, plt_entry_off, plt_entry_vaddr, target_got_vaddr)
550        }
551        Arch::Riscv64 => {
552            riscv64::patch_plt_entry(plt_data, plt_entry_off, plt_entry_vaddr, target_got_vaddr)
553        }
554        Arch::Riscv32 => {
555            riscv32::patch_plt_entry(plt_data, plt_entry_off, plt_entry_vaddr, target_got_vaddr)
556        }
557        Arch::Loongarch64 => {
558            loongarch64::patch_plt_entry(plt_data, plt_entry_off, plt_entry_vaddr, target_got_vaddr)
559        }
560    }
561}
562
563pub fn get_got_plt_init_value(arch: Arch, plt_vaddr: u64, plt_entry_off: u64) -> u64 {
564    // The initial value to be placed in the GOT.PLT entrys points to the instruction
565    // in the PLT entry that jumps to the resolver code. This varies by architecture.
566    match arch {
567        Arch::X86_64 | Arch::X86 => plt_vaddr + plt_entry_off + 6,
568        Arch::Aarch64 | Arch::Riscv64 | Arch::Arm => plt_vaddr,
569        Arch::Riscv32 | Arch::Loongarch64 => plt_vaddr + plt_entry_off + 16,
570    }
571}
572
573pub fn get_plt0_size(arch: Arch) -> u64 {
574    match arch {
575        Arch::X86_64 | Arch::X86 => 16,
576        Arch::Arm => 20,
577        Arch::Aarch64 | Arch::Riscv64 | Arch::Riscv32 | Arch::Loongarch64 => 32,
578    }
579}
580
581pub fn get_plt_entry_size(arch: Arch) -> u64 {
582    match arch {
583        Arch::Arm => 12,
584        Arch::X86_64 | Arch::X86 | Arch::Aarch64 | Arch::Riscv64 => 16,
585        Arch::Riscv32 | Arch::Loongarch64 => 32,
586    }
587}