wasmer_compiler/object/
module.rs

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