wasmer_compiler_llvm/
object_file.rs

1use object::{Object, ObjectSection, ObjectSymbol};
2use target_lexicon::BinaryFormat;
3
4use std::collections::{HashMap, HashSet};
5use std::convert::TryInto;
6use std::num::TryFromIntError;
7
8use wasmer_types::{CompileError, SourceLoc, entity::PrimaryMap};
9
10use wasmer_compiler::types::{
11    address_map::{FunctionAddressMap, InstructionAddressMap},
12    function::{CompiledFunctionFrameInfo, CustomSections, FunctionBody},
13    relocation::{Relocation, RelocationKind, RelocationTarget},
14    section::{CustomSection, CustomSectionProtection, SectionBody, SectionIndex},
15};
16
17use wasmer_vm::libcalls::LibCall;
18
19fn map_tryfromint_err(error: TryFromIntError) -> CompileError {
20    CompileError::Codegen(format!("int doesn't fit: {error}"))
21}
22
23fn map_object_err(error: object::read::Error) -> CompileError {
24    CompileError::Codegen(format!("error parsing object file: {error}"))
25}
26
27#[derive(Debug)]
28pub struct CompiledFunction {
29    pub compiled_function: wasmer_compiler::types::function::CompiledFunction,
30    pub custom_sections: CustomSections,
31    pub eh_frame_section_indices: Vec<SectionIndex>,
32    pub compact_unwind_section_indices: Vec<SectionIndex>,
33}
34
35static LIBCALLS_ELF: phf::Map<&'static str, LibCall> = phf::phf_map! {
36    "ceilf" => LibCall::CeilF32,
37    "ceil" => LibCall::CeilF64,
38    "floorf" => LibCall::FloorF32,
39    "floor" => LibCall::FloorF64,
40    "nearbyintf" => LibCall::NearestF32,
41    "nearbyint" => LibCall::NearestF64,
42    "truncf" => LibCall::TruncF32,
43    "trunc" => LibCall::TruncF64,
44    "wasmer_vm_f32_ceil" => LibCall::CeilF32,
45    "wasmer_vm_f64_ceil" => LibCall::CeilF64,
46    "wasmer_vm_f32_floor" => LibCall::FloorF32,
47    "wasmer_vm_f64_floor" => LibCall::FloorF64,
48    "wasmer_vm_f32_nearest" => LibCall::NearestF32,
49    "wasmer_vm_f64_nearest" => LibCall::NearestF64,
50    "wasmer_vm_f32_trunc" => LibCall::TruncF32,
51    "wasmer_vm_f64_trunc" => LibCall::TruncF64,
52    "wasmer_vm_memory32_size" => LibCall::Memory32Size,
53    "wasmer_vm_imported_memory32_size" => LibCall::ImportedMemory32Size,
54    "wasmer_vm_table_copy" => LibCall::TableCopy,
55    "wasmer_vm_table_init" => LibCall::TableInit,
56    "wasmer_vm_table_fill" => LibCall::TableFill,
57    "wasmer_vm_table_size" => LibCall::TableSize,
58    "wasmer_vm_imported_table_size" => LibCall::ImportedTableSize,
59    "wasmer_vm_table_get" => LibCall::TableGet,
60    "wasmer_vm_imported_table_get" => LibCall::ImportedTableGet,
61    "wasmer_vm_table_set" => LibCall::TableSet,
62    "wasmer_vm_imported_table_set" => LibCall::ImportedTableSet,
63    "wasmer_vm_table_grow" => LibCall::TableGrow,
64    "wasmer_vm_imported_table_grow" => LibCall::ImportedTableGrow,
65    "wasmer_vm_func_ref" => LibCall::FuncRef,
66    "wasmer_vm_elem_drop" => LibCall::ElemDrop,
67    "wasmer_vm_memory32_copy" => LibCall::Memory32Copy,
68    "wasmer_vm_imported_memory32_copy" => LibCall::ImportedMemory32Copy,
69    "wasmer_vm_memory32_fill" => LibCall::Memory32Fill,
70    "wasmer_vm_imported_memory32_fill" => LibCall::ImportedMemory32Fill,
71    "wasmer_vm_memory32_init" => LibCall::Memory32Init,
72    "wasmer_vm_data_drop" => LibCall::DataDrop,
73    "wasmer_vm_raise_trap" => LibCall::RaiseTrap,
74    "wasmer_vm_memory32_atomic_wait32" => LibCall::Memory32AtomicWait32,
75    "wasmer_vm_imported_memory32_atomic_wait32" => LibCall::ImportedMemory32AtomicWait32,
76    "wasmer_vm_memory32_atomic_wait64" => LibCall::Memory32AtomicWait64,
77    "wasmer_vm_imported_memory32_atomic_wait64" => LibCall::ImportedMemory32AtomicWait64,
78    "wasmer_vm_memory32_atomic_notify" => LibCall::Memory32AtomicNotify,
79    "wasmer_vm_imported_memory32_atomic_notify" => LibCall::ImportedMemory32AtomicNotify,
80    "wasmer_vm_throw" => LibCall::Throw,
81    "wasmer_vm_rethrow" => LibCall::Rethrow,
82    "wasmer_vm_alloc_exception" => LibCall::AllocException,
83    "wasmer_vm_delete_exception" => LibCall::DeleteException,
84    "wasmer_vm_read_exception" => LibCall::ReadException,
85    "wasmer_vm_dbg_usize" => LibCall::DebugUsize,
86    "wasmer_eh_personality" => LibCall::EHPersonality,
87    "wasmer_eh_personality2" => LibCall::EHPersonality2,
88    "wasmer_vm_dbg_str" => LibCall::DebugStr,
89};
90
91static LIBCALLS_MACHO: phf::Map<&'static str, LibCall> = phf::phf_map! {
92    "_ceilf" => LibCall::CeilF32,
93    "_ceil" => LibCall::CeilF64,
94    "_floorf" => LibCall::FloorF32,
95    "_floor" => LibCall::FloorF64,
96    "_nearbyintf" => LibCall::NearestF32,
97    "_nearbyint" => LibCall::NearestF64,
98    "_truncf" => LibCall::TruncF32,
99    "_trunc" => LibCall::TruncF64,
100    "_wasmer_vm_f32_ceil" => LibCall::CeilF32,
101    "_wasmer_vm_f64_ceil" => LibCall::CeilF64,
102    "_wasmer_vm_f32_floor" => LibCall::FloorF32,
103    "_wasmer_vm_f64_floor" => LibCall::FloorF64,
104    "_wasmer_vm_f32_nearest" => LibCall::NearestF32,
105    "_wasmer_vm_f64_nearest" => LibCall::NearestF64,
106    "_wasmer_vm_f32_trunc" => LibCall::TruncF32,
107    "_wasmer_vm_f64_trunc" => LibCall::TruncF64,
108    "_wasmer_vm_memory32_size" => LibCall::Memory32Size,
109    "_wasmer_vm_imported_memory32_size" => LibCall::ImportedMemory32Size,
110    "_wasmer_vm_table_copy" => LibCall::TableCopy,
111    "_wasmer_vm_table_init" => LibCall::TableInit,
112    "_wasmer_vm_table_fill" => LibCall::TableFill,
113    "_wasmer_vm_table_size" => LibCall::TableSize,
114    "_wasmer_vm_imported_table_size" => LibCall::ImportedTableSize,
115    "_wasmer_vm_table_get" => LibCall::TableGet,
116    "_wasmer_vm_imported_table_get" => LibCall::ImportedTableGet,
117    "_wasmer_vm_table_set" => LibCall::TableSet,
118    "_wasmer_vm_imported_table_set" => LibCall::ImportedTableSet,
119    "_wasmer_vm_table_grow" => LibCall::TableGrow,
120    "_wasmer_vm_imported_table_grow" => LibCall::ImportedTableGrow,
121    "_wasmer_vm_func_ref" => LibCall::FuncRef,
122    "_wasmer_vm_elem_drop" => LibCall::ElemDrop,
123    "_wasmer_vm_memory32_copy" => LibCall::Memory32Copy,
124    "_wasmer_vm_imported_memory32_copy" => LibCall::ImportedMemory32Copy,
125    "_wasmer_vm_memory32_fill" => LibCall::Memory32Fill,
126    "_wasmer_vm_imported_memory32_fill" => LibCall::ImportedMemory32Fill,
127    "_wasmer_vm_memory32_init" => LibCall::Memory32Init,
128    "_wasmer_vm_data_drop" => LibCall::DataDrop,
129    "_wasmer_vm_raise_trap" => LibCall::RaiseTrap,
130    "_wasmer_vm_memory32_atomic_wait32" => LibCall::Memory32AtomicWait32,
131    "_wasmer_vm_imported_memory32_atomic_wait32" => LibCall::ImportedMemory32AtomicWait32,
132    "_wasmer_vm_memory32_atomic_wait64" => LibCall::Memory32AtomicWait64,
133    "_wasmer_vm_imported_memory32_atomic_wait64" => LibCall::ImportedMemory32AtomicWait64,
134    "_wasmer_vm_memory32_atomic_notify" => LibCall::Memory32AtomicNotify,
135    "_wasmer_vm_imported_memory32_atomic_notify" => LibCall::ImportedMemory32AtomicNotify,
136    "_wasmer_vm_throw" => LibCall::Throw,
137    "_wasmer_vm_rethrow" => LibCall::Rethrow,
138    "_wasmer_vm_alloc_exception" => LibCall::AllocException,
139    "_wasmer_vm_delete_exception" => LibCall::DeleteException,
140    "_wasmer_vm_read_exception" => LibCall::ReadException,
141    "_wasmer_vm_dbg_usize" => LibCall::DebugUsize,
142    // Note: on macOS+Mach-O the personality function *must* be called like this, otherwise LLVM
143    // will generate things differently than "normal", wreaking havoc.
144    //
145    // todo: find out if it is a bug in LLVM or it is expected.
146    "___gxx_personality_v0" => LibCall::EHPersonality,
147    "_wasmer_eh_personality2" => LibCall::EHPersonality2,
148    "_wasmer_vm_dbg_str" => LibCall::DebugStr,
149};
150
151pub fn load_object_file<F>(
152    contents: &[u8],
153    root_section: &str,
154    root_section_reloc_target: RelocationTarget,
155    mut symbol_name_to_relocation_target: F,
156    binary_fmt: BinaryFormat,
157) -> Result<CompiledFunction, CompileError>
158where
159    F: FnMut(&str) -> Result<Option<RelocationTarget>, CompileError>,
160{
161    let obj = object::File::parse(contents).map_err(map_object_err)?;
162
163    let libcalls = match binary_fmt {
164        BinaryFormat::Elf => &LIBCALLS_ELF,
165        BinaryFormat::Macho => &LIBCALLS_MACHO,
166        _ => {
167            return Err(CompileError::UnsupportedTarget(format!(
168                "Unsupported binary format {binary_fmt:?}"
169            )));
170        }
171    };
172
173    let mut visited: HashSet<object::read::SectionIndex> = HashSet::new();
174    let mut worklist: Vec<object::read::SectionIndex> = Vec::new();
175    let mut section_targets: HashMap<object::read::SectionIndex, RelocationTarget> = HashMap::new();
176
177    let root_section_index = obj
178        .section_by_name(root_section)
179        .ok_or_else(|| CompileError::Codegen(format!("no section named {root_section}")))?
180        .index();
181
182    let mut section_to_custom_section = HashMap::new();
183
184    section_targets.insert(root_section_index, root_section_reloc_target);
185
186    let mut next_custom_section: u32 = 0;
187
188    let mut elf_section_to_target = |elf_section_index: object::read::SectionIndex| {
189        *section_targets.entry(elf_section_index).or_insert_with(|| {
190            let next = SectionIndex::from_u32(next_custom_section);
191            section_to_custom_section.insert(elf_section_index, next);
192            let target = RelocationTarget::CustomSection(next);
193            next_custom_section += 1;
194            target
195        })
196    };
197
198    // From elf section index to list of Relocations. Although we use a Vec,
199    // the order of relocations is not important.
200    let mut relocations: HashMap<object::read::SectionIndex, Vec<Relocation>> = HashMap::new();
201
202    // Each iteration of this loop pulls a section and the relocations
203    // that apply to it. We begin with the ".root_section"
204    // section, and then parse all relocation sections that apply to that
205    // section. Those relocations may refer to additional sections which we
206    // then add to the worklist until we've visited the closure of
207    // everything needed to run the code in ".root_section".
208    //
209    // `worklist` is the list of sections we have yet to visit. It never
210    // contains any duplicates or sections we've already visited. `visited`
211    // contains all the sections we've ever added to the worklist in a set
212    // so that we can quickly check whether a section is new before adding
213    // it to worklist. `section_to_custom_section` is filled in with all
214    // the sections we want to include.
215    worklist.push(root_section_index);
216    visited.insert(root_section_index);
217
218    // Add any .eh_frame sections.
219    let mut eh_frame_section_indices = vec![];
220
221    // Add macos-specific unwind sections.
222    let mut compact_unwind_section_indices = vec![];
223
224    for section in obj.sections() {
225        let index = section.index();
226        if section.kind() == object::SectionKind::Elf(object::elf::SHT_X86_64_UNWIND)
227            || section.name().unwrap_or_default() == "__eh_frame"
228        {
229            worklist.push(index);
230            eh_frame_section_indices.push(index);
231
232            // This allocates a custom section index for the ELF section.
233            elf_section_to_target(index);
234        } else if section.name().unwrap_or_default() == "__compact_unwind" {
235            worklist.push(index);
236            compact_unwind_section_indices.push(index);
237
238            elf_section_to_target(index);
239        }
240    }
241
242    while let Some(section_index) = worklist.pop() {
243        let sec = obj
244            .section_by_index(section_index)
245            .map_err(map_object_err)?;
246        let relocs = sec.relocations();
247        for (offset, reloc) in relocs {
248            let mut addend = reloc.addend();
249            let target = match reloc.target() {
250                object::read::RelocationTarget::Symbol(index) => {
251                    let symbol = obj.symbol_by_index(index).map_err(map_object_err)?;
252                    let symbol_name = symbol.name().map_err(map_object_err)?;
253                    if symbol.kind() == object::SymbolKind::Section {
254                        match symbol.section() {
255                            object::SymbolSection::Section(section_index) => {
256                                if section_index == root_section_index {
257                                    root_section_reloc_target
258                                } else {
259                                    if visited.insert(section_index) {
260                                        worklist.push(section_index);
261                                    }
262                                    elf_section_to_target(section_index)
263                                }
264                            }
265                            _ => {
266                                return Err(CompileError::Codegen(format!(
267                                    "relocation targets unknown section {reloc:?}",
268                                )));
269                            }
270                        }
271                        // Maybe a libcall then?
272                    } else if let Some(libcall) = libcalls.get(symbol_name) {
273                        RelocationTarget::LibCall(*libcall)
274                    } else if let Ok(Some(reloc_target)) =
275                        symbol_name_to_relocation_target(symbol_name)
276                    {
277                        reloc_target
278                    } else if let object::SymbolSection::Section(section_index) = symbol.section() {
279                        if matches!(
280                            reloc.kind(),
281                            object::RelocationKind::MachO {
282                                value: object::macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12,
283                                relative: false
284                            } | object::RelocationKind::MachO {
285                                value: object::macho::ARM64_RELOC_POINTER_TO_GOT,
286                                relative: true
287                            } | object::RelocationKind::MachO {
288                                value: object::macho::ARM64_RELOC_GOT_LOAD_PAGE21,
289                                relative: true
290                            } | object::RelocationKind::MachO {
291                                value: object::macho::ARM64_RELOC_PAGE21,
292                                relative: true
293                            } | object::RelocationKind::MachO {
294                                value: object::macho::ARM64_RELOC_PAGEOFF12,
295                                relative: false
296                            }
297                        ) {
298                            // (caveat: this comment comes from a point in time after the `addend`
299                            // math in the else branch)
300                            //
301                            // (caveat2: this is mach-o + aarch64 only)
302                            //
303                            // The tampering with the addend in the else branch causes some
304                            // problems with GOT-based relocs, as a non-zero addend has no meaning
305                            // when dealing with GOT entries, for our use-case.
306                            //
307                            // However, for some reasons, it happens that we conceptually need to
308                            // have relocations that pretty much mean "the contents of this GOT
309                            // entry plus a non-zero addend". When in this case, we will later
310                            // perform what is known as "GOT relaxation", i.e. we can change the
311                            // `ldr` opcode to an `add`.
312                            //
313                            // For this to make sense we need to fix the addend to be the delta
314                            // between the section whose address is an entry of the GOT and the
315                            // symbol that is the target of the relocation.
316
317                            let symbol_sec = obj
318                                .section_by_index(section_index)
319                                .map_err(map_object_err)?;
320
321                            addend = addend
322                                .wrapping_add((symbol.address() - symbol_sec.address()) as i64);
323                        } else {
324                            // TODO: Encode symbol address into addend, I think this is a bit hacky.
325                            addend = addend.wrapping_add(symbol.address() as i64);
326                        }
327
328                        if section_index == root_section_index {
329                            root_section_reloc_target
330                        } else {
331                            if visited.insert(section_index) {
332                                worklist.push(section_index);
333                            }
334
335                            elf_section_to_target(section_index)
336                        }
337                    } else {
338                        return Err(CompileError::Codegen(format!(
339                            "relocation {reloc:?} targets unknown symbol '{symbol:?}'",
340                        )));
341                    }
342                }
343
344                object::read::RelocationTarget::Section(index) => {
345                    if index == root_section_index {
346                        root_section_reloc_target
347                    } else {
348                        if visited.insert(index) {
349                            worklist.push(index);
350                        }
351                        elf_section_to_target(index)
352                    }
353                }
354
355                object::read::RelocationTarget::Absolute => {
356                    // Wasm-produced object files should never have absolute
357                    // addresses in them because none of the parts of the Wasm
358                    // VM, nor the generated code are loaded at fixed addresses.
359                    return Err(CompileError::Codegen(format!(
360                        "relocation targets absolute address {reloc:?}",
361                    )));
362                }
363
364                // `object::read::RelocationTarget` is a
365                // non-exhaustive enum (`#[non_exhaustive]`), so it
366                // could have additional variants added in the
367                // future. Therefore, when matching against variants
368                // of non-exhaustive enums, an extra wildcard arm must
369                // be added to account for any future variants.
370                t => {
371                    return Err(CompileError::Codegen(format!(
372                        "relocation target is unknown `{t:?}`",
373                    )));
374                }
375            };
376            let kind = match (obj.architecture(), reloc.kind(), reloc.size()) {
377                (_, object::RelocationKind::Absolute, 64) => RelocationKind::Abs8,
378                (_, object::RelocationKind::Absolute, 32) => RelocationKind::Abs4,
379                (
380                    object::Architecture::X86_64,
381                    object::RelocationKind::Elf(object::elf::R_X86_64_PC64),
382                    0,
383                ) => RelocationKind::X86PCRel8,
384                (object::Architecture::Aarch64, object::RelocationKind::PltRelative, 26) => {
385                    RelocationKind::Arm64Call
386                }
387                (
388                    object::Architecture::Aarch64,
389                    object::RelocationKind::Elf(object::elf::R_AARCH64_MOVW_UABS_G0_NC),
390                    0,
391                ) => RelocationKind::Arm64Movw0,
392                (
393                    object::Architecture::Aarch64,
394                    object::RelocationKind::Elf(object::elf::R_AARCH64_MOVW_UABS_G1_NC),
395                    0,
396                ) => RelocationKind::Arm64Movw1,
397                (
398                    object::Architecture::Aarch64,
399                    object::RelocationKind::Elf(object::elf::R_AARCH64_MOVW_UABS_G2_NC),
400                    0,
401                ) => RelocationKind::Arm64Movw2,
402                (
403                    object::Architecture::Aarch64,
404                    object::RelocationKind::Elf(object::elf::R_AARCH64_MOVW_UABS_G3),
405                    0,
406                ) => RelocationKind::Arm64Movw3,
407                (
408                    object::Architecture::Riscv64,
409                    object::RelocationKind::Elf(object::elf::R_RISCV_CALL_PLT),
410                    0,
411                ) => RelocationKind::RiscvCall,
412                (
413                    object::Architecture::Riscv64,
414                    object::RelocationKind::Elf(object::elf::R_RISCV_PCREL_HI20),
415                    0,
416                ) => RelocationKind::RiscvPCRelHi20,
417                (
418                    object::Architecture::Riscv64,
419                    object::RelocationKind::Elf(object::elf::R_RISCV_PCREL_LO12_I),
420                    0,
421                ) => RelocationKind::RiscvPCRelLo12I,
422                (
423                    object::Architecture::LoongArch64,
424                    object::RelocationKind::Elf(object::elf::R_LARCH_ABS_HI20),
425                    0,
426                ) => RelocationKind::LArchAbsHi20,
427                (
428                    object::Architecture::LoongArch64,
429                    object::RelocationKind::Elf(object::elf::R_LARCH_ABS_LO12),
430                    0,
431                ) => RelocationKind::LArchAbsLo12,
432                (
433                    object::Architecture::LoongArch64,
434                    object::RelocationKind::Elf(object::elf::R_LARCH_ABS64_HI12),
435                    0,
436                ) => RelocationKind::LArchAbs64Hi12,
437                (
438                    object::Architecture::LoongArch64,
439                    object::RelocationKind::Elf(object::elf::R_LARCH_ABS64_LO20),
440                    0,
441                ) => RelocationKind::LArchAbs64Lo20,
442                (
443                    object::Architecture::LoongArch64,
444                    // FIXME: Replace with R_LARCH_CALL36 while object is updated
445                    // to 0.32.2.
446                    // https://github.com/gimli-rs/object/commit/16b6d902f6c9b39ec7aaea141460f8981e57dd79
447                    object::RelocationKind::Elf(110),
448                    0,
449                ) => RelocationKind::LArchCall36,
450                (
451                    object::Architecture::LoongArch64,
452                    object::RelocationKind::Elf(object::elf::R_LARCH_PCALA_HI20),
453                    0,
454                ) => RelocationKind::LArchPCAlaHi20,
455                (
456                    object::Architecture::LoongArch64,
457                    object::RelocationKind::Elf(object::elf::R_LARCH_PCALA_LO12),
458                    0,
459                ) => RelocationKind::LArchPCAlaLo12,
460                (
461                    object::Architecture::LoongArch64,
462                    object::RelocationKind::Elf(object::elf::R_LARCH_PCALA64_HI12),
463                    0,
464                ) => RelocationKind::LArchPCAla64Hi12,
465                (
466                    object::Architecture::LoongArch64,
467                    object::RelocationKind::Elf(object::elf::R_LARCH_PCALA64_LO20),
468                    0,
469                ) => RelocationKind::LArchPCAla64Lo20,
470                (
471                    object::Architecture::Aarch64,
472                    object::RelocationKind::Elf(object::elf::R_AARCH64_ADR_PREL_LO21),
473                    0,
474                ) => RelocationKind::Aarch64AdrPrelLo21,
475                (
476                    object::Architecture::Aarch64,
477                    object::RelocationKind::Elf(object::elf::R_AARCH64_ADR_PREL_PG_HI21),
478                    0,
479                ) => RelocationKind::Aarch64AdrPrelPgHi21,
480                (
481                    object::Architecture::Aarch64,
482                    object::RelocationKind::Elf(object::elf::R_AARCH64_LDST128_ABS_LO12_NC),
483                    0,
484                ) => RelocationKind::Aarch64Ldst128AbsLo12Nc,
485                (
486                    object::Architecture::Aarch64,
487                    object::RelocationKind::Elf(object::elf::R_AARCH64_ADD_ABS_LO12_NC),
488                    0,
489                ) => RelocationKind::Aarch64AddAbsLo12Nc,
490                (
491                    object::Architecture::Aarch64,
492                    object::RelocationKind::Elf(object::elf::R_AARCH64_LDST64_ABS_LO12_NC),
493                    0,
494                ) => RelocationKind::Aarch64Ldst64AbsLo12Nc,
495                (object::Architecture::Aarch64, object::RelocationKind::MachO { value, .. }, _) => {
496                    match value {
497                        object::macho::ARM64_RELOC_UNSIGNED => {
498                            RelocationKind::MachoArm64RelocUnsigned
499                        }
500                        object::macho::ARM64_RELOC_SUBTRACTOR => {
501                            RelocationKind::MachoArm64RelocSubtractor
502                        }
503                        object::macho::ARM64_RELOC_BRANCH26 => {
504                            RelocationKind::MachoArm64RelocBranch26
505                        }
506                        object::macho::ARM64_RELOC_PAGE21 => RelocationKind::MachoArm64RelocPage21,
507                        object::macho::ARM64_RELOC_PAGEOFF12 => {
508                            RelocationKind::MachoArm64RelocPageoff12
509                        }
510                        object::macho::ARM64_RELOC_GOT_LOAD_PAGE21 => {
511                            RelocationKind::MachoArm64RelocGotLoadPage21
512                        }
513                        object::macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12 => {
514                            RelocationKind::MachoArm64RelocGotLoadPageoff12
515                        }
516                        object::macho::ARM64_RELOC_POINTER_TO_GOT => {
517                            RelocationKind::MachoArm64RelocPointerToGot
518                        }
519                        object::macho::ARM64_RELOC_TLVP_LOAD_PAGE21 => {
520                            RelocationKind::MachoArm64RelocTlvpLoadPage21
521                        }
522                        object::macho::ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => {
523                            RelocationKind::MachoArm64RelocTlvpLoadPageoff12
524                        }
525                        object::macho::ARM64_RELOC_ADDEND => RelocationKind::MachoArm64RelocAddend,
526                        _ => {
527                            return Err(CompileError::Codegen(format!(
528                                "unknown relocation {reloc:?}",
529                            )));
530                        }
531                    }
532                }
533                (object::Architecture::X86_64, object::RelocationKind::MachO { value, .. }, _) => {
534                    match value {
535                        object::macho::X86_64_RELOC_UNSIGNED => {
536                            RelocationKind::MachoX86_64RelocUnsigned
537                        }
538                        object::macho::X86_64_RELOC_SIGNED => {
539                            RelocationKind::MachoX86_64RelocSigned
540                        }
541                        object::macho::X86_64_RELOC_BRANCH => {
542                            RelocationKind::MachoX86_64RelocBranch
543                        }
544                        object::macho::X86_64_RELOC_GOT_LOAD => {
545                            RelocationKind::MachoX86_64RelocGotLoad
546                        }
547                        object::macho::X86_64_RELOC_GOT => RelocationKind::MachoX86_64RelocGot,
548                        object::macho::X86_64_RELOC_SUBTRACTOR => {
549                            RelocationKind::MachoX86_64RelocSubtractor
550                        }
551                        object::macho::X86_64_RELOC_SIGNED_1 => {
552                            RelocationKind::MachoX86_64RelocSigned1
553                        }
554                        object::macho::X86_64_RELOC_SIGNED_2 => {
555                            RelocationKind::MachoX86_64RelocSigned2
556                        }
557                        object::macho::X86_64_RELOC_SIGNED_4 => {
558                            RelocationKind::MachoX86_64RelocSigned4
559                        }
560                        object::macho::X86_64_RELOC_TLV => RelocationKind::MachoX86_64RelocTlv,
561                        _ => {
562                            return Err(CompileError::Codegen(format!(
563                                "unknown relocation {reloc:?}"
564                            )));
565                        }
566                    }
567                }
568                _ => {
569                    return Err(CompileError::Codegen(format!(
570                        "unknown relocation {reloc:?}",
571                    )));
572                }
573            };
574
575            relocations
576                .entry(section_index)
577                .or_default()
578                .push(Relocation {
579                    kind,
580                    reloc_target: target,
581                    offset: offset.try_into().map_err(map_tryfromint_err)?,
582                    addend,
583                });
584        }
585    }
586
587    let eh_frame_section_indices = eh_frame_section_indices
588        .iter()
589        .map(|index| {
590            section_to_custom_section.get(index).map_or_else(
591                || {
592                    Err(CompileError::Codegen(format!(
593                        ".eh_frame section with index={index:?} was never loaded",
594                    )))
595                },
596                |idx| Ok(*idx),
597            )
598        })
599        .collect::<Result<Vec<SectionIndex>, _>>()?;
600
601    let compact_unwind_section_indices = compact_unwind_section_indices
602        .iter()
603        .map(|index| {
604            section_to_custom_section.get(index).map_or_else(
605                || {
606                    Err(CompileError::Codegen(format!(
607                        "_compact_unwind section with index={index:?} was never loaded",
608                    )))
609                },
610                |idx| Ok(*idx),
611            )
612        })
613        .collect::<Result<Vec<SectionIndex>, _>>()?;
614
615    let mut custom_sections = section_to_custom_section
616        .iter()
617        .map(|(elf_section_index, custom_section_index)| {
618            let section = obj.section_by_index(*elf_section_index).unwrap();
619            (
620                custom_section_index,
621                CustomSection {
622                    protection: CustomSectionProtection::Read,
623                    alignment: Some(section.align()),
624                    bytes: SectionBody::new_with_vec(section.data().unwrap().to_vec()),
625                    relocations: relocations
626                        .remove_entry(elf_section_index)
627                        .map_or(vec![], |(_, v)| v),
628                },
629            )
630        })
631        .collect::<Vec<_>>();
632    custom_sections.sort_unstable_by_key(|a| a.0);
633    let custom_sections = custom_sections
634        .into_iter()
635        .map(|(_, v)| v)
636        .collect::<PrimaryMap<SectionIndex, _>>();
637
638    let function_body = FunctionBody {
639        body: obj
640            .section_by_index(root_section_index)
641            .unwrap()
642            .data()
643            .unwrap()
644            .to_vec(),
645        unwind_info: None,
646    };
647
648    let address_map = FunctionAddressMap {
649        instructions: vec![InstructionAddressMap {
650            srcloc: SourceLoc::default(),
651            code_offset: 0,
652            code_len: function_body.body.len(),
653        }],
654        start_srcloc: SourceLoc::default(),
655        end_srcloc: SourceLoc::default(),
656        body_offset: 0,
657        body_len: function_body.body.len(),
658    };
659
660    Ok(CompiledFunction {
661        compiled_function: wasmer_compiler::types::function::CompiledFunction {
662            body: function_body,
663            relocations: relocations
664                .remove_entry(&root_section_index)
665                .map_or(vec![], |(_, v)| v),
666            frame_info: CompiledFunctionFrameInfo {
667                address_map,
668                traps: vec![],
669            },
670        },
671        custom_sections,
672        eh_frame_section_indices,
673        compact_unwind_section_indices,
674    })
675}