ruby/lib/mjit/x86_assembler.rb
2023-03-05 22:11:20 -08:00

62 lines
1.5 KiB
Ruby

module RubyVM::MJIT
class X86Assembler
ByteWriter = CType::Immediate.parse('char')
def initialize
@bytes = []
end
def compile(compiler) = with_dump_disasm(compiler) do
C.mjit_mark_writable
write_bytes(compiler.write_addr, @bytes)
C.mjit_mark_executable
compiler.write_pos += @bytes.size
@bytes.clear
end
def add(_reg, imm)
# REX.W [83] RSI ib
@bytes.push(0x48, 0x83, 0xc6, imm)
end
def mov(reg, val)
case reg
when :rax
# REX.W [C7] RAX imm32
@bytes.push(0x48, 0xc7, 0xc0, val, 0x00, 0x00, 0x00)
else
# REX.W [89] [rdi+val],rsi
@bytes.push(0x48, 0x89, 0x77, reg.last)
end
end
def ret
# Near return
# [C3]
@bytes.push(0xc3)
end
private
def with_dump_disasm(compiler)
from = compiler.write_addr
yield
to = compiler.write_addr
if C.mjit_opts.dump_disasm && from < to
C.dump_disasm(from, to).each do |address, mnemonic, op_str|
puts " 0x#{"%p" % address}: #{mnemonic} #{op_str}"
end
end
end
def write_bytes(addr, bytes)
writer = ByteWriter.new(addr)
# If you pack bytes containing \x00, Ruby fails to recognize bytes after \x00.
# So writing byte by byte to avoid hitting that situation.
bytes.each_with_index do |byte, index|
writer[index] = byte
end
end
end
end