1 require 'voodoo/generators/common_code_generator'
2 require 'voodoo/generators/nasm_generator'
5 # = i386 NASM Code Generator
7 # The i386 NASM code generator generates i386 assembly code for use with
8 # the {Netwide Assembler}[http://www.nasm.us/].
10 # == Calling Convention
12 # Function arguments are pushed on the stack in reverse order, so that
13 # the first argument is pushed last. Each argument occupies one word
14 # of stack space. These arguments are removed from the stack by the
15 # caller after the called function returns.
17 # The return value is passed in +eax+.
21 # Call frames have the following layout:
34 class I386NasmGenerator < NasmGenerator
37 def initialize params = {}
38 # Number of bytes in a word
40 # Word name in NASM lingo
42 # Default alignment for code
44 # Default alignment for data
45 @DATA_ALIGNMENT = @WORDSIZE
46 # Default alignment for functions
47 @FUNCTION_ALIGNMENT = 16
48 # Register used for return values
50 # Register used as scratch register
69 emit "; call #{func} #{args.join ' '}\n"
70 revargs = args.reverse
71 revargs.each { |arg| push arg }
72 use_value "call", func
74 emit "add esp, #{WORDSIZE * args.length}\n"
78 # Emit function prologue.
79 def emit_function_prologue formals = []
80 emit "push ebp\nmov ebp, esp\n"
83 # Load the value of the nth argument
84 def load_arg n, reg = @SCRATCH_REG
85 "[ebp + #{n * @WORDSIZE + 8}]"
88 # Load the value of the nth local variable
89 def load_local n, reg = @SCRATCH_REG
90 "[ebp - #{(n + 1) * @WORDSIZE}]"
93 # Introduce a new local variable
94 def let symbol, *words
95 emit "; let #{symbol} #{words.join ' '}\n"
96 @environment.add_local symbol
101 # Push a word on the stack
103 #emit "; push #{value}\n"
104 value_ref = load_value value, "ebx"
105 emit "push dword #{value_ref}\n"
108 # Call a function, re-using the current call fram if possible
109 def tail_call fun, *args
110 emit "; tail-call #{fun} #{args.join ' '}\n"
111 if args.length > @environment.args
112 # Not enough space to do proper tail call; do normal call instead
113 emit "; not enough space for proper tail call; changed to regular call\n"
114 ret :call, fun, *args
116 # Any value in the current frame that is passed to the called
117 # function must be copied to a local variable if it would otherwise
118 # be overwritten before it is used
121 arg = (i >= 0) ? args[i] : fun
124 x = @environment[arg]
125 if x && x[0] == :arg && x[1] < args.length && x[1] > i &&
126 (i >= 0 || fun != args[x[1]])
128 newsym = @environment.gensym
143 (args.length - 1).downto(0).each do |i|
146 value_ref = load_value arg, "eax"
147 newarg_ref = "[ebp + #{(i + 2) * WORDSIZE}]"
148 # Elide code if source is same as destination
149 unless value_ref == newarg_ref
150 if memory_operand?(value_ref)
151 emit "mov eax, #{value_ref}\n"
154 emit "mov #{@WORD_NAME} [ebp + #{(i + 2) * WORDSIZE}], " +
161 emit "mov esp, ebp\npop ebp\n"
166 def use_value operation, value
167 value_ref = load_value value, "eax"
168 emit "#{operation} #{value_ref}\n"
171 # Define a machine word with the given value
179 Voodoo::CodeGenerator.register_generator I386NasmGenerator,
180 :architecture => :i386,