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