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
68 emit "; call #{func} #{args.join ' '}\n"
69 revargs = args.reverse
70 revargs.each { |arg| push arg }
71 use_value "call", func
73 emit "add esp, #{WORDSIZE * args.length}\n"
77 # Emit function prologue.
78 def emit_function_prologue formals = []
79 emit "push ebp\nmov ebp, esp\n"
82 # Load the value of the nth argument
83 def load_arg n, reg = @SCRATCH_REG
84 "[ebp + #{n * @WORDSIZE + 8}]"
87 # Load the value of the nth local variable
88 def load_local n, reg = @SCRATCH_REG
89 "[ebp - #{(n + 1) * @WORDSIZE}]"
92 # Introduce a new local variable
93 def let symbol, *words
94 emit "; let #{symbol} #{words.join ' '}\n"
95 @environment.add_local symbol
100 # Push a word on the stack
102 #emit "; push #{value}\n"
103 value_ref = load_value value, "ebx"
104 emit "push dword #{value_ref}\n"
107 # Call a function, re-using the current call fram if possible
108 def tail_call fun, *args
109 emit "; tail-call #{fun} #{args.join ' '}\n"
110 if args.length > @environment.args
111 # Not enough space to do proper tail call; do normal call instead
112 emit "; not enough space for proper tail call; changed to regular call\n"
113 ret :call, fun, *args
115 # Any value in the current frame that is passed to the called
116 # function must be copied to a local variable if it would otherwise
117 # be overwritten before it is used
120 arg = (i >= 0) ? args[i] : fun
123 x = @environment[arg]
124 if x && x[0] == :arg && x[1] < args.length && x[1] > i &&
125 (i >= 0 || fun != args[x[1]])
127 newsym = @environment.gensym
142 (args.length - 1).downto(0).each do |i|
145 value_ref = load_value arg, "eax"
146 newarg_ref = "[ebp + #{(i + 2) * WORDSIZE}]"
147 # Elide code if source is same as destination
148 unless value_ref == newarg_ref
149 if memory_operand?(value_ref)
150 emit "mov eax, #{value_ref}\n"
153 emit "mov #{@WORD_NAME} [ebp + #{(i + 2) * WORDSIZE}], " +
160 emit "mov esp, ebp\npop ebp\n"
165 def use_value operation, value
166 value_ref = load_value value, "eax"
167 emit "#{operation} #{value_ref}\n"
170 # Define a machine word with the given value
178 Voodoo::CodeGenerator.register_generator I386NasmGenerator,
179 :architecture => :i386,