Class: Voodoo::I386NasmGenerator
- Inherits:
-
NasmGenerator
- Object
- CommonCodeGenerator
- NasmGenerator
- Voodoo::I386NasmGenerator
- Defined in:
- lib/voodoo/generators/i386_nasm_generator.rb
Overview
i386 NASM Code Generator
The i386 NASM code generator generates i386 assembly code for use with the Netwide Assembler.
Calling Convention
Function arguments are pushed on the stack in reverse order, so that the first argument is pushed last. Each argument occupies one word of stack space. These arguments are removed from the stack by the caller after the called function returns.
The return value is passed in eax
.
Call Frames
Call frames have the following layout:
argn
:
arg1
arg0 <-- ebp + 8
oldeip <-- ebp + 4
oldebp <-- ebp
local0 <-- ebp - 4
local1 <-- ebp - 8
:
localn <-- esp
Direct Known Subclasses
Constant Summary collapse
- WORDSIZE =
4
Instance Method Summary collapse
-
#call(func, *args) ⇒ Object
Call a function.
-
#emit_function_prologue(formals = []) ⇒ Object
Emit function prologue.
-
#initialize(params = {}) ⇒ I386NasmGenerator
constructor
A new instance of I386NasmGenerator.
-
#let(symbol, *words) ⇒ Object
Introduce a new local variable.
-
#load_arg(n, reg = @SCRATCH_REG) ⇒ Object
Load the value of the nth argument.
-
#load_local(n, reg = @SCRATCH_REG) ⇒ Object
Load the value of the nth local variable.
-
#push(value) ⇒ Object
Push a word on the stack.
-
#tail_call(fun, *args) ⇒ Object
Call a function, re-using the current call frame if possible.
- #use_value(operation, value) ⇒ Object
-
#word(value) ⇒ Object
Define a machine word with the given value.
Methods inherited from NasmGenerator
#action_to_mnemonic, #align, #at_expr?, #begin_block, #begin_function, #binop, #binop2, #binop?, #byte, #comment, #common_if, #div, #div2, #dword, #emit_function_epilogue, #end_block, #end_function, #end_if, #eval_div, #eval_expr, #eval_mul, #export, #global?, #goto, #ifelse, #ifeq, #ifge, #ifgt, #ifle, #iflt, #ifne, #immediate_operand?, #import, #integer?, #label, #load_address, #load_at, #load_symbol, #load_value, #load_value_into_register, #memory_operand?, #mod, #mod2, #mul, #mul2, #qword, #ret, #set, #set_byte, #set_register, #set_word, #string, #symbol?, #symmetric_operation?, #write
Methods inherited from CommonCodeGenerator
#add, #add_function, #block, #each_statement, #emit, #features, #function, #gensym, #has_feature?, #in_section, #output_file_name, #output_file_suffix, #real_section_name, #section, #section=, #section_alias
Constructor Details
#initialize(params = {}) ⇒ I386NasmGenerator
Returns a new instance of I386NasmGenerator.
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/voodoo/generators/i386_nasm_generator.rb', line 37 def initialize params = {} # Number of bytes in a word @WORDSIZE = 4 # Word name in NASM lingo @WORD_NAME = 'dword' # Default alignment for code @CODE_ALIGNMENT = 0 # Default alignment for data @DATA_ALIGNMENT = @WORDSIZE # Default alignment for functions @FUNCTION_ALIGNMENT = 16 # Register used for return values @RETURN_REG = 'eax' # Register used as scratch register @SCRATCH_REG = 'ebx' # Accumulator index @AX = 'eax' # Base index @BX = 'ebx' # Count index @CX = 'ecx' # Data index @DX = 'edx' # Base pointer @BP = 'ebp' # Stack pointer @SP = 'esp' super params @features.merge! \ :'bits-per-word' => '32', :'byte-order' => 'little-endian', :'bytes-per-word' => '4' end |
Instance Method Details
#call(func, *args) ⇒ Object
Call a function
72 73 74 75 76 77 78 79 80 |
# File 'lib/voodoo/generators/i386_nasm_generator.rb', line 72 def call func, *args emit "; call #{func} #{args.join ' '}\n" revargs = args.reverse revargs.each { |arg| push arg } use_value "call", func if args.length > 0 emit "add esp, #{WORDSIZE * args.length}\n" end end |
#emit_function_prologue(formals = []) ⇒ Object
Emit function prologue.
83 84 85 |
# File 'lib/voodoo/generators/i386_nasm_generator.rb', line 83 def emit_function_prologue formals = [] emit "push ebp\nmov ebp, esp\n" end |
#let(symbol, *words) ⇒ Object
Introduce a new local variable
98 99 100 101 102 103 |
# File 'lib/voodoo/generators/i386_nasm_generator.rb', line 98 def let symbol, *words emit "; let #{symbol} #{words.join ' '}\n" @environment.add_local symbol eval_expr words emit "push eax\n" end |
#load_arg(n, reg = @SCRATCH_REG) ⇒ Object
Load the value of the nth argument
88 89 90 |
# File 'lib/voodoo/generators/i386_nasm_generator.rb', line 88 def load_arg n, reg = @SCRATCH_REG "[ebp + #{n * @WORDSIZE + 8}]" end |
#load_local(n, reg = @SCRATCH_REG) ⇒ Object
Load the value of the nth local variable
93 94 95 |
# File 'lib/voodoo/generators/i386_nasm_generator.rb', line 93 def load_local n, reg = @SCRATCH_REG "[ebp - #{(n + 1) * @WORDSIZE}]" end |
#push(value) ⇒ Object
Push a word on the stack
106 107 108 109 110 |
# File 'lib/voodoo/generators/i386_nasm_generator.rb', line 106 def push value #emit "; push #{value}\n" value_ref = load_value value, "ebx" emit "push dword #{value_ref}\n" end |
#tail_call(fun, *args) ⇒ Object
Call a function, re-using the current call frame if possible
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/voodoo/generators/i386_nasm_generator.rb', line 113 def tail_call fun, *args emit "; tail-call #{fun} #{args.join ' '}\n" if args.length > @environment.args # Not enough space to do proper tail call; do normal call instead emit "; not enough space for proper tail call; changed to regular call\n" ret :call, fun, *args else # Any value in the current frame that is passed to the called # function must be copied to a local variable if it would otherwise # be overwritten before it is used i = args.length - 1 while i >= -1 arg = (i >= 0) ? args[i] : fun if symbol?(arg) x = @environment[arg] if x && x[0] == :arg && x[1] < args.length && x[1] > i && (i >= 0 || fun != args[x[1]]) # Save value newsym = @environment.gensym let newsym, arg # Change reference if i >= 0 args[i] = newsym else fun = newsym end end end i = i - 1 end # Set arguments if args.length > 0 (args.length - 1).downto(0).each do |i| arg = args[i] value_ref = load_value arg, "eax" newarg_ref = "[ebp + #{(i + 2) * WORDSIZE}]" # Elide code if source is same as destination unless value_ref == newarg_ref if memory_operand?(value_ref) emit "mov eax, #{value_ref}\n" value_ref = "eax" end emit "mov #{@WORD_NAME} [ebp + #{(i + 2) * WORDSIZE}], " + "#{value_ref}\n" end end end # Tail call emit "mov esp, ebp\npop ebp\n" use_value "jmp", fun end end |
#use_value(operation, value) ⇒ Object
170 171 172 173 |
# File 'lib/voodoo/generators/i386_nasm_generator.rb', line 170 def use_value operation, value value_ref = load_value value, "eax" emit "#{operation} #{value_ref}\n" end |
#word(value) ⇒ Object
Define a machine word with the given value
176 177 178 |
# File 'lib/voodoo/generators/i386_nasm_generator.rb', line 176 def word value emit "dd #{value}\n" end |