wasmer_object/
module.rs

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