use enum_iterator::IntoEnumIterator;
use target_lexicon::Architecture;
use wasmer_types::LibCall;
use crate::types::{
relocation::{Relocation, RelocationKind, RelocationTarget},
section::{CustomSection, CustomSectionProtection, SectionBody},
target::Target,
};
const AARCH64_TRAMPOLINE: [u8; 16] = [
0x51, 0x00, 0x00, 0x58, 0x20, 0x02, 0x1f, 0xd6, 0, 0, 0, 0, 0, 0, 0, 0,
];
const X86_64_TRAMPOLINE: [u8; 16] = [
0xff, 0x25, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
const RISCV64_TRAMPOLINE: [u8; 24] = [
0x17, 0x03, 0x00, 0x00, 0x03, 0x33, 0x03, 0x01, 0x67, 0x00, 0x03, 0x00, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
];
const LOONGARCH64_TRAMPOLINE: [u8; 24] = [
0x0c, 0x00, 0x00, 0x0c, 0x8c, 0x41, 0xc0, 0x28, 0x80, 0x01, 0x00, 0x4c, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
];
fn make_trampoline(
target: &Target,
libcall: LibCall,
code: &mut Vec<u8>,
relocations: &mut Vec<Relocation>,
) {
match target.triple().architecture {
Architecture::Aarch64(_) => {
code.extend(AARCH64_TRAMPOLINE);
relocations.push(Relocation {
kind: RelocationKind::Abs8,
reloc_target: RelocationTarget::LibCall(libcall),
offset: code.len() as u32 - 8,
addend: 0,
});
}
Architecture::X86_64 => {
code.extend(X86_64_TRAMPOLINE);
relocations.push(Relocation {
kind: RelocationKind::Abs8,
reloc_target: RelocationTarget::LibCall(libcall),
offset: code.len() as u32 - 8,
addend: 0,
});
}
Architecture::Riscv64(_) => {
code.extend(RISCV64_TRAMPOLINE);
relocations.push(Relocation {
kind: RelocationKind::Abs8,
reloc_target: RelocationTarget::LibCall(libcall),
offset: code.len() as u32 - 8,
addend: 0,
});
}
Architecture::LoongArch64 => {
code.extend(LOONGARCH64_TRAMPOLINE);
relocations.push(Relocation {
kind: RelocationKind::Abs8,
reloc_target: RelocationTarget::LibCall(libcall),
offset: code.len() as u32 - 8,
addend: 0,
});
}
arch => panic!("Unsupported architecture: {}", arch),
};
}
pub fn libcall_trampoline_len(target: &Target) -> usize {
match target.triple().architecture {
Architecture::Aarch64(_) => AARCH64_TRAMPOLINE.len(),
Architecture::X86_64 => X86_64_TRAMPOLINE.len(),
Architecture::Riscv64(_) => RISCV64_TRAMPOLINE.len(),
Architecture::LoongArch64 => LOONGARCH64_TRAMPOLINE.len(),
arch => panic!("Unsupported architecture: {}", arch),
}
}
pub fn make_libcall_trampolines(target: &Target) -> CustomSection {
let mut code = vec![];
let mut relocations = vec![];
for libcall in LibCall::into_enum_iter() {
make_trampoline(target, libcall, &mut code, &mut relocations);
}
CustomSection {
protection: CustomSectionProtection::ReadExecute,
bytes: SectionBody::new_with_vec(code),
relocations,
}
}
pub fn get_libcall_trampoline(
libcall: LibCall,
libcall_trampolines: usize,
libcall_trampoline_len: usize,
) -> usize {
libcall_trampolines + libcall as usize * libcall_trampoline_len
}