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