1use crate::compiler::{CompiledObjects, emit_metadata_and_link};
6use crate::dwarf::{EhRelocation, EhTarget};
7use crate::misc::{CompiledFunctionExt, CompiledKind};
8use crate::object::get_object_for_target;
9use crate::types::function::{Compilation, FunctionBody};
10use crate::types::relocation::{Relocation, RelocationKind, RelocationTarget};
11use crate::types::section::CustomSection;
12use object::{
13 RelocationEncoding, RelocationFlags, RelocationKind as ObjectRelocationKind, SectionKind,
14 SymbolFlags, SymbolKind, SymbolScope, elf,
15 write::{
16 Object, Relocation as ObjectRelocation, SectionId, StandardSection, StandardSegment,
17 Symbol, SymbolId, SymbolSection,
18 },
19};
20use std::path::PathBuf;
21use wasmer_types::{
22 CompileError, LibCall, LocalFunctionIndex, TrapInformation, entity::PrimaryMap, target::Target,
23};
24use wasmer_types::{FunctionIndex, FunctionType};
25
26pub enum CompileOutput<T> {
31 InMemory(T),
33 Object(Vec<u8>, Option<usize>),
35}
36
37impl<T: crate::compiler::CompiledFunction> crate::compiler::CompiledFunction for CompileOutput<T> {}
38
39pub fn compile_output_objects<T>(outputs: Vec<CompileOutput<T>>) -> Vec<Vec<u8>> {
41 outputs
42 .into_iter()
43 .map(|output| match output {
44 CompileOutput::Object(object, _) => object,
45 CompileOutput::InMemory(_) => unreachable!(),
46 })
47 .collect()
48}
49
50pub fn compile_output_in_memory<T>(outputs: Vec<CompileOutput<T>>) -> Vec<T> {
52 outputs
53 .into_iter()
54 .map(|output| match output {
55 CompileOutput::InMemory(body) => body,
56 CompileOutput::Object(..) => unreachable!(),
57 })
58 .collect()
59}
60
61pub fn add_undefined_symbol(object: &mut Object<'static>, name: String) -> SymbolId {
63 object.add_symbol(Symbol {
64 name: name.into_bytes(),
65 value: 0,
66 size: 0,
67 kind: SymbolKind::Text,
68 scope: SymbolScope::Linkage,
69 weak: false,
70 section: SymbolSection::Undefined,
71 flags: SymbolFlags::None,
72 })
73}
74
75pub fn add_libcall_symbol(object: &mut Object<'static>, libcall: LibCall) -> SymbolId {
78 object.add_symbol(Symbol {
79 name: libcall.to_function_name().to_string().into_bytes(),
80 value: 0,
81 size: 0,
82 kind: SymbolKind::Unknown,
83 scope: SymbolScope::Dynamic,
84 weak: false,
85 section: SymbolSection::Undefined,
86 flags: SymbolFlags::None,
87 })
88}
89
90pub fn relocation_kind_to_flags(kind: RelocationKind) -> Result<RelocationFlags, CompileError> {
93 use ObjectRelocationKind as K;
94 Ok(match kind {
95 RelocationKind::Abs4 => RelocationFlags::Generic {
96 kind: K::Absolute,
97 encoding: RelocationEncoding::Generic,
98 size: 32,
99 },
100 RelocationKind::Abs8 => RelocationFlags::Generic {
101 kind: K::Absolute,
102 encoding: RelocationEncoding::Generic,
103 size: 64,
104 },
105 RelocationKind::PCRel4 => RelocationFlags::Generic {
106 kind: K::Relative,
107 encoding: RelocationEncoding::Generic,
108 size: 32,
109 },
110 RelocationKind::X86CallPCRel4 => RelocationFlags::Generic {
111 kind: K::Relative,
112 encoding: RelocationEncoding::X86Branch,
113 size: 32,
114 },
115 RelocationKind::X86CallPLTRel4 => RelocationFlags::Generic {
116 kind: K::PltRelative,
117 encoding: RelocationEncoding::X86Branch,
118 size: 32,
119 },
120 RelocationKind::X86GOTPCRel4 => RelocationFlags::Generic {
121 kind: K::GotRelative,
122 encoding: RelocationEncoding::Generic,
123 size: 32,
124 },
125 RelocationKind::Arm64Call => RelocationFlags::Elf {
126 r_type: elf::R_AARCH64_CALL26,
127 },
128 RelocationKind::RiscvPCRelHi20 => RelocationFlags::Elf {
131 r_type: elf::R_RISCV_PCREL_HI20,
132 },
133 RelocationKind::RiscvPCRelLo12I => RelocationFlags::Elf {
134 r_type: elf::R_RISCV_PCREL_LO12_I,
135 },
136 RelocationKind::RiscvCall => RelocationFlags::Elf {
137 r_type: elf::R_RISCV_CALL_PLT,
138 },
139 kind => {
140 return Err(CompileError::Codegen(format!(
141 "unsupported ELF relocation kind: {kind:?}"
142 )));
143 }
144 })
145}
146
147pub fn add_relocations(
149 object: &mut Object<'static>,
150 section: SectionId,
151 relocations: &[Relocation],
152 local_symbol: Option<(LocalFunctionIndex, SymbolId)>,
153) -> Result<(), CompileError> {
154 for relocation in relocations {
155 let symbol = match relocation.reloc_target {
156 RelocationTarget::LocalFunc(index) => local_symbol
157 .filter(|(local_index, _)| *local_index == index)
158 .map_or_else(
159 || {
160 add_undefined_symbol(
161 object,
162 CompiledKind::Local(index, String::new()).linkage_name(),
163 )
164 },
165 |(_, symbol)| symbol,
166 ),
167 RelocationTarget::CustomSection(index) => add_undefined_symbol(
168 object,
169 CompiledKind::ImportFunctionTrampoline(
170 FunctionIndex::from_u32(index.as_u32()),
171 FunctionType::default(),
172 )
173 .linkage_name(),
174 ),
175 RelocationTarget::LibCall(libcall) => add_libcall_symbol(object, libcall),
176 RelocationTarget::DynamicTrampoline(index) => add_undefined_symbol(
177 object,
178 CompiledKind::DynamicFunctionTrampoline(index, FunctionType::default())
179 .linkage_name(),
180 ),
181 };
182 let flags = relocation_kind_to_flags(relocation.kind)?;
183 object
184 .add_relocation(
185 section,
186 ObjectRelocation {
187 offset: relocation.offset as u64,
188 flags,
189 symbol,
190 addend: relocation.addend,
191 },
192 )
193 .map_err(|e| CompileError::Codegen(format!("failed to add ELF relocation: {e}")))?;
194 }
195 Ok(())
196}
197
198pub fn emit_trap_section(
201 object: &mut Object<'static>,
202 kind: &CompiledKind,
203 traps: &[TrapInformation],
204) {
205 let mut trap_data = Vec::with_capacity(traps.len() * 8 + size_of::<u32>());
206 trap_data.extend_from_slice(&(traps.len() as u32).to_le_bytes());
207 for trap in traps {
208 trap_data.extend_from_slice(&trap.code_offset.to_le_bytes());
209 trap_data.extend_from_slice(&(trap.trap_code as u32).to_le_bytes());
210 }
211 let traps_section = object.add_section(
212 object.segment_name(StandardSegment::Data).to_vec(),
213 crate::WASMER_TRAPS_SECTION_NAME.to_vec(),
214 SectionKind::Other,
215 );
216 let traps_symbol = object.add_symbol(Symbol {
217 name: kind.traps_name().into_bytes(),
218 value: 0,
219 size: trap_data.len() as u64,
220 kind: SymbolKind::Data,
221 scope: SymbolScope::Linkage,
222 weak: true,
223 section: SymbolSection::Section(traps_section),
224 flags: SymbolFlags::None,
225 });
226 object.add_symbol_data(traps_symbol, traps_section, &trap_data, 4);
227}
228
229pub fn emit_eh_frame_section(
233 object: &mut Object<'static>,
234 eh_frame_bytes: &[u8],
235 relocations: &[EhRelocation],
236 function_symbol: SymbolId,
237 lsda_section_symbol: Option<SymbolId>,
238) -> Result<(), CompileError> {
239 let section = object.add_section(
240 object.segment_name(StandardSegment::Debug).to_vec(),
241 crate::EH_FRAME_SECTION_NAME.to_vec(),
242 SectionKind::Other,
243 );
244 let data_offset = object.append_section_data(section, eh_frame_bytes, 4);
245
246 let mut personality_reference_symbol = None;
252 for relocation in relocations {
253 let symbol = match relocation.target {
254 EhTarget::Function => function_symbol,
255 EhTarget::Personality => {
256 if let Some(symbol) = personality_reference_symbol {
257 symbol
258 } else {
259 let personality_symbol = add_libcall_symbol(object, LibCall::EHPersonality);
260 let personality_section =
261 object.section_id(StandardSection::ReadOnlyDataWithRel);
262 let reference_symbol = object.add_symbol(Symbol {
263 name: b"DW.ref.wasmer_eh_personality".to_vec(),
264 value: 0,
265 size: 8,
266 kind: SymbolKind::Data,
267 scope: SymbolScope::Compilation,
268 weak: false,
269 section: SymbolSection::Undefined,
270 flags: SymbolFlags::None,
271 });
272 let reference_offset =
273 object.add_symbol_data(reference_symbol, personality_section, &[0; 8], 8);
274 object
275 .add_relocation(
276 personality_section,
277 ObjectRelocation {
278 offset: reference_offset,
279 flags: RelocationFlags::Generic {
280 kind: ObjectRelocationKind::Absolute,
281 encoding: RelocationEncoding::Generic,
282 size: 64,
283 },
284 symbol: personality_symbol,
285 addend: 0,
286 },
287 )
288 .map_err(|e| {
289 CompileError::Codegen(format!(
290 "failed to add personality reference relocation: {e}"
291 ))
292 })?;
293 personality_reference_symbol = Some(reference_symbol);
294 reference_symbol
295 }
296 }
297 EhTarget::Lsda => lsda_section_symbol.ok_or_else(|| {
298 CompileError::Codegen(
299 ".eh_frame references an LSDA but none was emitted".to_string(),
300 )
301 })?,
302 };
303 object
304 .add_relocation(
305 section,
306 ObjectRelocation {
307 offset: data_offset + relocation.offset,
308 flags: RelocationFlags::Generic {
309 kind: relocation.kind,
310 encoding: RelocationEncoding::Generic,
311 size: 8 * relocation.size,
312 },
313 symbol,
314 addend: relocation.addend,
315 },
316 )
317 .map_err(|e| {
318 CompileError::Codegen(format!("failed to add .eh_frame relocation: {e}"))
319 })?;
320 }
321 Ok(())
322}
323
324pub fn emit_function_body(
326 target: &Target,
327 kind: &CompiledKind,
328 body: &FunctionBody,
329) -> Result<Vec<u8>, CompileError> {
330 let mut object = get_object_for_target(target.triple())
331 .map_err(|e| CompileError::Codegen(format!("cannot create object: {e}")))?;
332 let symbol = object.add_symbol(Symbol {
333 name: kind.linkage_name().into_bytes(),
334 value: 0,
335 size: body.body.len() as u64,
336 kind: SymbolKind::Text,
337 scope: SymbolScope::Linkage,
338 weak: false,
339 section: SymbolSection::Undefined,
340 flags: SymbolFlags::None,
341 });
342 let text = object.section_id(StandardSection::Text);
343 object.add_symbol_data(symbol, text, &body.body, 4);
344 object
345 .write()
346 .map_err(|e| CompileError::Codegen(format!("failed to serialize object: {e}")))
347}
348
349pub fn emit_import_trampoline(
351 target: &Target,
352 kind: &CompiledKind,
353 section: &CustomSection,
354) -> Result<Vec<u8>, CompileError> {
355 let mut object = get_object_for_target(target.triple())
356 .map_err(|e| CompileError::Codegen(format!("cannot create object: {e}")))?;
357 let symbol = object.add_symbol(Symbol {
358 name: kind.linkage_name().into_bytes(),
359 value: 0,
360 size: section.bytes.len() as u64,
361 kind: SymbolKind::Text,
362 scope: SymbolScope::Linkage,
363 weak: false,
364 section: SymbolSection::Undefined,
365 flags: SymbolFlags::None,
366 });
367 let text = object.section_id(StandardSection::Text);
368 object.add_symbol_data(symbol, text, section.bytes.as_slice(), 4);
369 object
370 .write()
371 .map_err(|e| CompileError::Codegen(format!("failed to serialize object: {e}")))
372}
373#[allow(clippy::too_many_arguments)]
376pub fn link_module(
377 pool: &rayon::ThreadPool,
378 target: &Target,
379 compile_info_blob: &[u8],
380 object_files: Vec<Vec<u8>>,
381 import_trampoline_objects: Vec<Vec<u8>>,
382 trampoline_objects: Vec<Vec<u8>>,
383 dynamic_trampoline_objects: Vec<Vec<u8>>,
384 debug_dir: Option<PathBuf>,
385 module_hash: Option<String>,
386 function_max_stack_usage: PrimaryMap<LocalFunctionIndex, Option<usize>>,
387) -> Result<Compilation, CompileError> {
388 let elf = emit_metadata_and_link(
389 pool,
390 target,
391 compile_info_blob,
392 CompiledObjects {
393 object_files,
394 import_trampoline_object_files: import_trampoline_objects,
395 trampoline_object_files: trampoline_objects,
396 dynamic_trampoline_object_files: dynamic_trampoline_objects,
397 },
398 debug_dir,
399 module_hash,
400 )?;
401 Ok(Compilation::Elf {
402 data: elf,
403 function_max_stack_usage,
404 })
405}