mirror of
https://github.com/samsonjs/compiler.git
synced 2026-03-25 08:45:52 +00:00
183 lines
3.4 KiB
Ruby
183 lines
3.4 KiB
Ruby
# A subset of x86 assembly.
|
|
#
|
|
# sjs
|
|
# may 2009
|
|
|
|
require 'asm/asm'
|
|
|
|
module Assembler
|
|
|
|
# Assembler methods output nasm-friendly x86 asm code, line by
|
|
# line. This is dead easy and we can trust nasm to compile
|
|
# correct machine code, which isn't trivial.
|
|
class Text < AssemblerBase
|
|
|
|
def initialize(platform)
|
|
super
|
|
@vars = {} # Symbol table, maps names to locations in BSS.
|
|
@data = ''
|
|
@bss = ''
|
|
@code = ''
|
|
@templatefile = "#{ROOT}/template.#{platform}.asm"
|
|
raise "unsupported platform: #{platform}" unless File.readable?(@templatefile)
|
|
end
|
|
|
|
# Define a constant in the .data section.
|
|
def const(name, value)
|
|
@data << "#{name}\tequ #{value}"
|
|
end
|
|
|
|
# Define a variable with the given name and size (in dwords).
|
|
def defvar(name, dwords=1)
|
|
unless var?(name)
|
|
@bss << "#{name}: resd #{dwords}\n"
|
|
@vars[name] = name
|
|
else
|
|
STDERR.puts "[warning] attempted to redefine #{name}"
|
|
end
|
|
end
|
|
|
|
|
|
def var(name)
|
|
@vars[name]
|
|
end
|
|
alias_method :var?, :var
|
|
|
|
|
|
# Emit a line of code wrapped between a tab and a newline.
|
|
def emit(code, options={})
|
|
tab = options.has_key?(:tab) ? options[:tab] : "\t"
|
|
@code << "#{tab}#{code}\n"
|
|
end
|
|
|
|
def label(suffix=nil)
|
|
name = super
|
|
@labels[name] = name
|
|
return name
|
|
end
|
|
|
|
def output
|
|
File.read(@templatefile).
|
|
sub("{data}", @data).
|
|
sub("{bss}", @bss).
|
|
sub("{code}", @code)
|
|
end
|
|
|
|
def emit_label(name=label)
|
|
emit("#{name}:", :tab => nil)
|
|
end
|
|
|
|
def mov(dest, src)
|
|
emit("mov #{dest}, #{src}#{src.is_a?(Numeric) ? " ; 0x#{src.to_s(16)}" : ''}")
|
|
end
|
|
|
|
def movzx(dest, src)
|
|
emit("movzx #{dest}, #{src}")
|
|
end
|
|
|
|
def add(dest, src)
|
|
emit("add #{dest}, #{src}")
|
|
end
|
|
|
|
def sub(dest, src)
|
|
emit("sub #{dest}, #{src}")
|
|
end
|
|
|
|
def imul(op)
|
|
emit("imul #{op}")
|
|
end
|
|
|
|
def idiv(op)
|
|
emit("idiv #{op}")
|
|
end
|
|
|
|
def inc(op)
|
|
emit("inc #{op}")
|
|
end
|
|
|
|
def dec(op)
|
|
emit("dec #{op}")
|
|
end
|
|
|
|
def push(reg)
|
|
emit("push #{reg}")
|
|
end
|
|
|
|
def pop(reg)
|
|
emit("pop #{reg}")
|
|
end
|
|
|
|
def call(label)
|
|
emit("call #{label}")
|
|
end
|
|
|
|
def leave
|
|
emit("leave")
|
|
end
|
|
|
|
def neg(reg)
|
|
emit("neg #{reg}")
|
|
end
|
|
|
|
def not(rm32)
|
|
emit("not #{rm32}")
|
|
end
|
|
|
|
def xchg(op1, op2)
|
|
emit("xchg #{op1}, #{op2}")
|
|
end
|
|
|
|
def and_(op1, op2)
|
|
emit("and #{op1}, #{op2}")
|
|
end
|
|
|
|
def or(op1, op2)
|
|
emit("or #{op1}, #{op2}")
|
|
end
|
|
|
|
def xor(op1, op2)
|
|
emit("xor #{op1}, #{op2}")
|
|
end
|
|
|
|
def jz(label)
|
|
emit("jz #{label}")
|
|
end
|
|
|
|
def jnz(label)
|
|
emit("jnz #{label}")
|
|
end
|
|
|
|
def jmp(label)
|
|
emit("jmp #{label}")
|
|
end
|
|
|
|
def jl(label)
|
|
emit("jl #{label}")
|
|
end
|
|
|
|
def cmp(a, b)
|
|
emit("cmp #{a}, #{b}")
|
|
end
|
|
|
|
def lea(a, b)
|
|
emit("lea #{a}, #{b}")
|
|
end
|
|
|
|
def shr(a, b)
|
|
emit("shr #{a}, #{b}")
|
|
end
|
|
|
|
def loop_(label)
|
|
emit("loop #{label}")
|
|
end
|
|
|
|
def int(num)
|
|
emit("int 0x#{num.to_s(16)}")
|
|
end
|
|
|
|
def cdq
|
|
emit("cdq")
|
|
end
|
|
|
|
end
|
|
end
|