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    pub gcc_except_table_section_indices: Vec<SectionIndex>,
34}
35
36static LIBCALLS_ELF: phf::Map<&'static str, LibCall> = phf::phf_map! {
37    "ceilf" => LibCall::CeilF32,
38    "ceil" => LibCall::CeilF64,
39    "floorf" => LibCall::FloorF32,
40    "floor" => LibCall::FloorF64,
41    "nearbyintf" => LibCall::NearestF32,
42    "nearbyint" => LibCall::NearestF64,
43    "truncf" => LibCall::TruncF32,
44    "trunc" => LibCall::TruncF64,
45    "wasmer_vm_f32_ceil" => LibCall::CeilF32,
46    "wasmer_vm_f64_ceil" => LibCall::CeilF64,
47    "wasmer_vm_f32_floor" => LibCall::FloorF32,
48    "wasmer_vm_f64_floor" => LibCall::FloorF64,
49    "wasmer_vm_f32_nearest" => LibCall::NearestF32,
50    "wasmer_vm_f64_nearest" => LibCall::NearestF64,
51    "wasmer_vm_f32_trunc" => LibCall::TruncF32,
52    "wasmer_vm_f64_trunc" => LibCall::TruncF64,
53    "wasmer_vm_memory32_size" => LibCall::Memory32Size,
54    "wasmer_vm_imported_memory32_size" => LibCall::ImportedMemory32Size,
55    "wasmer_vm_table_copy" => LibCall::TableCopy,
56    "wasmer_vm_table_init" => LibCall::TableInit,
57    "wasmer_vm_table_fill" => LibCall::TableFill,
58    "wasmer_vm_table_size" => LibCall::TableSize,
59    "wasmer_vm_imported_table_size" => LibCall::ImportedTableSize,
60    "wasmer_vm_table_get" => LibCall::TableGet,
61    "wasmer_vm_imported_table_get" => LibCall::ImportedTableGet,
62    "wasmer_vm_table_set" => LibCall::TableSet,
63    "wasmer_vm_imported_table_set" => LibCall::ImportedTableSet,
64    "wasmer_vm_table_grow" => LibCall::TableGrow,
65    "wasmer_vm_imported_table_grow" => LibCall::ImportedTableGrow,
66    "wasmer_vm_func_ref" => LibCall::FuncRef,
67    "wasmer_vm_elem_drop" => LibCall::ElemDrop,
68    "wasmer_vm_memory32_copy" => LibCall::Memory32Copy,
69    "wasmer_vm_imported_memory32_copy" => LibCall::ImportedMemory32Copy,
70    "wasmer_vm_memory32_fill" => LibCall::Memory32Fill,
71    "wasmer_vm_imported_memory32_fill" => LibCall::ImportedMemory32Fill,
72    "wasmer_vm_memory32_init" => LibCall::Memory32Init,
73    "wasmer_vm_data_drop" => LibCall::DataDrop,
74    "wasmer_vm_raise_trap" => LibCall::RaiseTrap,
75    "wasmer_vm_memory32_atomic_wait32" => LibCall::Memory32AtomicWait32,
76    "wasmer_vm_imported_memory32_atomic_wait32" => LibCall::ImportedMemory32AtomicWait32,
77    "wasmer_vm_memory32_atomic_wait64" => LibCall::Memory32AtomicWait64,
78    "wasmer_vm_imported_memory32_atomic_wait64" => LibCall::ImportedMemory32AtomicWait64,
79    "wasmer_vm_memory32_atomic_notify" => LibCall::Memory32AtomicNotify,
80    "wasmer_vm_imported_memory32_atomic_notify" => LibCall::ImportedMemory32AtomicNotify,
81    "wasmer_vm_throw" => LibCall::Throw,
82    "wasmer_vm_alloc_exception" => LibCall::AllocException,
83    "wasmer_vm_read_exnref" => LibCall::ReadExnRef,
84    "wasmer_vm_exception_into_exnref" => LibCall::LibunwindExceptionIntoExnRef,
85    "wasmer_eh_personality" => LibCall::EHPersonality,
86    "wasmer_eh_personality2" => LibCall::EHPersonality2,
87    "wasmer_vm_dbg_usize" => LibCall::DebugUsize,
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
137    "_wasmer_vm_throw" => LibCall::Throw,
138    "_wasmer_vm_alloc_exception" => LibCall::AllocException,
139    "_wasmer_vm_read_exnref" => LibCall::ReadExnRef,
140    "_wasmer_vm_exception_into_exnref" => LibCall::LibunwindExceptionIntoExnRef,
141    // Note: on macOS+Mach-O the personality function *must* be called like this, otherwise LLVM
142    // will generate things differently than "normal", wreaking havoc.
143    //
144    // todo: find out if it is a bug in LLVM or it is expected.
145    "___gxx_personality_v0" => LibCall::EHPersonality,
146    "_wasmer_eh_personality2" => LibCall::EHPersonality2,
147    "_wasmer_vm_dbg_usize" => LibCall::DebugUsize,
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    // .gcc_except_table sections, which contain the actual LSDA data.
225    // We don't need the actual sections for anything (yet), but trampoline
226    // codegen checks custom section counts to verify there aren't any
227    // unexpected custom sections, so we do a bit of book-keeping here.
228    let mut gcc_except_table_section_indices = vec![];
229
230    for section in obj.sections() {
231        let index = section.index();
232        if section.kind() == object::SectionKind::Elf(object::elf::SHT_X86_64_UNWIND)
233            || section.name().unwrap_or_default() == "__eh_frame"
234        {
235            worklist.push(index);
236            eh_frame_section_indices.push(index);
237
238            // This allocates a custom section index for the ELF section.
239            elf_section_to_target(index);
240        } else if section.name().unwrap_or_default() == "__compact_unwind" {
241            worklist.push(index);
242            compact_unwind_section_indices.push(index);
243
244            elf_section_to_target(index);
245        } else if section.name().unwrap_or_default() == ".gcc_except_table" {
246            worklist.push(index);
247            gcc_except_table_section_indices.push(index);
248
249            elf_section_to_target(index);
250        }
251    }
252
253    while let Some(section_index) = worklist.pop() {
254        let sec = obj
255            .section_by_index(section_index)
256            .map_err(map_object_err)?;
257        let relocs = sec.relocations();
258        for (offset, reloc) in relocs {
259            let mut addend = reloc.addend();
260            let target = match reloc.target() {
261                object::read::RelocationTarget::Symbol(index) => {
262                    let symbol = obj.symbol_by_index(index).map_err(map_object_err)?;
263                    let symbol_name = symbol.name().map_err(map_object_err)?;
264                    if symbol.kind() == object::SymbolKind::Section {
265                        match symbol.section() {
266                            object::SymbolSection::Section(section_index) => {
267                                if section_index == root_section_index {
268                                    root_section_reloc_target
269                                } else {
270                                    if visited.insert(section_index) {
271                                        worklist.push(section_index);
272                                    }
273                                    elf_section_to_target(section_index)
274                                }
275                            }
276                            _ => {
277                                return Err(CompileError::Codegen(format!(
278                                    "relocation targets unknown section {reloc:?}",
279                                )));
280                            }
281                        }
282                        // Maybe a libcall then?
283                    } else if let Some(libcall) = libcalls.get(symbol_name) {
284                        RelocationTarget::LibCall(*libcall)
285                    } else if let Ok(Some(reloc_target)) =
286                        symbol_name_to_relocation_target(symbol_name)
287                    {
288                        reloc_target
289                    } else if let object::SymbolSection::Section(section_index) = symbol.section() {
290                        if matches!(
291                            reloc.flags(),
292                            object::RelocationFlags::MachO {
293                                r_type: object::macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12,
294                                r_pcrel: false,
295                                ..
296                            } | object::RelocationFlags::MachO {
297                                r_type: object::macho::ARM64_RELOC_POINTER_TO_GOT,
298                                r_pcrel: true,
299                                ..
300                            } | object::RelocationFlags::MachO {
301                                r_type: object::macho::ARM64_RELOC_GOT_LOAD_PAGE21,
302                                r_pcrel: true,
303                                ..
304                            } | object::RelocationFlags::MachO {
305                                r_type: object::macho::ARM64_RELOC_PAGE21,
306                                r_pcrel: true,
307                                ..
308                            } | object::RelocationFlags::MachO {
309                                r_type: object::macho::ARM64_RELOC_PAGEOFF12,
310                                r_pcrel: false,
311                                ..
312                            }
313                        ) {
314                            // (caveat: this comment comes from a point in time after the `addend`
315                            // math in the else branch)
316                            //
317                            // (caveat2: this is mach-o + aarch64 only)
318                            //
319                            // The tampering with the addend in the else branch causes some
320                            // problems with GOT-based relocs, as a non-zero addend has no meaning
321                            // when dealing with GOT entries, for our use-case.
322                            //
323                            // However, for some reasons, it happens that we conceptually need to
324                            // have relocations that pretty much mean "the contents of this GOT
325                            // entry plus a non-zero addend". When in this case, we will later
326                            // perform what is known as "GOT relaxation", i.e. we can change the
327                            // `ldr` opcode to an `add`.
328                            //
329                            // For this to make sense we need to fix the addend to be the delta
330                            // between the section whose address is an entry of the GOT and the
331                            // symbol that is the target of the relocation.
332
333                            let symbol_sec = obj
334                                .section_by_index(section_index)
335                                .map_err(map_object_err)?;
336
337                            addend = addend
338                                .wrapping_add((symbol.address() - symbol_sec.address()) as i64);
339                        } else {
340                            // TODO: Encode symbol address into addend, I think this is a bit hacky.
341                            addend = addend.wrapping_add(symbol.address() as i64);
342                        }
343
344                        if section_index == root_section_index {
345                            root_section_reloc_target
346                        } else {
347                            if visited.insert(section_index) {
348                                worklist.push(section_index);
349                            }
350
351                            elf_section_to_target(section_index)
352                        }
353                    } else {
354                        return Err(CompileError::Codegen(format!(
355                            "relocation {reloc:?} targets unknown symbol '{symbol:?}'",
356                        )));
357                    }
358                }
359
360                object::read::RelocationTarget::Section(index) => {
361                    if index == root_section_index {
362                        root_section_reloc_target
363                    } else {
364                        if visited.insert(index) {
365                            worklist.push(index);
366                        }
367                        elf_section_to_target(index)
368                    }
369                }
370
371                object::read::RelocationTarget::Absolute => {
372                    // Wasm-produced object files should never have absolute
373                    // addresses in them because none of the parts of the Wasm
374                    // VM, nor the generated code are loaded at fixed addresses.
375                    return Err(CompileError::Codegen(format!(
376                        "relocation targets absolute address {reloc:?}",
377                    )));
378                }
379
380                // `object::read::RelocationTarget` is a
381                // non-exhaustive enum (`#[non_exhaustive]`), so it
382                // could have additional variants added in the
383                // future. Therefore, when matching against variants
384                // of non-exhaustive enums, an extra wildcard arm must
385                // be added to account for any future variants.
386                t => {
387                    return Err(CompileError::Codegen(format!(
388                        "relocation target is unknown `{t:?}`",
389                    )));
390                }
391            };
392            let kind = match (obj.architecture(), reloc.flags(), reloc.size()) {
393                (
394                    _,
395                    object::RelocationFlags::Elf {
396                        r_type: object::elf::R_X86_64_64,
397                    },
398                    64,
399                ) => RelocationKind::Abs8,
400                (
401                    _,
402                    object::RelocationFlags::Elf {
403                        r_type: object::elf::R_386_32,
404                    },
405                    32,
406                ) => RelocationKind::Abs4,
407                (
408                    object::Architecture::X86_64,
409                    object::RelocationFlags::Elf {
410                        r_type: object::elf::R_X86_64_PC64,
411                    },
412                    0,
413                ) => RelocationKind::X86PCRel8,
414                (
415                    object::Architecture::Aarch64,
416                    object::RelocationFlags::Elf {
417                        r_type: object::elf::R_AARCH64_CALL26,
418                    },
419                    26,
420                ) => RelocationKind::Arm64Call,
421                (
422                    object::Architecture::Aarch64,
423                    object::RelocationFlags::Elf {
424                        r_type: object::elf::R_AARCH64_MOVW_UABS_G0_NC,
425                    },
426                    0,
427                ) => RelocationKind::Arm64Movw0,
428                (
429                    object::Architecture::Aarch64,
430                    object::RelocationFlags::Elf {
431                        r_type: object::elf::R_AARCH64_MOVW_UABS_G1_NC,
432                    },
433                    0,
434                ) => RelocationKind::Arm64Movw1,
435                (
436                    object::Architecture::Aarch64,
437                    object::RelocationFlags::Elf {
438                        r_type: object::elf::R_AARCH64_MOVW_UABS_G2_NC,
439                    },
440                    0,
441                ) => RelocationKind::Arm64Movw2,
442                (
443                    object::Architecture::Aarch64,
444                    object::RelocationFlags::Elf {
445                        r_type: object::elf::R_AARCH64_MOVW_UABS_G3,
446                    },
447                    0,
448                ) => RelocationKind::Arm64Movw3,
449                (
450                    object::Architecture::Riscv64,
451                    object::RelocationFlags::Elf {
452                        r_type: object::elf::R_RISCV_CALL_PLT,
453                    },
454                    0,
455                ) => RelocationKind::RiscvCall,
456                (
457                    object::Architecture::Riscv64,
458                    object::RelocationFlags::Elf {
459                        r_type: object::elf::R_RISCV_PCREL_HI20,
460                    },
461                    0,
462                ) => RelocationKind::RiscvPCRelHi20,
463                (
464                    object::Architecture::Riscv64,
465                    object::RelocationFlags::Elf {
466                        r_type: object::elf::R_RISCV_PCREL_LO12_I,
467                    },
468                    0,
469                ) => RelocationKind::RiscvPCRelLo12I,
470                (
471                    object::Architecture::LoongArch64,
472                    object::RelocationFlags::Elf {
473                        r_type: object::elf::R_LARCH_ABS_HI20,
474                    },
475                    0,
476                ) => RelocationKind::LArchAbsHi20,
477                (
478                    object::Architecture::LoongArch64,
479                    object::RelocationFlags::Elf {
480                        r_type: object::elf::R_LARCH_ABS_LO12,
481                    },
482                    0,
483                ) => RelocationKind::LArchAbsLo12,
484                (
485                    object::Architecture::LoongArch64,
486                    object::RelocationFlags::Elf {
487                        r_type: object::elf::R_LARCH_ABS64_HI12,
488                    },
489                    0,
490                ) => RelocationKind::LArchAbs64Hi12,
491                (
492                    object::Architecture::LoongArch64,
493                    object::RelocationFlags::Elf {
494                        r_type: object::elf::R_LARCH_ABS64_LO20,
495                    },
496                    0,
497                ) => RelocationKind::LArchAbs64Lo20,
498                (
499                    object::Architecture::LoongArch64,
500                    object::RelocationFlags::Elf {
501                        r_type: object::elf::R_LARCH_CALL36,
502                    },
503                    0,
504                ) => RelocationKind::LArchCall36,
505                (
506                    object::Architecture::LoongArch64,
507                    object::RelocationFlags::Elf {
508                        r_type: object::elf::R_LARCH_PCALA_HI20,
509                    },
510                    0,
511                ) => RelocationKind::LArchPCAlaHi20,
512                (
513                    object::Architecture::LoongArch64,
514                    object::RelocationFlags::Elf {
515                        r_type: object::elf::R_LARCH_PCALA_LO12,
516                    },
517                    0,
518                ) => RelocationKind::LArchPCAlaLo12,
519                (
520                    object::Architecture::LoongArch64,
521                    object::RelocationFlags::Elf {
522                        r_type: object::elf::R_LARCH_PCALA64_HI12,
523                    },
524                    0,
525                ) => RelocationKind::LArchPCAla64Hi12,
526                (
527                    object::Architecture::LoongArch64,
528                    object::RelocationFlags::Elf {
529                        r_type: object::elf::R_LARCH_PCALA64_LO20,
530                    },
531                    0,
532                ) => RelocationKind::LArchPCAla64Lo20,
533                (
534                    object::Architecture::Aarch64,
535                    object::RelocationFlags::Elf {
536                        r_type: object::elf::R_AARCH64_ADR_PREL_LO21,
537                    },
538                    0,
539                ) => RelocationKind::Aarch64AdrPrelLo21,
540                (
541                    object::Architecture::Aarch64,
542                    object::RelocationFlags::Elf {
543                        r_type: object::elf::R_AARCH64_ADR_PREL_PG_HI21,
544                    },
545                    0,
546                ) => RelocationKind::Aarch64AdrPrelPgHi21,
547                (
548                    object::Architecture::Aarch64,
549                    object::RelocationFlags::Elf {
550                        r_type: object::elf::R_AARCH64_LDST128_ABS_LO12_NC,
551                    },
552                    0,
553                ) => RelocationKind::Aarch64Ldst128AbsLo12Nc,
554                (
555                    object::Architecture::Aarch64,
556                    object::RelocationFlags::Elf {
557                        r_type: object::elf::R_AARCH64_ADD_ABS_LO12_NC,
558                    },
559                    0,
560                ) => RelocationKind::Aarch64AddAbsLo12Nc,
561                (
562                    object::Architecture::Aarch64,
563                    object::RelocationFlags::Elf {
564                        r_type: object::elf::R_AARCH64_LDST64_ABS_LO12_NC,
565                    },
566                    0,
567                ) => RelocationKind::Aarch64Ldst64AbsLo12Nc,
568                (
569                    object::Architecture::Aarch64,
570                    object::RelocationFlags::MachO { r_type: value, .. },
571                    _,
572                ) => match value {
573                    object::macho::ARM64_RELOC_UNSIGNED => RelocationKind::MachoArm64RelocUnsigned,
574                    object::macho::ARM64_RELOC_SUBTRACTOR => {
575                        RelocationKind::MachoArm64RelocSubtractor
576                    }
577                    object::macho::ARM64_RELOC_BRANCH26 => RelocationKind::MachoArm64RelocBranch26,
578                    object::macho::ARM64_RELOC_PAGE21 => RelocationKind::MachoArm64RelocPage21,
579                    object::macho::ARM64_RELOC_PAGEOFF12 => {
580                        RelocationKind::MachoArm64RelocPageoff12
581                    }
582                    object::macho::ARM64_RELOC_GOT_LOAD_PAGE21 => {
583                        RelocationKind::MachoArm64RelocGotLoadPage21
584                    }
585                    object::macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12 => {
586                        RelocationKind::MachoArm64RelocGotLoadPageoff12
587                    }
588                    object::macho::ARM64_RELOC_POINTER_TO_GOT => {
589                        RelocationKind::MachoArm64RelocPointerToGot
590                    }
591                    object::macho::ARM64_RELOC_TLVP_LOAD_PAGE21 => {
592                        RelocationKind::MachoArm64RelocTlvpLoadPage21
593                    }
594                    object::macho::ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => {
595                        RelocationKind::MachoArm64RelocTlvpLoadPageoff12
596                    }
597                    object::macho::ARM64_RELOC_ADDEND => RelocationKind::MachoArm64RelocAddend,
598                    _ => {
599                        return Err(CompileError::Codegen(format!(
600                            "unknown relocation {reloc:?}",
601                        )));
602                    }
603                },
604                (
605                    object::Architecture::X86_64,
606                    object::RelocationFlags::MachO { r_type: value, .. },
607                    _,
608                ) => match value {
609                    object::macho::X86_64_RELOC_UNSIGNED => {
610                        RelocationKind::MachoX86_64RelocUnsigned
611                    }
612                    object::macho::X86_64_RELOC_SIGNED => RelocationKind::MachoX86_64RelocSigned,
613                    object::macho::X86_64_RELOC_BRANCH => RelocationKind::MachoX86_64RelocBranch,
614                    object::macho::X86_64_RELOC_GOT_LOAD => RelocationKind::MachoX86_64RelocGotLoad,
615                    object::macho::X86_64_RELOC_GOT => RelocationKind::MachoX86_64RelocGot,
616                    object::macho::X86_64_RELOC_SUBTRACTOR => {
617                        RelocationKind::MachoX86_64RelocSubtractor
618                    }
619                    object::macho::X86_64_RELOC_SIGNED_1 => RelocationKind::MachoX86_64RelocSigned1,
620                    object::macho::X86_64_RELOC_SIGNED_2 => RelocationKind::MachoX86_64RelocSigned2,
621                    object::macho::X86_64_RELOC_SIGNED_4 => RelocationKind::MachoX86_64RelocSigned4,
622                    object::macho::X86_64_RELOC_TLV => RelocationKind::MachoX86_64RelocTlv,
623                    _ => {
624                        return Err(CompileError::Codegen(format!(
625                            "unknown relocation {reloc:?}"
626                        )));
627                    }
628                },
629                _ => {
630                    return Err(CompileError::Codegen(format!(
631                        "unknown relocation {reloc:?}",
632                    )));
633                }
634            };
635
636            relocations
637                .entry(section_index)
638                .or_default()
639                .push(Relocation {
640                    kind,
641                    reloc_target: target,
642                    offset: offset.try_into().map_err(map_tryfromint_err)?,
643                    addend,
644                });
645        }
646    }
647
648    let eh_frame_section_indices = eh_frame_section_indices
649        .iter()
650        .map(|index| {
651            section_to_custom_section.get(index).map_or_else(
652                || {
653                    Err(CompileError::Codegen(format!(
654                        ".eh_frame section with index={index:?} was never loaded",
655                    )))
656                },
657                |idx| Ok(*idx),
658            )
659        })
660        .collect::<Result<Vec<SectionIndex>, _>>()?;
661
662    let compact_unwind_section_indices = compact_unwind_section_indices
663        .iter()
664        .map(|index| {
665            section_to_custom_section.get(index).map_or_else(
666                || {
667                    Err(CompileError::Codegen(format!(
668                        "_compact_unwind section with index={index:?} was never loaded",
669                    )))
670                },
671                |idx| Ok(*idx),
672            )
673        })
674        .collect::<Result<Vec<SectionIndex>, _>>()?;
675
676    let gcc_except_table_section_indices = gcc_except_table_section_indices
677        .iter()
678        .map(|index| {
679            section_to_custom_section.get(index).map_or_else(
680                || {
681                    Err(CompileError::Codegen(format!(
682                        ".gcc_except_table section with index={index:?} was never loaded",
683                    )))
684                },
685                |idx| Ok(*idx),
686            )
687        })
688        .collect::<Result<Vec<SectionIndex>, _>>()?;
689
690    let mut custom_sections = section_to_custom_section
691        .iter()
692        .map(|(elf_section_index, custom_section_index)| {
693            let section = obj.section_by_index(*elf_section_index).unwrap();
694            (
695                custom_section_index,
696                CustomSection {
697                    protection: CustomSectionProtection::Read,
698                    alignment: Some(section.align()),
699                    bytes: SectionBody::new_with_vec(section.data().unwrap().to_vec()),
700                    relocations: relocations
701                        .remove_entry(elf_section_index)
702                        .map_or(vec![], |(_, v)| v),
703                },
704            )
705        })
706        .collect::<Vec<_>>();
707    custom_sections.sort_unstable_by_key(|a| a.0);
708    let custom_sections = custom_sections
709        .into_iter()
710        .map(|(_, v)| v)
711        .collect::<PrimaryMap<SectionIndex, _>>();
712
713    let function_body = FunctionBody {
714        body: obj
715            .section_by_index(root_section_index)
716            .unwrap()
717            .data()
718            .unwrap()
719            .to_vec(),
720        unwind_info: None,
721    };
722
723    let address_map = FunctionAddressMap {
724        instructions: vec![InstructionAddressMap {
725            srcloc: SourceLoc::default(),
726            code_offset: 0,
727            code_len: function_body.body.len(),
728        }],
729        start_srcloc: SourceLoc::default(),
730        end_srcloc: SourceLoc::default(),
731        body_offset: 0,
732        body_len: function_body.body.len(),
733    };
734
735    Ok(CompiledFunction {
736        compiled_function: wasmer_compiler::types::function::CompiledFunction {
737            body: function_body,
738            relocations: relocations
739                .remove_entry(&root_section_index)
740                .map_or(vec![], |(_, v)| v),
741            frame_info: CompiledFunctionFrameInfo {
742                address_map,
743                traps: vec![],
744            },
745        },
746        custom_sections,
747        eh_frame_section_indices,
748        compact_unwind_section_indices,
749        gcc_except_table_section_indices,
750    })
751}