/src/wasmer/lib/compiler/src/artifact_builders/trampoline.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! Trampolines for libcalls. |
2 | | //! |
3 | | //! This is needed because the target of libcall relocations are not reachable |
4 | | //! through normal branch instructions. |
5 | | |
6 | | use enum_iterator::IntoEnumIterator; |
7 | | use wasmer_types::{ |
8 | | Architecture, CustomSection, CustomSectionProtection, LibCall, Relocation, RelocationKind, |
9 | | RelocationTarget, SectionBody, Target, |
10 | | }; |
11 | | |
12 | | // SystemV says that both x16 and x17 are available as intra-procedural scratch |
13 | | // registers but Apple's ABI restricts us to use x17. |
14 | | // LDR x17, [PC, #8] 51 00 00 58 |
15 | | // BR x17 20 02 1f d6 |
16 | | // JMPADDR 00 00 00 00 00 00 00 00 |
17 | | const AARCH64_TRAMPOLINE: [u8; 16] = [ |
18 | | 0x51, 0x00, 0x00, 0x58, 0x20, 0x02, 0x1f, 0xd6, 0, 0, 0, 0, 0, 0, 0, 0, |
19 | | ]; |
20 | | |
21 | | // 2 padding bytes are used to preserve alignment. |
22 | | // JMP [RIP + 2] FF 25 02 00 00 00 [00 00] |
23 | | // 64-bit ADDR 00 00 00 00 00 00 00 00 |
24 | | const X86_64_TRAMPOLINE: [u8; 16] = [ |
25 | | 0xff, 0x25, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
26 | | ]; |
27 | | |
28 | | // can it be shorter than this? |
29 | | // 4 padding bytes are used to preserve alignment. |
30 | | // AUIPC t1,0 17 03 00 00 |
31 | | // LD t1, 16(t1) 03 33 03 01 |
32 | | // JR t1 67 00 03 00 [00 00 00 00] |
33 | | // JMPADDR 00 00 00 00 00 00 00 00 |
34 | | const RISCV64_TRAMPOLINE: [u8; 24] = [ |
35 | | 0x17, 0x03, 0x00, 0x00, 0x03, 0x33, 0x03, 0x01, 0x67, 0x00, 0x03, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, |
36 | | 0, 0, 0, 0, |
37 | | ]; |
38 | | |
39 | 1.57M | fn make_trampoline( |
40 | 1.57M | target: &Target, |
41 | 1.57M | libcall: LibCall, |
42 | 1.57M | code: &mut Vec<u8>, |
43 | 1.57M | relocations: &mut Vec<Relocation>, |
44 | 1.57M | ) { |
45 | 1.57M | match target.triple().architecture { |
46 | 0 | Architecture::Aarch64(_) => { |
47 | 0 | code.extend(AARCH64_TRAMPOLINE); |
48 | 0 | relocations.push(Relocation { |
49 | 0 | kind: RelocationKind::Abs8, |
50 | 0 | reloc_target: RelocationTarget::LibCall(libcall), |
51 | 0 | offset: code.len() as u32 - 8, |
52 | 0 | addend: 0, |
53 | 0 | }); |
54 | 0 | } |
55 | 1.57M | Architecture::X86_64 => { |
56 | 1.57M | code.extend(X86_64_TRAMPOLINE); |
57 | 1.57M | relocations.push(Relocation { |
58 | 1.57M | kind: RelocationKind::Abs8, |
59 | 1.57M | reloc_target: RelocationTarget::LibCall(libcall), |
60 | 1.57M | offset: code.len() as u32 - 8, |
61 | 1.57M | addend: 0, |
62 | 1.57M | }); |
63 | 1.57M | } |
64 | 0 | Architecture::Riscv64(_) => { |
65 | 0 | code.extend(RISCV64_TRAMPOLINE); |
66 | 0 | relocations.push(Relocation { |
67 | 0 | kind: RelocationKind::Abs8, |
68 | 0 | reloc_target: RelocationTarget::LibCall(libcall), |
69 | 0 | offset: code.len() as u32 - 8, |
70 | 0 | addend: 0, |
71 | 0 | }); |
72 | 0 | } |
73 | 0 | arch => panic!("Unsupported architecture: {}", arch), |
74 | | }; |
75 | 1.57M | } wasmer_compiler::artifact_builders::trampoline::make_trampoline Line | Count | Source | 39 | 1.11M | fn make_trampoline( | 40 | 1.11M | target: &Target, | 41 | 1.11M | libcall: LibCall, | 42 | 1.11M | code: &mut Vec<u8>, | 43 | 1.11M | relocations: &mut Vec<Relocation>, | 44 | 1.11M | ) { | 45 | 1.11M | match target.triple().architecture { | 46 | 0 | Architecture::Aarch64(_) => { | 47 | 0 | code.extend(AARCH64_TRAMPOLINE); | 48 | 0 | relocations.push(Relocation { | 49 | 0 | kind: RelocationKind::Abs8, | 50 | 0 | reloc_target: RelocationTarget::LibCall(libcall), | 51 | 0 | offset: code.len() as u32 - 8, | 52 | 0 | addend: 0, | 53 | 0 | }); | 54 | 0 | } | 55 | 1.11M | Architecture::X86_64 => { | 56 | 1.11M | code.extend(X86_64_TRAMPOLINE); | 57 | 1.11M | relocations.push(Relocation { | 58 | 1.11M | kind: RelocationKind::Abs8, | 59 | 1.11M | reloc_target: RelocationTarget::LibCall(libcall), | 60 | 1.11M | offset: code.len() as u32 - 8, | 61 | 1.11M | addend: 0, | 62 | 1.11M | }); | 63 | 1.11M | } | 64 | 0 | Architecture::Riscv64(_) => { | 65 | 0 | code.extend(RISCV64_TRAMPOLINE); | 66 | 0 | relocations.push(Relocation { | 67 | 0 | kind: RelocationKind::Abs8, | 68 | 0 | reloc_target: RelocationTarget::LibCall(libcall), | 69 | 0 | offset: code.len() as u32 - 8, | 70 | 0 | addend: 0, | 71 | 0 | }); | 72 | 0 | } | 73 | 0 | arch => panic!("Unsupported architecture: {}", arch), | 74 | | }; | 75 | 1.11M | } |
wasmer_compiler::artifact_builders::trampoline::make_trampoline Line | Count | Source | 39 | 451k | fn make_trampoline( | 40 | 451k | target: &Target, | 41 | 451k | libcall: LibCall, | 42 | 451k | code: &mut Vec<u8>, | 43 | 451k | relocations: &mut Vec<Relocation>, | 44 | 451k | ) { | 45 | 451k | match target.triple().architecture { | 46 | 0 | Architecture::Aarch64(_) => { | 47 | 0 | code.extend(AARCH64_TRAMPOLINE); | 48 | 0 | relocations.push(Relocation { | 49 | 0 | kind: RelocationKind::Abs8, | 50 | 0 | reloc_target: RelocationTarget::LibCall(libcall), | 51 | 0 | offset: code.len() as u32 - 8, | 52 | 0 | addend: 0, | 53 | 0 | }); | 54 | 0 | } | 55 | 451k | Architecture::X86_64 => { | 56 | 451k | code.extend(X86_64_TRAMPOLINE); | 57 | 451k | relocations.push(Relocation { | 58 | 451k | kind: RelocationKind::Abs8, | 59 | 451k | reloc_target: RelocationTarget::LibCall(libcall), | 60 | 451k | offset: code.len() as u32 - 8, | 61 | 451k | addend: 0, | 62 | 451k | }); | 63 | 451k | } | 64 | 0 | Architecture::Riscv64(_) => { | 65 | 0 | code.extend(RISCV64_TRAMPOLINE); | 66 | 0 | relocations.push(Relocation { | 67 | 0 | kind: RelocationKind::Abs8, | 68 | 0 | reloc_target: RelocationTarget::LibCall(libcall), | 69 | 0 | offset: code.len() as u32 - 8, | 70 | 0 | addend: 0, | 71 | 0 | }); | 72 | 0 | } | 73 | 0 | arch => panic!("Unsupported architecture: {}", arch), | 74 | | }; | 75 | 451k | } |
|
76 | | |
77 | | /// Returns the length of a libcall trampoline. |
78 | 42.4k | pub fn libcall_trampoline_len(target: &Target) -> usize { |
79 | 42.4k | match target.triple().architecture { |
80 | 0 | Architecture::Aarch64(_) => AARCH64_TRAMPOLINE.len(), |
81 | 42.4k | Architecture::X86_64 => X86_64_TRAMPOLINE.len(), |
82 | 0 | Architecture::Riscv64(_) => RISCV64_TRAMPOLINE.len(), |
83 | 0 | arch => panic!("Unsupported architecture: {}", arch), |
84 | | } |
85 | 42.4k | } wasmer_compiler::artifact_builders::trampoline::libcall_trampoline_len Line | Count | Source | 78 | 30.2k | pub fn libcall_trampoline_len(target: &Target) -> usize { | 79 | 30.2k | match target.triple().architecture { | 80 | 0 | Architecture::Aarch64(_) => AARCH64_TRAMPOLINE.len(), | 81 | 30.2k | Architecture::X86_64 => X86_64_TRAMPOLINE.len(), | 82 | 0 | Architecture::Riscv64(_) => RISCV64_TRAMPOLINE.len(), | 83 | 0 | arch => panic!("Unsupported architecture: {}", arch), | 84 | | } | 85 | 30.2k | } |
wasmer_compiler::artifact_builders::trampoline::libcall_trampoline_len Line | Count | Source | 78 | 12.2k | pub fn libcall_trampoline_len(target: &Target) -> usize { | 79 | 12.2k | match target.triple().architecture { | 80 | 0 | Architecture::Aarch64(_) => AARCH64_TRAMPOLINE.len(), | 81 | 12.2k | Architecture::X86_64 => X86_64_TRAMPOLINE.len(), | 82 | 0 | Architecture::Riscv64(_) => RISCV64_TRAMPOLINE.len(), | 83 | 0 | arch => panic!("Unsupported architecture: {}", arch), | 84 | | } | 85 | 12.2k | } |
|
86 | | |
87 | | /// Creates a custom section containing the libcall trampolines. |
88 | 42.4k | pub fn make_libcall_trampolines(target: &Target) -> CustomSection { |
89 | 42.4k | let mut code = vec![]; |
90 | 42.4k | let mut relocations = vec![]; |
91 | 1.61M | for libcall in LibCall::into_enum_iter() { |
92 | 1.57M | make_trampoline(target, libcall, &mut code, &mut relocations); |
93 | 1.57M | } |
94 | 42.4k | CustomSection { |
95 | 42.4k | protection: CustomSectionProtection::ReadExecute, |
96 | 42.4k | bytes: SectionBody::new_with_vec(code), |
97 | 42.4k | relocations, |
98 | 42.4k | } |
99 | 42.4k | } wasmer_compiler::artifact_builders::trampoline::make_libcall_trampolines Line | Count | Source | 88 | 30.2k | pub fn make_libcall_trampolines(target: &Target) -> CustomSection { | 89 | 30.2k | let mut code = vec![]; | 90 | 30.2k | let mut relocations = vec![]; | 91 | 1.14M | for libcall in LibCall::into_enum_iter() { | 92 | 1.11M | make_trampoline(target, libcall, &mut code, &mut relocations); | 93 | 1.11M | } | 94 | 30.2k | CustomSection { | 95 | 30.2k | protection: CustomSectionProtection::ReadExecute, | 96 | 30.2k | bytes: SectionBody::new_with_vec(code), | 97 | 30.2k | relocations, | 98 | 30.2k | } | 99 | 30.2k | } |
wasmer_compiler::artifact_builders::trampoline::make_libcall_trampolines Line | Count | Source | 88 | 12.2k | pub fn make_libcall_trampolines(target: &Target) -> CustomSection { | 89 | 12.2k | let mut code = vec![]; | 90 | 12.2k | let mut relocations = vec![]; | 91 | 464k | for libcall in LibCall::into_enum_iter() { | 92 | 451k | make_trampoline(target, libcall, &mut code, &mut relocations); | 93 | 451k | } | 94 | 12.2k | CustomSection { | 95 | 12.2k | protection: CustomSectionProtection::ReadExecute, | 96 | 12.2k | bytes: SectionBody::new_with_vec(code), | 97 | 12.2k | relocations, | 98 | 12.2k | } | 99 | 12.2k | } |
|
100 | | |
101 | | /// Returns the address of a trampoline in the libcall trampolines section. |
102 | 0 | pub fn get_libcall_trampoline( |
103 | 0 | libcall: LibCall, |
104 | 0 | libcall_trampolines: usize, |
105 | 0 | libcall_trampoline_len: usize, |
106 | 0 | ) -> usize { |
107 | 0 | libcall_trampolines + libcall as usize * libcall_trampoline_len |
108 | 0 | } Unexecuted instantiation: wasmer_compiler::artifact_builders::trampoline::get_libcall_trampoline Unexecuted instantiation: wasmer_compiler::artifact_builders::trampoline::get_libcall_trampoline |