wasmer_engine_universal/
link.rs

1//! Linking for Universal-compiled code.
2
3use std::ptr::{read_unaligned, write_unaligned};
4use wasmer_compiler::{Relocation, RelocationKind, RelocationTarget, Relocations, SectionIndex};
5use wasmer_engine::FunctionExtent;
6use wasmer_engine_universal_artifact::get_libcall_trampoline;
7use wasmer_types::entity::PrimaryMap;
8use wasmer_types::{LocalFunctionIndex, ModuleInfo};
9use wasmer_vm::libcalls::function_pointer;
10use wasmer_vm::SectionBodyPtr;
11
12fn apply_relocation(
13    body: usize,
14    r: &Relocation,
15    allocated_functions: &PrimaryMap<LocalFunctionIndex, FunctionExtent>,
16    allocated_sections: &PrimaryMap<SectionIndex, SectionBodyPtr>,
17    libcall_trampolines: SectionIndex,
18    libcall_trampoline_len: usize,
19) {
20    let target_func_address: usize = match r.reloc_target {
21        RelocationTarget::LocalFunc(index) => *allocated_functions[index].ptr as usize,
22        RelocationTarget::LibCall(libcall) => {
23            // Use the direct target of the libcall if the relocation supports
24            // a full 64-bit address. Otherwise use a trampoline.
25            if r.kind == RelocationKind::Abs8 || r.kind == RelocationKind::X86PCRel8 {
26                function_pointer(libcall)
27            } else {
28                get_libcall_trampoline(
29                    libcall,
30                    allocated_sections[libcall_trampolines].0 as usize,
31                    libcall_trampoline_len,
32                )
33            }
34        }
35        RelocationTarget::CustomSection(custom_section) => {
36            *allocated_sections[custom_section] as usize
37        }
38    };
39
40    match r.kind {
41        RelocationKind::Abs8 => unsafe {
42            let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
43            write_unaligned(reloc_address as *mut u64, reloc_delta);
44        },
45        RelocationKind::X86PCRel4 => unsafe {
46            let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
47            write_unaligned(reloc_address as *mut u32, reloc_delta as _);
48        },
49        RelocationKind::X86PCRel8 => unsafe {
50            let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
51            write_unaligned(reloc_address as *mut u64, reloc_delta);
52        },
53        RelocationKind::X86CallPCRel4 => unsafe {
54            let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
55            write_unaligned(reloc_address as *mut u32, reloc_delta as _);
56        },
57        RelocationKind::Arm64Call => unsafe {
58            let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
59            if (reloc_delta as i64).abs() >= 0x1000_0000 {
60                panic!(
61                    "Relocation to big for {:?} for {:?} with {:x}, current val {:x}",
62                    r.kind,
63                    r.reloc_target,
64                    reloc_delta,
65                    read_unaligned(reloc_address as *mut u32)
66                )
67            }
68            let reloc_delta = (((reloc_delta / 4) as u32) & 0x3ff_ffff)
69                | (read_unaligned(reloc_address as *mut u32) & 0xfc00_0000);
70            write_unaligned(reloc_address as *mut u32, reloc_delta);
71        },
72        kind => panic!(
73            "Relocation kind unsupported in the current architecture {}",
74            kind
75        ),
76    }
77}
78
79/// Links a module, patching the allocated functions with the
80/// required relocations and jump tables.
81pub fn link_module(
82    _module: &ModuleInfo,
83    allocated_functions: &PrimaryMap<LocalFunctionIndex, FunctionExtent>,
84    function_relocations: Relocations,
85    allocated_sections: &PrimaryMap<SectionIndex, SectionBodyPtr>,
86    section_relocations: &PrimaryMap<SectionIndex, Vec<Relocation>>,
87    libcall_trampolines: SectionIndex,
88    trampoline_len: usize,
89) {
90    for (i, section_relocs) in section_relocations.iter() {
91        let body = *allocated_sections[i] as usize;
92        for r in section_relocs {
93            apply_relocation(
94                body,
95                r,
96                allocated_functions,
97                allocated_sections,
98                libcall_trampolines,
99                trampoline_len,
100            );
101        }
102    }
103    for (i, function_relocs) in function_relocations.iter() {
104        let body = *allocated_functions[i].ptr as usize;
105        for r in function_relocs {
106            apply_relocation(
107                body,
108                r,
109                allocated_functions,
110                allocated_sections,
111                libcall_trampolines,
112                trampoline_len,
113            );
114        }
115    }
116}