1 require 'voodoo/generators/common_code_generator'
4 # = i386 NASM Code Generator
6 # The i386 NASM code generator generates i386 assembly code for use with
7 # the {Netwide Assembler}[http://www.nasm.us/].
9 # == Calling Convention
11 # Function arguments are pushed on the stack in reverse order, so that
12 # the first argument is pushed last. Each argument occupies one word
13 # of stack space. These arguments are removed from the stack by the
14 # caller after the called function returns.
16 # The return value is passed in +eax+.
20 # Call frames have the following layout:
33 class I386NasmGenerator < NasmGenerator
36 def initialize params = {}
37 # Number of bytes in a word
39 # Word name in NASM lingo
41 # Default alignment for code
43 # Default alignment for data
44 @DATA_ALIGNMENT = @WORDSIZE
45 # Default alignment for functions
46 @FUNCTION_ALIGNMENT = 16
47 # Register used for return values
49 # Register used as scratch register
64 emit "; call #{func} #{args.join ' '}\n"
65 revargs = args.reverse
66 revargs.each { |arg| push arg }
67 use_value "call", func
69 emit "add esp, #{WORDSIZE * args.length}\n"
73 # Emit function prologue.
74 def emit_function_prologue formals = []
75 emit "push ebp\nmov ebp, esp\n"
78 # Load the value of the nth argument
79 def load_arg n, reg = @SCRATCH_REG
80 "[ebp + #{n * @WORDSIZE + 8}]"
83 # Load the value of the nth local variable
84 def load_local n, reg = @SCRATCH_REG
85 "[ebp - #{(n + 1) * @WORDSIZE}]"
88 # Introduce a new local variable
89 def let symbol, *words
90 emit "; let #{symbol} #{words.join ' '}\n"
91 @environment.add_local symbol
96 # Push a word on the stack
98 #emit "; push #{value}\n"
99 value_ref = load_value value, "ebx"
100 emit "push dword #{value_ref}\n"
103 # Call a function, re-using the current call fram if possible
104 def tail_call fun, *args
105 emit "; tail-call #{fun} #{args.join ' '}\n"
106 if args.length > @environment.args
107 # Not enough space to do proper tail call; do normal call instead
108 emit "; not enough space for proper tail call; changed to regular call\n"
109 ret :call, fun, *args
111 # Any value in the current frame that is passed to the called
112 # function must be copied to a local variable if it would otherwise
113 # be overwritten before it is used
116 arg = (i >= 0) ? args[i] : fun
119 x = @environment[arg]
120 if x && x[0] == :arg && x[1] < args.length && x[1] > i &&
121 (i >= 0 || fun != args[x[1]])
123 newsym = @environment.gensym
138 (args.length - 1).downto(0).each do |i|
141 value_ref = load_value arg, "eax"
142 newarg_ref = "[ebp + #{(i + 2) * WORDSIZE}]"
143 # Elide code if source is same as destination
144 unless value_ref == newarg_ref
145 if memory_operand?(value_ref)
146 emit "mov eax, #{value_ref}\n"
149 emit "mov #{@WORD_NAME} [ebp + #{(i + 2) * WORDSIZE}], " +
156 emit "mov esp, ebp\npop ebp\n"
161 def use_value operation, value
162 value_ref = load_value value, "eax"
163 emit "#{operation} #{value_ref}\n"
166 # Define a machine word with the given value
174 Voodoo::CodeGenerator.register_generator I386NasmGenerator,
175 :architecture => :i386,