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    pub data_dw_ref_personality_section_indices: Vec<SectionIndex>,
35}
36
37static LIBCALLS_ELF: phf::Map<&'static str, LibCall> = phf::phf_map! {
38    "ceilf" => LibCall::CeilF32,
39    "ceil" => LibCall::CeilF64,
40    "floorf" => LibCall::FloorF32,
41    "floor" => LibCall::FloorF64,
42    "nearbyintf" => LibCall::NearestF32,
43    "nearbyint" => LibCall::NearestF64,
44    "truncf" => LibCall::TruncF32,
45    "trunc" => LibCall::TruncF64,
46    "wasmer_vm_f32_ceil" => LibCall::CeilF32,
47    "wasmer_vm_f64_ceil" => LibCall::CeilF64,
48    "wasmer_vm_f32_floor" => LibCall::FloorF32,
49    "wasmer_vm_f64_floor" => LibCall::FloorF64,
50    "wasmer_vm_f32_nearest" => LibCall::NearestF32,
51    "wasmer_vm_f64_nearest" => LibCall::NearestF64,
52    "wasmer_vm_f32_trunc" => LibCall::TruncF32,
53    "wasmer_vm_f64_trunc" => LibCall::TruncF64,
54    "wasmer_vm_memory32_size" => LibCall::Memory32Size,
55    "wasmer_vm_imported_memory32_size" => LibCall::ImportedMemory32Size,
56    "wasmer_vm_table_copy" => LibCall::TableCopy,
57    "wasmer_vm_table_init" => LibCall::TableInit,
58    "wasmer_vm_table_fill" => LibCall::TableFill,
59    "wasmer_vm_table_size" => LibCall::TableSize,
60    "wasmer_vm_imported_table_size" => LibCall::ImportedTableSize,
61    "wasmer_vm_table_get" => LibCall::TableGet,
62    "wasmer_vm_imported_table_get" => LibCall::ImportedTableGet,
63    "wasmer_vm_table_set" => LibCall::TableSet,
64    "wasmer_vm_imported_table_set" => LibCall::ImportedTableSet,
65    "wasmer_vm_table_grow" => LibCall::TableGrow,
66    "wasmer_vm_imported_table_grow" => LibCall::ImportedTableGrow,
67    "wasmer_vm_func_ref" => LibCall::FuncRef,
68    "wasmer_vm_elem_drop" => LibCall::ElemDrop,
69    "wasmer_vm_memory32_copy" => LibCall::Memory32Copy,
70    "wasmer_vm_imported_memory32_copy" => LibCall::ImportedMemory32Copy,
71    "wasmer_vm_memory32_fill" => LibCall::Memory32Fill,
72    "wasmer_vm_imported_memory32_fill" => LibCall::ImportedMemory32Fill,
73    "wasmer_vm_memory32_init" => LibCall::Memory32Init,
74    "wasmer_vm_data_drop" => LibCall::DataDrop,
75    "wasmer_vm_raise_trap" => LibCall::RaiseTrap,
76    "wasmer_vm_memory32_atomic_wait32" => LibCall::Memory32AtomicWait32,
77    "wasmer_vm_imported_memory32_atomic_wait32" => LibCall::ImportedMemory32AtomicWait32,
78    "wasmer_vm_memory32_atomic_wait64" => LibCall::Memory32AtomicWait64,
79    "wasmer_vm_imported_memory32_atomic_wait64" => LibCall::ImportedMemory32AtomicWait64,
80    "wasmer_vm_memory32_atomic_notify" => LibCall::Memory32AtomicNotify,
81    "wasmer_vm_imported_memory32_atomic_notify" => LibCall::ImportedMemory32AtomicNotify,
82    "wasmer_vm_throw" => LibCall::Throw,
83    "wasmer_vm_alloc_exception" => LibCall::AllocException,
84    "wasmer_vm_read_exnref" => LibCall::ReadExnRef,
85    "wasmer_vm_exception_into_exnref" => LibCall::LibunwindExceptionIntoExnRef,
86    "wasmer_eh_personality" => LibCall::EHPersonality,
87    "wasmer_eh_personality2" => LibCall::EHPersonality2,
88    "wasmer_vm_dbg_usize" => LibCall::DebugUsize,
89    "wasmer_vm_dbg_str" => LibCall::DebugStr,
90};
91
92static LIBCALLS_MACHO: phf::Map<&'static str, LibCall> = phf::phf_map! {
93    "_ceilf" => LibCall::CeilF32,
94    "_ceil" => LibCall::CeilF64,
95    "_floorf" => LibCall::FloorF32,
96    "_floor" => LibCall::FloorF64,
97    "_nearbyintf" => LibCall::NearestF32,
98    "_nearbyint" => LibCall::NearestF64,
99    "_truncf" => LibCall::TruncF32,
100    "_trunc" => LibCall::TruncF64,
101    "_wasmer_vm_f32_ceil" => LibCall::CeilF32,
102    "_wasmer_vm_f64_ceil" => LibCall::CeilF64,
103    "_wasmer_vm_f32_floor" => LibCall::FloorF32,
104    "_wasmer_vm_f64_floor" => LibCall::FloorF64,
105    "_wasmer_vm_f32_nearest" => LibCall::NearestF32,
106    "_wasmer_vm_f64_nearest" => LibCall::NearestF64,
107    "_wasmer_vm_f32_trunc" => LibCall::TruncF32,
108    "_wasmer_vm_f64_trunc" => LibCall::TruncF64,
109    "_wasmer_vm_memory32_size" => LibCall::Memory32Size,
110    "_wasmer_vm_imported_memory32_size" => LibCall::ImportedMemory32Size,
111    "_wasmer_vm_table_copy" => LibCall::TableCopy,
112    "_wasmer_vm_table_init" => LibCall::TableInit,
113    "_wasmer_vm_table_fill" => LibCall::TableFill,
114    "_wasmer_vm_table_size" => LibCall::TableSize,
115    "_wasmer_vm_imported_table_size" => LibCall::ImportedTableSize,
116    "_wasmer_vm_table_get" => LibCall::TableGet,
117    "_wasmer_vm_imported_table_get" => LibCall::ImportedTableGet,
118    "_wasmer_vm_table_set" => LibCall::TableSet,
119    "_wasmer_vm_imported_table_set" => LibCall::ImportedTableSet,
120    "_wasmer_vm_table_grow" => LibCall::TableGrow,
121    "_wasmer_vm_imported_table_grow" => LibCall::ImportedTableGrow,
122    "_wasmer_vm_func_ref" => LibCall::FuncRef,
123    "_wasmer_vm_elem_drop" => LibCall::ElemDrop,
124    "_wasmer_vm_memory32_copy" => LibCall::Memory32Copy,
125    "_wasmer_vm_imported_memory32_copy" => LibCall::ImportedMemory32Copy,
126    "_wasmer_vm_memory32_fill" => LibCall::Memory32Fill,
127    "_wasmer_vm_imported_memory32_fill" => LibCall::ImportedMemory32Fill,
128    "_wasmer_vm_memory32_init" => LibCall::Memory32Init,
129    "_wasmer_vm_data_drop" => LibCall::DataDrop,
130    "_wasmer_vm_raise_trap" => LibCall::RaiseTrap,
131    "_wasmer_vm_memory32_atomic_wait32" => LibCall::Memory32AtomicWait32,
132    "_wasmer_vm_imported_memory32_atomic_wait32" => LibCall::ImportedMemory32AtomicWait32,
133    "_wasmer_vm_memory32_atomic_wait64" => LibCall::Memory32AtomicWait64,
134    "_wasmer_vm_imported_memory32_atomic_wait64" => LibCall::ImportedMemory32AtomicWait64,
135    "_wasmer_vm_memory32_atomic_notify" => LibCall::Memory32AtomicNotify,
136    "_wasmer_vm_imported_memory32_atomic_notify" => LibCall::ImportedMemory32AtomicNotify,
137
138    "_wasmer_vm_throw" => LibCall::Throw,
139    "_wasmer_vm_alloc_exception" => LibCall::AllocException,
140    "_wasmer_vm_read_exnref" => LibCall::ReadExnRef,
141    "_wasmer_vm_exception_into_exnref" => LibCall::LibunwindExceptionIntoExnRef,
142    // Note: on macOS+Mach-O the personality function *must* be called like this, otherwise LLVM
143    // will generate things differently than "normal", wreaking havoc.
144    //
145    // todo: find out if it is a bug in LLVM or it is expected.
146    "___gxx_personality_v0" => LibCall::EHPersonality,
147    "_wasmer_eh_personality2" => LibCall::EHPersonality2,
148    "_wasmer_vm_dbg_usize" => LibCall::DebugUsize,
149    "_wasmer_vm_dbg_str" => LibCall::DebugStr,
150};
151
152pub fn load_object_file<F>(
153    contents: &[u8],
154    root_section: &str,
155    root_section_reloc_target: RelocationTarget,
156    mut symbol_name_to_relocation_target: F,
157    binary_fmt: BinaryFormat,
158) -> Result<CompiledFunction, CompileError>
159where
160    F: FnMut(&str) -> Result<Option<RelocationTarget>, CompileError>,
161{
162    let obj = object::File::parse(contents).map_err(map_object_err)?;
163
164    let libcalls = match binary_fmt {
165        BinaryFormat::Elf => &LIBCALLS_ELF,
166        BinaryFormat::Macho => &LIBCALLS_MACHO,
167        _ => {
168            return Err(CompileError::UnsupportedTarget(format!(
169                "Unsupported binary format {binary_fmt:?}"
170            )));
171        }
172    };
173
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
217    // Add any .eh_frame sections.
218    let mut eh_frame_section_indices = vec![];
219
220    // Add macos-specific unwind sections.
221    let mut compact_unwind_section_indices = vec![];
222
223    // .gcc_except_table sections, which contain the actual LSDA data.
224    // We don't need the actual sections for anything (yet), but trampoline
225    // codegen checks custom section counts to verify there aren't any
226    // unexpected custom sections, so we do a bit of book-keeping here.
227    let mut gcc_except_table_section_indices = vec![];
228
229    let mut data_dw_ref_personality_section_indices = vec![];
230
231    for section in obj.sections() {
232        let index = section.index();
233        let Ok(section_name) = section.name() else {
234            continue;
235        };
236
237        match section_name {
238            "__eh_frame" | ".eh_frame" => {
239                worklist.push(index);
240                eh_frame_section_indices.push(index);
241
242                // This allocates a custom section index for the ELF section.
243                elf_section_to_target(index);
244            }
245            "__compact_unwind" => {
246                worklist.push(index);
247                compact_unwind_section_indices.push(index);
248
249                elf_section_to_target(index);
250            }
251            ".gcc_except_table" => {
252                worklist.push(index);
253                gcc_except_table_section_indices.push(index);
254
255                elf_section_to_target(index);
256            }
257            ".data.DW.ref.wasmer_eh_personality" => {
258                worklist.push(index);
259                data_dw_ref_personality_section_indices.push(index);
260
261                elf_section_to_target(index);
262            }
263            _ => {}
264        }
265    }
266
267    let mut visited: HashSet<_> = HashSet::from_iter(worklist.iter().copied());
268    while let Some(section_index) = worklist.pop() {
269        let sec = obj
270            .section_by_index(section_index)
271            .map_err(map_object_err)?;
272        let relocs = sec.relocations();
273        for (offset, reloc) in relocs {
274            let mut addend = reloc.addend();
275            let target = match reloc.target() {
276                object::read::RelocationTarget::Symbol(index) => {
277                    let symbol = obj.symbol_by_index(index).map_err(map_object_err)?;
278                    let symbol_name = symbol.name().map_err(map_object_err)?;
279                    if symbol.kind() == object::SymbolKind::Section {
280                        match symbol.section() {
281                            object::SymbolSection::Section(section_index) => {
282                                if section_index == root_section_index {
283                                    root_section_reloc_target
284                                } else {
285                                    if visited.insert(section_index) {
286                                        worklist.push(section_index);
287                                    }
288                                    elf_section_to_target(section_index)
289                                }
290                            }
291                            _ => {
292                                return Err(CompileError::Codegen(format!(
293                                    "relocation targets unknown section {reloc:?}",
294                                )));
295                            }
296                        }
297                        // Maybe a libcall then?
298                    } else if let Some(libcall) = libcalls.get(symbol_name) {
299                        RelocationTarget::LibCall(*libcall)
300                    } else if let Ok(Some(reloc_target)) =
301                        symbol_name_to_relocation_target(symbol_name)
302                    {
303                        reloc_target
304                    } else if let object::SymbolSection::Section(section_index) = symbol.section() {
305                        if matches!(
306                            reloc.flags(),
307                            object::RelocationFlags::MachO {
308                                r_type: object::macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12,
309                                r_pcrel: false,
310                                ..
311                            } | object::RelocationFlags::MachO {
312                                r_type: object::macho::ARM64_RELOC_POINTER_TO_GOT,
313                                r_pcrel: true,
314                                ..
315                            } | object::RelocationFlags::MachO {
316                                r_type: object::macho::ARM64_RELOC_GOT_LOAD_PAGE21,
317                                r_pcrel: true,
318                                ..
319                            } | object::RelocationFlags::MachO {
320                                r_type: object::macho::ARM64_RELOC_PAGE21,
321                                r_pcrel: true,
322                                ..
323                            } | object::RelocationFlags::MachO {
324                                r_type: object::macho::ARM64_RELOC_PAGEOFF12,
325                                r_pcrel: false,
326                                ..
327                            }
328                        ) {
329                            // (caveat: this comment comes from a point in time after the `addend`
330                            // math in the else branch)
331                            //
332                            // (caveat2: this is mach-o + aarch64 only)
333                            //
334                            // The tampering with the addend in the else branch causes some
335                            // problems with GOT-based relocs, as a non-zero addend has no meaning
336                            // when dealing with GOT entries, for our use-case.
337                            //
338                            // However, for some reasons, it happens that we conceptually need to
339                            // have relocations that pretty much mean "the contents of this GOT
340                            // entry plus a non-zero addend". When in this case, we will later
341                            // perform what is known as "GOT relaxation", i.e. we can change the
342                            // `ldr` opcode to an `add`.
343                            //
344                            // For this to make sense we need to fix the addend to be the delta
345                            // between the section whose address is an entry of the GOT and the
346                            // symbol that is the target of the relocation.
347
348                            let symbol_sec = obj
349                                .section_by_index(section_index)
350                                .map_err(map_object_err)?;
351
352                            addend = addend
353                                .wrapping_add((symbol.address() - symbol_sec.address()) as i64);
354                        } else {
355                            // TODO: Encode symbol address into addend, I think this is a bit hacky.
356                            addend = addend.wrapping_add(symbol.address() as i64);
357                        }
358
359                        if section_index == root_section_index {
360                            root_section_reloc_target
361                        } else {
362                            if visited.insert(section_index) {
363                                worklist.push(section_index);
364                            }
365
366                            elf_section_to_target(section_index)
367                        }
368                    } else {
369                        return Err(CompileError::Codegen(format!(
370                            "relocation {reloc:?} targets unknown symbol '{symbol:?}'",
371                        )));
372                    }
373                }
374
375                object::read::RelocationTarget::Section(index) => {
376                    if index == root_section_index {
377                        root_section_reloc_target
378                    } else {
379                        if visited.insert(index) {
380                            worklist.push(index);
381                        }
382                        elf_section_to_target(index)
383                    }
384                }
385
386                object::read::RelocationTarget::Absolute => {
387                    // Wasm-produced object files should never have absolute
388                    // addresses in them because none of the parts of the Wasm
389                    // VM, nor the generated code are loaded at fixed addresses.
390                    return Err(CompileError::Codegen(format!(
391                        "relocation targets absolute address {reloc:?}",
392                    )));
393                }
394
395                // `object::read::RelocationTarget` is a
396                // non-exhaustive enum (`#[non_exhaustive]`), so it
397                // could have additional variants added in the
398                // future. Therefore, when matching against variants
399                // of non-exhaustive enums, an extra wildcard arm must
400                // be added to account for any future variants.
401                t => {
402                    return Err(CompileError::Codegen(format!(
403                        "relocation target is unknown `{t:?}`",
404                    )));
405                }
406            };
407            let kind = match (obj.architecture(), reloc.flags(), reloc.size()) {
408                (
409                    _,
410                    object::RelocationFlags::Elf {
411                        r_type: object::elf::R_X86_64_64,
412                    },
413                    64,
414                ) => RelocationKind::Abs8,
415                (
416                    object::Architecture::X86_64,
417                    object::RelocationFlags::Elf {
418                        r_type: object::elf::R_X86_64_PC64,
419                    },
420                    0,
421                ) => RelocationKind::PCRel8,
422                (
423                    object::Architecture::Aarch64,
424                    object::RelocationFlags::Elf {
425                        r_type: object::elf::R_AARCH64_CALL26,
426                    },
427                    26,
428                ) => RelocationKind::Arm64Call,
429                (
430                    object::Architecture::Aarch64,
431                    object::RelocationFlags::Elf {
432                        r_type: object::elf::R_AARCH64_MOVW_UABS_G0_NC,
433                    },
434                    0,
435                ) => RelocationKind::Arm64Movw0,
436                (
437                    object::Architecture::Aarch64,
438                    object::RelocationFlags::Elf {
439                        r_type: object::elf::R_AARCH64_MOVW_UABS_G1_NC,
440                    },
441                    0,
442                ) => RelocationKind::Arm64Movw1,
443                (
444                    object::Architecture::Aarch64,
445                    object::RelocationFlags::Elf {
446                        r_type: object::elf::R_AARCH64_MOVW_UABS_G2_NC,
447                    },
448                    0,
449                ) => RelocationKind::Arm64Movw2,
450                (
451                    object::Architecture::Aarch64,
452                    object::RelocationFlags::Elf {
453                        r_type: object::elf::R_AARCH64_MOVW_UABS_G3,
454                    },
455                    0,
456                ) => RelocationKind::Arm64Movw3,
457                (
458                    object::Architecture::Riscv64,
459                    object::RelocationFlags::Elf {
460                        r_type: object::elf::R_RISCV_CALL_PLT,
461                    },
462                    0,
463                ) => RelocationKind::RiscvCall,
464                (
465                    object::Architecture::Riscv64,
466                    object::RelocationFlags::Elf {
467                        r_type: object::elf::R_RISCV_PCREL_HI20,
468                    },
469                    0,
470                ) => RelocationKind::RiscvPCRelHi20,
471                (
472                    object::Architecture::Riscv64,
473                    object::RelocationFlags::Elf {
474                        r_type: object::elf::R_RISCV_PCREL_LO12_I,
475                    },
476                    0,
477                ) => RelocationKind::RiscvPCRelLo12I,
478                (
479                    object::Architecture::Riscv64,
480                    object::RelocationFlags::Elf {
481                        r_type: object::elf::R_RISCV_ADD8,
482                    },
483                    0,
484                ) => RelocationKind::Add,
485                (
486                    object::Architecture::Riscv64,
487                    object::RelocationFlags::Elf {
488                        r_type: object::elf::R_RISCV_ADD16,
489                    },
490                    0,
491                ) => RelocationKind::Add2,
492                (
493                    object::Architecture::Riscv64,
494                    object::RelocationFlags::Elf {
495                        r_type: object::elf::R_RISCV_ADD32,
496                    },
497                    0,
498                ) => RelocationKind::Add4,
499                (
500                    object::Architecture::Riscv64,
501                    object::RelocationFlags::Elf {
502                        r_type: object::elf::R_RISCV_ADD64,
503                    },
504                    0,
505                ) => RelocationKind::Add8,
506                (
507                    object::Architecture::Riscv64,
508                    object::RelocationFlags::Elf {
509                        r_type: object::elf::R_RISCV_SUB6,
510                    },
511                    0,
512                ) => RelocationKind::Sub6Bits,
513                (
514                    object::Architecture::Riscv64,
515                    object::RelocationFlags::Elf {
516                        r_type: object::elf::R_RISCV_SUB8,
517                    },
518                    0,
519                ) => RelocationKind::Sub,
520                (
521                    object::Architecture::Riscv64,
522                    object::RelocationFlags::Elf {
523                        r_type: object::elf::R_RISCV_SUB16,
524                    },
525                    0,
526                ) => RelocationKind::Sub2,
527                (
528                    object::Architecture::Riscv64,
529                    object::RelocationFlags::Elf {
530                        r_type: object::elf::R_RISCV_SUB32,
531                    },
532                    0,
533                ) => RelocationKind::Sub4,
534                (
535                    object::Architecture::Riscv64,
536                    object::RelocationFlags::Elf {
537                        r_type: object::elf::R_RISCV_SUB64,
538                    },
539                    0,
540                ) => RelocationKind::Sub8,
541                (
542                    object::Architecture::Riscv64,
543                    object::RelocationFlags::Elf {
544                        r_type: object::elf::R_RISCV_SET6,
545                    },
546                    0,
547                ) => RelocationKind::Abs6Bits,
548                (
549                    object::Architecture::Riscv64,
550                    object::RelocationFlags::Elf {
551                        r_type: object::elf::R_RISCV_SET8,
552                    },
553                    0,
554                ) => RelocationKind::Abs,
555                (
556                    object::Architecture::Riscv64,
557                    object::RelocationFlags::Elf {
558                        r_type: object::elf::R_RISCV_SET16,
559                    },
560                    0,
561                ) => RelocationKind::Abs2,
562                (
563                    object::Architecture::Riscv64,
564                    object::RelocationFlags::Elf {
565                        r_type: object::elf::R_RISCV_SET32,
566                    },
567                    0,
568                ) => RelocationKind::Abs4,
569                (
570                    object::Architecture::Riscv64,
571                    object::RelocationFlags::Elf {
572                        r_type: object::elf::R_RISCV_32,
573                    },
574                    32,
575                ) => RelocationKind::Abs4,
576                (
577                    object::Architecture::Riscv64,
578                    object::RelocationFlags::Elf {
579                        r_type: object::elf::R_RISCV_64,
580                    },
581                    64,
582                ) => RelocationKind::Abs8,
583                (
584                    object::Architecture::Riscv64,
585                    object::RelocationFlags::Elf {
586                        r_type: object::elf::R_RISCV_32_PCREL,
587                    },
588                    0,
589                ) => RelocationKind::PCRel4,
590                (
591                    object::Architecture::LoongArch64,
592                    object::RelocationFlags::Elf {
593                        r_type: object::elf::R_LARCH_ABS_HI20,
594                    },
595                    0,
596                ) => RelocationKind::LArchAbsHi20,
597                (
598                    object::Architecture::LoongArch64,
599                    object::RelocationFlags::Elf {
600                        r_type: object::elf::R_LARCH_ABS_LO12,
601                    },
602                    0,
603                ) => RelocationKind::LArchAbsLo12,
604                (
605                    object::Architecture::LoongArch64,
606                    object::RelocationFlags::Elf {
607                        r_type: object::elf::R_LARCH_ABS64_HI12,
608                    },
609                    0,
610                ) => RelocationKind::LArchAbs64Hi12,
611                (
612                    object::Architecture::LoongArch64,
613                    object::RelocationFlags::Elf {
614                        r_type: object::elf::R_LARCH_ABS64_LO20,
615                    },
616                    0,
617                ) => RelocationKind::LArchAbs64Lo20,
618                (
619                    object::Architecture::LoongArch64,
620                    object::RelocationFlags::Elf {
621                        r_type: object::elf::R_LARCH_CALL36,
622                    },
623                    0,
624                ) => RelocationKind::LArchCall36,
625                (
626                    object::Architecture::LoongArch64,
627                    object::RelocationFlags::Elf {
628                        r_type: object::elf::R_LARCH_PCALA_HI20,
629                    },
630                    0,
631                ) => RelocationKind::LArchPCAlaHi20,
632                (
633                    object::Architecture::LoongArch64,
634                    object::RelocationFlags::Elf {
635                        r_type: object::elf::R_LARCH_PCALA_LO12,
636                    },
637                    0,
638                ) => RelocationKind::LArchPCAlaLo12,
639                (
640                    object::Architecture::LoongArch64,
641                    object::RelocationFlags::Elf {
642                        r_type: object::elf::R_LARCH_PCALA64_HI12,
643                    },
644                    0,
645                ) => RelocationKind::LArchPCAla64Hi12,
646                (
647                    object::Architecture::LoongArch64,
648                    object::RelocationFlags::Elf {
649                        r_type: object::elf::R_LARCH_PCALA64_LO20,
650                    },
651                    0,
652                ) => RelocationKind::LArchPCAla64Lo20,
653                (
654                    object::Architecture::Aarch64,
655                    object::RelocationFlags::Elf {
656                        r_type: object::elf::R_AARCH64_ADR_PREL_LO21,
657                    },
658                    0,
659                ) => RelocationKind::Aarch64AdrPrelLo21,
660                (
661                    object::Architecture::LoongArch64,
662                    object::RelocationFlags::Elf {
663                        r_type: object::elf::R_LARCH_64,
664                    },
665                    64,
666                ) => RelocationKind::Abs8,
667                (
668                    object::Architecture::LoongArch64,
669                    object::RelocationFlags::Elf {
670                        r_type: object::elf::R_LARCH_32_PCREL,
671                    },
672                    32,
673                ) => RelocationKind::PCRel4,
674                (
675                    object::Architecture::Aarch64,
676                    object::RelocationFlags::Elf {
677                        r_type: object::elf::R_AARCH64_ADR_PREL_PG_HI21,
678                    },
679                    0,
680                ) => RelocationKind::Aarch64AdrPrelPgHi21,
681                (
682                    object::Architecture::Aarch64,
683                    object::RelocationFlags::Elf {
684                        r_type: object::elf::R_AARCH64_LDST128_ABS_LO12_NC,
685                    },
686                    0,
687                ) => RelocationKind::Aarch64Ldst128AbsLo12Nc,
688                (
689                    object::Architecture::Aarch64,
690                    object::RelocationFlags::Elf {
691                        r_type: object::elf::R_AARCH64_ADD_ABS_LO12_NC,
692                    },
693                    0,
694                ) => RelocationKind::Aarch64AddAbsLo12Nc,
695                (
696                    object::Architecture::Aarch64,
697                    object::RelocationFlags::Elf {
698                        r_type: object::elf::R_AARCH64_LDST64_ABS_LO12_NC,
699                    },
700                    0,
701                ) => RelocationKind::Aarch64Ldst64AbsLo12Nc,
702                (
703                    object::Architecture::Aarch64,
704                    object::RelocationFlags::Elf {
705                        r_type: object::elf::R_AARCH64_PREL64,
706                    },
707                    64,
708                ) => RelocationKind::PCRel8,
709                (
710                    object::Architecture::Aarch64,
711                    object::RelocationFlags::Elf {
712                        r_type: object::elf::R_AARCH64_ABS64,
713                    },
714                    64,
715                ) => RelocationKind::Abs8,
716                (
717                    object::Architecture::Aarch64,
718                    object::RelocationFlags::MachO { r_type: value, .. },
719                    _,
720                ) => match value {
721                    object::macho::ARM64_RELOC_UNSIGNED => RelocationKind::MachoArm64RelocUnsigned,
722                    object::macho::ARM64_RELOC_SUBTRACTOR => {
723                        RelocationKind::MachoArm64RelocSubtractor
724                    }
725                    object::macho::ARM64_RELOC_BRANCH26 => RelocationKind::MachoArm64RelocBranch26,
726                    object::macho::ARM64_RELOC_PAGE21 => RelocationKind::MachoArm64RelocPage21,
727                    object::macho::ARM64_RELOC_PAGEOFF12 => {
728                        RelocationKind::MachoArm64RelocPageoff12
729                    }
730                    object::macho::ARM64_RELOC_GOT_LOAD_PAGE21 => {
731                        RelocationKind::MachoArm64RelocGotLoadPage21
732                    }
733                    object::macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12 => {
734                        RelocationKind::MachoArm64RelocGotLoadPageoff12
735                    }
736                    object::macho::ARM64_RELOC_POINTER_TO_GOT => {
737                        RelocationKind::MachoArm64RelocPointerToGot
738                    }
739                    object::macho::ARM64_RELOC_TLVP_LOAD_PAGE21 => {
740                        RelocationKind::MachoArm64RelocTlvpLoadPage21
741                    }
742                    object::macho::ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => {
743                        RelocationKind::MachoArm64RelocTlvpLoadPageoff12
744                    }
745                    object::macho::ARM64_RELOC_ADDEND => RelocationKind::MachoArm64RelocAddend,
746                    _ => {
747                        return Err(CompileError::Codegen(format!(
748                            "unknown relocation {reloc:?}",
749                        )));
750                    }
751                },
752                (
753                    object::Architecture::X86_64,
754                    object::RelocationFlags::MachO { r_type: value, .. },
755                    _,
756                ) => match value {
757                    object::macho::X86_64_RELOC_UNSIGNED => {
758                        RelocationKind::MachoX86_64RelocUnsigned
759                    }
760                    object::macho::X86_64_RELOC_SIGNED => RelocationKind::MachoX86_64RelocSigned,
761                    object::macho::X86_64_RELOC_BRANCH => RelocationKind::MachoX86_64RelocBranch,
762                    object::macho::X86_64_RELOC_GOT_LOAD => RelocationKind::MachoX86_64RelocGotLoad,
763                    object::macho::X86_64_RELOC_GOT => RelocationKind::MachoX86_64RelocGot,
764                    object::macho::X86_64_RELOC_SUBTRACTOR => {
765                        RelocationKind::MachoX86_64RelocSubtractor
766                    }
767                    object::macho::X86_64_RELOC_SIGNED_1 => RelocationKind::MachoX86_64RelocSigned1,
768                    object::macho::X86_64_RELOC_SIGNED_2 => RelocationKind::MachoX86_64RelocSigned2,
769                    object::macho::X86_64_RELOC_SIGNED_4 => RelocationKind::MachoX86_64RelocSigned4,
770                    object::macho::X86_64_RELOC_TLV => RelocationKind::MachoX86_64RelocTlv,
771                    _ => {
772                        return Err(CompileError::Codegen(format!(
773                            "unknown relocation {reloc:?}"
774                        )));
775                    }
776                },
777                _ => {
778                    return Err(CompileError::Codegen(format!(
779                        "unknown relocation {reloc:?}",
780                    )));
781                }
782            };
783
784            relocations
785                .entry(section_index)
786                .or_default()
787                .push(Relocation {
788                    kind,
789                    reloc_target: target,
790                    offset: offset.try_into().map_err(map_tryfromint_err)?,
791                    addend,
792                });
793        }
794    }
795
796    let eh_frame_section_indices = eh_frame_section_indices
797        .iter()
798        .map(|index| {
799            section_to_custom_section.get(index).map_or_else(
800                || {
801                    Err(CompileError::Codegen(format!(
802                        ".eh_frame section with index={index:?} was never loaded",
803                    )))
804                },
805                |idx| Ok(*idx),
806            )
807        })
808        .collect::<Result<Vec<SectionIndex>, _>>()?;
809
810    let compact_unwind_section_indices = compact_unwind_section_indices
811        .iter()
812        .map(|index| {
813            section_to_custom_section.get(index).map_or_else(
814                || {
815                    Err(CompileError::Codegen(format!(
816                        "_compact_unwind section with index={index:?} was never loaded",
817                    )))
818                },
819                |idx| Ok(*idx),
820            )
821        })
822        .collect::<Result<Vec<SectionIndex>, _>>()?;
823
824    let gcc_except_table_section_indices = gcc_except_table_section_indices
825        .iter()
826        .map(|index| {
827            section_to_custom_section.get(index).map_or_else(
828                || {
829                    Err(CompileError::Codegen(format!(
830                        ".gcc_except_table section with index={index:?} was never loaded",
831                    )))
832                },
833                |idx| Ok(*idx),
834            )
835        })
836        .collect::<Result<Vec<SectionIndex>, _>>()?;
837
838    let data_dw_ref_personality_section_indices = data_dw_ref_personality_section_indices
839        .iter()
840        .map(|index| {
841            section_to_custom_section.get(index).map_or_else(
842                || {
843                    Err(CompileError::Codegen(format!(
844                        ".data.DW.ref.wasmer_eh_personality section with index={index:?} was never loaded",
845                    )))
846                },
847                |idx| Ok(*idx),
848            )
849        })
850        .collect::<Result<Vec<SectionIndex>, _>>()?;
851
852    let mut custom_sections = section_to_custom_section
853        .iter()
854        .map(|(elf_section_index, custom_section_index)| {
855            let section = obj.section_by_index(*elf_section_index).unwrap();
856            (
857                custom_section_index,
858                CustomSection {
859                    protection: CustomSectionProtection::Read,
860                    alignment: Some(section.align()),
861                    bytes: SectionBody::new_with_vec(section.data().unwrap().to_vec()),
862                    relocations: relocations
863                        .remove_entry(elf_section_index)
864                        .map_or(vec![], |(_, v)| v),
865                },
866            )
867        })
868        .collect::<Vec<_>>();
869    custom_sections.sort_unstable_by_key(|a| a.0);
870    let custom_sections = custom_sections
871        .into_iter()
872        .map(|(_, v)| v)
873        .collect::<PrimaryMap<SectionIndex, _>>();
874
875    let function_body = FunctionBody {
876        body: obj
877            .section_by_index(root_section_index)
878            .unwrap()
879            .data()
880            .unwrap()
881            .to_vec(),
882        unwind_info: None,
883    };
884
885    let address_map = FunctionAddressMap {
886        instructions: vec![InstructionAddressMap {
887            srcloc: SourceLoc::default(),
888            code_offset: 0,
889            code_len: function_body.body.len(),
890        }],
891        start_srcloc: SourceLoc::default(),
892        end_srcloc: SourceLoc::default(),
893        body_offset: 0,
894        body_len: function_body.body.len(),
895    };
896
897    Ok(CompiledFunction {
898        compiled_function: wasmer_compiler::types::function::CompiledFunction {
899            body: function_body,
900            relocations: relocations
901                .remove_entry(&root_section_index)
902                .map_or(vec![], |(_, v)| v),
903            frame_info: CompiledFunctionFrameInfo {
904                address_map,
905                traps: vec![],
906            },
907        },
908        custom_sections,
909        eh_frame_section_indices,
910        compact_unwind_section_indices,
911        gcc_except_table_section_indices,
912        data_dw_ref_personality_section_indices,
913    })
914}