wasmer_compiler/object/
module.rs

1use super::error::ObjectError;
2use crate::types::{
3    function::Compilation,
4    relocation::{RelocationKind as Reloc, RelocationTarget},
5    section::{CustomSectionProtection, SectionIndex},
6    symbols::{Symbol, SymbolRegistry},
7    target::{Architecture, BinaryFormat, Endianness, Triple},
8};
9use object::{
10    elf, macho,
11    write::{
12        Object, Relocation, StandardSection, StandardSegment, Symbol as ObjSymbol, SymbolSection,
13    },
14    FileFlags, RelocationEncoding, RelocationKind, SectionKind, SymbolFlags, SymbolKind,
15    SymbolScope,
16};
17use wasmer_types::entity::PrimaryMap;
18use wasmer_types::LocalFunctionIndex;
19
20const DWARF_SECTION_NAME: &[u8] = b".eh_frame";
21
22/// Create an object for a given target `Triple`.
23///
24/// # Usage
25///
26/// ```rust
27/// # use wasmer_compiler::types::target::Triple;
28/// # use wasmer_compiler::object::{ObjectError, get_object_for_target};
29///
30/// # fn generate_object_for_target(triple: &Triple) -> Result<(), ObjectError> {
31/// let mut object = get_object_for_target(&triple)?;
32///
33/// # Ok(())
34/// # }
35/// ```
36pub fn get_object_for_target(triple: &Triple) -> Result<Object, ObjectError> {
37    let obj_binary_format = match triple.binary_format {
38        BinaryFormat::Elf => object::BinaryFormat::Elf,
39        BinaryFormat::Macho => object::BinaryFormat::MachO,
40        BinaryFormat::Coff => object::BinaryFormat::Coff,
41        binary_format => {
42            return Err(ObjectError::UnsupportedBinaryFormat(format!(
43                "{binary_format}"
44            )));
45        }
46    };
47    let obj_architecture = match triple.architecture {
48        Architecture::X86_64 => object::Architecture::X86_64,
49        Architecture::Aarch64(_) => object::Architecture::Aarch64,
50        Architecture::Riscv64(_) => object::Architecture::Riscv64,
51        Architecture::LoongArch64 => object::Architecture::LoongArch64,
52        architecture => {
53            return Err(ObjectError::UnsupportedArchitecture(format!(
54                "{architecture}"
55            )));
56        }
57    };
58    let obj_endianness = match triple
59        .endianness()
60        .map_err(|_| ObjectError::UnknownEndianness)?
61    {
62        Endianness::Little => object::Endianness::Little,
63        Endianness::Big => object::Endianness::Big,
64    };
65
66    let mut object = Object::new(obj_binary_format, obj_architecture, obj_endianness);
67
68    if let Architecture::Riscv64(_) = triple.architecture {
69        object.flags = FileFlags::Elf {
70            e_flags: elf::EF_RISCV_FLOAT_ABI_DOUBLE,
71            os_abi: 2,
72            abi_version: 0,
73        };
74    }
75
76    Ok(object)
77}
78
79/// Write data into an existing object.
80///
81/// # Usage
82///
83/// ```rust
84/// # use wasmer_compiler::types::target::Triple;
85/// # use wasmer_compiler::object::{ObjectError, get_object_for_target, emit_data};
86///
87/// # fn emit_data_into_object(triple: &Triple) -> Result<(), ObjectError> {
88/// let mut object = get_object_for_target(&triple)?;
89/// emit_data(&mut object, b"WASMER_METADATA", &b"Hello, World!"[..], 1)?;
90///
91/// # Ok(())
92/// # }
93/// ```
94pub fn emit_data(
95    obj: &mut Object,
96    name: &[u8],
97    data: &[u8],
98    align: u64,
99) -> Result<(), ObjectError> {
100    let symbol_id = obj.add_symbol(ObjSymbol {
101        name: name.to_vec(),
102        value: 0,
103        size: 0,
104        kind: SymbolKind::Data,
105        scope: SymbolScope::Dynamic,
106        weak: false,
107        section: SymbolSection::Undefined,
108        flags: SymbolFlags::None,
109    });
110    let section_id = obj.section_id(StandardSection::Data);
111    obj.add_symbol_data(symbol_id, section_id, data, align);
112
113    Ok(())
114}
115
116/// Emit the compilation result into an existing object.
117///
118/// # Usage
119///
120/// ```rust
121/// # use wasmer_compiler::types::{ symbols::SymbolRegistry, target::{Triple}, function::{Compilation} };
122/// # use wasmer_compiler::object::{ObjectError, get_object_for_target, emit_compilation};
123///
124/// # fn emit_compilation_into_object(
125/// #     triple: &Triple,
126/// #     compilation: Compilation,
127/// #     symbol_registry: impl SymbolRegistry,
128/// # ) -> Result<(), ObjectError> {
129/// let mut object = get_object_for_target(&triple)?;
130/// emit_compilation(&mut object, compilation, &symbol_registry, &triple)?;
131/// # Ok(())
132/// # }
133/// ```
134pub fn emit_compilation(
135    obj: &mut Object,
136    compilation: Compilation,
137    symbol_registry: &impl SymbolRegistry,
138    triple: &Triple,
139) -> Result<(), ObjectError> {
140    let mut function_bodies = PrimaryMap::with_capacity(compilation.functions.len());
141    let mut function_relocations = PrimaryMap::with_capacity(compilation.functions.len());
142    for (_, func) in compilation.functions.into_iter() {
143        function_bodies.push(func.body);
144        function_relocations.push(func.relocations);
145    }
146    let custom_section_relocations = compilation
147        .custom_sections
148        .iter()
149        .map(|(_, section)| section.relocations.clone())
150        .collect::<PrimaryMap<SectionIndex, _>>();
151
152    let debug_index = compilation.unwind_info.eh_frame;
153
154    let align = match triple.architecture {
155        Architecture::X86_64 => 1,
156        // In Arm64 is recommended a 4-byte alignment
157        Architecture::Aarch64(_) => 4,
158        _ => 1,
159    };
160
161    // Add sections
162    let custom_section_ids = compilation
163        .custom_sections
164        .into_iter()
165        .map(|(section_index, custom_section)| {
166            if debug_index.map_or(false, |d| d == section_index) {
167                // If this is the debug section
168                let segment = obj.segment_name(StandardSegment::Debug).to_vec();
169                let section_id =
170                    obj.add_section(segment, DWARF_SECTION_NAME.to_vec(), SectionKind::Debug);
171                obj.append_section_data(section_id, custom_section.bytes.as_slice(), align);
172                let section_name = symbol_registry.symbol_to_name(Symbol::Section(section_index));
173                let symbol_id = obj.add_symbol(ObjSymbol {
174                    name: section_name.into_bytes(),
175                    value: 0,
176                    size: custom_section.bytes.len() as _,
177                    kind: SymbolKind::Data,
178                    scope: SymbolScope::Compilation,
179                    weak: false,
180                    section: SymbolSection::Section(section_id),
181                    flags: SymbolFlags::None,
182                });
183                (section_id, symbol_id)
184            } else {
185                let section_name = symbol_registry.symbol_to_name(Symbol::Section(section_index));
186                let (section_kind, standard_section) = match custom_section.protection {
187                    CustomSectionProtection::ReadExecute => {
188                        (SymbolKind::Text, StandardSection::Text)
189                    }
190                    CustomSectionProtection::Read => (SymbolKind::Data, StandardSection::Data),
191                };
192                let section_id = obj.section_id(standard_section);
193                let symbol_id = obj.add_symbol(ObjSymbol {
194                    name: section_name.into_bytes(),
195                    value: 0,
196                    size: custom_section.bytes.len() as _,
197                    kind: section_kind,
198                    scope: SymbolScope::Dynamic,
199                    weak: false,
200                    section: SymbolSection::Section(section_id),
201                    flags: SymbolFlags::None,
202                });
203                obj.add_symbol_data(
204                    symbol_id,
205                    section_id,
206                    custom_section.bytes.as_slice(),
207                    align,
208                );
209                (section_id, symbol_id)
210            }
211        })
212        .collect::<PrimaryMap<SectionIndex, _>>();
213
214    // Add functions
215    let function_symbol_ids = function_bodies
216        .into_iter()
217        .map(|(function_local_index, function)| {
218            let function_name =
219                symbol_registry.symbol_to_name(Symbol::LocalFunction(function_local_index));
220            let section_id = obj.section_id(StandardSection::Text);
221            let symbol_id = obj.add_symbol(ObjSymbol {
222                name: function_name.into_bytes(),
223                value: 0,
224                size: function.body.len() as _,
225                kind: SymbolKind::Text,
226                scope: SymbolScope::Dynamic,
227                weak: false,
228                section: SymbolSection::Section(section_id),
229                flags: SymbolFlags::None,
230            });
231            obj.add_symbol_data(symbol_id, section_id, &function.body, align);
232            (section_id, symbol_id)
233        })
234        .collect::<PrimaryMap<LocalFunctionIndex, _>>();
235
236    // Add function call trampolines
237    for (signature_index, function) in compilation.function_call_trampolines.into_iter() {
238        let function_name =
239            symbol_registry.symbol_to_name(Symbol::FunctionCallTrampoline(signature_index));
240        let section_id = obj.section_id(StandardSection::Text);
241        let symbol_id = obj.add_symbol(ObjSymbol {
242            name: function_name.into_bytes(),
243            value: 0,
244            size: function.body.len() as _,
245            kind: SymbolKind::Text,
246            scope: SymbolScope::Dynamic,
247            weak: false,
248            section: SymbolSection::Section(section_id),
249            flags: SymbolFlags::None,
250        });
251        obj.add_symbol_data(symbol_id, section_id, &function.body, align);
252    }
253
254    // Add dynamic function trampolines
255    for (func_index, function) in compilation.dynamic_function_trampolines.into_iter() {
256        let function_name =
257            symbol_registry.symbol_to_name(Symbol::DynamicFunctionTrampoline(func_index));
258        let section_id = obj.section_id(StandardSection::Text);
259        let symbol_id = obj.add_symbol(ObjSymbol {
260            name: function_name.into_bytes(),
261            value: 0,
262            size: function.body.len() as _,
263            kind: SymbolKind::Text,
264            scope: SymbolScope::Dynamic,
265            weak: false,
266            section: SymbolSection::Section(section_id),
267            flags: SymbolFlags::None,
268        });
269        obj.add_symbol_data(symbol_id, section_id, &function.body, align);
270    }
271
272    let mut all_relocations = Vec::new();
273
274    for (function_local_index, relocations) in function_relocations.into_iter() {
275        let (section_id, symbol_id) = function_symbol_ids.get(function_local_index).unwrap();
276        all_relocations.push((*section_id, *symbol_id, relocations))
277    }
278
279    for (section_index, relocations) in custom_section_relocations.into_iter() {
280        if !debug_index.map_or(false, |d| d == section_index) {
281            // Skip DWARF relocations just yet
282            let (section_id, symbol_id) = custom_section_ids.get(section_index).unwrap();
283            all_relocations.push((*section_id, *symbol_id, relocations));
284        }
285    }
286
287    for (section_id, symbol_id, relocations) in all_relocations.into_iter() {
288        let (_symbol_id, section_offset) = obj.symbol_section_and_offset(symbol_id).unwrap();
289
290        for r in relocations {
291            let relocation_address = section_offset + r.offset as u64;
292
293            let (relocation_kind, relocation_encoding, relocation_size) = match r.kind {
294                Reloc::Abs4 => (RelocationKind::Absolute, RelocationEncoding::Generic, 32),
295                Reloc::Abs8 => (RelocationKind::Absolute, RelocationEncoding::Generic, 64),
296                Reloc::X86PCRel4 => (RelocationKind::Relative, RelocationEncoding::Generic, 32),
297                Reloc::X86CallPCRel4 => {
298                    (RelocationKind::Relative, RelocationEncoding::X86Branch, 32)
299                }
300                Reloc::X86CallPLTRel4 => (
301                    RelocationKind::PltRelative,
302                    RelocationEncoding::X86Branch,
303                    32,
304                ),
305                Reloc::X86GOTPCRel4 => {
306                    (RelocationKind::GotRelative, RelocationEncoding::Generic, 32)
307                }
308                Reloc::Arm64Call => (
309                    match obj.format() {
310                        object::BinaryFormat::Elf => RelocationKind::Elf(elf::R_AARCH64_CALL26),
311                        object::BinaryFormat::MachO => RelocationKind::MachO {
312                            value: macho::ARM64_RELOC_BRANCH26,
313                            relative: true,
314                        },
315                        fmt => panic!("unsupported binary format {fmt:?}"),
316                    },
317                    RelocationEncoding::Generic,
318                    32,
319                ),
320                Reloc::ElfX86_64TlsGd => (
321                    RelocationKind::Elf(elf::R_X86_64_TLSGD),
322                    RelocationEncoding::Generic,
323                    32,
324                ),
325                other => {
326                    return Err(ObjectError::UnsupportedArchitecture(format!(
327                        "{} (relocation: {}",
328                        triple.architecture, other
329                    )))
330                }
331            };
332
333            match r.reloc_target {
334                RelocationTarget::LocalFunc(index) => {
335                    let (_, target_symbol) = function_symbol_ids.get(index).unwrap();
336                    obj.add_relocation(
337                        section_id,
338                        Relocation {
339                            offset: relocation_address,
340                            size: relocation_size,
341                            kind: relocation_kind,
342                            encoding: relocation_encoding,
343                            symbol: *target_symbol,
344                            addend: r.addend,
345                        },
346                    )
347                    .map_err(ObjectError::Write)?;
348                }
349                RelocationTarget::LibCall(libcall) => {
350                    let libcall_fn_name = libcall.to_function_name().as_bytes();
351                    // We add the symols lazily as we see them
352                    let target_symbol = obj.symbol_id(libcall_fn_name).unwrap_or_else(|| {
353                        obj.add_symbol(ObjSymbol {
354                            name: libcall_fn_name.to_vec(),
355                            value: 0,
356                            size: 0,
357                            kind: SymbolKind::Unknown,
358                            scope: SymbolScope::Unknown,
359                            weak: false,
360                            section: SymbolSection::Undefined,
361                            flags: SymbolFlags::None,
362                        })
363                    });
364                    obj.add_relocation(
365                        section_id,
366                        Relocation {
367                            offset: relocation_address,
368                            size: relocation_size,
369                            kind: relocation_kind,
370                            encoding: relocation_encoding,
371                            symbol: target_symbol,
372                            addend: r.addend,
373                        },
374                    )
375                    .map_err(ObjectError::Write)?;
376                }
377                RelocationTarget::CustomSection(section_index) => {
378                    let (_, target_symbol) = custom_section_ids.get(section_index).unwrap();
379                    obj.add_relocation(
380                        section_id,
381                        Relocation {
382                            offset: relocation_address,
383                            size: relocation_size,
384                            kind: relocation_kind,
385                            encoding: relocation_encoding,
386                            symbol: *target_symbol,
387                            addend: r.addend,
388                        },
389                    )
390                    .map_err(ObjectError::Write)?;
391                }
392            };
393        }
394    }
395
396    Ok(())
397}
398
399/// Emit the compilation result into an existing object.
400///
401/// # Usage
402///
403/// ```rust
404/// # use wasmer_compiler::types::{ symbols::SymbolRegistry, target::{Triple}, function::{Compilation} };
405/// # use wasmer_compiler::object::{ObjectError, get_object_for_target, emit_serialized};
406///
407/// # fn emit_compilation_into_object(
408/// #     triple: &Triple,
409/// #     compilation: Compilation,
410/// #     symbol_registry: impl SymbolRegistry,
411/// # ) -> Result<(), ObjectError> {
412/// let bytes = &[ /* compilation bytes */];
413/// let mut object = get_object_for_target(&triple)?;
414/// emit_serialized(&mut object, bytes, &triple, "WASMER_MODULE")?;
415/// # Ok(())
416/// # }
417/// ```
418pub fn emit_serialized(
419    obj: &mut Object,
420    sercomp: &[u8],
421    triple: &Triple,
422    object_name: &str,
423) -> Result<(), ObjectError> {
424    obj.set_mangling(object::write::Mangling::None);
425    //let module_name = module.compile_info.module.name.clone();
426    let len_name = format!("{object_name}_LENGTH");
427    let data_name = format!("{object_name}_DATA");
428    //let metadata_name = "WASMER_MODULE_METADATA";
429
430    let align = match triple.architecture {
431        Architecture::X86_64 => 1,
432        // In Arm64 is recommended a 4-byte alignment
433        Architecture::Aarch64(_) => 4,
434        _ => 1,
435    };
436
437    let len = sercomp.len();
438    let section_id = obj.section_id(StandardSection::Data);
439    let symbol_id = obj.add_symbol(ObjSymbol {
440        name: len_name.as_bytes().to_vec(),
441        value: 0,
442        size: len.to_le_bytes().len() as _,
443        kind: SymbolKind::Data,
444        scope: SymbolScope::Dynamic,
445        weak: false,
446        section: SymbolSection::Section(section_id),
447        flags: SymbolFlags::None,
448    });
449    obj.add_symbol_data(symbol_id, section_id, &len.to_le_bytes(), align);
450
451    let section_id = obj.section_id(StandardSection::Data);
452    let symbol_id = obj.add_symbol(ObjSymbol {
453        name: data_name.as_bytes().to_vec(),
454        value: 0,
455        size: sercomp.len() as _,
456        kind: SymbolKind::Data,
457        scope: SymbolScope::Dynamic,
458        weak: false,
459        section: SymbolSection::Section(section_id),
460        flags: SymbolFlags::None,
461    });
462    obj.add_symbol_data(symbol_id, section_id, sercomp, align);
463
464    Ok(())
465}