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#[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 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 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 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 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 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 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 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 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
303pub(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 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}