1 require 'voodoo/generators/common_code_generator'
4 # Mixin for code generators that target NASM
6 # Requires the following methods and constants:
8 # - #emit_function_prologue
13 # - @FUNCTION_ALIGNMENT
15 class NasmGenerator < CommonCodeGenerator
21 # Export symbols from the current section
23 emit "global #{symbols.join ', '}\n"
26 # Import labels into the current section
28 emit "extern #{symbols.join ', '}\n"
31 # Define a label in the current section
40 # Define a byte with the given value
45 # Define a dword with the given value
50 # Define a qword with the given value
55 # Define a string with the given value
59 value.each_byte do |b|
83 def align_data alignment = @DATA_ALIGNMENT
84 in_section(:data) { emit "align #{alignment},db 0" }
87 def align_code alignment = @CODE_ALIGNMENT
88 in_section(:code) { emit "align #{alignment},nop" }
91 def align_function alignment = @FUNCTION_ALIGNMENT
92 in_section(:code) { emit "align #{alignment},nop" }
99 # Emit function preamble and declare _formals_ as function arguments
100 def begin_function *formals
101 emit "; function #{formals.join ' '}\n"
102 environment = Environment.new @environment
103 environment.add_args formals
104 @environment = environment
105 emit_function_prologue formals
108 # End a function body
110 emit "; end function\n\n"
111 if @environment == @top_level
112 raise "Cannot end function when not in a function"
114 @environment = @top_level
122 # End a conditional body
124 label = @if_labels.pop
129 # == Value Classification
132 # Test if op is a binary operation
134 [:div, :mod, :sub].member?(op) || symmetric_operation?(op)
137 # Test if a value is an integer
139 value.kind_of? Integer
142 # Test if a symbol refers to a global
144 symbol?(symbol) && @environment[symbol] == nil
147 # Tests if an operand is an immediate operand
148 def immediate_operand? operand
149 integer?(operand) || global?(operand)
152 # Tests if an operand is a memory operand
153 def memory_operand? operand
157 # Test if a value is a symbol
159 value.kind_of? Symbol
162 # Test if op is a symmetric operation (i.e. it will yield the
163 # same result if the order of its source operands is changed).
164 def symmetric_operation? op
165 [:add, :and, :mul, :or, :xor].member? op
172 # Load the value associated with the given symbol.
173 # Returns a string that can be used to refer to the loaded value.
174 def load_symbol symbol, reg = @SCRATCH_REG
175 x = @environment[symbol]
183 raise "Invalid variable type: #{x[0]}"
192 # Returns a string that can be used to refer to the loaded value.
193 def load_value value, reg = @SCRATCH_REG
195 # Integers can be used as is
198 load_symbol value, reg
215 # Write generated code to the given IO object.
217 io.puts "bits #{@WORDSIZE * 8}\n\n"
218 @sections.each do |section,code|
222 section_name = '.text'
224 section_name = '.data'
226 section_name = '.text'
228 section_name = section.to_s
230 io.puts "section #{section_name}"