wasmer_compiler/object/
module.rs

1use super::error::ObjectError;
2use crate::{
3    serialize::MetadataHeader,
4    types::{
5        function::Compilation,
6        relocation::{RelocationKind as Reloc, RelocationTarget},
7        section::{CustomSectionProtection, SectionIndex},
8        symbols::{ModuleMetadata, Symbol, SymbolRegistry},
9    },
10};
11use object::{
12    FileFlags, RelocationEncoding, RelocationFlags, RelocationKind, SectionKind, SymbolFlags,
13    SymbolKind, SymbolScope, elf, macho,
14    write::{
15        Object, Relocation, StandardSection, StandardSegment, Symbol as ObjSymbol, SymbolId,
16        SymbolSection,
17    },
18};
19use wasmer_types::LocalFunctionIndex;
20use wasmer_types::entity::{EntityRef, PrimaryMap};
21use wasmer_types::target::{Architecture, BinaryFormat, Endianness, PointerWidth, Triple};
22
23const DWARF_SECTION_NAME: &[u8] = b".eh_frame";
24
25/// Create an object for a given target `Triple`.
26///
27/// # Usage
28///
29/// ```rust
30/// # use wasmer_types::target::Triple;
31/// # use wasmer_compiler::object::{ObjectError, get_object_for_target};
32///
33/// # fn generate_object_for_target(triple: &Triple) -> Result<(), ObjectError> {
34/// let mut object = get_object_for_target(&triple)?;
35///
36/// # Ok(())
37/// # }
38/// ```
39pub fn get_object_for_target(triple: &Triple) -> Result<Object<'static>, ObjectError> {
40    let obj_binary_format = match triple.binary_format {
41        BinaryFormat::Elf => object::BinaryFormat::Elf,
42        BinaryFormat::Macho => object::BinaryFormat::MachO,
43        BinaryFormat::Coff => object::BinaryFormat::Coff,
44        binary_format => {
45            return Err(ObjectError::UnsupportedBinaryFormat(format!(
46                "{binary_format}"
47            )));
48        }
49    };
50    let obj_architecture = match triple.architecture {
51        Architecture::X86_64 => object::Architecture::X86_64,
52        Architecture::Aarch64(_) => object::Architecture::Aarch64,
53        Architecture::Riscv64(_) => object::Architecture::Riscv64,
54        Architecture::Riscv32(_) => object::Architecture::Riscv32,
55        Architecture::LoongArch64 => object::Architecture::LoongArch64,
56        architecture => {
57            return Err(ObjectError::UnsupportedArchitecture(format!(
58                "{architecture}"
59            )));
60        }
61    };
62    let obj_endianness = match triple
63        .endianness()
64        .map_err(|_| ObjectError::UnknownEndianness)?
65    {
66        Endianness::Little => object::Endianness::Little,
67        Endianness::Big => object::Endianness::Big,
68    };
69
70    let mut object = Object::new(obj_binary_format, obj_architecture, obj_endianness);
71
72    if let Architecture::Riscv64(_) = triple.architecture {
73        object.flags = FileFlags::Elf {
74            e_flags: elf::EF_RISCV_FLOAT_ABI_DOUBLE,
75            os_abi: 2,
76            abi_version: 0,
77        };
78    }
79
80    Ok(object)
81}
82
83/// Write data into an existing object.
84///
85/// # Usage
86///
87/// ```rust
88/// # use wasmer_types::target::Triple;
89/// # use wasmer_compiler::object::{ObjectError, get_object_for_target, emit_data};
90///
91/// # fn emit_data_into_object(triple: &Triple) -> Result<(), ObjectError> {
92/// let mut object = get_object_for_target(&triple)?;
93/// emit_data(&mut object, b"WASMER_METADATA", &b"Hello, World!"[..], 1)?;
94///
95/// # Ok(())
96/// # }
97/// ```
98pub fn emit_data(
99    obj: &mut Object,
100    name: &[u8],
101    data: &[u8],
102    align: u64,
103) -> Result<u64, ObjectError> {
104    let symbol_id = obj.add_symbol(ObjSymbol {
105        name: name.to_vec(),
106        value: 0,
107        size: 0,
108        kind: SymbolKind::Data,
109        scope: SymbolScope::Dynamic,
110        weak: false,
111        section: SymbolSection::Undefined,
112        flags: SymbolFlags::None,
113    });
114    let section_id = obj.section_id(StandardSection::Data);
115    let offset = obj.add_symbol_data(symbol_id, section_id, data, align);
116
117    Ok(offset)
118}
119
120/// Emit the compilation result into an existing object.
121///
122/// # Usage
123///
124/// ```rust
125/// # use wasmer_compiler::types::{ symbols::SymbolRegistry, function::{Compilation} };
126/// # use wasmer_types::target::Triple;
127/// # use wasmer_compiler::object::{ObjectError, ObjectMetadataBuilder, get_object_for_target, emit_compilation};
128///
129/// # fn emit_compilation_into_object(
130/// #     triple: &Triple,
131/// #     compilation: Compilation,
132/// #     builder: ObjectMetadataBuilder,
133/// #     symbol_registry: impl SymbolRegistry,
134/// # ) -> Result<(), ObjectError> {
135/// let mut object = get_object_for_target(&triple)?;
136/// emit_compilation(&mut object, compilation, &symbol_registry, &triple, &builder)?;
137/// # Ok(())
138/// # }
139/// ```
140pub fn emit_compilation(
141    obj: &mut Object,
142    compilation: Compilation,
143    symbol_registry: &impl SymbolRegistry,
144    triple: &Triple,
145    relocs_builder: &ObjectMetadataBuilder,
146) -> Result<(), ObjectError> {
147    let mut function_bodies = PrimaryMap::with_capacity(compilation.functions.len());
148    let mut function_relocations = PrimaryMap::with_capacity(compilation.functions.len());
149    for (_, func) in compilation.functions.into_iter() {
150        function_bodies.push(func.body);
151        function_relocations.push(func.relocations);
152    }
153    let custom_section_relocations = compilation
154        .custom_sections
155        .iter()
156        .map(|(_, section)| section.relocations.clone())
157        .collect::<PrimaryMap<SectionIndex, _>>();
158
159    let debug_index = compilation.unwind_info.eh_frame;
160
161    let default_align = match triple.architecture {
162        target_lexicon::Architecture::Aarch64(_) => {
163            if matches!(
164                triple.operating_system,
165                target_lexicon::OperatingSystem::Darwin(_)
166            ) {
167                8
168            } else {
169                4
170            }
171        }
172        _ => 1,
173    };
174
175    // Add sections
176    let custom_section_ids = compilation
177        .custom_sections
178        .into_iter()
179        .map(|(section_index, custom_section)| {
180            if debug_index == Some(section_index) {
181                // If this is the debug section
182                let segment = obj.segment_name(StandardSegment::Debug).to_vec();
183                let section_id =
184                    obj.add_section(segment, DWARF_SECTION_NAME.to_vec(), SectionKind::Debug);
185                obj.append_section_data(section_id, custom_section.bytes.as_slice(), default_align);
186                let section_name = symbol_registry.symbol_to_name(Symbol::Section(section_index));
187                let symbol_id = obj.add_symbol(ObjSymbol {
188                    name: section_name.into_bytes(),
189                    value: 0,
190                    size: custom_section.bytes.len() as _,
191                    kind: SymbolKind::Data,
192                    scope: SymbolScope::Compilation,
193                    weak: false,
194                    section: SymbolSection::Section(section_id),
195                    flags: SymbolFlags::None,
196                });
197                (section_id, symbol_id)
198            } else {
199                let section_name = symbol_registry.symbol_to_name(Symbol::Section(section_index));
200                let (section_kind, standard_section) = match custom_section.protection {
201                    CustomSectionProtection::ReadExecute => {
202                        (SymbolKind::Text, StandardSection::Text)
203                    }
204                    CustomSectionProtection::Read => (SymbolKind::Data, StandardSection::Data),
205                };
206                let section_id = obj.section_id(standard_section);
207                let symbol_id = obj.add_symbol(ObjSymbol {
208                    name: section_name.into_bytes(),
209                    value: 0,
210                    size: custom_section.bytes.len() as _,
211                    kind: section_kind,
212                    scope: SymbolScope::Dynamic,
213                    weak: false,
214                    section: SymbolSection::Section(section_id),
215                    flags: SymbolFlags::None,
216                });
217                obj.add_symbol_data(
218                    symbol_id,
219                    section_id,
220                    custom_section.bytes.as_slice(),
221                    custom_section.alignment.unwrap_or(default_align),
222                );
223                (section_id, symbol_id)
224            }
225        })
226        .collect::<PrimaryMap<SectionIndex, _>>();
227
228    // Add functions
229    let function_symbol_ids = function_bodies
230        .into_iter()
231        .map(|(function_local_index, function)| {
232            let function_name =
233                symbol_registry.symbol_to_name(Symbol::LocalFunction(function_local_index));
234            let section_id = obj.section_id(StandardSection::Text);
235            let symbol_id = obj.add_symbol(ObjSymbol {
236                name: function_name.into_bytes(),
237                value: 0,
238                size: function.body.len() as _,
239                kind: SymbolKind::Text,
240                scope: SymbolScope::Dynamic,
241                weak: false,
242                section: SymbolSection::Section(section_id),
243                flags: SymbolFlags::None,
244            });
245            let symbol_offset =
246                obj.add_symbol_data(symbol_id, section_id, &function.body, default_align);
247            (section_id, symbol_id, symbol_offset)
248        })
249        .collect::<PrimaryMap<LocalFunctionIndex, _>>();
250    for (i, (_, symbol_id, _)) in function_symbol_ids.iter() {
251        relocs_builder.setup_function_pointer(obj, i.index(), *symbol_id)?;
252    }
253
254    // Add function call trampolines
255    for (signature_index, function) in compilation.function_call_trampolines.into_iter() {
256        let function_name =
257            symbol_registry.symbol_to_name(Symbol::FunctionCallTrampoline(signature_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, default_align);
270
271        relocs_builder.setup_trampoline(obj, signature_index.index(), symbol_id)?;
272    }
273
274    // Add dynamic function trampolines
275    for (func_index, function) in compilation.dynamic_function_trampolines.into_iter() {
276        let function_name =
277            symbol_registry.symbol_to_name(Symbol::DynamicFunctionTrampoline(func_index));
278        let section_id = obj.section_id(StandardSection::Text);
279        let symbol_id = obj.add_symbol(ObjSymbol {
280            name: function_name.into_bytes(),
281            value: 0,
282            size: function.body.len() as _,
283            kind: SymbolKind::Text,
284            scope: SymbolScope::Dynamic,
285            weak: false,
286            section: SymbolSection::Section(section_id),
287            flags: SymbolFlags::None,
288        });
289        obj.add_symbol_data(symbol_id, section_id, &function.body, default_align);
290
291        relocs_builder.setup_dynamic_function_trampoline_pointer(
292            obj,
293            func_index.index(),
294            symbol_id,
295        )?;
296    }
297
298    let mut all_relocations = Vec::new();
299
300    for (function_local_index, relocations) in function_relocations.into_iter() {
301        let (section_id, symbol_id, _) = function_symbol_ids.get(function_local_index).unwrap();
302        all_relocations.push((*section_id, *symbol_id, relocations))
303    }
304
305    for (section_index, relocations) in custom_section_relocations.into_iter() {
306        if debug_index != Some(section_index) {
307            // Skip DWARF relocations just yet
308            let (section_id, symbol_id) = custom_section_ids.get(section_index).unwrap();
309            all_relocations.push((*section_id, *symbol_id, relocations));
310        }
311    }
312
313    for (section_id, symbol_id, relocations) in all_relocations.into_iter() {
314        let (_symbol_id, section_offset) = obj.symbol_section_and_offset(symbol_id).unwrap();
315
316        for r in relocations {
317            let relocation_address = section_offset + r.offset as u64;
318
319            let relocation_flags = match r.kind {
320                Reloc::Abs4 => RelocationFlags::Generic {
321                    kind: RelocationKind::Absolute,
322                    encoding: RelocationEncoding::Generic,
323                    size: 32,
324                },
325                Reloc::Abs8 => RelocationFlags::Generic {
326                    kind: RelocationKind::Absolute,
327                    encoding: RelocationEncoding::Generic,
328                    size: 64,
329                },
330                Reloc::PCRel4 => RelocationFlags::Generic {
331                    kind: RelocationKind::Relative,
332                    encoding: RelocationEncoding::Generic,
333                    size: 32,
334                },
335                Reloc::X86CallPCRel4 => RelocationFlags::Generic {
336                    kind: RelocationKind::Relative,
337                    encoding: RelocationEncoding::X86Branch,
338                    size: 32,
339                },
340                Reloc::X86CallPLTRel4 => RelocationFlags::Generic {
341                    kind: RelocationKind::PltRelative,
342                    encoding: RelocationEncoding::X86Branch,
343                    size: 32,
344                },
345                Reloc::X86GOTPCRel4 => RelocationFlags::Generic {
346                    kind: RelocationKind::GotRelative,
347                    encoding: RelocationEncoding::Generic,
348                    size: 32,
349                },
350                Reloc::Arm64Call => match obj.format() {
351                    object::BinaryFormat::Elf => RelocationFlags::Elf {
352                        r_type: elf::R_AARCH64_CALL26,
353                    },
354                    object::BinaryFormat::MachO => RelocationFlags::MachO {
355                        r_type: macho::ARM64_RELOC_BRANCH26,
356                        r_pcrel: true,
357                        r_length: 32,
358                    },
359                    fmt => panic!("unsupported binary format {fmt:?}"),
360                },
361                Reloc::ElfX86_64TlsGd => RelocationFlags::Elf {
362                    r_type: elf::R_X86_64_TLSGD,
363                },
364                Reloc::MachoArm64RelocBranch26 => RelocationFlags::MachO {
365                    r_type: macho::ARM64_RELOC_BRANCH26,
366                    r_pcrel: true,
367                    r_length: 32,
368                },
369
370                Reloc::MachoArm64RelocUnsigned => RelocationFlags::MachO {
371                    r_type: macho::ARM64_RELOC_UNSIGNED,
372                    r_pcrel: true,
373                    r_length: 32,
374                },
375                Reloc::MachoArm64RelocSubtractor => RelocationFlags::MachO {
376                    r_type: macho::ARM64_RELOC_SUBTRACTOR,
377                    r_pcrel: false,
378                    r_length: 64,
379                },
380                Reloc::MachoArm64RelocPage21 => RelocationFlags::MachO {
381                    r_type: macho::ARM64_RELOC_PAGE21,
382                    r_pcrel: true,
383                    r_length: 32,
384                },
385                Reloc::MachoArm64RelocPageoff12 => RelocationFlags::MachO {
386                    r_type: macho::ARM64_RELOC_PAGEOFF12,
387                    r_pcrel: false,
388                    r_length: 32,
389                },
390                Reloc::MachoArm64RelocGotLoadPage21 => RelocationFlags::MachO {
391                    r_type: macho::ARM64_RELOC_GOT_LOAD_PAGE21,
392                    r_pcrel: true,
393                    r_length: 32,
394                },
395                Reloc::MachoArm64RelocGotLoadPageoff12 => RelocationFlags::MachO {
396                    r_type: macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12,
397                    r_pcrel: true,
398                    r_length: 32,
399                },
400                Reloc::MachoArm64RelocPointerToGot => RelocationFlags::MachO {
401                    r_type: macho::ARM64_RELOC_POINTER_TO_GOT,
402                    r_pcrel: true,
403                    r_length: 32,
404                },
405                Reloc::MachoArm64RelocTlvpLoadPage21 => RelocationFlags::MachO {
406                    r_type: macho::ARM64_RELOC_TLVP_LOAD_PAGE21,
407                    r_pcrel: true,
408                    r_length: 32,
409                },
410                Reloc::MachoArm64RelocTlvpLoadPageoff12 => RelocationFlags::MachO {
411                    r_type: macho::ARM64_RELOC_TLVP_LOAD_PAGEOFF12,
412                    r_pcrel: true,
413                    r_length: 32,
414                },
415                Reloc::MachoArm64RelocAddend => RelocationFlags::MachO {
416                    r_type: macho::ARM64_RELOC_ADDEND,
417                    r_pcrel: false,
418                    r_length: 32,
419                },
420                // For RISC-V relocations, please refer to:
421                // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/2484f950a551c653f1823f1bd11926bf5a57fae3/riscv-elf.adoc#relocations
422                Reloc::RiscvPCRelHi20 => RelocationFlags::Elf {
423                    r_type: elf::R_RISCV_PCREL_HI20,
424                },
425                Reloc::RiscvPCRelLo12I => RelocationFlags::Elf {
426                    r_type: elf::R_RISCV_PCREL_LO12_I,
427                },
428                Reloc::RiscvCall => RelocationFlags::Elf {
429                    r_type: elf::R_RISCV_CALL_PLT,
430                },
431                other => {
432                    return Err(ObjectError::UnsupportedArchitecture(format!(
433                        "{} (relocation: {other:?})",
434                        triple.architecture
435                    )));
436                }
437            };
438
439            match r.reloc_target {
440                RelocationTarget::LocalFunc(index) => {
441                    let (target_section, target_symbol, target_symbol_offset) =
442                        function_symbol_ids.get(index).unwrap();
443                    if r.kind == Reloc::RiscvPCRelLo12I && r.addend != 0 {
444                        // R_RISCV_PCREL_LO12_I requires addend must be zero, lld would ignore
445                        // non-zero addend values, resulting in linking failures. We must create
446                        // new symbols for R_RISCV_PCREL_LO12_I targets(R_RISCV_PCREL_HI20 addresses).
447                        let function_name =
448                            symbol_registry.symbol_to_name(Symbol::LocalFunction(index));
449                        let hi_symbol_name = format!("{}_offset_{}", function_name, r.addend);
450                        let hi_symbol =
451                            obj.symbol_id(hi_symbol_name.as_bytes()).unwrap_or_else(|| {
452                                obj.add_symbol(ObjSymbol {
453                                    name: hi_symbol_name.as_bytes().to_vec(),
454                                    value: *target_symbol_offset + r.addend as u64,
455                                    size: 0,
456                                    kind: SymbolKind::Label,
457                                    scope: SymbolScope::Compilation,
458                                    weak: false,
459                                    section: SymbolSection::Section(*target_section),
460                                    flags: SymbolFlags::None,
461                                })
462                            });
463                        obj.add_relocation(
464                            section_id,
465                            Relocation {
466                                offset: relocation_address,
467                                flags: relocation_flags,
468                                symbol: hi_symbol,
469                                addend: 0,
470                            },
471                        )
472                        .map_err(ObjectError::Write)?;
473                    } else {
474                        obj.add_relocation(
475                            section_id,
476                            Relocation {
477                                offset: relocation_address,
478                                flags: relocation_flags,
479                                symbol: *target_symbol,
480                                addend: r.addend,
481                            },
482                        )
483                        .map_err(ObjectError::Write)?;
484                    }
485                }
486                RelocationTarget::DynamicTrampoline(_) => todo!("Not supported yet"),
487                RelocationTarget::LibCall(libcall) => {
488                    let mut libcall_fn_name = libcall.to_function_name().to_string();
489                    if matches!(triple.binary_format, BinaryFormat::Macho) {
490                        libcall_fn_name = format!("_{libcall_fn_name}");
491                    }
492
493                    let libcall_fn_name = libcall_fn_name.as_bytes();
494
495                    // We add the symols lazily as we see them
496                    let target_symbol = obj.symbol_id(libcall_fn_name).unwrap_or_else(|| {
497                        obj.add_symbol(ObjSymbol {
498                            name: libcall_fn_name.to_vec(),
499                            value: 0,
500                            size: 0,
501                            kind: SymbolKind::Unknown,
502                            scope: SymbolScope::Unknown,
503                            weak: false,
504                            section: SymbolSection::Undefined,
505                            flags: SymbolFlags::None,
506                        })
507                    });
508                    obj.add_relocation(
509                        section_id,
510                        Relocation {
511                            offset: relocation_address,
512                            flags: relocation_flags,
513                            symbol: target_symbol,
514                            addend: r.addend,
515                        },
516                    )
517                    .map_err(ObjectError::Write)?;
518                }
519                RelocationTarget::CustomSection(section_index) => {
520                    let (_, target_symbol) = custom_section_ids.get(section_index).unwrap();
521                    obj.add_relocation(
522                        section_id,
523                        Relocation {
524                            offset: relocation_address,
525                            flags: relocation_flags,
526                            symbol: *target_symbol,
527                            addend: r.addend,
528                        },
529                    )
530                    .map_err(ObjectError::Write)?;
531                }
532            };
533        }
534    }
535
536    Ok(())
537}
538
539/// Emit the compilation result into an existing object.
540///
541/// # Usage
542///
543/// ```rust
544/// # use wasmer_compiler::types::{ symbols::SymbolRegistry, function::{Compilation} };
545/// # use wasmer_types::target::Triple;
546/// # use wasmer_compiler::object::{ObjectError, get_object_for_target, emit_serialized};
547///
548/// # fn emit_compilation_into_object(
549/// #     triple: &Triple,
550/// #     compilation: Compilation,
551/// #     symbol_registry: impl SymbolRegistry,
552/// # ) -> Result<(), ObjectError> {
553/// let bytes = &[ /* compilation bytes */];
554/// let mut object = get_object_for_target(&triple)?;
555/// emit_serialized(&mut object, bytes, &triple, "WASMER_MODULE")?;
556/// # Ok(())
557/// # }
558/// ```
559pub fn emit_serialized(
560    obj: &mut Object,
561    sercomp: &[u8],
562    triple: &Triple,
563    object_name: &str,
564) -> Result<(), ObjectError> {
565    obj.set_mangling(object::write::Mangling::None);
566    //let module_name = module.compile_info.module.name.clone();
567    let len_name = format!("{object_name}_LENGTH");
568    let data_name = format!("{object_name}_DATA");
569    //let metadata_name = "WASMER_MODULE_METADATA";
570
571    let align = match triple.architecture {
572        Architecture::X86_64 => 1,
573        // In Arm64 is recommended a 4-byte alignment
574        Architecture::Aarch64(_) => 4,
575        _ => 1,
576    };
577
578    let len = sercomp.len();
579    let section_id = obj.section_id(StandardSection::Data);
580    let symbol_id = obj.add_symbol(ObjSymbol {
581        name: len_name.as_bytes().to_vec(),
582        value: 0,
583        size: len.to_le_bytes().len() as _,
584        kind: SymbolKind::Data,
585        scope: SymbolScope::Dynamic,
586        weak: false,
587        section: SymbolSection::Section(section_id),
588        flags: SymbolFlags::None,
589    });
590    obj.add_symbol_data(symbol_id, section_id, &len.to_le_bytes(), align);
591
592    let section_id = obj.section_id(StandardSection::Data);
593    let symbol_id = obj.add_symbol(ObjSymbol {
594        name: data_name.as_bytes().to_vec(),
595        value: 0,
596        size: sercomp.len() as _,
597        kind: SymbolKind::Data,
598        scope: SymbolScope::Dynamic,
599        weak: false,
600        section: SymbolSection::Section(section_id),
601        flags: SymbolFlags::None,
602    });
603    obj.add_symbol_data(symbol_id, section_id, sercomp, align);
604
605    Ok(())
606}
607
608/// ObjectMetadataBuilder builds serialized module metadata include in
609/// an object. In addition, it also relies on information from ModuleInfo
610/// to build a table of function pointers, trmampolines and dynamic function
611/// trampoline pointers. ObjectMetadataBuilder takes care of setting up
612/// relocations, so a linker can automatically fill in actuall addesses of
613/// all relavant functions. There is no need to piece the information together
614/// in the glue C file.
615pub struct ObjectMetadataBuilder {
616    placeholder_data: Vec<u8>,
617    metadata_length: u64,
618    section_offset: u64,
619    num_function_pointers: u64,
620    num_trampolines: u64,
621    num_dynamic_function_trampoline_pointers: u64,
622    endianness: Endianness,
623    pointer_width: PointerWidth,
624}
625
626impl ObjectMetadataBuilder {
627    /// Creates a new FunctionRelocsBuilder
628    pub fn new(metadata: &ModuleMetadata, triple: &Triple) -> Result<Self, ObjectError> {
629        let serialized_data = metadata.serialize()?;
630        let mut metadata_binary = vec![];
631        metadata_binary.extend(MetadataHeader::new(serialized_data.len()).into_bytes());
632        metadata_binary.extend(serialized_data);
633        let metadata_length = metadata_binary.len() as u64;
634
635        let pointer_width = triple.pointer_width().unwrap();
636        let endianness = triple
637            .endianness()
638            .map_err(|_| ObjectError::UnknownEndianness)?;
639
640        let module = &metadata.compile_info.module;
641        let num_function_pointers = module
642            .functions
643            .iter()
644            .filter(|(f_index, _)| module.local_func_index(*f_index).is_some())
645            .count() as u64;
646        let num_trampolines = module.signatures.len() as u64;
647        let num_dynamic_function_trampoline_pointers = module.num_imported_functions as u64;
648
649        let mut aself = Self {
650            placeholder_data: metadata_binary,
651            metadata_length,
652            section_offset: 0,
653            num_function_pointers,
654            num_trampolines,
655            num_dynamic_function_trampoline_pointers,
656            endianness,
657            pointer_width,
658        };
659
660        aself
661            .placeholder_data
662            .extend_from_slice(&aself.serialize_value(aself.num_function_pointers));
663        aself.placeholder_data.extend_from_slice(&vec![
664            0u8;
665            (aself.pointer_bytes() * aself.num_function_pointers)
666                as usize
667        ]);
668        aself
669            .placeholder_data
670            .extend_from_slice(&aself.serialize_value(aself.num_trampolines));
671        aself.placeholder_data.extend_from_slice(&vec![
672            0u8;
673            (aself.pointer_bytes() * aself.num_trampolines)
674                as usize
675        ]);
676        aself.placeholder_data.extend_from_slice(
677            &aself.serialize_value(aself.num_dynamic_function_trampoline_pointers),
678        );
679        aself.placeholder_data.extend_from_slice(&vec![
680            0u8;
681            (aself.pointer_bytes() * aself.num_dynamic_function_trampoline_pointers)
682                as usize
683        ]);
684
685        Ok(aself)
686    }
687
688    /// Sets section offset used in relocations
689    pub fn set_section_offset(&mut self, offset: u64) {
690        self.section_offset = offset;
691    }
692
693    /// Placeholder data for emit_data call
694    pub fn placeholder_data(&self) -> &[u8] {
695        &self.placeholder_data
696    }
697
698    /// Bytes of a pointer for target architecture
699    pub fn pointer_bytes(&self) -> u64 {
700        self.pointer_width.bytes() as u64
701    }
702
703    /// Sets up relocation for a function pointer
704    pub fn setup_function_pointer(
705        &self,
706        obj: &mut Object,
707        index: usize,
708        symbol_id: SymbolId,
709    ) -> Result<(), ObjectError> {
710        let section_id = obj.section_id(StandardSection::Data);
711        obj.add_relocation(
712            section_id,
713            Relocation {
714                offset: self.function_pointers_start_offset()
715                    + self.pointer_bytes() * (index as u64),
716                flags: RelocationFlags::Generic {
717                    kind: RelocationKind::Absolute,
718                    encoding: RelocationEncoding::Generic,
719                    size: self.pointer_width.bits(),
720                },
721                symbol: symbol_id,
722                addend: 0,
723            },
724        )
725        .map_err(ObjectError::Write)
726    }
727
728    /// Sets up relocation for a trampoline
729    pub fn setup_trampoline(
730        &self,
731        obj: &mut Object,
732        index: usize,
733        symbol_id: SymbolId,
734    ) -> Result<(), ObjectError> {
735        let section_id = obj.section_id(StandardSection::Data);
736        obj.add_relocation(
737            section_id,
738            Relocation {
739                offset: self.trampolines_start_offset() + self.pointer_bytes() * (index as u64),
740                flags: RelocationFlags::Generic {
741                    kind: RelocationKind::Absolute,
742                    encoding: RelocationEncoding::Generic,
743                    size: self.pointer_width.bits(),
744                },
745                symbol: symbol_id,
746                addend: 0,
747            },
748        )
749        .map_err(ObjectError::Write)
750    }
751
752    /// Sets up relocation for a dynamic function trampoline pointer
753    pub fn setup_dynamic_function_trampoline_pointer(
754        &self,
755        obj: &mut Object,
756        index: usize,
757        symbol_id: SymbolId,
758    ) -> Result<(), ObjectError> {
759        let section_id = obj.section_id(StandardSection::Data);
760        obj.add_relocation(
761            section_id,
762            Relocation {
763                offset: self.dynamic_function_trampoline_pointers_start_offset()
764                    + self.pointer_bytes() * (index as u64),
765                flags: RelocationFlags::Generic {
766                    kind: RelocationKind::Absolute,
767                    encoding: RelocationEncoding::Generic,
768                    size: self.pointer_width.bits(),
769                },
770                symbol: symbol_id,
771                addend: 0,
772            },
773        )
774        .map_err(ObjectError::Write)
775    }
776
777    fn function_pointers_start_offset(&self) -> u64 {
778        self.section_offset + self.metadata_length + self.pointer_bytes()
779    }
780
781    fn trampolines_start_offset(&self) -> u64 {
782        self.function_pointers_start_offset()
783            + self.pointer_bytes() * self.num_function_pointers
784            + self.pointer_bytes()
785    }
786
787    fn dynamic_function_trampoline_pointers_start_offset(&self) -> u64 {
788        self.trampolines_start_offset()
789            + self.pointer_bytes() * self.num_trampolines
790            + self.pointer_bytes()
791    }
792
793    fn serialize_value(&self, value: u64) -> Vec<u8> {
794        match (self.endianness, self.pointer_width) {
795            (Endianness::Little, PointerWidth::U16) => (value as u16).to_le_bytes().to_vec(),
796            (Endianness::Big, PointerWidth::U16) => (value as u16).to_be_bytes().to_vec(),
797            (Endianness::Little, PointerWidth::U32) => (value as u32).to_le_bytes().to_vec(),
798            (Endianness::Big, PointerWidth::U32) => (value as u32).to_be_bytes().to_vec(),
799            (Endianness::Little, PointerWidth::U64) => value.to_le_bytes().to_vec(),
800            (Endianness::Big, PointerWidth::U64) => value.to_be_bytes().to_vec(),
801        }
802    }
803}