Skip to main content

wasmer_compiler_llvm/
object_file.rs

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