solana_sbpf/
jit.rs

1//! Just-in-time compiler (Linux x86, macOS x86)
2
3// Derived from uBPF <https://github.com/iovisor/ubpf>
4// Copyright 2015 Big Switch Networks, Inc
5//      (uBPF: JIT algorithm, originally in C)
6// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
7//      (Translation to Rust, MetaBuff addition)
8// Copyright 2020 Solana Maintainers <maintainers@solana.com>
9//
10// Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
11// the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
12// copied, modified, or distributed except according to those terms.
13
14#![allow(clippy::arithmetic_side_effects)]
15
16#[cfg(not(feature = "shuttle-test"))]
17use rand::{thread_rng, Rng};
18
19#[cfg(feature = "shuttle-test")]
20use shuttle::rand::{thread_rng, Rng};
21
22use rand::{
23    distributions::{Distribution, Uniform},
24    rngs::SmallRng,
25    SeedableRng,
26};
27use std::{fmt::Debug, mem, ptr};
28
29use crate::{
30    ebpf::{self, FIRST_SCRATCH_REG, FRAME_PTR_REG, INSN_SIZE, SCRATCH_REGS},
31    elf::Executable,
32    error::{EbpfError, ProgramResult},
33    memory_management::{
34        allocate_pages, free_pages, get_system_page_size, protect_pages, round_to_page_size,
35    },
36    memory_region::MemoryMapping,
37    program::BuiltinFunction,
38    vm::{get_runtime_environment_key, Config, ContextObject, EbpfVm, RuntimeEnvironmentSlot},
39    x86::{
40        FenceType, X86IndirectAccess, X86Instruction,
41        X86Register::{self, *},
42        ARGUMENT_REGISTERS, CALLEE_SAVED_REGISTERS, CALLER_SAVED_REGISTERS,
43    },
44};
45
46/// The maximum machine code length in bytes of a program with no guest instructions
47pub const MAX_EMPTY_PROGRAM_MACHINE_CODE_LENGTH: usize = 4096;
48/// The maximum machine code length in bytes of a single guest instruction
49pub const MAX_MACHINE_CODE_LENGTH_PER_INSTRUCTION: usize = 110;
50/// The maximum machine code length in bytes of an instruction meter checkpoint
51pub const MACHINE_CODE_PER_INSTRUCTION_METER_CHECKPOINT: usize = 24;
52/// The maximum machine code length of the randomized padding
53pub const MAX_START_PADDING_LENGTH: usize = 256;
54
55/// The program compiled to native host machinecode
56pub struct JitProgram {
57    /// OS page size in bytes and the alignment of the sections
58    page_size: usize,
59    /// Byte offset in the text_section for each BPF instruction
60    pc_section: &'static mut [u32],
61    /// The x86 machinecode
62    text_section: &'static mut [u8],
63}
64
65impl JitProgram {
66    fn new(pc: usize, code_size: usize) -> Result<Self, EbpfError> {
67        let page_size = get_system_page_size();
68        let pc_loc_table_size = round_to_page_size(pc * std::mem::size_of::<u32>(), page_size);
69        let over_allocated_code_size = round_to_page_size(code_size, page_size);
70        unsafe {
71            let raw = allocate_pages(pc_loc_table_size + over_allocated_code_size)?;
72            Ok(Self {
73                page_size,
74                pc_section: std::slice::from_raw_parts_mut(raw.cast::<u32>(), pc),
75                text_section: std::slice::from_raw_parts_mut(
76                    raw.add(pc_loc_table_size),
77                    over_allocated_code_size,
78                ),
79            })
80        }
81    }
82
83    fn seal(&mut self, text_section_usage: usize) -> Result<(), EbpfError> {
84        if self.page_size == 0 {
85            return Ok(());
86        }
87        let raw = self.pc_section.as_ptr() as *mut u8;
88        let pc_loc_table_size =
89            round_to_page_size(std::mem::size_of_val(self.pc_section), self.page_size);
90        let over_allocated_code_size = round_to_page_size(self.text_section.len(), self.page_size);
91        let code_size = round_to_page_size(text_section_usage, self.page_size);
92        unsafe {
93            // Fill with debugger traps
94            std::ptr::write_bytes(
95                raw.add(pc_loc_table_size).add(text_section_usage),
96                0xcc,
97                code_size - text_section_usage,
98            );
99            if over_allocated_code_size > code_size {
100                free_pages(
101                    raw.add(pc_loc_table_size).add(code_size),
102                    over_allocated_code_size - code_size,
103                )?;
104            }
105            self.text_section =
106                std::slice::from_raw_parts_mut(raw.add(pc_loc_table_size), text_section_usage);
107            protect_pages(
108                self.pc_section.as_mut_ptr().cast::<u8>(),
109                pc_loc_table_size,
110                false,
111            )?;
112            protect_pages(self.text_section.as_mut_ptr(), code_size, true)?;
113        }
114        Ok(())
115    }
116
117    pub(crate) fn invoke<C: ContextObject>(
118        &self,
119        _config: &Config,
120        vm: &mut EbpfVm<C>,
121        registers: [u64; 12],
122    ) {
123        unsafe {
124            let runtime_environment = std::ptr::addr_of_mut!(*vm)
125                .cast::<u64>()
126                .offset(get_runtime_environment_key() as isize);
127            let instruction_meter =
128                (vm.previous_instruction_meter as i64).wrapping_add(registers[11] as i64);
129            let entrypoint = &self.text_section
130                [self.pc_section[registers[11] as usize] as usize & (i32::MAX as u32 as usize)]
131                as *const u8;
132            macro_rules! stmt_expr_attribute_asm {
133                ($($prologue:literal,)+ cfg(not(feature = $feature:literal)), $guarded:tt, $($epilogue:tt)+) => {
134                    #[cfg(feature = $feature)]
135                    std::arch::asm!($($prologue,)+ $($epilogue)+);
136                    #[cfg(not(feature = $feature))]
137                    std::arch::asm!($($prologue,)+ $guarded, $($epilogue)+);
138                }
139            }
140            stmt_expr_attribute_asm!(
141                // RBP and RBX must be saved and restored manually in the current version of rustc and llvm.
142                "push rbx",
143                "push rbp",
144                "mov [{host_stack_pointer}], rsp",
145                "add QWORD PTR [{host_stack_pointer}], -8",
146                // RBP is zeroed out in order not to compromise the runtime environment (RDI) encryption.
147                cfg(not(feature = "jit-enable-host-stack-frames")),
148                "xor rbp, rbp",
149                "mov [rsp-8], rax",
150                "mov rax, [r11 + 0x00]",
151                "mov rsi, [r11 + 0x08]",
152                "mov rdx, [r11 + 0x10]",
153                "mov rcx, [r11 + 0x18]",
154                "mov r8,  [r11 + 0x20]",
155                "mov r9,  [r11 + 0x28]",
156                "mov rbx, [r11 + 0x30]",
157                "mov r12, [r11 + 0x38]",
158                "mov r13, [r11 + 0x40]",
159                "mov r14, [r11 + 0x48]",
160                "mov r15, [r11 + 0x50]",
161                "mov r11, [r11 + 0x58]",
162                "call [rsp-8]",
163                "pop rbp",
164                "pop rbx",
165                host_stack_pointer = in(reg) &mut vm.host_stack_pointer,
166                inlateout("rdi") runtime_environment => _,
167                inlateout("r10") instruction_meter => _,
168                inlateout("rax") entrypoint => _,
169                inlateout("r11") &registers => _,
170                lateout("rsi") _, lateout("rdx") _, lateout("rcx") _, lateout("r8") _,
171                lateout("r9") _, lateout("r12") _, lateout("r13") _, lateout("r14") _, lateout("r15") _,
172                // lateout("rbp") _, lateout("rbx") _,
173            );
174        }
175    }
176
177    /// The length of the host machinecode in bytes
178    pub fn machine_code_length(&self) -> usize {
179        self.text_section.len()
180    }
181
182    /// The total memory used in bytes rounded up to page boundaries
183    pub fn mem_size(&self) -> usize {
184        let pc_loc_table_size =
185            round_to_page_size(std::mem::size_of_val(self.pc_section), self.page_size);
186        let code_size = round_to_page_size(self.text_section.len(), self.page_size);
187        pc_loc_table_size + code_size
188    }
189}
190
191impl Drop for JitProgram {
192    fn drop(&mut self) {
193        let pc_loc_table_size =
194            round_to_page_size(std::mem::size_of_val(self.pc_section), self.page_size);
195        let code_size = round_to_page_size(self.text_section.len(), self.page_size);
196        if pc_loc_table_size + code_size > 0 {
197            unsafe {
198                let _ = free_pages(
199                    self.pc_section.as_ptr() as *mut u8,
200                    pc_loc_table_size + code_size,
201                );
202            }
203        }
204    }
205}
206
207impl Debug for JitProgram {
208    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209        fmt.write_fmt(format_args!("JitProgram {:?}", self as *const _))
210    }
211}
212
213impl PartialEq for JitProgram {
214    fn eq(&self, other: &Self) -> bool {
215        std::ptr::eq(self as *const _, other as *const _)
216    }
217}
218
219// Used to define subroutines and then call them
220// See JitCompiler::set_anchor() and JitCompiler::relative_to_anchor()
221const ANCHOR_TRACE: usize = 0;
222const ANCHOR_THROW_EXCEEDED_MAX_INSTRUCTIONS: usize = 1;
223const ANCHOR_EPILOGUE: usize = 2;
224const ANCHOR_THROW_EXCEPTION_UNCHECKED: usize = 3;
225const ANCHOR_EXIT: usize = 4;
226const ANCHOR_THROW_EXCEPTION: usize = 5;
227const ANCHOR_CALL_DEPTH_EXCEEDED: usize = 6;
228const ANCHOR_CALL_OUTSIDE_TEXT_SEGMENT: usize = 7;
229const ANCHOR_DIV_BY_ZERO: usize = 8;
230const ANCHOR_DIV_OVERFLOW: usize = 9;
231const ANCHOR_CALL_REG_UNSUPPORTED_INSTRUCTION: usize = 10;
232const ANCHOR_CALL_UNSUPPORTED_INSTRUCTION: usize = 11;
233const ANCHOR_EXTERNAL_FUNCTION_CALL: usize = 12;
234const ANCHOR_INTERNAL_FUNCTION_CALL_PROLOGUE: usize = 13;
235const ANCHOR_INTERNAL_FUNCTION_CALL_REG: usize = 14;
236const ANCHOR_TRANSLATE_MEMORY_ADDRESS: usize = 21;
237const ANCHOR_COUNT: usize = 34; // Update me when adding or removing anchors
238
239const REGISTER_MAP: [X86Register; 11] = [
240    CALLER_SAVED_REGISTERS[0], // RAX
241    ARGUMENT_REGISTERS[1],     // RSI
242    ARGUMENT_REGISTERS[2],     // RDX
243    ARGUMENT_REGISTERS[3],     // RCX
244    ARGUMENT_REGISTERS[4],     // R8
245    ARGUMENT_REGISTERS[5],     // R9
246    CALLEE_SAVED_REGISTERS[1], // RBX
247    CALLEE_SAVED_REGISTERS[2], // R12
248    CALLEE_SAVED_REGISTERS[3], // R13
249    CALLEE_SAVED_REGISTERS[4], // R14
250    CALLEE_SAVED_REGISTERS[5], // R15
251];
252
253/// RDI: Used together with slot_in_vm()
254const REGISTER_PTR_TO_VM: X86Register = ARGUMENT_REGISTERS[0];
255/// R10: Program counter limit
256const REGISTER_INSTRUCTION_METER: X86Register = CALLER_SAVED_REGISTERS[7];
257/// R11: Scratch register
258const REGISTER_SCRATCH: X86Register = CALLER_SAVED_REGISTERS[8];
259
260/// Bit width of an instruction operand
261#[derive(Copy, Clone, Debug)]
262pub enum OperandSize {
263    /// Empty
264    S0 = 0,
265    /// 8 bit
266    S8 = 8,
267    /// 16 bit
268    S16 = 16,
269    /// 32 bit
270    S32 = 32,
271    /// 64 bit
272    S64 = 64,
273}
274
275enum Value {
276    Register(X86Register),
277    RegisterIndirect(X86Register, i32, bool),
278    RegisterPlusConstant32(X86Register, i32, bool),
279    RegisterPlusConstant64(X86Register, i64, bool),
280    Constant64(i64, bool),
281}
282
283struct Argument {
284    index: usize,
285    value: Value,
286}
287
288#[derive(Debug)]
289struct Jump {
290    location: *const u8,
291    target_pc: usize,
292}
293
294/* Explanation of the Instruction Meter
295
296    The instruction meter serves two purposes: First, measure how many BPF instructions are
297    executed (profiling) and second, limit this number by stopping the program with an exception
298    once a given threshold is reached (validation). One approach would be to increment and
299    validate the instruction meter before each instruction. However, this would heavily impact
300    performance. Thus, we only profile and validate the instruction meter at branches.
301
302    For this, we implicitly sum up all the instructions between two branches.
303    It is easy to know the end of such a slice of instructions, but how do we know where it
304    started? There could be multiple ways to jump onto a path which all lead to the same final
305    branch. This is, where the integral technique comes in. The program is basically a sequence
306    of instructions with the x-axis being the program counter (short "pc"). The cost function is
307    a constant function which returns one for every point on the x axis. Now, the instruction
308    meter needs to calculate the definite integral of the cost function between the start and the
309    end of the current slice of instructions. For that we need the indefinite integral of the cost
310    function. Fortunately, the derivative of the pc is the cost function (it increases by one for
311    every instruction), thus the pc is an antiderivative of the the cost function and a valid
312    indefinite integral. So, to calculate an definite integral of the cost function, we just need
313    to subtract the start pc from the end pc of the slice. This difference can then be subtracted
314    from the remaining instruction counter until it goes below zero at which point it reaches
315    the instruction meter limit. Ok, but how do we know the start of the slice at the end?
316
317    The trick is: We do not need to know. As subtraction and addition are associative operations,
318    we can reorder them, even beyond the current branch. Thus, we can simply account for the
319    amount the start will subtract at the next branch by already adding that to the remaining
320    instruction counter at the current branch. So, every branch just subtracts its current pc
321    (the end of the slice) and adds the target pc (the start of the next slice) to the remaining
322    instruction counter. This way, no branch needs to know the pc of the last branch explicitly.
323    Another way to think about this trick is as follows: The remaining instruction counter now
324    measures what the maximum pc is, that we can reach with the remaining budget after the last
325    branch.
326
327    One problem are conditional branches. There are basically two ways to handle them: Either,
328    only do the profiling if the branch is taken, which requires two jumps (one for the profiling
329    and one to get to the target pc). Or, always profile it as if the jump to the target pc was
330    taken, but then behind the conditional branch, undo the profiling (as it was not taken). We
331    use the second method and the undo profiling is the same as the normal profiling, just with
332    reversed plus and minus signs.
333
334    Another special case to keep in mind are return instructions. They would require us to know
335    the return address (target pc), but in the JIT we already converted that to be a host address.
336    Of course, one could also save the BPF return address on the stack, but an even simpler
337    solution exists: Just count as if you were jumping to an specific target pc before the exit,
338    and then after returning use the undo profiling. The trick is, that the undo profiling now
339    has the current pc which is the BPF return address. The virtual target pc we count towards
340    and undo again can be anything, so we just set it to zero.
341*/
342
343/// Temporary object which stores the compilation context
344pub struct JitCompiler<'a, C: ContextObject> {
345    result: JitProgram,
346    text_section_jumps: Vec<Jump>,
347    anchors: [*const u8; ANCHOR_COUNT],
348    offset_in_text_section: usize,
349    executable: &'a Executable<C>,
350    program: &'a [u8],
351    program_vm_addr: u64,
352    config: &'a Config,
353    pc: usize,
354    last_instruction_meter_validation_pc: usize,
355    next_noop_insertion: u32,
356    noop_range: Uniform<u32>,
357    runtime_environment_key: i32,
358    immediate_value_key: i64,
359    diversification_rng: SmallRng,
360    stopwatch_is_active: bool,
361}
362
363#[rustfmt::skip]
364impl<'a, C: ContextObject> JitCompiler<'a, C> {
365    /// Constructs a new compiler and allocates memory for the compilation output
366    pub fn new(executable: &'a Executable<C>) -> Result<Self, EbpfError> {
367        let config = executable.get_config();
368        let (program_vm_addr, program) = executable.get_text_bytes();
369
370        // Scan through program to find actual number of instructions
371        let mut pc = 0;
372        if !executable.get_sbpf_version().disable_lddw() {
373            while (pc + 1) * ebpf::INSN_SIZE <= program.len() {
374                let insn = ebpf::get_insn_unchecked(program, pc);
375                pc += match insn.opc {
376                    ebpf::LD_DW_IMM => 2,
377                    _ => 1,
378                };
379            }
380        } else {
381            pc = program.len() / ebpf::INSN_SIZE;
382        }
383
384        let mut code_length_estimate = MAX_EMPTY_PROGRAM_MACHINE_CODE_LENGTH + MAX_START_PADDING_LENGTH + MAX_MACHINE_CODE_LENGTH_PER_INSTRUCTION * pc;
385        if config.noop_instruction_rate != 0 {
386            code_length_estimate += code_length_estimate / config.noop_instruction_rate as usize;
387        }
388        if config.instruction_meter_checkpoint_distance != 0 {
389            code_length_estimate += pc / config.instruction_meter_checkpoint_distance * MACHINE_CODE_PER_INSTRUCTION_METER_CHECKPOINT;
390        }
391        // Relative jump destinations limit the maximum output size
392        debug_assert!(code_length_estimate < (i32::MAX as usize));
393
394        let runtime_environment_key = get_runtime_environment_key();
395        let mut diversification_rng = SmallRng::from_rng(thread_rng()).map_err(|_| EbpfError::JitNotCompiled)?;
396        let immediate_value_key = diversification_rng.gen::<i64>();
397
398        Ok(Self {
399            result: JitProgram::new(pc, code_length_estimate)?,
400            text_section_jumps: vec![],
401            anchors: [std::ptr::null(); ANCHOR_COUNT],
402            offset_in_text_section: 0,
403            executable,
404            program_vm_addr,
405            program,
406            config,
407            pc: 0,
408            last_instruction_meter_validation_pc: 0,
409            next_noop_insertion: if config.noop_instruction_rate == 0 { u32::MAX } else { diversification_rng.gen_range(0..config.noop_instruction_rate * 2) },
410            noop_range: Uniform::new_inclusive(0, config.noop_instruction_rate * 2),
411            runtime_environment_key,
412            immediate_value_key,
413            diversification_rng,
414            stopwatch_is_active: false,
415        })
416    }
417
418    /// Compiles the given executable, consuming the compiler
419    pub fn compile(mut self) -> Result<JitProgram, EbpfError> {
420        // Randomized padding at the start before random intervals begin
421        if self.config.noop_instruction_rate != 0 {
422            for _ in 0..self.diversification_rng.gen_range(0..MAX_START_PADDING_LENGTH) {
423                // X86Instruction::noop().emit(self)?;
424                self.emit::<u8>(0x90);
425            }
426        }
427
428        self.emit_subroutines();
429
430        let mut function_iter = self.executable.get_function_registry().keys().map(|insn_ptr| insn_ptr as usize).peekable();
431        while self.pc * ebpf::INSN_SIZE < self.program.len() {
432            if self.offset_in_text_section + MAX_MACHINE_CODE_LENGTH_PER_INSTRUCTION * 2 >= self.result.text_section.len() {
433                return Err(EbpfError::ExhaustedTextSegment(self.pc));
434            }
435            let mut insn = ebpf::get_insn_unchecked(self.program, self.pc);
436            self.result.pc_section[self.pc] = self.offset_in_text_section as u32;
437            if self.executable.get_sbpf_version().static_syscalls() {
438                if function_iter.peek() == Some(&self.pc) {
439                    function_iter.next();
440                } else {
441                    self.result.pc_section[self.pc] |= 1 << 31;
442                }
443            }
444
445            // Regular instruction meter checkpoints to prevent long linear runs from exceeding their budget
446            if self.last_instruction_meter_validation_pc + self.config.instruction_meter_checkpoint_distance <= self.pc {
447                self.emit_validate_instruction_count(Some(self.pc));
448            }
449
450            if self.config.enable_instruction_tracing {
451                self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, self.pc as i64));
452                self.emit_ins(X86Instruction::call_immediate(self.relative_to_anchor(ANCHOR_TRACE, 5)));
453                self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, 0));
454            }
455
456            let dst = REGISTER_MAP[insn.dst as usize];
457            let src = REGISTER_MAP[insn.src as usize];
458            let target_pc = (self.pc as isize + insn.off as isize + 1) as usize;
459
460            match insn.opc {
461                ebpf::LD_DW_IMM if !self.executable.get_sbpf_version().disable_lddw() => {
462                    self.emit_validate_and_profile_instruction_count(Some(self.pc + 2));
463                    self.pc += 1;
464                    self.result.pc_section[self.pc] = unsafe { self.anchors[ANCHOR_CALL_UNSUPPORTED_INSTRUCTION].offset_from(self.result.text_section.as_ptr()) as u32 };
465                    ebpf::augment_lddw_unchecked(self.program, &mut insn);
466                    if self.should_sanitize_constant(insn.imm) {
467                        self.emit_sanitized_load_immediate(dst, insn.imm);
468                    } else {
469                        self.emit_ins(X86Instruction::load_immediate(dst, insn.imm));
470                    }
471                },
472
473                // BPF_LDX class
474                ebpf::LD_B_REG  if !self.executable.get_sbpf_version().move_memory_instruction_classes() => {
475                    self.emit_address_translation(Some(dst), Value::RegisterPlusConstant64(src, insn.off as i64, true), 1, None);
476                },
477                ebpf::LD_H_REG  if !self.executable.get_sbpf_version().move_memory_instruction_classes() => {
478                    self.emit_address_translation(Some(dst), Value::RegisterPlusConstant64(src, insn.off as i64, true), 2, None);
479                },
480                ebpf::LD_W_REG  if !self.executable.get_sbpf_version().move_memory_instruction_classes() => {
481                    self.emit_address_translation(Some(dst), Value::RegisterPlusConstant64(src, insn.off as i64, true), 4, None);
482                },
483                ebpf::LD_DW_REG if !self.executable.get_sbpf_version().move_memory_instruction_classes() => {
484                    self.emit_address_translation(Some(dst), Value::RegisterPlusConstant64(src, insn.off as i64, true), 8, None);
485                },
486
487                // BPF_ST class
488                ebpf::ST_B_IMM  if !self.executable.get_sbpf_version().move_memory_instruction_classes() => {
489                    self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 1, Some(Value::Constant64(insn.imm, true)));
490                },
491                ebpf::ST_H_IMM  if !self.executable.get_sbpf_version().move_memory_instruction_classes() => {
492                    self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 2, Some(Value::Constant64(insn.imm, true)));
493                },
494                ebpf::ST_W_IMM  if !self.executable.get_sbpf_version().move_memory_instruction_classes() => {
495                    self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 4, Some(Value::Constant64(insn.imm, true)));
496                },
497                ebpf::ST_DW_IMM if !self.executable.get_sbpf_version().move_memory_instruction_classes() => {
498                    self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 8, Some(Value::Constant64(insn.imm, true)));
499                },
500
501                // BPF_STX class
502                ebpf::ST_B_REG  if !self.executable.get_sbpf_version().move_memory_instruction_classes() => {
503                    self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 1, Some(Value::Register(src)));
504                },
505                ebpf::ST_H_REG  if !self.executable.get_sbpf_version().move_memory_instruction_classes() => {
506                    self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 2, Some(Value::Register(src)));
507                },
508                ebpf::ST_W_REG  if !self.executable.get_sbpf_version().move_memory_instruction_classes() => {
509                    self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 4, Some(Value::Register(src)));
510                },
511                ebpf::ST_DW_REG if !self.executable.get_sbpf_version().move_memory_instruction_classes() => {
512                    self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 8, Some(Value::Register(src)));
513                },
514
515                // BPF_ALU32_LOAD class
516                ebpf::ADD32_IMM  => {
517                    self.emit_sanitized_alu(OperandSize::S32, 0x01, 0, dst, insn.imm);
518                    if !self.executable.get_sbpf_version().explicit_sign_extension_of_results() {
519                        self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x63, dst, dst, None)); // sign extend i32 to i64
520                    }
521                },
522                ebpf::ADD32_REG  => {
523                    self.emit_ins(X86Instruction::alu(OperandSize::S32, 0x01, src, dst, None));
524                    if !self.executable.get_sbpf_version().explicit_sign_extension_of_results() {
525                        self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x63, dst, dst, None)); // sign extend i32 to i64
526                    }
527                },
528                ebpf::SUB32_IMM  => {
529                    if self.executable.get_sbpf_version().swap_sub_reg_imm_operands() {
530                        self.emit_ins(X86Instruction::alu_immediate(OperandSize::S32, 0xf7, 3, dst, 0, None));
531                        if insn.imm != 0 {
532                            self.emit_sanitized_alu(OperandSize::S32, 0x01, 0, dst, insn.imm);
533                        }
534                    } else {
535                        self.emit_sanitized_alu(OperandSize::S32, 0x29, 5, dst, insn.imm);
536                    }
537                    if !self.executable.get_sbpf_version().explicit_sign_extension_of_results() {
538                        self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x63, dst, dst, None)); // sign extend i32 to i64
539                    }
540                },
541                ebpf::SUB32_REG  => {
542                    self.emit_ins(X86Instruction::alu(OperandSize::S32, 0x29, src, dst, None));
543                    if !self.executable.get_sbpf_version().explicit_sign_extension_of_results() {
544                        self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x63, dst, dst, None)); // sign extend i32 to i64
545                    }
546                },
547                ebpf::MUL32_IMM | ebpf::DIV32_IMM | ebpf::MOD32_IMM if !self.executable.get_sbpf_version().enable_pqr() =>
548                    self.emit_product_quotient_remainder(
549                        OperandSize::S32,
550                        (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MOD,
551                        (insn.opc & ebpf::BPF_ALU_OP_MASK) != ebpf::BPF_MUL,
552                        (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MUL,
553                        dst, dst, Some(insn.imm),
554                    ),
555                ebpf::LD_1B_REG  if self.executable.get_sbpf_version().move_memory_instruction_classes() => {
556                    self.emit_address_translation(Some(dst), Value::RegisterPlusConstant64(src, insn.off as i64, true), 1, None);
557                },
558                ebpf::MUL32_REG | ebpf::DIV32_REG | ebpf::MOD32_REG if !self.executable.get_sbpf_version().enable_pqr() =>
559                    self.emit_product_quotient_remainder(
560                        OperandSize::S32,
561                        (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MOD,
562                        (insn.opc & ebpf::BPF_ALU_OP_MASK) != ebpf::BPF_MUL,
563                        (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MUL,
564                        src, dst, None,
565                    ),
566                ebpf::LD_2B_REG  if self.executable.get_sbpf_version().move_memory_instruction_classes() => {
567                    self.emit_address_translation(Some(dst), Value::RegisterPlusConstant64(src, insn.off as i64, true), 2, None);
568                },
569                ebpf::OR32_IMM   => self.emit_sanitized_alu(OperandSize::S32, 0x09, 1, dst, insn.imm),
570                ebpf::OR32_REG   => self.emit_ins(X86Instruction::alu(OperandSize::S32, 0x09, src, dst, None)),
571                ebpf::AND32_IMM  => self.emit_sanitized_alu(OperandSize::S32, 0x21, 4, dst, insn.imm),
572                ebpf::AND32_REG  => self.emit_ins(X86Instruction::alu(OperandSize::S32, 0x21, src, dst, None)),
573                ebpf::LSH32_IMM  => self.emit_shift(OperandSize::S32, 4, REGISTER_SCRATCH, dst, Some(insn.imm)),
574                ebpf::LSH32_REG  => self.emit_shift(OperandSize::S32, 4, src, dst, None),
575                ebpf::RSH32_IMM  => self.emit_shift(OperandSize::S32, 5, REGISTER_SCRATCH, dst, Some(insn.imm)),
576                ebpf::RSH32_REG  => self.emit_shift(OperandSize::S32, 5, src, dst, None),
577                ebpf::NEG32      if !self.executable.get_sbpf_version().disable_neg() => self.emit_ins(X86Instruction::alu_immediate(OperandSize::S32, 0xf7, 3, dst, 0, None)),
578                ebpf::LD_4B_REG  if self.executable.get_sbpf_version().move_memory_instruction_classes() => {
579                    self.emit_address_translation(Some(dst), Value::RegisterPlusConstant64(src, insn.off as i64, true), 4, None);
580                },
581                ebpf::LD_8B_REG  if self.executable.get_sbpf_version().move_memory_instruction_classes() => {
582                    self.emit_address_translation(Some(dst), Value::RegisterPlusConstant64(src, insn.off as i64, true), 8, None);
583                },
584                ebpf::XOR32_IMM  => self.emit_sanitized_alu(OperandSize::S32, 0x31, 6, dst, insn.imm),
585                ebpf::XOR32_REG  => self.emit_ins(X86Instruction::alu(OperandSize::S32, 0x31, src, dst, None)),
586                ebpf::MOV32_IMM  => {
587                    if self.should_sanitize_constant(insn.imm) {
588                        self.emit_sanitized_load_immediate(dst, insn.imm as u32 as u64 as i64);
589                    } else {
590                        self.emit_ins(X86Instruction::load_immediate(dst, insn.imm as u32 as u64 as i64));
591                    }
592                }
593                ebpf::MOV32_REG  => {
594                    if self.executable.get_sbpf_version().explicit_sign_extension_of_results() {
595                        self.emit_ins(X86Instruction::mov_with_sign_extension(OperandSize::S64, src, dst));
596                    } else {
597                        self.emit_ins(X86Instruction::mov(OperandSize::S32, src, dst));
598                    }
599                }
600                ebpf::ARSH32_IMM => self.emit_shift(OperandSize::S32, 7, REGISTER_SCRATCH, dst, Some(insn.imm)),
601                ebpf::ARSH32_REG => self.emit_shift(OperandSize::S32, 7, src, dst, None),
602                ebpf::LE if !self.executable.get_sbpf_version().disable_le() => {
603                    match insn.imm {
604                        16 => {
605                            self.emit_ins(X86Instruction::alu_immediate(OperandSize::S32, 0x81, 4, dst, 0xffff, None)); // Mask to 16 bit
606                        }
607                        32 => {
608                            self.emit_ins(X86Instruction::alu_immediate(OperandSize::S32, 0x81, 4, dst, -1, None)); // Mask to 32 bit
609                        }
610                        64 => {}
611                        _ => {
612                            return Err(EbpfError::InvalidInstruction);
613                        }
614                    }
615                },
616                ebpf::BE         => {
617                    match insn.imm {
618                        16 => {
619                            self.emit_ins(X86Instruction::bswap(OperandSize::S16, dst));
620                            self.emit_ins(X86Instruction::alu_immediate(OperandSize::S32, 0x81, 4, dst, 0xffff, None)); // Mask to 16 bit
621                        }
622                        32 => self.emit_ins(X86Instruction::bswap(OperandSize::S32, dst)),
623                        64 => self.emit_ins(X86Instruction::bswap(OperandSize::S64, dst)),
624                        _ => {
625                            return Err(EbpfError::InvalidInstruction);
626                        }
627                    }
628                },
629
630                // BPF_ALU64_STORE class
631                ebpf::ADD64_IMM  => self.emit_sanitized_alu(OperandSize::S64, 0x01, 0, dst, insn.imm),
632                ebpf::ADD64_REG  => self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x01, src, dst, None)),
633                ebpf::SUB64_IMM  => {
634                    if self.executable.get_sbpf_version().swap_sub_reg_imm_operands() {
635                        self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0xf7, 3, dst, 0, None));
636                        if insn.imm != 0 {
637                            self.emit_sanitized_alu(OperandSize::S64, 0x01, 0, dst, insn.imm);
638                        }
639                    } else {
640                        self.emit_sanitized_alu(OperandSize::S64, 0x29, 5, dst, insn.imm);
641                    }
642                }
643                ebpf::SUB64_REG  => self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x29, src, dst, None)),
644                ebpf::MUL64_IMM | ebpf::DIV64_IMM | ebpf::MOD64_IMM if !self.executable.get_sbpf_version().enable_pqr() =>
645                    self.emit_product_quotient_remainder(
646                        OperandSize::S64,
647                        (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MOD,
648                        (insn.opc & ebpf::BPF_ALU_OP_MASK) != ebpf::BPF_MUL,
649                        (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MUL,
650                        dst, dst, Some(insn.imm),
651                    ),
652                ebpf::ST_1B_IMM  if self.executable.get_sbpf_version().move_memory_instruction_classes() => {
653                    self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 1, Some(Value::Constant64(insn.imm, true)));
654                },
655                ebpf::ST_2B_IMM  if self.executable.get_sbpf_version().move_memory_instruction_classes() => {
656                    self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 2, Some(Value::Constant64(insn.imm, true)));
657                },
658                ebpf::MUL64_REG | ebpf::DIV64_REG | ebpf::MOD64_REG if !self.executable.get_sbpf_version().enable_pqr() =>
659                    self.emit_product_quotient_remainder(
660                        OperandSize::S64,
661                        (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MOD,
662                        (insn.opc & ebpf::BPF_ALU_OP_MASK) != ebpf::BPF_MUL,
663                        (insn.opc & ebpf::BPF_ALU_OP_MASK) == ebpf::BPF_MUL,
664                        src, dst, None,
665                    ),
666                ebpf::ST_1B_REG  if self.executable.get_sbpf_version().move_memory_instruction_classes() => {
667                    self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 1, Some(Value::Register(src)));
668                },
669                ebpf::ST_2B_REG  if self.executable.get_sbpf_version().move_memory_instruction_classes() => {
670                    self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 2, Some(Value::Register(src)));
671                },
672                ebpf::OR64_IMM   => self.emit_sanitized_alu(OperandSize::S64, 0x09, 1, dst, insn.imm),
673                ebpf::OR64_REG   => self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x09, src, dst, None)),
674                ebpf::AND64_IMM  => self.emit_sanitized_alu(OperandSize::S64, 0x21, 4, dst, insn.imm),
675                ebpf::AND64_REG  => self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x21, src, dst, None)),
676                ebpf::LSH64_IMM  => self.emit_shift(OperandSize::S64, 4, REGISTER_SCRATCH, dst, Some(insn.imm)),
677                ebpf::LSH64_REG  => self.emit_shift(OperandSize::S64, 4, src, dst, None),
678                ebpf::RSH64_IMM  => self.emit_shift(OperandSize::S64, 5, REGISTER_SCRATCH, dst, Some(insn.imm)),
679                ebpf::RSH64_REG  => self.emit_shift(OperandSize::S64, 5, src, dst, None),
680                ebpf::ST_4B_IMM  if self.executable.get_sbpf_version().move_memory_instruction_classes() => {
681                    self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 4, Some(Value::Constant64(insn.imm, true)));
682                },
683                ebpf::NEG64      if !self.executable.get_sbpf_version().disable_neg() => self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0xf7, 3, dst, 0, None)),
684                ebpf::ST_4B_REG  if self.executable.get_sbpf_version().move_memory_instruction_classes() => {
685                    self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 4, Some(Value::Register(src)));
686                },
687                ebpf::ST_8B_IMM  if self.executable.get_sbpf_version().move_memory_instruction_classes() => {
688                    self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 8, Some(Value::Constant64(insn.imm, true)));
689                },
690                ebpf::ST_8B_REG  if self.executable.get_sbpf_version().move_memory_instruction_classes() => {
691                    self.emit_address_translation(None, Value::RegisterPlusConstant64(dst, insn.off as i64, true), 8, Some(Value::Register(src)));
692                },
693                ebpf::XOR64_IMM  => self.emit_sanitized_alu(OperandSize::S64, 0x31, 6, dst, insn.imm),
694                ebpf::XOR64_REG  => self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x31, src, dst, None)),
695                ebpf::MOV64_IMM  => {
696                    if self.should_sanitize_constant(insn.imm) {
697                        self.emit_sanitized_load_immediate(dst, insn.imm);
698                    } else {
699                        self.emit_ins(X86Instruction::load_immediate(dst, insn.imm));
700                    }
701                }
702                ebpf::MOV64_REG  => self.emit_ins(X86Instruction::mov(OperandSize::S64, src, dst)),
703                ebpf::ARSH64_IMM => self.emit_shift(OperandSize::S64, 7, REGISTER_SCRATCH, dst, Some(insn.imm)),
704                ebpf::ARSH64_REG => self.emit_shift(OperandSize::S64, 7, src, dst, None),
705                ebpf::HOR64_IMM if self.executable.get_sbpf_version().disable_lddw() => {
706                    self.emit_sanitized_alu(OperandSize::S64, 0x09, 1, dst, (insn.imm as u64).wrapping_shl(32) as i64);
707                }
708
709                // BPF_PQR class
710                ebpf::LMUL32_IMM | ebpf::LMUL64_IMM | ebpf::UHMUL64_IMM | ebpf::SHMUL64_IMM |
711                ebpf::UDIV32_IMM | ebpf::UDIV64_IMM | ebpf::UREM32_IMM | ebpf::UREM64_IMM |
712                ebpf::SDIV32_IMM | ebpf::SDIV64_IMM | ebpf::SREM32_IMM | ebpf::SREM64_IMM
713                if self.executable.get_sbpf_version().enable_pqr() => {
714                    let signed = insn.opc & (1 << 7) != 0;
715                    let mut imm = insn.imm;
716                    if !signed {
717                        imm &= u32::MAX as i64;
718                    }
719                    self.emit_product_quotient_remainder(
720                        if insn.opc & (1 << 4) != 0 { OperandSize::S64 } else { OperandSize::S32 },
721                        insn.opc & (1 << 5) != 0,
722                        insn.opc & (1 << 6) != 0,
723                        signed,
724                        dst, dst, Some(imm),
725                    )
726                }
727                ebpf::LMUL32_REG | ebpf::LMUL64_REG | ebpf::UHMUL64_REG | ebpf::SHMUL64_REG |
728                ebpf::UDIV32_REG | ebpf::UDIV64_REG | ebpf::UREM32_REG | ebpf::UREM64_REG |
729                ebpf::SDIV32_REG | ebpf::SDIV64_REG | ebpf::SREM32_REG | ebpf::SREM64_REG
730                if self.executable.get_sbpf_version().enable_pqr() =>
731                    self.emit_product_quotient_remainder(
732                        if insn.opc & (1 << 4) != 0 { OperandSize::S64 } else { OperandSize::S32 },
733                        insn.opc & (1 << 5) != 0,
734                        insn.opc & (1 << 6) != 0,
735                        insn.opc & (1 << 7) != 0,
736                        src, dst, None,
737                    ),
738
739                // BPF_JMP class
740                ebpf::JA         => {
741                    self.emit_validate_and_profile_instruction_count(Some(target_pc));
742                    self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, target_pc as i64));
743                    let jump_offset = self.relative_to_target_pc(target_pc, 5);
744                    self.emit_ins(X86Instruction::jump_immediate(jump_offset));
745                },
746                ebpf::JEQ_IMM    => self.emit_conditional_branch_imm(0x84, false, insn.imm, dst, target_pc),
747                ebpf::JEQ_REG    => self.emit_conditional_branch_reg(0x84, false, src, dst, target_pc),
748                ebpf::JGT_IMM    => self.emit_conditional_branch_imm(0x87, false, insn.imm, dst, target_pc),
749                ebpf::JGT_REG    => self.emit_conditional_branch_reg(0x87, false, src, dst, target_pc),
750                ebpf::JGE_IMM    => self.emit_conditional_branch_imm(0x83, false, insn.imm, dst, target_pc),
751                ebpf::JGE_REG    => self.emit_conditional_branch_reg(0x83, false, src, dst, target_pc),
752                ebpf::JLT_IMM    => self.emit_conditional_branch_imm(0x82, false, insn.imm, dst, target_pc),
753                ebpf::JLT_REG    => self.emit_conditional_branch_reg(0x82, false, src, dst, target_pc),
754                ebpf::JLE_IMM    => self.emit_conditional_branch_imm(0x86, false, insn.imm, dst, target_pc),
755                ebpf::JLE_REG    => self.emit_conditional_branch_reg(0x86, false, src, dst, target_pc),
756                ebpf::JSET_IMM   => self.emit_conditional_branch_imm(0x85, true, insn.imm, dst, target_pc),
757                ebpf::JSET_REG   => self.emit_conditional_branch_reg(0x85, true, src, dst, target_pc),
758                ebpf::JNE_IMM    => self.emit_conditional_branch_imm(0x85, false, insn.imm, dst, target_pc),
759                ebpf::JNE_REG    => self.emit_conditional_branch_reg(0x85, false, src, dst, target_pc),
760                ebpf::JSGT_IMM   => self.emit_conditional_branch_imm(0x8f, false, insn.imm, dst, target_pc),
761                ebpf::JSGT_REG   => self.emit_conditional_branch_reg(0x8f, false, src, dst, target_pc),
762                ebpf::JSGE_IMM   => self.emit_conditional_branch_imm(0x8d, false, insn.imm, dst, target_pc),
763                ebpf::JSGE_REG   => self.emit_conditional_branch_reg(0x8d, false, src, dst, target_pc),
764                ebpf::JSLT_IMM   => self.emit_conditional_branch_imm(0x8c, false, insn.imm, dst, target_pc),
765                ebpf::JSLT_REG   => self.emit_conditional_branch_reg(0x8c, false, src, dst, target_pc),
766                ebpf::JSLE_IMM   => self.emit_conditional_branch_imm(0x8e, false, insn.imm, dst, target_pc),
767                ebpf::JSLE_REG   => self.emit_conditional_branch_reg(0x8e, false, src, dst, target_pc),
768                ebpf::CALL_IMM => {
769                    // For JIT, external functions MUST be registered at compile time.
770                    if let (false, Some((_, function))) =
771                            (self.executable.get_sbpf_version().static_syscalls(),
772                                self.executable.get_loader().get_function_registry().lookup_by_key(insn.imm as u32)) {
773                        // SBPFv0 syscall
774                        self.emit_syscall_dispatch(function);
775                    } else if let Some((_function_name, target_pc)) =
776                            self.executable
777                                .get_function_registry()
778                                .lookup_by_key(
779                                    self
780                                        .executable
781                                        .get_sbpf_version()
782                                        .calculate_call_imm_target_pc(self.pc, insn.imm)
783                            ) {
784                        // BPF to BPF call
785                        self.emit_internal_call(Value::Constant64(target_pc as i64, true));
786                    } else {
787                        self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, self.pc as i64));
788                        self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_CALL_UNSUPPORTED_INSTRUCTION, 5)));
789                    }
790                },
791                ebpf::SYSCALL if self.executable.get_sbpf_version().static_syscalls() => {
792                    if let Some((_, function)) = self.executable.get_loader().get_function_registry().lookup_by_key(insn.imm as u32) {
793                        self.emit_syscall_dispatch(function);
794                    } else {
795                        debug_assert!(false, "Invalid syscall should have been detected in the verifier.")
796                    }
797                },
798                ebpf::CALL_REG  => {
799                    let target_pc = if self.executable.get_sbpf_version().callx_uses_src_reg() {
800                        src
801                    } else {
802                        REGISTER_MAP[insn.imm as usize]
803                    };
804                    self.emit_internal_call(Value::Register(target_pc));
805                },
806                ebpf::RETURN
807                | ebpf::EXIT      => {
808                    if (insn.opc == ebpf::EXIT && self.executable.get_sbpf_version().static_syscalls())
809                        || (insn.opc == ebpf::RETURN && !self.executable.get_sbpf_version().static_syscalls()) {
810                        return Err(EbpfError::UnsupportedInstruction);
811                    }
812                    self.emit_validate_and_profile_instruction_count(Some(0));
813
814                    let call_depth_access = X86IndirectAccess::Offset(self.slot_in_vm(RuntimeEnvironmentSlot::CallDepth));
815                    // If env.call_depth == 0, we've reached the exit instruction of the entry point
816                    self.emit_ins(X86Instruction::cmp_immediate(OperandSize::S32, REGISTER_PTR_TO_VM, 0, Some(call_depth_access)));
817                    // we're done
818                    self.emit_ins(X86Instruction::conditional_jump_immediate(0x84, self.relative_to_anchor(ANCHOR_EXIT, 6)));
819
820                    // else decrement and update env.call_depth
821                    self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 5, REGISTER_PTR_TO_VM, 1, Some(call_depth_access))); // env.call_depth -= 1;
822
823                    // and return
824                    self.emit_ins(X86Instruction::return_near());
825                },
826
827                _               => return Err(EbpfError::UnsupportedInstruction),
828            }
829
830            self.pc += 1;
831        }
832
833        // Bumper in case there was no final exit
834        if self.offset_in_text_section + MAX_MACHINE_CODE_LENGTH_PER_INSTRUCTION * 2 >= self.result.text_section.len() {
835            return Err(EbpfError::ExhaustedTextSegment(self.pc));
836        }
837        self.emit_validate_and_profile_instruction_count(Some(self.pc + 1));
838        self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, self.pc as i64)); // Save pc
839        self.emit_set_exception_kind(EbpfError::ExecutionOverrun);
840        self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_THROW_EXCEPTION, 5)));
841
842        self.resolve_jumps();
843        self.result.seal(self.offset_in_text_section)?;
844        Ok(self.result)
845    }
846
847    fn should_sanitize_constant(&self, value: i64) -> bool {
848        if !self.config.sanitize_user_provided_values {
849            return false;
850        }
851
852        match value as u64 {
853            0xFFFF
854            | 0xFFFFFF
855            | 0xFFFFFFFF
856            | 0xFFFFFFFFFF
857            | 0xFFFFFFFFFFFF
858            | 0xFFFFFFFFFFFFFF
859            | 0xFFFFFFFFFFFFFFFF => false,
860            v if v <= 0xFF => false,
861            v if !v <= 0xFF => false,
862            _ => true
863        }
864    }
865
866    fn slot_in_vm(&self, slot: RuntimeEnvironmentSlot) -> i32 {
867        8 * (slot as i32 - self.runtime_environment_key)
868    }
869
870    pub(crate) fn emit<T>(&mut self, data: T) {
871        unsafe {
872            let ptr = self.result.text_section.as_ptr().add(self.offset_in_text_section);
873            #[allow(clippy::cast_ptr_alignment)]
874            ptr::write_unaligned(ptr as *mut T, data as T);
875        }
876        self.offset_in_text_section += mem::size_of::<T>();
877    }
878
879    pub(crate) fn emit_variable_length(&mut self, size: OperandSize, data: u64) {
880        match size {
881            OperandSize::S0 => {},
882            OperandSize::S8 => self.emit::<u8>(data as u8),
883            OperandSize::S16 => self.emit::<u16>(data as u16),
884            OperandSize::S32 => self.emit::<u32>(data as u32),
885            OperandSize::S64 => self.emit::<u64>(data),
886        }
887    }
888
889    // This function helps the optimizer to inline the machinecode emission while avoiding stack allocations
890    #[inline(always)]
891    fn emit_ins(&mut self, instruction: X86Instruction) {
892        instruction.emit(self);
893        if self.next_noop_insertion == 0 {
894            self.next_noop_insertion = self.noop_range.sample(&mut self.diversification_rng);
895            // X86Instruction::noop().emit(self)?;
896            self.emit::<u8>(0x90);
897        } else {
898            self.next_noop_insertion -= 1;
899        }
900    }
901
902    fn emit_sanitized_load_immediate(&mut self, destination: X86Register, value: i64) {
903        let lower_key = self.immediate_value_key as i32 as i64;
904        if value >= i32::MIN as i64 && value <= i32::MAX as i64 {
905            self.emit_ins(X86Instruction::load_immediate(destination, value.wrapping_sub(lower_key)));
906            self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 0, destination, lower_key, None)); // wrapping_add(lower_key)
907        } else if value as u64 & u32::MAX as u64 == 0 {
908            self.emit_ins(X86Instruction::load_immediate(destination, value.rotate_right(32).wrapping_sub(lower_key)));
909            self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 0, destination, lower_key, None)); // wrapping_add(lower_key)
910            self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0xc1, 4, destination, 32, None)); // shift_left(32)
911        } else if destination != REGISTER_SCRATCH {
912            self.emit_ins(X86Instruction::load_immediate(destination, value.wrapping_sub(self.immediate_value_key)));
913            self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, self.immediate_value_key));
914            self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x01, REGISTER_SCRATCH, destination, None)); // wrapping_add(immediate_value_key)
915        } else {
916            let upper_key = (self.immediate_value_key >> 32) as i32 as i64;
917            self.emit_ins(X86Instruction::load_immediate(destination, value.wrapping_sub(lower_key).rotate_right(32).wrapping_sub(upper_key)));
918            self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 0, destination, upper_key, None)); // wrapping_add(upper_key)
919            self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0xc1, 1, destination, 32, None)); // rotate_right(32)
920            self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 0, destination, lower_key, None)); // wrapping_add(lower_key)
921        }
922    }
923
924    fn emit_sanitized_alu(&mut self, size: OperandSize, opcode: u8, opcode_extension: u8, destination: X86Register, immediate: i64) {
925        if self.should_sanitize_constant(immediate) {
926            self.emit_sanitized_load_immediate(REGISTER_SCRATCH, immediate);
927            self.emit_ins(X86Instruction::alu(size, opcode, REGISTER_SCRATCH, destination, None));
928        } else if immediate >= i32::MIN as i64 && immediate <= i32::MAX as i64 {
929            self.emit_ins(X86Instruction::alu_immediate(size, 0x81, opcode_extension, destination, immediate, None));
930        } else {
931            self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, immediate));
932            self.emit_ins(X86Instruction::alu(size, opcode, REGISTER_SCRATCH, destination, None));
933        }
934    }
935
936    #[allow(dead_code)]
937    fn emit_stopwatch(&mut self, begin: bool) {
938        self.stopwatch_is_active = true;
939        self.emit_ins(X86Instruction::push(RDX, None));
940        self.emit_ins(X86Instruction::push(RAX, None));
941        self.emit_ins(X86Instruction::fence(FenceType::Load)); // lfence
942        self.emit_ins(X86Instruction::cycle_count()); // rdtsc
943        self.emit_ins(X86Instruction::fence(FenceType::Load)); // lfence
944        self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0xc1, 4, RDX, 32, None)); // RDX <<= 32;
945        self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x09, RDX, RAX, None)); // RAX |= RDX;
946        if begin {
947            self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x29, RAX, REGISTER_PTR_TO_VM, Some(X86IndirectAccess::Offset(self.slot_in_vm(RuntimeEnvironmentSlot::StopwatchNumerator))))); // *numerator -= RAX;
948        } else {
949            self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x01, RAX, REGISTER_PTR_TO_VM, Some(X86IndirectAccess::Offset(self.slot_in_vm(RuntimeEnvironmentSlot::StopwatchNumerator))))); // *numerator += RAX;
950            self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 0, REGISTER_PTR_TO_VM, 1, Some(X86IndirectAccess::Offset(self.slot_in_vm(RuntimeEnvironmentSlot::StopwatchDenominator))))); // *denominator += 1;
951        }
952        self.emit_ins(X86Instruction::pop(RAX));
953        self.emit_ins(X86Instruction::pop(RDX));
954    }
955
956    fn emit_validate_instruction_count(&mut self, pc: Option<usize>) {
957        if !self.config.enable_instruction_meter {
958            return;
959        }
960        // Update `MACHINE_CODE_PER_INSTRUCTION_METER_CHECKPOINT` if you change the code generation here
961        if let Some(pc) = pc {
962            self.last_instruction_meter_validation_pc = pc;
963            self.emit_sanitized_load_immediate(REGISTER_SCRATCH, pc as i64);
964        }
965        // If instruction_meter >= pc, throw ExceededMaxInstructions
966        self.emit_ins(X86Instruction::cmp(OperandSize::S64, REGISTER_SCRATCH, REGISTER_INSTRUCTION_METER, None));
967        self.emit_ins(X86Instruction::conditional_jump_immediate(0x86, self.relative_to_anchor(ANCHOR_THROW_EXCEEDED_MAX_INSTRUCTIONS, 6)));
968    }
969
970    fn emit_profile_instruction_count(&mut self, target_pc: Option<usize>) {
971        if !self.config.enable_instruction_meter {
972            return;
973        }
974        match target_pc {
975            Some(target_pc) => {
976                self.emit_sanitized_alu(OperandSize::S64, 0x01, 0, REGISTER_INSTRUCTION_METER, target_pc as i64 - self.pc as i64 - 1); // instruction_meter += target_pc - (self.pc + 1);
977            },
978            None => {
979                self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x01, REGISTER_SCRATCH, REGISTER_INSTRUCTION_METER, None)); // instruction_meter += target_pc;
980                self.emit_sanitized_alu(OperandSize::S64, 0x81, 5, REGISTER_INSTRUCTION_METER, self.pc as i64 + 1); // instruction_meter -= self.pc + 1;
981            },
982        }
983    }
984
985    fn emit_undo_profile_instruction_count(&mut self, target_pc: usize) {
986        if self.config.enable_instruction_meter {
987            self.emit_sanitized_alu(OperandSize::S64, 0x01, 0, REGISTER_INSTRUCTION_METER, self.pc as i64 + 1 - target_pc as i64); // instruction_meter += (self.pc + 1) - target_pc;
988        }
989    }
990
991    fn emit_validate_and_profile_instruction_count(&mut self, target_pc: Option<usize>) {
992        self.emit_validate_instruction_count(Some(self.pc));
993        self.emit_profile_instruction_count(target_pc);
994    }
995
996    fn emit_rust_call(&mut self, target: Value, arguments: &[Argument], result_reg: Option<X86Register>) {
997        let mut saved_registers = CALLER_SAVED_REGISTERS.to_vec();
998        if let Some(reg) = result_reg {
999            if let Some(dst) = saved_registers.iter().position(|x| *x == reg) {
1000                saved_registers.remove(dst);
1001            }
1002        }
1003    
1004        // Save registers on stack
1005        for reg in saved_registers.iter() {
1006            self.emit_ins(X86Instruction::push(*reg, None));
1007        }
1008
1009        let stack_arguments = arguments.len().saturating_sub(ARGUMENT_REGISTERS.len()) as i64;
1010        if stack_arguments % 2 != 0 {
1011            // If we're going to pass an odd number of stack args we need to pad
1012            // to preserve alignment
1013            self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 5, RSP, 8, None));
1014        }
1015
1016        // Pass arguments
1017        for argument in arguments {
1018            let is_stack_argument = argument.index >= ARGUMENT_REGISTERS.len();
1019            let dst = if is_stack_argument {
1020                RSP // Never used
1021            } else {
1022                ARGUMENT_REGISTERS[argument.index]
1023            };
1024            match argument.value {
1025                Value::Register(reg) => {
1026                    if is_stack_argument {
1027                        self.emit_ins(X86Instruction::push(reg, None));
1028                    } else if reg != dst {
1029                        self.emit_ins(X86Instruction::mov(OperandSize::S64, reg, dst));
1030                    }
1031                },
1032                Value::RegisterIndirect(reg, offset, user_provided) => {
1033                    debug_assert!(!user_provided);
1034                    if is_stack_argument {
1035                        debug_assert!(reg != RSP);
1036                        self.emit_ins(X86Instruction::push(reg, Some(X86IndirectAccess::Offset(offset))));
1037                    } else if reg == RSP {
1038                        self.emit_ins(X86Instruction::load(OperandSize::S64, RSP, dst, X86IndirectAccess::OffsetIndexShift(offset, RSP, 0)));
1039                    } else {
1040                        self.emit_ins(X86Instruction::load(OperandSize::S64, reg, dst, X86IndirectAccess::Offset(offset)));
1041                    }
1042                },
1043                Value::RegisterPlusConstant32(reg, offset, user_provided) => {
1044                    debug_assert!(!user_provided);
1045                    if is_stack_argument {
1046                        self.emit_ins(X86Instruction::push(reg, None));
1047                        self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 0, RSP, offset as i64, Some(X86IndirectAccess::OffsetIndexShift(0, RSP, 0))));
1048                    } else if reg == RSP {
1049                        self.emit_ins(X86Instruction::lea(OperandSize::S64, RSP, dst, Some(X86IndirectAccess::OffsetIndexShift(offset, RSP, 0))));
1050                    } else {
1051                        self.emit_ins(X86Instruction::lea(OperandSize::S64, reg, dst, Some(X86IndirectAccess::Offset(offset))));
1052                    }
1053                },
1054                Value::RegisterPlusConstant64(reg, offset, user_provided) => {
1055                    debug_assert!(!user_provided);
1056                    if is_stack_argument {
1057                        self.emit_ins(X86Instruction::push(reg, None));
1058                        self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 0, RSP, offset, Some(X86IndirectAccess::OffsetIndexShift(0, RSP, 0))));
1059                    } else {
1060                        self.emit_ins(X86Instruction::load_immediate(dst, offset));
1061                        self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x01, reg, dst, None));
1062                    }
1063                },
1064                Value::Constant64(value, user_provided) => {
1065                    debug_assert!(!user_provided && !is_stack_argument);
1066                    self.emit_ins(X86Instruction::load_immediate(dst, value));
1067                },
1068            }
1069        }
1070    
1071        match target {
1072            Value::Register(reg) => {
1073                self.emit_ins(X86Instruction::call_reg(reg, None));
1074            },
1075            Value::Constant64(value, user_provided) => {
1076                debug_assert!(!user_provided);
1077                self.emit_ins(X86Instruction::load_immediate(RAX, value));
1078                self.emit_ins(X86Instruction::call_reg(RAX, None));
1079            },
1080            _ => {
1081                #[cfg(debug_assertions)]
1082                unreachable!();
1083            }
1084        }
1085    
1086        // Save returned value in result register
1087        if let Some(reg) = result_reg {
1088            self.emit_ins(X86Instruction::mov(OperandSize::S64, RAX, reg));
1089        }
1090    
1091        // Restore registers from stack
1092        self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 0, RSP,
1093            if stack_arguments % 2 != 0 { stack_arguments + 1 } else { stack_arguments } * 8, None));
1094
1095        for reg in saved_registers.iter().rev() {
1096            self.emit_ins(X86Instruction::pop(*reg));
1097        }
1098    }
1099
1100    fn emit_internal_call(&mut self, dst: Value) {
1101        // Store PC in case the bounds check fails
1102        self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, self.pc as i64));
1103        self.last_instruction_meter_validation_pc = self.pc;
1104        self.emit_ins(X86Instruction::call_immediate(self.relative_to_anchor(ANCHOR_INTERNAL_FUNCTION_CALL_PROLOGUE, 5)));
1105
1106        match dst {
1107            Value::Register(reg) => {
1108                // REGISTER_SCRATCH contains self.pc, and we must store it for proper error handling.
1109                // We can discard the value if callx succeeds, so we are not incrementing the stack pointer (RSP).
1110                self.emit_ins(X86Instruction::store(OperandSize::S64, REGISTER_SCRATCH, RSP, X86IndirectAccess::OffsetIndexShift(-24, RSP, 0)));
1111                // Move guest_target_address into REGISTER_SCRATCH
1112                self.emit_ins(X86Instruction::mov(OperandSize::S64, reg, REGISTER_SCRATCH));
1113                self.emit_ins(X86Instruction::call_immediate(self.relative_to_anchor(ANCHOR_INTERNAL_FUNCTION_CALL_REG, 5)));
1114            },
1115            Value::Constant64(target_pc, user_provided) => {
1116                debug_assert!(user_provided);
1117                self.emit_profile_instruction_count(Some(target_pc as usize));
1118                if user_provided && self.should_sanitize_constant(target_pc) {
1119                    self.emit_sanitized_load_immediate(REGISTER_SCRATCH, target_pc);
1120                } else {
1121                    self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, target_pc));
1122                }
1123                let jump_offset = self.relative_to_target_pc(target_pc as usize, 5);
1124                self.emit_ins(X86Instruction::call_immediate(jump_offset));
1125            },
1126            _ => {
1127                #[cfg(debug_assertions)]
1128                unreachable!();
1129            }
1130        }
1131
1132        self.emit_undo_profile_instruction_count(0);
1133
1134        // Restore the previous frame pointer
1135        self.emit_ins(X86Instruction::pop(REGISTER_MAP[FRAME_PTR_REG]));
1136        for reg in REGISTER_MAP.iter().skip(FIRST_SCRATCH_REG).take(SCRATCH_REGS).rev() {
1137            self.emit_ins(X86Instruction::pop(*reg));
1138        }
1139    }
1140
1141    fn emit_syscall_dispatch(&mut self, function: BuiltinFunction<C>) {
1142        self.emit_validate_and_profile_instruction_count(Some(0));
1143        self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, function as usize as i64));
1144        self.emit_ins(X86Instruction::call_immediate(self.relative_to_anchor(ANCHOR_EXTERNAL_FUNCTION_CALL, 5)));
1145        self.emit_undo_profile_instruction_count(0);
1146    }
1147
1148    fn emit_address_translation(&mut self, dst: Option<X86Register>, vm_addr: Value, len: u64, value: Option<Value>) {
1149        debug_assert_ne!(dst.is_some(), value.is_some());
1150
1151        let stack_slot_of_value_to_store = X86IndirectAccess::OffsetIndexShift(-96, RSP, 0);
1152        match value {
1153            Some(Value::Register(reg)) => {
1154                self.emit_ins(X86Instruction::store(OperandSize::S64, reg, RSP, stack_slot_of_value_to_store));
1155            }
1156            Some(Value::Constant64(constant, user_provided)) => {
1157                debug_assert!(user_provided);
1158                // First half of emit_sanitized_load_immediate(stack_slot_of_value_to_store, constant)
1159                let lower_key = self.immediate_value_key as i32 as i64;
1160                self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, constant.wrapping_sub(lower_key)));
1161                self.emit_ins(X86Instruction::store(OperandSize::S64, REGISTER_SCRATCH, RSP, stack_slot_of_value_to_store));
1162            }
1163            _ => {}
1164        }
1165
1166        match vm_addr {
1167            Value::RegisterPlusConstant64(reg, constant, user_provided) => {
1168                if user_provided && self.should_sanitize_constant(constant) {
1169                    self.emit_sanitized_load_immediate(REGISTER_SCRATCH, constant);
1170                } else {
1171                    self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, constant));
1172                }
1173                self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x01, reg, REGISTER_SCRATCH, None));
1174            },
1175            _ => {
1176                #[cfg(debug_assertions)]
1177                unreachable!();
1178            },
1179        }
1180
1181        if self.config.enable_address_translation {
1182            let anchor_base = match value {
1183                Some(Value::Register(_reg)) => 4,
1184                Some(Value::Constant64(_constant, _user_provided)) => 8,
1185                _ => 0,
1186            };
1187            let anchor = ANCHOR_TRANSLATE_MEMORY_ADDRESS + anchor_base + len.trailing_zeros() as usize;
1188            self.emit_ins(X86Instruction::push_immediate(OperandSize::S64, self.pc as i32));
1189            self.emit_ins(X86Instruction::call_immediate(self.relative_to_anchor(anchor, 5)));
1190            if let Some(dst) = dst {
1191                self.emit_ins(X86Instruction::mov(OperandSize::S64, REGISTER_SCRATCH, dst));
1192            }
1193        } else if let Some(dst) = dst {
1194            match len {
1195                1 => self.emit_ins(X86Instruction::load(OperandSize::S8, REGISTER_SCRATCH, dst, X86IndirectAccess::Offset(0))),
1196                2 => self.emit_ins(X86Instruction::load(OperandSize::S16, REGISTER_SCRATCH, dst, X86IndirectAccess::Offset(0))),
1197                4 => self.emit_ins(X86Instruction::load(OperandSize::S32, REGISTER_SCRATCH, dst, X86IndirectAccess::Offset(0))),
1198                8 => self.emit_ins(X86Instruction::load(OperandSize::S64, REGISTER_SCRATCH, dst, X86IndirectAccess::Offset(0))),
1199                _ => unreachable!(),
1200            }
1201        } else {
1202            self.emit_ins(X86Instruction::xchg(OperandSize::S64, RSP, REGISTER_MAP[0], Some(stack_slot_of_value_to_store))); // Save REGISTER_MAP[0] and retrieve value to store
1203            match len {
1204                1 => self.emit_ins(X86Instruction::store(OperandSize::S8, REGISTER_MAP[0], REGISTER_SCRATCH, X86IndirectAccess::Offset(0))),
1205                2 => self.emit_ins(X86Instruction::store(OperandSize::S16, REGISTER_MAP[0], REGISTER_SCRATCH, X86IndirectAccess::Offset(0))),
1206                4 => self.emit_ins(X86Instruction::store(OperandSize::S32, REGISTER_MAP[0], REGISTER_SCRATCH, X86IndirectAccess::Offset(0))),
1207                8 => self.emit_ins(X86Instruction::store(OperandSize::S64, REGISTER_MAP[0], REGISTER_SCRATCH, X86IndirectAccess::Offset(0))),
1208                _ => unreachable!(),
1209            }
1210            self.emit_ins(X86Instruction::xchg(OperandSize::S64, RSP, REGISTER_MAP[0], Some(stack_slot_of_value_to_store))); // Restore REGISTER_MAP[0]
1211        }
1212    }
1213
1214    fn emit_conditional_branch_reg(&mut self, op: u8, bitwise: bool, first_operand: X86Register, second_operand: X86Register, target_pc: usize) {
1215        self.emit_validate_and_profile_instruction_count(Some(target_pc));
1216        if bitwise { // Logical
1217            self.emit_ins(X86Instruction::test(OperandSize::S64, first_operand, second_operand, None));
1218        } else { // Arithmetic
1219            self.emit_ins(X86Instruction::cmp(OperandSize::S64, first_operand, second_operand, None));
1220        }
1221        self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, target_pc as i64));
1222        let jump_offset = self.relative_to_target_pc(target_pc, 6);
1223        self.emit_ins(X86Instruction::conditional_jump_immediate(op, jump_offset));
1224        self.emit_undo_profile_instruction_count(target_pc);
1225    }
1226
1227    fn emit_conditional_branch_imm(&mut self, op: u8, bitwise: bool, immediate: i64, second_operand: X86Register, target_pc: usize) {
1228        self.emit_validate_and_profile_instruction_count(Some(target_pc));
1229        if self.should_sanitize_constant(immediate) {
1230            self.emit_sanitized_load_immediate(REGISTER_SCRATCH, immediate);
1231            if bitwise { // Logical
1232                self.emit_ins(X86Instruction::test(OperandSize::S64, REGISTER_SCRATCH, second_operand, None));
1233            } else { // Arithmetic
1234                self.emit_ins(X86Instruction::cmp(OperandSize::S64, REGISTER_SCRATCH, second_operand, None));
1235            }
1236        } else if bitwise { // Logical
1237            self.emit_ins(X86Instruction::test_immediate(OperandSize::S64, second_operand, immediate, None));
1238        } else { // Arithmetic
1239            self.emit_ins(X86Instruction::cmp_immediate(OperandSize::S64, second_operand, immediate, None));
1240        }
1241        self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, target_pc as i64));
1242        let jump_offset = self.relative_to_target_pc(target_pc, 6);
1243        self.emit_ins(X86Instruction::conditional_jump_immediate(op, jump_offset));
1244        self.emit_undo_profile_instruction_count(target_pc);
1245    }
1246
1247    fn emit_shift(&mut self, size: OperandSize, opcode_extension: u8, source: X86Register, destination: X86Register, immediate: Option<i64>) {
1248        if let Some(immediate) = immediate {
1249            self.emit_ins(X86Instruction::alu_immediate(size, 0xc1, opcode_extension, destination, immediate, None));
1250            return;
1251        }
1252        if let OperandSize::S32 = size {
1253            self.emit_ins(X86Instruction::mov(OperandSize::S32, destination, destination)); // Truncate to 32 bit
1254        }
1255        if source == RCX {
1256            self.emit_ins(X86Instruction::alu_immediate(size, 0xd3, opcode_extension, destination, 0, None));
1257        } else if destination == RCX {
1258            self.emit_ins(X86Instruction::push(source, None));
1259            self.emit_ins(X86Instruction::xchg(OperandSize::S64, source, RCX, None));
1260            self.emit_ins(X86Instruction::alu_immediate(size, 0xd3, opcode_extension, source, 0, None));
1261            self.emit_ins(X86Instruction::mov(OperandSize::S64, source, RCX));
1262            self.emit_ins(X86Instruction::pop(source));
1263        } else {
1264            self.emit_ins(X86Instruction::push(RCX, None));
1265            self.emit_ins(X86Instruction::mov(OperandSize::S64, source, RCX));
1266            self.emit_ins(X86Instruction::alu_immediate(size, 0xd3, opcode_extension, destination, 0, None));
1267            self.emit_ins(X86Instruction::pop(RCX));
1268        }
1269    }
1270
1271    #[allow(clippy::too_many_arguments)]
1272    fn emit_product_quotient_remainder(
1273        &mut self,
1274        size: OperandSize,
1275        alt_dst: bool,
1276        division: bool,
1277        signed: bool,
1278        src: X86Register,
1279        dst: X86Register,
1280        imm: Option<i64>,
1281    ) {
1282        //         LMUL UHMUL SHMUL UDIV SDIV UREM SREM
1283        // ALU     F7/4 F7/4  F7/5  F7/6 F7/7 F7/6 F7/7
1284        // src-in  REGISTER_SCRATCH  REGISTER_SCRATCH   REGISTER_SCRATCH   REGISTER_SCRATCH  REGISTER_SCRATCH  REGISTER_SCRATCH  REGISTER_SCRATCH
1285        // dst-in  RAX  RAX   RAX   RAX  RAX  RAX  RAX
1286        // dst-out RAX  RDX   RDX   RAX  RAX  RDX  RDX
1287
1288        if division {
1289            // Prevent division by zero
1290            if imm.is_none() {
1291                self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, self.pc as i64)); // Save pc
1292                self.emit_ins(X86Instruction::test(size, src, src, None)); // src == 0
1293                self.emit_ins(X86Instruction::conditional_jump_immediate(0x84, self.relative_to_anchor(ANCHOR_DIV_BY_ZERO, 6)));
1294            }
1295
1296            // Signed division overflows with MIN / -1.
1297            // If we have an immediate and it's not -1, we can skip the following check.
1298            if signed && imm.unwrap_or(-1) == -1 {
1299                self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, if let OperandSize::S64 = size { i64::MIN } else { i32::MIN as i64 }));
1300                self.emit_ins(X86Instruction::cmp(size, dst, REGISTER_SCRATCH, None)); // dst == MIN
1301
1302                if imm.is_none() {
1303                    // The exception case is: dst == MIN && src == -1
1304                    // Via De Morgan's law becomes: !(dst != MIN || src != -1)
1305                    // Also, we know that src != 0 in here, so we can use it to set REGISTER_SCRATCH to something not zero
1306                    self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, 0)); // No XOR here because we need to keep the status flags
1307                    self.emit_ins(X86Instruction::cmov(size, 0x45, src, REGISTER_SCRATCH)); // if dst != MIN { REGISTER_SCRATCH = src; }
1308                    self.emit_ins(X86Instruction::cmp_immediate(size, src, -1, None)); // src == -1
1309                    self.emit_ins(X86Instruction::cmov(size, 0x45, src, REGISTER_SCRATCH)); // if src != -1 { REGISTER_SCRATCH = src; }
1310                    self.emit_ins(X86Instruction::test(size, REGISTER_SCRATCH, REGISTER_SCRATCH, None)); // REGISTER_SCRATCH == 0
1311                }
1312
1313                // MIN / -1, raise EbpfError::DivideOverflow
1314                self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, self.pc as i64));
1315                self.emit_ins(X86Instruction::conditional_jump_immediate(0x84, self.relative_to_anchor(ANCHOR_DIV_OVERFLOW, 6)));
1316            }
1317        }
1318
1319        if let Some(imm) = imm {
1320            if self.should_sanitize_constant(imm) {
1321                self.emit_sanitized_load_immediate(REGISTER_SCRATCH, imm);
1322            } else {
1323                self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, imm));
1324            }
1325        } else {
1326            self.emit_ins(X86Instruction::mov(OperandSize::S64, src, REGISTER_SCRATCH));
1327        }
1328        if dst != RAX {
1329            self.emit_ins(X86Instruction::push(RAX, None));
1330            self.emit_ins(X86Instruction::mov(OperandSize::S64, dst, RAX));
1331        }
1332        if dst != RDX {
1333            self.emit_ins(X86Instruction::push(RDX, None));
1334        }
1335        if division {
1336            if signed {
1337                self.emit_ins(X86Instruction::sign_extend_rax_rdx(size));
1338            } else {
1339                self.emit_ins(X86Instruction::alu(size, 0x31, RDX, RDX, None)); // RDX = 0
1340            }
1341        }
1342
1343        self.emit_ins(X86Instruction::alu_immediate(size, 0xf7, 0x4 | ((division as u8) << 1) | signed as u8, REGISTER_SCRATCH, 0, None));
1344
1345        if dst != RDX {
1346            if alt_dst {
1347                self.emit_ins(X86Instruction::mov(OperandSize::S64, RDX, dst));
1348            }
1349            self.emit_ins(X86Instruction::pop(RDX));
1350        }
1351        if dst != RAX {
1352            if !alt_dst {
1353                self.emit_ins(X86Instruction::mov(OperandSize::S64, RAX, dst));
1354            }
1355            self.emit_ins(X86Instruction::pop(RAX));
1356        }
1357        if let OperandSize::S32 = size {
1358            if signed && !self.executable.get_sbpf_version().explicit_sign_extension_of_results() {
1359                self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x63, dst, dst, None)); // sign extend i32 to i64
1360            }
1361        }
1362    }
1363
1364    fn emit_set_exception_kind(&mut self, err: EbpfError) {
1365        let err_kind = unsafe { *std::ptr::addr_of!(err).cast::<u64>() };
1366        let err_discriminant = ProgramResult::Err(err).discriminant();
1367        self.emit_ins(X86Instruction::lea(OperandSize::S64, REGISTER_PTR_TO_VM, REGISTER_MAP[0], Some(X86IndirectAccess::Offset(self.slot_in_vm(RuntimeEnvironmentSlot::ProgramResult)))));
1368        self.emit_ins(X86Instruction::store_immediate(OperandSize::S64, REGISTER_MAP[0], X86IndirectAccess::Offset(0), err_discriminant as i64)); // result.discriminant = err_discriminant;
1369        self.emit_ins(X86Instruction::store_immediate(OperandSize::S64, REGISTER_MAP[0], X86IndirectAccess::Offset(std::mem::size_of::<u64>() as i32), err_kind as i64)); // err.kind = err_kind;
1370    }
1371
1372    fn emit_result_is_err(&mut self, destination: X86Register) {
1373        let ok = ProgramResult::Ok(0);
1374        let ok_discriminant = ok.discriminant();
1375        self.emit_ins(X86Instruction::lea(OperandSize::S64, REGISTER_PTR_TO_VM, destination, Some(X86IndirectAccess::Offset(self.slot_in_vm(RuntimeEnvironmentSlot::ProgramResult)))));
1376        self.emit_ins(X86Instruction::cmp_immediate(OperandSize::S64, destination, ok_discriminant as i64, Some(X86IndirectAccess::Offset(0))));
1377    }
1378
1379    fn emit_subroutines(&mut self) {
1380        // Routine for instruction tracing
1381        if self.config.enable_instruction_tracing {
1382            self.set_anchor(ANCHOR_TRACE);
1383            // Save registers on stack
1384            self.emit_ins(X86Instruction::push(REGISTER_SCRATCH, None));
1385            for reg in REGISTER_MAP.iter().rev() {
1386                self.emit_ins(X86Instruction::push(*reg, None));
1387            }
1388            self.emit_ins(X86Instruction::mov(OperandSize::S64, RSP, REGISTER_MAP[0]));
1389            self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 0, RSP, - 8 * 3, None)); // RSP -= 8 * 3;
1390            self.emit_rust_call(Value::Constant64(C::trace as *const u8 as i64, false), &[
1391                Argument { index: 1, value: Value::Register(REGISTER_MAP[0]) }, // registers
1392                Argument { index: 0, value: Value::RegisterIndirect(REGISTER_PTR_TO_VM, self.slot_in_vm(RuntimeEnvironmentSlot::ContextObjectPointer), false) },
1393            ], None);
1394            // Pop stack and return
1395            self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 0, RSP, 8 * 3, None)); // RSP += 8 * 3;
1396            self.emit_ins(X86Instruction::pop(REGISTER_MAP[0]));
1397            self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 0, RSP, 8 * (REGISTER_MAP.len() - 1) as i64, None)); // RSP += 8 * (REGISTER_MAP.len() - 1);
1398            self.emit_ins(X86Instruction::pop(REGISTER_SCRATCH));
1399            self.emit_ins(X86Instruction::return_near());
1400        }
1401
1402        // Epilogue
1403        self.set_anchor(ANCHOR_EPILOGUE);
1404        if self.config.enable_instruction_meter {
1405            self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 5, REGISTER_INSTRUCTION_METER, 1, None)); // REGISTER_INSTRUCTION_METER -= 1;
1406            self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x29, REGISTER_SCRATCH, REGISTER_INSTRUCTION_METER, None)); // REGISTER_INSTRUCTION_METER -= pc;
1407            // *DueInsnCount = *PreviousInstructionMeter - REGISTER_INSTRUCTION_METER;
1408            self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x2B, REGISTER_INSTRUCTION_METER, REGISTER_PTR_TO_VM, Some(X86IndirectAccess::Offset(self.slot_in_vm(RuntimeEnvironmentSlot::PreviousInstructionMeter))))); // REGISTER_INSTRUCTION_METER -= *PreviousInstructionMeter;
1409            self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0xf7, 3, REGISTER_INSTRUCTION_METER, 0, None)); // REGISTER_INSTRUCTION_METER = -REGISTER_INSTRUCTION_METER;
1410            self.emit_ins(X86Instruction::store(OperandSize::S64, REGISTER_INSTRUCTION_METER, REGISTER_PTR_TO_VM, X86IndirectAccess::Offset(self.slot_in_vm(RuntimeEnvironmentSlot::DueInsnCount)))); // *DueInsnCount = REGISTER_INSTRUCTION_METER;
1411        }
1412        // Print stop watch value
1413        fn stopwatch_result(numerator: u64, denominator: u64) {
1414            println!("Stop watch: {} / {} = {}", numerator, denominator, if denominator == 0 { 0.0 } else { numerator as f64 / denominator as f64 });
1415        }
1416        if self.stopwatch_is_active {
1417            self.emit_rust_call(Value::Constant64(stopwatch_result as *const u8 as i64, false), &[
1418                Argument { index: 1, value: Value::RegisterIndirect(REGISTER_PTR_TO_VM, self.slot_in_vm(RuntimeEnvironmentSlot::StopwatchDenominator), false) },
1419                Argument { index: 0, value: Value::RegisterIndirect(REGISTER_PTR_TO_VM, self.slot_in_vm(RuntimeEnvironmentSlot::StopwatchNumerator), false) },
1420            ], None);
1421        }
1422        // Restore stack pointer in case we did not exit gracefully
1423        self.emit_ins(X86Instruction::load(OperandSize::S64, REGISTER_PTR_TO_VM, RSP, X86IndirectAccess::Offset(self.slot_in_vm(RuntimeEnvironmentSlot::HostStackPointer))));
1424        self.emit_ins(X86Instruction::return_near());
1425
1426        // Handler for EbpfError::ExceededMaxInstructions
1427        self.set_anchor(ANCHOR_THROW_EXCEEDED_MAX_INSTRUCTIONS);
1428        self.emit_set_exception_kind(EbpfError::ExceededMaxInstructions);
1429        self.emit_ins(X86Instruction::mov(OperandSize::S64, REGISTER_INSTRUCTION_METER, REGISTER_SCRATCH)); // REGISTER_SCRATCH = REGISTER_INSTRUCTION_METER;
1430        // Fall through
1431
1432        // Epilogue for errors
1433        self.set_anchor(ANCHOR_THROW_EXCEPTION_UNCHECKED);
1434        self.emit_ins(X86Instruction::store(OperandSize::S64, REGISTER_SCRATCH, REGISTER_PTR_TO_VM, X86IndirectAccess::Offset(self.slot_in_vm(RuntimeEnvironmentSlot::Registers) + 11 * std::mem::size_of::<u64>() as i32))); // registers[11] = pc;
1435        self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_EPILOGUE, 5)));
1436
1437        // Quit gracefully
1438        self.set_anchor(ANCHOR_EXIT);
1439        if self.config.enable_instruction_meter {
1440            self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 0, REGISTER_INSTRUCTION_METER, 1, None)); // REGISTER_INSTRUCTION_METER += 1;
1441        }
1442        self.emit_ins(X86Instruction::lea(OperandSize::S64, REGISTER_PTR_TO_VM, REGISTER_SCRATCH, Some(X86IndirectAccess::Offset(self.slot_in_vm(RuntimeEnvironmentSlot::ProgramResult)))));
1443        self.emit_ins(X86Instruction::store(OperandSize::S64, REGISTER_MAP[0], REGISTER_SCRATCH, X86IndirectAccess::Offset(std::mem::size_of::<u64>() as i32))); // result.return_value = R0;
1444        self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x31, REGISTER_SCRATCH, REGISTER_SCRATCH, None)); // REGISTER_SCRATCH ^= REGISTER_SCRATCH; // REGISTER_SCRATCH = 0;
1445        self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_EPILOGUE, 5)));
1446
1447        // Handler for exceptions which report their pc
1448        self.set_anchor(ANCHOR_THROW_EXCEPTION);
1449        // Validate that we did not reach the instruction meter limit before the exception occured
1450        self.emit_validate_instruction_count(None);
1451        self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_THROW_EXCEPTION_UNCHECKED, 5)));
1452
1453        // Handler for EbpfError::CallDepthExceeded
1454        self.set_anchor(ANCHOR_CALL_DEPTH_EXCEEDED);
1455        self.emit_set_exception_kind(EbpfError::CallDepthExceeded);
1456        self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_THROW_EXCEPTION, 5)));
1457
1458        // Handler for EbpfError::CallOutsideTextSegment
1459        self.set_anchor(ANCHOR_CALL_OUTSIDE_TEXT_SEGMENT);
1460        self.emit_set_exception_kind(EbpfError::CallOutsideTextSegment);
1461        self.emit_ins(X86Instruction::load(OperandSize::S64, RSP, REGISTER_SCRATCH, X86IndirectAccess::OffsetIndexShift(-8, RSP, 0)));
1462        self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_THROW_EXCEPTION, 5)));
1463
1464        // Handler for EbpfError::DivideByZero
1465        self.set_anchor(ANCHOR_DIV_BY_ZERO);
1466        self.emit_set_exception_kind(EbpfError::DivideByZero);
1467        self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_THROW_EXCEPTION, 5)));
1468
1469        // Handler for EbpfError::DivideOverflow
1470        self.set_anchor(ANCHOR_DIV_OVERFLOW);
1471        self.emit_set_exception_kind(EbpfError::DivideOverflow);
1472        self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_THROW_EXCEPTION, 5)));
1473
1474        // See `ANCHOR_INTERNAL_FUNCTION_CALL_REG` for more details.
1475        self.set_anchor(ANCHOR_CALL_REG_UNSUPPORTED_INSTRUCTION);
1476        self.emit_ins(X86Instruction::load(OperandSize::S64, RSP, REGISTER_SCRATCH, X86IndirectAccess::OffsetIndexShift(-8, RSP, 0))); // Retrieve the current program counter from the stack
1477        self.emit_ins(X86Instruction::pop(REGISTER_MAP[0])); // Restore the clobbered REGISTER_MAP[0]
1478        // Fall through
1479
1480        // Handler for EbpfError::UnsupportedInstruction
1481        self.set_anchor(ANCHOR_CALL_UNSUPPORTED_INSTRUCTION);
1482        if self.config.enable_instruction_tracing {
1483            self.emit_ins(X86Instruction::call_immediate(self.relative_to_anchor(ANCHOR_TRACE, 5)));
1484        }
1485        self.emit_set_exception_kind(EbpfError::UnsupportedInstruction);
1486        self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_THROW_EXCEPTION, 5)));
1487
1488        // Routine for external functions
1489        self.set_anchor(ANCHOR_EXTERNAL_FUNCTION_CALL);
1490        self.emit_ins(X86Instruction::push_immediate(OperandSize::S64, -1)); // Used as PC value in error case, acts as stack padding otherwise
1491        if self.config.enable_instruction_meter {
1492            self.emit_ins(X86Instruction::store(OperandSize::S64, REGISTER_INSTRUCTION_METER, REGISTER_PTR_TO_VM, X86IndirectAccess::Offset(self.slot_in_vm(RuntimeEnvironmentSlot::DueInsnCount)))); // *DueInsnCount = REGISTER_INSTRUCTION_METER;
1493        }
1494        self.emit_rust_call(Value::Register(REGISTER_SCRATCH), &[
1495            Argument { index: 5, value: Value::Register(ARGUMENT_REGISTERS[5]) },
1496            Argument { index: 4, value: Value::Register(ARGUMENT_REGISTERS[4]) },
1497            Argument { index: 3, value: Value::Register(ARGUMENT_REGISTERS[3]) },
1498            Argument { index: 2, value: Value::Register(ARGUMENT_REGISTERS[2]) },
1499            Argument { index: 1, value: Value::Register(ARGUMENT_REGISTERS[1]) },
1500            Argument { index: 0, value: Value::Register(REGISTER_PTR_TO_VM) },
1501        ], None);
1502        if self.config.enable_instruction_meter {
1503            self.emit_ins(X86Instruction::load(OperandSize::S64, REGISTER_PTR_TO_VM, REGISTER_INSTRUCTION_METER, X86IndirectAccess::Offset(self.slot_in_vm(RuntimeEnvironmentSlot::PreviousInstructionMeter)))); // REGISTER_INSTRUCTION_METER = *PreviousInstructionMeter;
1504        }
1505
1506        // Test if result indicates that an error occured
1507        self.emit_result_is_err(REGISTER_SCRATCH);
1508        self.emit_ins(X86Instruction::pop(REGISTER_SCRATCH));
1509        self.emit_ins(X86Instruction::conditional_jump_immediate(0x85, self.relative_to_anchor(ANCHOR_EPILOGUE, 6)));
1510        // Store Ok value in result register
1511        self.emit_ins(X86Instruction::lea(OperandSize::S64, REGISTER_PTR_TO_VM, REGISTER_SCRATCH, Some(X86IndirectAccess::Offset(self.slot_in_vm(RuntimeEnvironmentSlot::ProgramResult)))));
1512        self.emit_ins(X86Instruction::load(OperandSize::S64, REGISTER_SCRATCH, REGISTER_MAP[0], X86IndirectAccess::Offset(8)));
1513        self.emit_ins(X86Instruction::return_near());
1514
1515        // Routine for prologue of emit_internal_call()
1516        self.set_anchor(ANCHOR_INTERNAL_FUNCTION_CALL_PROLOGUE);
1517        self.emit_validate_instruction_count(None);
1518        self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 5, RSP, 8 * (SCRATCH_REGS + 1) as i64, None)); // alloca
1519        self.emit_ins(X86Instruction::store(OperandSize::S64, REGISTER_SCRATCH, RSP, X86IndirectAccess::OffsetIndexShift(0, RSP, 0))); // Save original REGISTER_SCRATCH
1520        self.emit_ins(X86Instruction::load(OperandSize::S64, RSP, REGISTER_SCRATCH, X86IndirectAccess::OffsetIndexShift(8 * (SCRATCH_REGS + 1) as i32, RSP, 0))); // Load return address
1521        for (i, reg) in REGISTER_MAP.iter().skip(FIRST_SCRATCH_REG).take(SCRATCH_REGS).enumerate() {
1522            self.emit_ins(X86Instruction::store(OperandSize::S64, *reg, RSP, X86IndirectAccess::OffsetIndexShift(8 * (SCRATCH_REGS - i + 1) as i32, RSP, 0))); // Push SCRATCH_REG
1523        }
1524        // Push the caller's frame pointer. The code to restore it is emitted at the end of emit_internal_call().
1525        self.emit_ins(X86Instruction::store(OperandSize::S64, REGISTER_MAP[FRAME_PTR_REG], RSP, X86IndirectAccess::OffsetIndexShift(8, RSP, 0)));
1526        self.emit_ins(X86Instruction::xchg(OperandSize::S64, REGISTER_SCRATCH, RSP, Some(X86IndirectAccess::OffsetIndexShift(0, RSP, 0)))); // Push return address and restore original REGISTER_SCRATCH
1527        // Increase env.call_depth
1528        let call_depth_access = X86IndirectAccess::Offset(self.slot_in_vm(RuntimeEnvironmentSlot::CallDepth));
1529        self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 0, REGISTER_PTR_TO_VM, 1, Some(call_depth_access))); // env.call_depth += 1;
1530        // If env.call_depth == self.config.max_call_depth, throw CallDepthExceeded
1531        self.emit_ins(X86Instruction::cmp_immediate(OperandSize::S32, REGISTER_PTR_TO_VM, self.config.max_call_depth as i64, Some(call_depth_access)));
1532        self.emit_ins(X86Instruction::conditional_jump_immediate(0x83, self.relative_to_anchor(ANCHOR_CALL_DEPTH_EXCEEDED, 6)));
1533        // Setup the frame pointer for the new frame. What we do depends on whether we're using dynamic or fixed frames.
1534        if !self.executable.get_sbpf_version().dynamic_stack_frames() {
1535            // With fixed frames we start the new frame at the next fixed offset
1536            let stack_frame_size = self.config.stack_frame_size as i64 * if self.config.enable_stack_frame_gaps { 2 } else { 1 };
1537            self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 0, REGISTER_MAP[FRAME_PTR_REG], stack_frame_size, None)); // REGISTER_MAP[FRAME_PTR_REG] += stack_frame_size;
1538        }
1539        self.emit_ins(X86Instruction::return_near());
1540
1541        // Routine for emit_internal_call(Value::Register())
1542        // Inputs: Guest current pc in X86IndirectAccess::OffsetIndexShift(-16, RSP, 0), Guest target address in REGISTER_SCRATCH
1543        // Outputs: Guest current pc in X86IndirectAccess::OffsetIndexShift(-16, RSP, 0), Guest target pc in REGISTER_SCRATCH, Host target address in RIP
1544        self.set_anchor(ANCHOR_INTERNAL_FUNCTION_CALL_REG);
1545        self.emit_ins(X86Instruction::push(REGISTER_MAP[0], None));
1546        // Calculate offset relative to program_vm_addr
1547        self.emit_ins(X86Instruction::load_immediate(REGISTER_MAP[0], self.program_vm_addr as i64));
1548        self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x29, REGISTER_MAP[0], REGISTER_SCRATCH, None)); // guest_target_pc = guest_target_address - self.program_vm_addr;
1549        // Force alignment of guest_target_pc
1550        self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 4, REGISTER_SCRATCH, !(INSN_SIZE as i64 - 1), None)); // guest_target_pc &= !(INSN_SIZE - 1);
1551        // Bound check
1552        // if(guest_target_pc >= number_of_instructions * INSN_SIZE) throw CALL_OUTSIDE_TEXT_SEGMENT;
1553        let number_of_instructions = self.result.pc_section.len();
1554        self.emit_ins(X86Instruction::cmp_immediate(OperandSize::S64, REGISTER_SCRATCH, (number_of_instructions * INSN_SIZE) as i64, None)); // guest_target_pc.cmp(number_of_instructions * INSN_SIZE)
1555        self.emit_ins(X86Instruction::conditional_jump_immediate(0x83, self.relative_to_anchor(ANCHOR_CALL_OUTSIDE_TEXT_SEGMENT, 6)));
1556        // Calculate the guest_target_pc (dst / INSN_SIZE) to update REGISTER_INSTRUCTION_METER
1557        // and as target_pc for potential ANCHOR_CALL_REG_UNSUPPORTED_INSTRUCTION
1558        let shift_amount = INSN_SIZE.trailing_zeros();
1559        debug_assert_eq!(INSN_SIZE, 1 << shift_amount);
1560        self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0xc1, 5, REGISTER_SCRATCH, shift_amount as i64, None)); // guest_target_pc /= INSN_SIZE;
1561        // Load host_target_address offset from self.result.pc_section
1562        self.emit_ins(X86Instruction::load_immediate(REGISTER_MAP[0], self.result.pc_section.as_ptr() as i64)); // host_target_address = self.result.pc_section;
1563        self.emit_ins(X86Instruction::load(OperandSize::S32, REGISTER_MAP[0], REGISTER_MAP[0], X86IndirectAccess::OffsetIndexShift(0, REGISTER_SCRATCH, 2))); // host_target_address = self.result.pc_section[guest_target_pc];
1564        // Check destination is valid
1565        self.emit_ins(X86Instruction::test_immediate(OperandSize::S32, REGISTER_MAP[0], 1 << 31, None)); // host_target_address & (1 << 31)
1566        self.emit_ins(X86Instruction::conditional_jump_immediate(0x85, self.relative_to_anchor(ANCHOR_CALL_REG_UNSUPPORTED_INSTRUCTION, 6))); // If host_target_address & (1 << 31) != 0, throw UnsupportedInstruction
1567        self.emit_ins(X86Instruction::alu_immediate(OperandSize::S32, 0x81, 4, REGISTER_MAP[0], i32::MAX as i64, None)); // host_target_address &= (1 << 31) - 1;
1568        // A version of `self.emit_profile_instruction_count(None);` which reads self.pc from the stack
1569        self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x2b, REGISTER_INSTRUCTION_METER, RSP, Some(X86IndirectAccess::OffsetIndexShift(-8, RSP, 0)))); // instruction_meter -= guest_current_pc;
1570        self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 5, REGISTER_INSTRUCTION_METER, 1, None)); // instruction_meter -= 1;
1571        self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x01, REGISTER_SCRATCH, REGISTER_INSTRUCTION_METER, None)); // instruction_meter += guest_target_pc;
1572        // Offset host_target_address by self.result.text_section
1573        self.emit_ins(X86Instruction::mov_mmx(OperandSize::S64, REGISTER_SCRATCH, MM0));
1574        self.emit_ins(X86Instruction::load_immediate(REGISTER_SCRATCH, self.result.text_section.as_ptr() as i64)); // REGISTER_SCRATCH = self.result.text_section;
1575        self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x01, REGISTER_SCRATCH, REGISTER_MAP[0], None)); // host_target_address += self.result.text_section;
1576        self.emit_ins(X86Instruction::mov_mmx(OperandSize::S64, MM0, REGISTER_SCRATCH));
1577        // Restore the clobbered REGISTER_MAP[0]
1578        self.emit_ins(X86Instruction::xchg(OperandSize::S64, REGISTER_MAP[0], RSP, Some(X86IndirectAccess::OffsetIndexShift(0, RSP, 0)))); // Swap REGISTER_MAP[0] and host_target_address
1579        self.emit_ins(X86Instruction::return_near()); // Tail call to host_target_address
1580
1581        // Translates a vm memory address to a host memory address
1582        let lower_key = self.immediate_value_key as i32 as i64;
1583        for (anchor_base, len) in &[
1584            (0, 1i32), (0, 2i32), (0, 4i32), (0, 8i32),
1585            (4, 1i32), (4, 2i32), (4, 4i32), (4, 8i32),
1586            (8, 1i32), (8, 2i32), (8, 4i32), (8, 8i32),
1587        ] {
1588            let target_offset = *anchor_base + len.trailing_zeros() as usize;
1589            self.set_anchor(ANCHOR_TRANSLATE_MEMORY_ADDRESS + target_offset);
1590            // call MemoryMapping::(load|store) storing the result in RuntimeEnvironmentSlot::ProgramResult
1591            if *anchor_base == 0 { // AccessType::Load
1592                let load = match len {
1593                    1 => MemoryMapping::load::<u8> as *const u8 as i64,
1594                    2 => MemoryMapping::load::<u16> as *const u8 as i64,
1595                    4 => MemoryMapping::load::<u32> as *const u8 as i64,
1596                    8 => MemoryMapping::load::<u64> as *const u8 as i64,
1597                    _ => unreachable!()
1598                };
1599                self.emit_rust_call(Value::Constant64(load, false), &[
1600                    Argument { index: 2, value: Value::Register(REGISTER_SCRATCH) }, // Specify first as the src register could be overwritten by other arguments
1601                    Argument { index: 3, value: Value::Constant64(0, false) }, // self.pc is set later
1602                    Argument { index: 1, value: Value::RegisterPlusConstant32(REGISTER_PTR_TO_VM, self.slot_in_vm(RuntimeEnvironmentSlot::MemoryMapping), false) },
1603                    Argument { index: 0, value: Value::RegisterPlusConstant32(REGISTER_PTR_TO_VM, self.slot_in_vm(RuntimeEnvironmentSlot::ProgramResult), false) },
1604                ], None);
1605            } else { // AccessType::Store
1606                if *anchor_base == 8 {
1607                    // Second half of emit_sanitized_load_immediate(stack_slot_of_value_to_store, constant)
1608                    self.emit_ins(X86Instruction::alu_immediate(OperandSize::S64, 0x81, 0, RSP, lower_key, Some(X86IndirectAccess::OffsetIndexShift(-80, RSP, 0))));
1609                }
1610                let store = match len {
1611                    1 => MemoryMapping::store::<u8> as *const u8 as i64,
1612                    2 => MemoryMapping::store::<u16> as *const u8 as i64,
1613                    4 => MemoryMapping::store::<u32> as *const u8 as i64,
1614                    8 => MemoryMapping::store::<u64> as *const u8 as i64,
1615                    _ => unreachable!()
1616                };
1617                self.emit_rust_call(Value::Constant64(store, false), &[
1618                    Argument { index: 3, value: Value::Register(REGISTER_SCRATCH) }, // Specify first as the src register could be overwritten by other arguments
1619                    Argument { index: 2, value: Value::RegisterIndirect(RSP, -8, false) },
1620                    Argument { index: 4, value: Value::Constant64(0, false) }, // self.pc is set later
1621                    Argument { index: 1, value: Value::RegisterPlusConstant32(REGISTER_PTR_TO_VM, self.slot_in_vm(RuntimeEnvironmentSlot::MemoryMapping), false) },
1622                    Argument { index: 0, value: Value::RegisterPlusConstant32(REGISTER_PTR_TO_VM, self.slot_in_vm(RuntimeEnvironmentSlot::ProgramResult), false) },
1623                ], None);
1624            }
1625
1626            // Throw error if the result indicates one
1627            self.emit_result_is_err(REGISTER_SCRATCH);
1628            self.emit_ins(X86Instruction::pop(REGISTER_SCRATCH)); // REGISTER_SCRATCH = self.pc
1629            self.emit_ins(X86Instruction::xchg(OperandSize::S64, REGISTER_SCRATCH, RSP, Some(X86IndirectAccess::OffsetIndexShift(0, RSP, 0)))); // Swap return address and self.pc
1630            self.emit_ins(X86Instruction::conditional_jump_immediate(0x85, self.relative_to_anchor(ANCHOR_THROW_EXCEPTION, 6)));
1631
1632            if *anchor_base == 0 { // AccessType::Load
1633                // unwrap() the result into REGISTER_SCRATCH
1634                self.emit_ins(X86Instruction::load(OperandSize::S64, REGISTER_PTR_TO_VM, REGISTER_SCRATCH, X86IndirectAccess::Offset(self.slot_in_vm(RuntimeEnvironmentSlot::ProgramResult) + std::mem::size_of::<u64>() as i32)));
1635            }
1636
1637            self.emit_ins(X86Instruction::return_near());
1638        }
1639    }
1640
1641    fn set_anchor(&mut self, anchor: usize) {
1642        self.anchors[anchor] = unsafe { self.result.text_section.as_ptr().add(self.offset_in_text_section) };
1643    }
1644
1645    // instruction_length = 5 (Unconditional jump / call)
1646    // instruction_length = 6 (Conditional jump)
1647    fn relative_to_anchor(&self, anchor: usize, instruction_length: usize) -> i32 {
1648        let instruction_end = unsafe { self.result.text_section.as_ptr().add(self.offset_in_text_section).add(instruction_length) };
1649        let destination = self.anchors[anchor];
1650        debug_assert!(!destination.is_null());
1651        (unsafe { destination.offset_from(instruction_end) } as i32) // Relative jump
1652    }
1653
1654    fn relative_to_target_pc(&mut self, target_pc: usize, instruction_length: usize) -> i32 {
1655        let instruction_end = unsafe { self.result.text_section.as_ptr().add(self.offset_in_text_section).add(instruction_length) };
1656        let destination = if self.result.pc_section[target_pc] != 0 {
1657            // Backward jump
1658            &self.result.text_section[self.result.pc_section[target_pc] as usize & (i32::MAX as u32 as usize)] as *const u8
1659        } else {
1660            // Forward jump, needs relocation
1661            self.text_section_jumps.push(Jump { location: unsafe { instruction_end.sub(4) }, target_pc });
1662            return 0;
1663        };
1664        debug_assert!(!destination.is_null());
1665        (unsafe { destination.offset_from(instruction_end) } as i32) // Relative jump
1666    }
1667
1668    fn resolve_jumps(&mut self) {
1669        // Relocate forward jumps
1670        for jump in &self.text_section_jumps {
1671            let destination = &self.result.text_section[self.result.pc_section[jump.target_pc] as usize & (i32::MAX as u32 as usize)] as *const u8;
1672            let offset_value = 
1673                unsafe { destination.offset_from(jump.location) } as i32 // Relative jump
1674                - mem::size_of::<i32>() as i32; // Jump from end of instruction
1675            unsafe { ptr::write_unaligned(jump.location as *mut i32, offset_value); }
1676        }
1677    }
1678}