wasmer_engine_universal_artifact/
trampoline.rs

1//! Trampolines for libcalls.
2//!
3//! This is needed because the target of libcall relocations are not reachable
4//! through normal branch instructions.
5
6use enum_iterator::IntoEnumIterator;
7use wasmer_compiler::{
8    Architecture, CustomSection, CustomSectionProtection, Relocation, RelocationKind,
9    RelocationTarget, SectionBody, Target,
10};
11use wasmer_types::LibCall;
12
13// SystemV says that both x16 and x17 are available as intra-procedural scratch
14// registers but Apple's ABI restricts us to use x17.
15// LDR x17, [PC, #8]  51 00 00 58
16// BR x17             20 02 1f d6
17// JMPADDR            00 00 00 00 00 00 00 00
18const AARCH64_TRAMPOLINE: [u8; 16] = [
19    0x51, 0x00, 0x00, 0x58, 0x20, 0x02, 0x1f, 0xd6, 0, 0, 0, 0, 0, 0, 0, 0,
20];
21
22// 2 padding bytes are used to preserve alignment.
23// JMP [RIP + 2]   FF 25 02 00 00 00 [00 00]
24// 64-bit ADDR     00 00 00 00 00 00 00 00
25const X86_64_TRAMPOLINE: [u8; 16] = [
26    0xff, 0x25, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
27];
28
29fn make_trampoline(
30    target: &Target,
31    libcall: LibCall,
32    code: &mut Vec<u8>,
33    relocations: &mut Vec<Relocation>,
34) {
35    match target.triple().architecture {
36        Architecture::Aarch64(_) => {
37            code.extend(&AARCH64_TRAMPOLINE);
38            relocations.push(Relocation {
39                kind: RelocationKind::Abs8,
40                reloc_target: RelocationTarget::LibCall(libcall),
41                offset: code.len() as u32 - 8,
42                addend: 0,
43            });
44        }
45        Architecture::X86_64 => {
46            code.extend(&X86_64_TRAMPOLINE);
47            relocations.push(Relocation {
48                kind: RelocationKind::Abs8,
49                reloc_target: RelocationTarget::LibCall(libcall),
50                offset: code.len() as u32 - 8,
51                addend: 0,
52            });
53        }
54        arch => panic!("Unsupported architecture: {}", arch),
55    };
56}
57
58/// Returns the length of a libcall trampoline.
59pub fn libcall_trampoline_len(target: &Target) -> usize {
60    match target.triple().architecture {
61        Architecture::Aarch64(_) => AARCH64_TRAMPOLINE.len(),
62        Architecture::X86_64 => X86_64_TRAMPOLINE.len(),
63        arch => panic!("Unsupported architecture: {}", arch),
64    }
65}
66
67/// Creates a custom section containing the libcall trampolines.
68pub fn make_libcall_trampolines(target: &Target) -> CustomSection {
69    let mut code = vec![];
70    let mut relocations = vec![];
71    for libcall in LibCall::into_enum_iter() {
72        make_trampoline(target, libcall, &mut code, &mut relocations);
73    }
74    CustomSection {
75        protection: CustomSectionProtection::ReadExecute,
76        bytes: SectionBody::new_with_vec(code),
77        relocations,
78    }
79}
80
81/// Returns the address of a trampoline in the libcall trampolines section.
82pub fn get_libcall_trampoline(
83    libcall: LibCall,
84    libcall_trampolines: usize,
85    libcall_trampoline_len: usize,
86) -> usize {
87    libcall_trampolines + libcall as usize * libcall_trampoline_len
88}