wasmer_compiler_llvm/
object_file.rs

1use object::{Object, ObjectSection, ObjectSymbol};
2use target_lexicon::{
3    Architecture, BinaryFormat, Riscv32Architecture, Riscv64Architecture, Triple,
4};
5
6use std::collections::{HashMap, HashSet};
7use std::convert::TryInto;
8use std::num::TryFromIntError;
9
10use wasmer_types::{CompileError, SourceLoc, entity::PrimaryMap};
11
12use wasmer_compiler::types::{
13    address_map::{FunctionAddressMap, InstructionAddressMap},
14    function::{CompiledFunctionFrameInfo, CustomSections, FunctionBody},
15    relocation::{Relocation, RelocationKind, RelocationTarget},
16    section::{CustomSection, CustomSectionProtection, SectionBody, SectionIndex},
17};
18
19use wasmer_vm::libcalls::LibCall;
20
21fn map_tryfromint_err(error: TryFromIntError) -> CompileError {
22    CompileError::Codegen(format!("int doesn't fit: {error}"))
23}
24
25fn map_object_err(error: object::read::Error) -> CompileError {
26    CompileError::Codegen(format!("error parsing object file: {error}"))
27}
28
29#[derive(Debug)]
30pub struct CompiledFunction {
31    pub compiled_function: wasmer_compiler::types::function::CompiledFunction,
32    pub custom_sections: CustomSections,
33    pub eh_frame_section_indices: Vec<SectionIndex>,
34    pub compact_unwind_section_indices: Vec<SectionIndex>,
35    pub gcc_except_table_section_indices: Vec<SectionIndex>,
36    pub data_dw_ref_personality_section_indices: Vec<SectionIndex>,
37}
38
39impl wasmer_compiler::CompiledFunction for CompiledFunction {}
40
41static LIBCALLS_ELF: phf::Map<&'static str, LibCall> = phf::phf_map! {
42    "ceilf" => LibCall::CeilF32,
43    "ceil" => LibCall::CeilF64,
44    "floorf" => LibCall::FloorF32,
45    "floor" => LibCall::FloorF64,
46    "nearbyintf" => LibCall::NearestF32,
47    "nearbyint" => LibCall::NearestF64,
48    "sqrtf" => LibCall::SqrtF32,
49    "sqrt" => LibCall::SqrtF64,
50    "truncf" => LibCall::TruncF32,
51    "trunc" => LibCall::TruncF64,
52    "__chkstk" => LibCall::Probestack,
53    "wasmer_vm_f32_ceil" => LibCall::CeilF32,
54    "wasmer_vm_f64_ceil" => LibCall::CeilF64,
55    "wasmer_vm_f32_floor" => LibCall::FloorF32,
56    "wasmer_vm_f64_floor" => LibCall::FloorF64,
57    "wasmer_vm_f32_nearest" => LibCall::NearestF32,
58    "wasmer_vm_f64_nearest" => LibCall::NearestF64,
59    "wasmer_vm_f32_sqrt" => LibCall::SqrtF32,
60    "wasmer_vm_f64_sqrt" => LibCall::SqrtF64,
61    "wasmer_vm_f32_trunc" => LibCall::TruncF32,
62    "wasmer_vm_f64_trunc" => LibCall::TruncF64,
63    "wasmer_vm_memory32_size" => LibCall::Memory32Size,
64    "wasmer_vm_imported_memory32_size" => LibCall::ImportedMemory32Size,
65    "wasmer_vm_table_copy" => LibCall::TableCopy,
66    "wasmer_vm_table_init" => LibCall::TableInit,
67    "wasmer_vm_table_fill" => LibCall::TableFill,
68    "wasmer_vm_table_size" => LibCall::TableSize,
69    "wasmer_vm_imported_table_size" => LibCall::ImportedTableSize,
70    "wasmer_vm_table_get" => LibCall::TableGet,
71    "wasmer_vm_imported_table_get" => LibCall::ImportedTableGet,
72    "wasmer_vm_table_set" => LibCall::TableSet,
73    "wasmer_vm_imported_table_set" => LibCall::ImportedTableSet,
74    "wasmer_vm_table_grow" => LibCall::TableGrow,
75    "wasmer_vm_imported_table_grow" => LibCall::ImportedTableGrow,
76    "wasmer_vm_func_ref" => LibCall::FuncRef,
77    "wasmer_vm_elem_drop" => LibCall::ElemDrop,
78    "wasmer_vm_memory32_copy" => LibCall::Memory32Copy,
79    "wasmer_vm_imported_memory32_copy" => LibCall::ImportedMemory32Copy,
80    "wasmer_vm_memory32_fill" => LibCall::Memory32Fill,
81    "wasmer_vm_imported_memory32_fill" => LibCall::ImportedMemory32Fill,
82    "wasmer_vm_memory32_init" => LibCall::Memory32Init,
83    "wasmer_vm_data_drop" => LibCall::DataDrop,
84    "wasmer_vm_raise_trap" => LibCall::RaiseTrap,
85    "wasmer_vm_memory32_atomic_wait32" => LibCall::Memory32AtomicWait32,
86    "wasmer_vm_imported_memory32_atomic_wait32" => LibCall::ImportedMemory32AtomicWait32,
87    "wasmer_vm_memory32_atomic_wait64" => LibCall::Memory32AtomicWait64,
88    "wasmer_vm_imported_memory32_atomic_wait64" => LibCall::ImportedMemory32AtomicWait64,
89    "wasmer_vm_memory32_atomic_notify" => LibCall::Memory32AtomicNotify,
90    "wasmer_vm_imported_memory32_atomic_notify" => LibCall::ImportedMemory32AtomicNotify,
91    "wasmer_vm_throw" => LibCall::Throw,
92    "wasmer_vm_alloc_exception" => LibCall::AllocException,
93    "wasmer_vm_read_exnref" => LibCall::ReadExnRef,
94    "wasmer_vm_exception_into_exnref" => LibCall::LibunwindExceptionIntoExnRef,
95    "wasmer_eh_personality" => LibCall::EHPersonality,
96    "wasmer_eh_personality2" => LibCall::EHPersonality2,
97    "wasmer_vm_dbg_usize" => LibCall::DebugUsize,
98    "wasmer_vm_dbg_str" => LibCall::DebugStr,
99};
100
101// Soft-float routines that LLVM may emit for RISC-V ELF targets.  The map is
102// unconditional because `load_object_file` runs on the host while the ELF it
103// processes was compiled for the LLVM output target (a runtime value); gating
104// on host target_arch would break cross-compilation (e.g. macOS → riscv64).
105static SOFTFLOAT_LIBCALLS_ELF: phf::Map<&'static str, LibCall> = phf::phf_map! {
106    // §3.2.1 Arithmetic
107    "__addsf3" => LibCall::Addsf3,
108    "__adddf3" => LibCall::Adddf3,
109    "__subsf3" => LibCall::Subsf3,
110    "__subdf3" => LibCall::Subdf3,
111    "__mulsf3" => LibCall::Mulsf3,
112    "__muldf3" => LibCall::Muldf3,
113    "__divsf3" => LibCall::Divsf3,
114    "__divdf3" => LibCall::Divdf3,
115    "__negsf2" => LibCall::Negsf2,
116    "__negdf2" => LibCall::Negdf2,
117    // §3.2.2 Conversion
118    "__extendsfdf2" => LibCall::Extendsfdf2,
119    "__truncdfsf2" => LibCall::Truncdfsf2,
120    "__fixsfsi" => LibCall::Fixsfsi,
121    "__fixdfsi" => LibCall::Fixdfsi,
122    "__fixsfdi" => LibCall::Fixsfdi,
123    "__fixdfdi" => LibCall::Fixdfdi,
124    "__fixunssfsi" => LibCall::Fixunssfsi,
125    "__fixunsdfsi" => LibCall::Fixunsdfsi,
126    "__fixunssfdi" => LibCall::Fixunssfdi,
127    "__fixunsdfdi" => LibCall::Fixunsdfdi,
128    "__floatsisf" => LibCall::Floatsisf,
129    "__floatsidf" => LibCall::Floatsidf,
130    "__floatdisf" => LibCall::Floatdisf,
131    "__floatdidf" => LibCall::Floatdidf,
132    "__floatunsisf" => LibCall::Floatunsisf,
133    "__floatunsidf" => LibCall::Floatunsidf,
134    "__floatundisf" => LibCall::Floatundisf,
135    "__floatundidf" => LibCall::Floatundidf,
136    // §3.2.3 Comparison
137    "__unordsf2" => LibCall::Unordsf2,
138    "__unorddf2" => LibCall::Unorddf2,
139    "__eqsf2" => LibCall::Eqsf2,
140    "__eqdf2" => LibCall::Eqdf2,
141    "__nesf2" => LibCall::Nesf2,
142    "__nedf2" => LibCall::Nedf2,
143    "__gesf2" => LibCall::Gesf2,
144    "__gedf2" => LibCall::Gedf2,
145    "__ltsf2" => LibCall::Ltsf2,
146    "__ltdf2" => LibCall::Ltdf2,
147    "__lesf2" => LibCall::Lesf2,
148    "__ledf2" => LibCall::Ledf2,
149    "__gtsf2" => LibCall::Gtsf2,
150    "__gtdf2" => LibCall::Gtdf2,
151};
152
153static LIBCALLS_MACHO: phf::Map<&'static str, LibCall> = phf::phf_map! {
154    "_ceilf" => LibCall::CeilF32,
155    "_ceil" => LibCall::CeilF64,
156    "_floorf" => LibCall::FloorF32,
157    "_floor" => LibCall::FloorF64,
158    "_nearbyintf" => LibCall::NearestF32,
159    "_nearbyint" => LibCall::NearestF64,
160    "_sqrtf" => LibCall::SqrtF32,
161    "_sqrt" => LibCall::SqrtF64,
162    "_truncf" => LibCall::TruncF32,
163    "_trunc" => LibCall::TruncF64,
164    "_wasmer_vm_f32_ceil" => LibCall::CeilF32,
165    "_wasmer_vm_f64_ceil" => LibCall::CeilF64,
166    "_wasmer_vm_f32_floor" => LibCall::FloorF32,
167    "_wasmer_vm_f64_floor" => LibCall::FloorF64,
168    "_wasmer_vm_f32_nearest" => LibCall::NearestF32,
169    "_wasmer_vm_f64_nearest" => LibCall::NearestF64,
170    "_wasmer_vm_f32_sqrt" => LibCall::SqrtF32,
171    "_wasmer_vm_f64_sqrt" => LibCall::SqrtF64,
172    "_wasmer_vm_f32_trunc" => LibCall::TruncF32,
173    "_wasmer_vm_f64_trunc" => LibCall::TruncF64,
174    "_wasmer_vm_memory32_size" => LibCall::Memory32Size,
175    "_wasmer_vm_imported_memory32_size" => LibCall::ImportedMemory32Size,
176    "_wasmer_vm_table_copy" => LibCall::TableCopy,
177    "_wasmer_vm_table_init" => LibCall::TableInit,
178    "_wasmer_vm_table_fill" => LibCall::TableFill,
179    "_wasmer_vm_table_size" => LibCall::TableSize,
180    "_wasmer_vm_imported_table_size" => LibCall::ImportedTableSize,
181    "_wasmer_vm_table_get" => LibCall::TableGet,
182    "_wasmer_vm_imported_table_get" => LibCall::ImportedTableGet,
183    "_wasmer_vm_table_set" => LibCall::TableSet,
184    "_wasmer_vm_imported_table_set" => LibCall::ImportedTableSet,
185    "_wasmer_vm_table_grow" => LibCall::TableGrow,
186    "_wasmer_vm_imported_table_grow" => LibCall::ImportedTableGrow,
187    "_wasmer_vm_func_ref" => LibCall::FuncRef,
188    "_wasmer_vm_elem_drop" => LibCall::ElemDrop,
189    "_wasmer_vm_memory32_copy" => LibCall::Memory32Copy,
190    "_wasmer_vm_imported_memory32_copy" => LibCall::ImportedMemory32Copy,
191    "_wasmer_vm_memory32_fill" => LibCall::Memory32Fill,
192    "_wasmer_vm_imported_memory32_fill" => LibCall::ImportedMemory32Fill,
193    "_wasmer_vm_memory32_init" => LibCall::Memory32Init,
194    "_wasmer_vm_data_drop" => LibCall::DataDrop,
195    "_wasmer_vm_raise_trap" => LibCall::RaiseTrap,
196    "_wasmer_vm_memory32_atomic_wait32" => LibCall::Memory32AtomicWait32,
197    "_wasmer_vm_imported_memory32_atomic_wait32" => LibCall::ImportedMemory32AtomicWait32,
198    "_wasmer_vm_memory32_atomic_wait64" => LibCall::Memory32AtomicWait64,
199    "_wasmer_vm_imported_memory32_atomic_wait64" => LibCall::ImportedMemory32AtomicWait64,
200    "_wasmer_vm_memory32_atomic_notify" => LibCall::Memory32AtomicNotify,
201    "_wasmer_vm_imported_memory32_atomic_notify" => LibCall::ImportedMemory32AtomicNotify,
202
203    "_wasmer_vm_throw" => LibCall::Throw,
204    "_wasmer_vm_alloc_exception" => LibCall::AllocException,
205    "_wasmer_vm_read_exnref" => LibCall::ReadExnRef,
206    "_wasmer_vm_exception_into_exnref" => LibCall::LibunwindExceptionIntoExnRef,
207    // Note: on macOS+Mach-O the personality function *must* be called like this, otherwise LLVM
208    // will generate things differently than "normal", wreaking havoc.
209    //
210    // todo: find out if it is a bug in LLVM or it is expected.
211    "___gxx_personality_v0" => LibCall::EHPersonality,
212    "_wasmer_eh_personality2" => LibCall::EHPersonality2,
213    "_wasmer_vm_dbg_usize" => LibCall::DebugUsize,
214    "_wasmer_vm_dbg_str" => LibCall::DebugStr,
215};
216
217/// Returns whether `arch` is a RISC-V variant that lacks hardware floating-point
218/// (i.e. does not include the F/D ISA extensions, either explicitly or via the `gc` profile).
219fn is_riscv_softfloat(arch: &Architecture) -> bool {
220    match arch {
221        Architecture::Riscv64(Riscv64Architecture::Riscv64gc | Riscv64Architecture::Riscv64a23)
222        | Architecture::Riscv32(
223            Riscv32Architecture::Riscv32gc | Riscv32Architecture::Riscv32imafc,
224        ) => false,
225        Architecture::Riscv64(_) | Architecture::Riscv32(_) => true,
226        _ => false,
227    }
228}
229
230fn lookup_libcall(name: &str, fmt: BinaryFormat, triple: &Triple) -> Option<LibCall> {
231    let base = match fmt {
232        BinaryFormat::Elf => &LIBCALLS_ELF,
233        BinaryFormat::Macho => &LIBCALLS_MACHO,
234        _ => return None,
235    };
236    if let Some(&lc) = base.get(name) {
237        return Some(lc);
238    }
239    // Soft-float libcalls are only emitted by LLVM for RISC-V targets without
240    // hardware floating-point.  We use the runtime LLVM output triple rather than
241    // the host target_arch so that cross-compilation (e.g. macOS → riscv64) works.
242    if fmt == BinaryFormat::Elf
243        && is_riscv_softfloat(&triple.architecture)
244        && let Some(&lc) = SOFTFLOAT_LIBCALLS_ELF.get(name)
245    {
246        return Some(lc);
247    }
248    None
249}
250
251pub fn load_object_file<F>(
252    contents: &[u8],
253    root_section: &str,
254    root_section_reloc_target: RelocationTarget,
255    mut symbol_name_to_relocation_target: F,
256    binary_fmt: BinaryFormat,
257    triple: &Triple,
258) -> Result<CompiledFunction, CompileError>
259where
260    F: FnMut(&str) -> Result<Option<RelocationTarget>, CompileError>,
261{
262    let obj = object::File::parse(contents).map_err(map_object_err)?;
263
264    if !matches!(binary_fmt, BinaryFormat::Elf | BinaryFormat::Macho) {
265        return Err(CompileError::UnsupportedTarget(format!(
266            "Unsupported binary format {binary_fmt:?}"
267        )));
268    }
269
270    let mut worklist: Vec<object::read::SectionIndex> = Vec::new();
271    let mut section_targets: HashMap<object::read::SectionIndex, RelocationTarget> = HashMap::new();
272
273    let root_section_index = obj
274        .section_by_name(root_section)
275        .ok_or_else(|| CompileError::Codegen(format!("no section named {root_section}")))?
276        .index();
277
278    let mut section_to_custom_section = HashMap::new();
279
280    section_targets.insert(root_section_index, root_section_reloc_target);
281
282    let mut next_custom_section: u32 = 0;
283
284    let mut elf_section_to_target = |elf_section_index: object::read::SectionIndex| {
285        *section_targets.entry(elf_section_index).or_insert_with(|| {
286            let next = SectionIndex::from_u32(next_custom_section);
287            section_to_custom_section.insert(elf_section_index, next);
288            let target = RelocationTarget::CustomSection(next);
289            next_custom_section += 1;
290            target
291        })
292    };
293
294    // From elf section index to list of Relocations. Although we use a Vec,
295    // the order of relocations is not important.
296    let mut relocations: HashMap<object::read::SectionIndex, Vec<Relocation>> = HashMap::new();
297
298    // Each iteration of this loop pulls a section and the relocations
299    // that apply to it. We begin with the ".root_section"
300    // section, and then parse all relocation sections that apply to that
301    // section. Those relocations may refer to additional sections which we
302    // then add to the worklist until we've visited the closure of
303    // everything needed to run the code in ".root_section".
304    //
305    // `worklist` is the list of sections we have yet to visit. It never
306    // contains any duplicates or sections we've already visited. `visited`
307    // contains all the sections we've ever added to the worklist in a set
308    // so that we can quickly check whether a section is new before adding
309    // it to worklist. `section_to_custom_section` is filled in with all
310    // the sections we want to include.
311    worklist.push(root_section_index);
312
313    // Add any .eh_frame sections.
314    let mut eh_frame_section_indices = vec![];
315
316    // Add macos-specific unwind sections.
317    let mut compact_unwind_section_indices = vec![];
318
319    // .gcc_except_table sections, which contain the actual LSDA data.
320    // We don't need the actual sections for anything (yet), but trampoline
321    // codegen checks custom section counts to verify there aren't any
322    // unexpected custom sections, so we do a bit of book-keeping here.
323    let mut gcc_except_table_section_indices = vec![];
324
325    let mut data_dw_ref_personality_section_indices = vec![];
326
327    for section in obj.sections() {
328        let index = section.index();
329        let Ok(section_name) = section.name() else {
330            continue;
331        };
332
333        match section_name {
334            "__eh_frame" | ".eh_frame" => {
335                worklist.push(index);
336                eh_frame_section_indices.push(index);
337
338                // This allocates a custom section index for the ELF section.
339                elf_section_to_target(index);
340            }
341            "__compact_unwind" => {
342                worklist.push(index);
343                compact_unwind_section_indices.push(index);
344
345                elf_section_to_target(index);
346            }
347            ".gcc_except_table" => {
348                worklist.push(index);
349                gcc_except_table_section_indices.push(index);
350
351                elf_section_to_target(index);
352            }
353            ".data.DW.ref.wasmer_eh_personality" => {
354                worklist.push(index);
355                data_dw_ref_personality_section_indices.push(index);
356
357                elf_section_to_target(index);
358            }
359            _ => {}
360        }
361    }
362
363    let mut visited: HashSet<_> = HashSet::from_iter(worklist.iter().copied());
364    while let Some(section_index) = worklist.pop() {
365        let sec = obj
366            .section_by_index(section_index)
367            .map_err(map_object_err)?;
368        let relocs = sec.relocations();
369        for (offset, reloc) in relocs {
370            let mut addend = reloc.addend();
371            let target = match reloc.target() {
372                object::read::RelocationTarget::Symbol(index) => {
373                    let symbol = obj.symbol_by_index(index).map_err(map_object_err)?;
374                    let symbol_name = symbol.name().map_err(map_object_err)?;
375                    if symbol.kind() == object::SymbolKind::Section {
376                        match symbol.section() {
377                            object::SymbolSection::Section(section_index) => {
378                                if section_index == root_section_index {
379                                    root_section_reloc_target
380                                } else {
381                                    if visited.insert(section_index) {
382                                        worklist.push(section_index);
383                                    }
384                                    elf_section_to_target(section_index)
385                                }
386                            }
387                            _ => {
388                                return Err(CompileError::Codegen(format!(
389                                    "relocation targets unknown section {reloc:?}",
390                                )));
391                            }
392                        }
393                        // Maybe a libcall then?
394                    } else if let Some(libcall) = lookup_libcall(symbol_name, binary_fmt, triple) {
395                        RelocationTarget::LibCall(libcall)
396                    } else if let Ok(Some(reloc_target)) =
397                        symbol_name_to_relocation_target(symbol_name)
398                    {
399                        reloc_target
400                    } else if let object::SymbolSection::Section(section_index) = symbol.section() {
401                        if matches!(
402                            reloc.flags(),
403                            object::RelocationFlags::MachO {
404                                r_type: object::macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12,
405                                r_pcrel: false,
406                                ..
407                            } | object::RelocationFlags::MachO {
408                                r_type: object::macho::ARM64_RELOC_POINTER_TO_GOT,
409                                r_pcrel: true,
410                                ..
411                            } | object::RelocationFlags::MachO {
412                                r_type: object::macho::ARM64_RELOC_GOT_LOAD_PAGE21,
413                                r_pcrel: true,
414                                ..
415                            } | object::RelocationFlags::MachO {
416                                r_type: object::macho::ARM64_RELOC_PAGE21,
417                                r_pcrel: true,
418                                ..
419                            } | object::RelocationFlags::MachO {
420                                r_type: object::macho::ARM64_RELOC_PAGEOFF12,
421                                r_pcrel: false,
422                                ..
423                            }
424                        ) {
425                            // (caveat: this comment comes from a point in time after the `addend`
426                            // math in the else branch)
427                            //
428                            // (caveat2: this is mach-o + aarch64 only)
429                            //
430                            // The tampering with the addend in the else branch causes some
431                            // problems with GOT-based relocs, as a non-zero addend has no meaning
432                            // when dealing with GOT entries, for our use-case.
433                            //
434                            // However, for some reasons, it happens that we conceptually need to
435                            // have relocations that pretty much mean "the contents of this GOT
436                            // entry plus a non-zero addend". When in this case, we will later
437                            // perform what is known as "GOT relaxation", i.e. we can change the
438                            // `ldr` opcode to an `add`.
439                            //
440                            // For this to make sense we need to fix the addend to be the delta
441                            // between the section whose address is an entry of the GOT and the
442                            // symbol that is the target of the relocation.
443
444                            let symbol_sec = obj
445                                .section_by_index(section_index)
446                                .map_err(map_object_err)?;
447
448                            addend = addend
449                                .wrapping_add((symbol.address() - symbol_sec.address()) as i64);
450                        } else {
451                            // TODO: Encode symbol address into addend, I think this is a bit hacky.
452                            addend = addend.wrapping_add(symbol.address() as i64);
453                        }
454
455                        if section_index == root_section_index {
456                            root_section_reloc_target
457                        } else {
458                            if visited.insert(section_index) {
459                                worklist.push(section_index);
460                            }
461
462                            elf_section_to_target(section_index)
463                        }
464                    } else {
465                        return Err(CompileError::Codegen(format!(
466                            "relocation {reloc:?} targets unknown symbol '{symbol:?}'",
467                        )));
468                    }
469                }
470
471                object::read::RelocationTarget::Section(index) => {
472                    if index == root_section_index {
473                        root_section_reloc_target
474                    } else {
475                        if visited.insert(index) {
476                            worklist.push(index);
477                        }
478                        elf_section_to_target(index)
479                    }
480                }
481
482                object::read::RelocationTarget::Absolute => {
483                    // Wasm-produced object files should never have absolute
484                    // addresses in them because none of the parts of the Wasm
485                    // VM, nor the generated code are loaded at fixed addresses.
486                    return Err(CompileError::Codegen(format!(
487                        "relocation targets absolute address {reloc:?}",
488                    )));
489                }
490
491                // `object::read::RelocationTarget` is a
492                // non-exhaustive enum (`#[non_exhaustive]`), so it
493                // could have additional variants added in the
494                // future. Therefore, when matching against variants
495                // of non-exhaustive enums, an extra wildcard arm must
496                // be added to account for any future variants.
497                t => {
498                    return Err(CompileError::Codegen(format!(
499                        "relocation target is unknown `{t:?}`",
500                    )));
501                }
502            };
503            let kind = match (obj.architecture(), reloc.flags(), reloc.size()) {
504                (
505                    _,
506                    object::RelocationFlags::Elf {
507                        r_type: object::elf::R_X86_64_64,
508                    },
509                    64,
510                ) => RelocationKind::Abs8,
511                (
512                    object::Architecture::X86_64,
513                    object::RelocationFlags::Elf {
514                        r_type: object::elf::R_X86_64_PC64,
515                    },
516                    0,
517                ) => RelocationKind::PCRel8,
518                (
519                    object::Architecture::Aarch64,
520                    object::RelocationFlags::Elf {
521                        r_type: object::elf::R_AARCH64_CALL26,
522                    },
523                    26,
524                ) => RelocationKind::Arm64Call,
525                (
526                    object::Architecture::Aarch64,
527                    object::RelocationFlags::Elf {
528                        r_type: object::elf::R_AARCH64_JUMP26,
529                    },
530                    0,
531                ) => RelocationKind::Arm64Call,
532                (
533                    object::Architecture::Aarch64,
534                    object::RelocationFlags::Elf {
535                        r_type: object::elf::R_AARCH64_MOVW_UABS_G0_NC,
536                    },
537                    0,
538                ) => RelocationKind::Arm64Movw0,
539                (
540                    object::Architecture::Aarch64,
541                    object::RelocationFlags::Elf {
542                        r_type: object::elf::R_AARCH64_MOVW_UABS_G1_NC,
543                    },
544                    0,
545                ) => RelocationKind::Arm64Movw1,
546                (
547                    object::Architecture::Aarch64,
548                    object::RelocationFlags::Elf {
549                        r_type: object::elf::R_AARCH64_MOVW_UABS_G2_NC,
550                    },
551                    0,
552                ) => RelocationKind::Arm64Movw2,
553                (
554                    object::Architecture::Aarch64,
555                    object::RelocationFlags::Elf {
556                        r_type: object::elf::R_AARCH64_MOVW_UABS_G3,
557                    },
558                    0,
559                ) => RelocationKind::Arm64Movw3,
560                (
561                    object::Architecture::Riscv64 | object::Architecture::Riscv32,
562                    object::RelocationFlags::Elf {
563                        r_type: object::elf::R_RISCV_64,
564                    },
565                    64,
566                ) => RelocationKind::Abs8,
567                (
568                    object::Architecture::Riscv64 | object::Architecture::Riscv32,
569                    object::RelocationFlags::Elf {
570                        r_type: object::elf::R_RISCV_CALL_PLT,
571                    },
572                    0,
573                ) => RelocationKind::RiscvCall,
574                (
575                    object::Architecture::Riscv64 | object::Architecture::Riscv32,
576                    object::RelocationFlags::Elf {
577                        r_type: object::elf::R_RISCV_PCREL_HI20,
578                    },
579                    0,
580                ) => RelocationKind::RiscvPCRelHi20,
581                (
582                    object::Architecture::Riscv64 | object::Architecture::Riscv32,
583                    object::RelocationFlags::Elf {
584                        r_type: object::elf::R_RISCV_PCREL_LO12_I,
585                    },
586                    0,
587                ) => RelocationKind::RiscvPCRelLo12I,
588                (
589                    object::Architecture::Riscv64,
590                    object::RelocationFlags::Elf {
591                        r_type: object::elf::R_RISCV_ADD8,
592                    },
593                    0,
594                ) => RelocationKind::Add,
595                (
596                    object::Architecture::Riscv64,
597                    object::RelocationFlags::Elf {
598                        r_type: object::elf::R_RISCV_ADD16,
599                    },
600                    0,
601                ) => RelocationKind::Add2,
602                (
603                    object::Architecture::Riscv64,
604                    object::RelocationFlags::Elf {
605                        r_type: object::elf::R_RISCV_ADD32,
606                    },
607                    0,
608                ) => RelocationKind::Add4,
609                (
610                    object::Architecture::Riscv64,
611                    object::RelocationFlags::Elf {
612                        r_type: object::elf::R_RISCV_ADD64,
613                    },
614                    0,
615                ) => RelocationKind::Add8,
616                (
617                    object::Architecture::Riscv64,
618                    object::RelocationFlags::Elf {
619                        r_type: object::elf::R_RISCV_SUB6,
620                    },
621                    0,
622                ) => RelocationKind::Sub6Bits,
623                (
624                    object::Architecture::Riscv64,
625                    object::RelocationFlags::Elf {
626                        r_type: object::elf::R_RISCV_SUB8,
627                    },
628                    0,
629                ) => RelocationKind::Sub,
630                (
631                    object::Architecture::Riscv64,
632                    object::RelocationFlags::Elf {
633                        r_type: object::elf::R_RISCV_SUB16,
634                    },
635                    0,
636                ) => RelocationKind::Sub2,
637                (
638                    object::Architecture::Riscv64,
639                    object::RelocationFlags::Elf {
640                        r_type: object::elf::R_RISCV_SUB32,
641                    },
642                    0,
643                ) => RelocationKind::Sub4,
644                (
645                    object::Architecture::Riscv64,
646                    object::RelocationFlags::Elf {
647                        r_type: object::elf::R_RISCV_SUB64,
648                    },
649                    0,
650                ) => RelocationKind::Sub8,
651                (
652                    object::Architecture::Riscv64,
653                    object::RelocationFlags::Elf {
654                        r_type: object::elf::R_RISCV_SET6,
655                    },
656                    0,
657                ) => RelocationKind::Abs6Bits,
658                (
659                    object::Architecture::Riscv64,
660                    object::RelocationFlags::Elf {
661                        r_type: object::elf::R_RISCV_SET8,
662                    },
663                    0,
664                ) => RelocationKind::Abs,
665                (
666                    object::Architecture::Riscv64,
667                    object::RelocationFlags::Elf {
668                        r_type: object::elf::R_RISCV_SET16,
669                    },
670                    0,
671                ) => RelocationKind::Abs2,
672                (
673                    object::Architecture::Riscv64,
674                    object::RelocationFlags::Elf {
675                        r_type: object::elf::R_RISCV_SET32,
676                    },
677                    0,
678                ) => RelocationKind::Abs4,
679                (
680                    object::Architecture::Riscv64,
681                    object::RelocationFlags::Elf {
682                        r_type: object::elf::R_RISCV_32,
683                    },
684                    32,
685                ) => RelocationKind::Abs4,
686                (
687                    object::Architecture::Riscv64,
688                    object::RelocationFlags::Elf {
689                        r_type: object::elf::R_RISCV_32_PCREL,
690                    },
691                    0,
692                ) => RelocationKind::PCRel4,
693                (
694                    object::Architecture::LoongArch64,
695                    object::RelocationFlags::Elf {
696                        r_type: object::elf::R_LARCH_ABS_HI20,
697                    },
698                    0,
699                ) => RelocationKind::LArchAbsHi20,
700                (
701                    object::Architecture::LoongArch64,
702                    object::RelocationFlags::Elf {
703                        r_type: object::elf::R_LARCH_ABS_LO12,
704                    },
705                    0,
706                ) => RelocationKind::LArchAbsLo12,
707                (
708                    object::Architecture::LoongArch64,
709                    object::RelocationFlags::Elf {
710                        r_type: object::elf::R_LARCH_ABS64_HI12,
711                    },
712                    0,
713                ) => RelocationKind::LArchAbs64Hi12,
714                (
715                    object::Architecture::LoongArch64,
716                    object::RelocationFlags::Elf {
717                        r_type: object::elf::R_LARCH_ABS64_LO20,
718                    },
719                    0,
720                ) => RelocationKind::LArchAbs64Lo20,
721                (
722                    object::Architecture::LoongArch64,
723                    object::RelocationFlags::Elf {
724                        r_type: object::elf::R_LARCH_CALL36,
725                    },
726                    0,
727                ) => RelocationKind::LArchCall36,
728                (
729                    object::Architecture::LoongArch64,
730                    object::RelocationFlags::Elf {
731                        r_type: object::elf::R_LARCH_PCALA_HI20,
732                    },
733                    0,
734                ) => RelocationKind::LArchPCAlaHi20,
735                (
736                    object::Architecture::LoongArch64,
737                    object::RelocationFlags::Elf {
738                        r_type: object::elf::R_LARCH_PCALA_LO12,
739                    },
740                    0,
741                ) => RelocationKind::LArchPCAlaLo12,
742                (
743                    object::Architecture::LoongArch64,
744                    object::RelocationFlags::Elf {
745                        r_type: object::elf::R_LARCH_PCALA64_HI12,
746                    },
747                    0,
748                ) => RelocationKind::LArchPCAla64Hi12,
749                (
750                    object::Architecture::LoongArch64,
751                    object::RelocationFlags::Elf {
752                        r_type: object::elf::R_LARCH_PCALA64_LO20,
753                    },
754                    0,
755                ) => RelocationKind::LArchPCAla64Lo20,
756                (
757                    object::Architecture::Aarch64,
758                    object::RelocationFlags::Elf {
759                        r_type: object::elf::R_AARCH64_ADR_PREL_LO21,
760                    },
761                    0,
762                ) => RelocationKind::Aarch64AdrPrelLo21,
763                (
764                    object::Architecture::LoongArch64,
765                    object::RelocationFlags::Elf {
766                        r_type: object::elf::R_LARCH_64,
767                    },
768                    64,
769                ) => RelocationKind::Abs8,
770                (
771                    object::Architecture::LoongArch64,
772                    object::RelocationFlags::Elf {
773                        r_type: object::elf::R_LARCH_32_PCREL,
774                    },
775                    32,
776                ) => RelocationKind::PCRel4,
777                (
778                    object::Architecture::Aarch64,
779                    object::RelocationFlags::Elf {
780                        r_type: object::elf::R_AARCH64_ADR_PREL_PG_HI21,
781                    },
782                    0,
783                ) => RelocationKind::Aarch64AdrPrelPgHi21,
784                (
785                    object::Architecture::Aarch64,
786                    object::RelocationFlags::Elf {
787                        r_type: object::elf::R_AARCH64_LDST128_ABS_LO12_NC,
788                    },
789                    0,
790                ) => RelocationKind::Aarch64Ldst128AbsLo12Nc,
791                (
792                    object::Architecture::Aarch64,
793                    object::RelocationFlags::Elf {
794                        r_type: object::elf::R_AARCH64_ADD_ABS_LO12_NC,
795                    },
796                    0,
797                ) => RelocationKind::Aarch64AddAbsLo12Nc,
798                (
799                    object::Architecture::Aarch64,
800                    object::RelocationFlags::Elf {
801                        r_type: object::elf::R_AARCH64_LDST64_ABS_LO12_NC,
802                    },
803                    0,
804                ) => RelocationKind::Aarch64Ldst64AbsLo12Nc,
805                (
806                    object::Architecture::Aarch64,
807                    object::RelocationFlags::Elf {
808                        r_type: object::elf::R_AARCH64_PREL64,
809                    },
810                    64,
811                ) => RelocationKind::PCRel8,
812                (
813                    object::Architecture::Aarch64,
814                    object::RelocationFlags::Elf {
815                        r_type: object::elf::R_AARCH64_ABS64,
816                    },
817                    64,
818                ) => RelocationKind::Abs8,
819                (
820                    object::Architecture::Aarch64,
821                    object::RelocationFlags::MachO { r_type: value, .. },
822                    _,
823                ) => match value {
824                    object::macho::ARM64_RELOC_UNSIGNED => RelocationKind::MachoArm64RelocUnsigned,
825                    object::macho::ARM64_RELOC_SUBTRACTOR => {
826                        RelocationKind::MachoArm64RelocSubtractor
827                    }
828                    object::macho::ARM64_RELOC_BRANCH26 => RelocationKind::MachoArm64RelocBranch26,
829                    object::macho::ARM64_RELOC_PAGE21 => RelocationKind::MachoArm64RelocPage21,
830                    object::macho::ARM64_RELOC_PAGEOFF12 => {
831                        RelocationKind::MachoArm64RelocPageoff12
832                    }
833                    object::macho::ARM64_RELOC_GOT_LOAD_PAGE21 => {
834                        RelocationKind::MachoArm64RelocGotLoadPage21
835                    }
836                    object::macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12 => {
837                        RelocationKind::MachoArm64RelocGotLoadPageoff12
838                    }
839                    object::macho::ARM64_RELOC_POINTER_TO_GOT => {
840                        RelocationKind::MachoArm64RelocPointerToGot
841                    }
842                    object::macho::ARM64_RELOC_TLVP_LOAD_PAGE21 => {
843                        RelocationKind::MachoArm64RelocTlvpLoadPage21
844                    }
845                    object::macho::ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => {
846                        RelocationKind::MachoArm64RelocTlvpLoadPageoff12
847                    }
848                    object::macho::ARM64_RELOC_ADDEND => RelocationKind::MachoArm64RelocAddend,
849                    _ => {
850                        return Err(CompileError::Codegen(format!(
851                            "unknown relocation {reloc:?}",
852                        )));
853                    }
854                },
855                (
856                    object::Architecture::X86_64,
857                    object::RelocationFlags::MachO { r_type: value, .. },
858                    _,
859                ) => match value {
860                    object::macho::X86_64_RELOC_UNSIGNED => {
861                        RelocationKind::MachoX86_64RelocUnsigned
862                    }
863                    object::macho::X86_64_RELOC_SIGNED => RelocationKind::MachoX86_64RelocSigned,
864                    object::macho::X86_64_RELOC_BRANCH => RelocationKind::MachoX86_64RelocBranch,
865                    object::macho::X86_64_RELOC_GOT_LOAD => RelocationKind::MachoX86_64RelocGotLoad,
866                    object::macho::X86_64_RELOC_GOT => RelocationKind::MachoX86_64RelocGot,
867                    object::macho::X86_64_RELOC_SUBTRACTOR => {
868                        RelocationKind::MachoX86_64RelocSubtractor
869                    }
870                    object::macho::X86_64_RELOC_SIGNED_1 => RelocationKind::MachoX86_64RelocSigned1,
871                    object::macho::X86_64_RELOC_SIGNED_2 => RelocationKind::MachoX86_64RelocSigned2,
872                    object::macho::X86_64_RELOC_SIGNED_4 => RelocationKind::MachoX86_64RelocSigned4,
873                    object::macho::X86_64_RELOC_TLV => RelocationKind::MachoX86_64RelocTlv,
874                    _ => {
875                        return Err(CompileError::Codegen(format!(
876                            "unknown relocation {reloc:?}"
877                        )));
878                    }
879                },
880                _ => {
881                    return Err(CompileError::Codegen(format!(
882                        "unknown relocation {reloc:?}",
883                    )));
884                }
885            };
886
887            relocations
888                .entry(section_index)
889                .or_default()
890                .push(Relocation {
891                    kind,
892                    reloc_target: target,
893                    offset: offset.try_into().map_err(map_tryfromint_err)?,
894                    addend,
895                });
896        }
897    }
898
899    let eh_frame_section_indices = eh_frame_section_indices
900        .iter()
901        .map(|index| {
902            section_to_custom_section.get(index).map_or_else(
903                || {
904                    Err(CompileError::Codegen(format!(
905                        ".eh_frame section with index={index:?} was never loaded",
906                    )))
907                },
908                |idx| Ok(*idx),
909            )
910        })
911        .collect::<Result<Vec<SectionIndex>, _>>()?;
912
913    let compact_unwind_section_indices = compact_unwind_section_indices
914        .iter()
915        .map(|index| {
916            section_to_custom_section.get(index).map_or_else(
917                || {
918                    Err(CompileError::Codegen(format!(
919                        "_compact_unwind section with index={index:?} was never loaded",
920                    )))
921                },
922                |idx| Ok(*idx),
923            )
924        })
925        .collect::<Result<Vec<SectionIndex>, _>>()?;
926
927    let gcc_except_table_section_indices = gcc_except_table_section_indices
928        .iter()
929        .map(|index| {
930            section_to_custom_section.get(index).map_or_else(
931                || {
932                    Err(CompileError::Codegen(format!(
933                        ".gcc_except_table section with index={index:?} was never loaded",
934                    )))
935                },
936                |idx| Ok(*idx),
937            )
938        })
939        .collect::<Result<Vec<SectionIndex>, _>>()?;
940
941    let data_dw_ref_personality_section_indices = data_dw_ref_personality_section_indices
942        .iter()
943        .map(|index| {
944            section_to_custom_section.get(index).map_or_else(
945                || {
946                    Err(CompileError::Codegen(format!(
947                        ".data.DW.ref.wasmer_eh_personality section with index={index:?} was never loaded",
948                    )))
949                },
950                |idx| Ok(*idx),
951            )
952        })
953        .collect::<Result<Vec<SectionIndex>, _>>()?;
954
955    let mut custom_sections = section_to_custom_section
956        .iter()
957        .map(|(elf_section_index, custom_section_index)| {
958            let section = obj.section_by_index(*elf_section_index).unwrap();
959            (
960                custom_section_index,
961                CustomSection {
962                    protection: CustomSectionProtection::Read,
963                    alignment: Some(section.align()),
964                    bytes: SectionBody::new_with_vec(section.data().unwrap().to_vec()),
965                    relocations: relocations
966                        .remove_entry(elf_section_index)
967                        .map_or(vec![], |(_, v)| v),
968                },
969            )
970        })
971        .collect::<Vec<_>>();
972    custom_sections.sort_unstable_by_key(|a| a.0);
973    let custom_sections = custom_sections
974        .into_iter()
975        .map(|(_, v)| v)
976        .collect::<PrimaryMap<SectionIndex, _>>();
977
978    let function_body = FunctionBody {
979        body: obj
980            .section_by_index(root_section_index)
981            .unwrap()
982            .data()
983            .unwrap()
984            .to_vec(),
985        unwind_info: None,
986    };
987
988    let address_map = FunctionAddressMap {
989        instructions: vec![InstructionAddressMap {
990            srcloc: SourceLoc::default(),
991            code_offset: 0,
992            code_len: function_body.body.len(),
993        }],
994        start_srcloc: SourceLoc::default(),
995        end_srcloc: SourceLoc::default(),
996        body_offset: 0,
997        body_len: function_body.body.len(),
998    };
999
1000    Ok(CompiledFunction {
1001        compiled_function: wasmer_compiler::types::function::CompiledFunction {
1002            body: function_body,
1003            relocations: relocations
1004                .remove_entry(&root_section_index)
1005                .map_or(vec![], |(_, v)| v),
1006            frame_info: CompiledFunctionFrameInfo {
1007                address_map,
1008                traps: vec![],
1009            },
1010            maximum_stack_usage: None,
1011        },
1012        custom_sections,
1013        eh_frame_section_indices,
1014        compact_unwind_section_indices,
1015        gcc_except_table_section_indices,
1016        data_dw_ref_personality_section_indices,
1017    })
1018}