linera_wasmer_compiler/engine/
link.rs1use crate::get_libcall_trampoline;
4use crate::FunctionExtent;
5use std::collections::HashMap;
6use std::ptr::{read_unaligned, write_unaligned};
7use wasmer_types::entity::PrimaryMap;
8use wasmer_types::RelocationLike;
9use wasmer_types::{LocalFunctionIndex, ModuleInfo};
10use wasmer_types::{RelocationKind, RelocationTarget, SectionIndex};
11use wasmer_vm::libcalls::function_pointer;
12use wasmer_vm::SectionBodyPtr;
13
14fn apply_relocation(
15 body: usize,
16 r: &impl RelocationLike,
17 allocated_functions: &PrimaryMap<LocalFunctionIndex, FunctionExtent>,
18 allocated_sections: &PrimaryMap<SectionIndex, SectionBodyPtr>,
19 libcall_trampolines: SectionIndex,
20 libcall_trampoline_len: usize,
21 riscv_pcrel_hi20s: &mut HashMap<usize, u32>,
22) {
23 let target_func_address: usize = match r.reloc_target() {
24 RelocationTarget::LocalFunc(index) => *allocated_functions[index].ptr as usize,
25 RelocationTarget::LibCall(libcall) => {
26 if r.kind() == RelocationKind::Abs8 || r.kind() == RelocationKind::X86PCRel8 {
29 function_pointer(libcall)
30 } else {
31 get_libcall_trampoline(
32 libcall,
33 allocated_sections[libcall_trampolines].0 as usize,
34 libcall_trampoline_len,
35 )
36 }
37 }
38 RelocationTarget::CustomSection(custom_section) => {
39 *allocated_sections[custom_section] as usize
40 }
41 };
42
43 match r.kind() {
44 RelocationKind::Abs8 => unsafe {
45 let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
46 write_unaligned(reloc_address as *mut u64, reloc_delta);
47 },
48 RelocationKind::X86PCRel4 => unsafe {
49 let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
50 write_unaligned(reloc_address as *mut u32, reloc_delta as _);
51 },
52 RelocationKind::X86PCRel8 => unsafe {
53 let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
54 write_unaligned(reloc_address as *mut u64, reloc_delta);
55 },
56 RelocationKind::X86CallPCRel4 => unsafe {
57 let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
58 write_unaligned(reloc_address as *mut u32, reloc_delta as _);
59 },
60 RelocationKind::Arm64Call => unsafe {
61 let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
62 if (reloc_delta as i64).abs() >= 0x1000_0000 {
63 panic!(
64 "Relocation to big for {:?} for {:?} with {:x}, current val {:x}",
65 r.kind(),
66 r.reloc_target(),
67 reloc_delta,
68 read_unaligned(reloc_address as *mut u32)
69 )
70 }
71 let reloc_delta = (((reloc_delta / 4) as u32) & 0x3ff_ffff)
72 | (read_unaligned(reloc_address as *mut u32) & 0xfc00_0000);
73 write_unaligned(reloc_address as *mut u32, reloc_delta);
74 },
75 RelocationKind::Arm64Movw0 => unsafe {
76 let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
77 let reloc_delta =
78 (((reloc_delta & 0xffff) as u32) << 5) | read_unaligned(reloc_address as *mut u32);
79 write_unaligned(reloc_address as *mut u32, reloc_delta);
80 },
81 RelocationKind::Arm64Movw1 => unsafe {
82 let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
83 let reloc_delta = ((((reloc_delta >> 16) & 0xffff) as u32) << 5)
84 | read_unaligned(reloc_address as *mut u32);
85 write_unaligned(reloc_address as *mut u32, reloc_delta);
86 },
87 RelocationKind::Arm64Movw2 => unsafe {
88 let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
89 let reloc_delta = ((((reloc_delta >> 32) & 0xffff) as u32) << 5)
90 | read_unaligned(reloc_address as *mut u32);
91 write_unaligned(reloc_address as *mut u32, reloc_delta);
92 },
93 RelocationKind::Arm64Movw3 => unsafe {
94 let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
95 let reloc_delta = ((((reloc_delta >> 48) & 0xffff) as u32) << 5)
96 | read_unaligned(reloc_address as *mut u32);
97 write_unaligned(reloc_address as *mut u32, reloc_delta);
98 },
99 RelocationKind::RiscvPCRelHi20 => unsafe {
100 let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
101
102 riscv_pcrel_hi20s.insert(reloc_address, reloc_delta as u32);
104
105 let reloc_delta = ((reloc_delta.wrapping_add(0x800) & 0xfffff000) as u32)
106 | read_unaligned(reloc_address as *mut u32);
107 write_unaligned(reloc_address as *mut u32, reloc_delta);
108 },
109 RelocationKind::RiscvPCRelLo12I => unsafe {
110 let (reloc_address, reloc_abs) = r.for_address(body, target_func_address as u64);
111 let reloc_delta = ((riscv_pcrel_hi20s.get(&(reloc_abs as usize)).expect(
112 "R_RISCV_PCREL_LO12_I relocation target must be a symbol with R_RISCV_PCREL_HI20",
113 ) & 0xfff)
114 << 20)
115 | read_unaligned(reloc_address as *mut u32);
116 write_unaligned(reloc_address as *mut u32, reloc_delta);
117 },
118 RelocationKind::RiscvCall => unsafe {
119 let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
120 let reloc_delta = ((reloc_delta & 0xfff) << 52)
121 | (reloc_delta.wrapping_add(0x800) & 0xfffff000)
122 | read_unaligned(reloc_address as *mut u64);
123 write_unaligned(reloc_address as *mut u64, reloc_delta);
124 },
125 kind => panic!(
126 "Relocation kind unsupported in the current architecture {}",
127 kind
128 ),
129 }
130}
131
132pub fn link_module<'a>(
135 _module: &ModuleInfo,
136 allocated_functions: &PrimaryMap<LocalFunctionIndex, FunctionExtent>,
137 function_relocations: impl Iterator<
138 Item = (
139 LocalFunctionIndex,
140 impl Iterator<Item = &'a (impl RelocationLike + 'a)>,
141 ),
142 >,
143 allocated_sections: &PrimaryMap<SectionIndex, SectionBodyPtr>,
144 section_relocations: impl Iterator<
145 Item = (
146 SectionIndex,
147 impl Iterator<Item = &'a (impl RelocationLike + 'a)>,
148 ),
149 >,
150 libcall_trampolines: SectionIndex,
151 trampoline_len: usize,
152) {
153 let mut riscv_pcrel_hi20s: HashMap<usize, u32> = HashMap::new();
154
155 for (i, section_relocs) in section_relocations {
156 let body = *allocated_sections[i] as usize;
157 for r in section_relocs {
158 apply_relocation(
159 body,
160 r,
161 allocated_functions,
162 allocated_sections,
163 libcall_trampolines,
164 trampoline_len,
165 &mut riscv_pcrel_hi20s,
166 );
167 }
168 }
169 for (i, function_relocs) in function_relocations {
170 let body = *allocated_functions[i].ptr as usize;
171 for r in function_relocs {
172 apply_relocation(
173 body,
174 r,
175 allocated_functions,
176 allocated_sections,
177 libcall_trampolines,
178 trampoline_len,
179 &mut riscv_pcrel_hi20s,
180 );
181 }
182 }
183}