wasmer_compiler_llvm/
object_file.rs

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