Class: Voodoo::NasmGenerator

Inherits:
CommonCodeGenerator show all
Defined in:
lib/voodoo/generators/nasm_generator.rb

Overview

NASM Code Generator

The NASM code generator is a common base class for generators that output assembly code for use with the Netwide Assembler.

This class is used by both the I386NasmGenerator and the AMD64NasmGenerator, and contains the functionality that is common to both.

To use the functionality from this class, a subclass must define the following methods and constants:

  • #begin_function

  • @CODE_ALIGNMENT

  • @DATA_ALIGNMENT

  • @FUNCTION_ALIGNMENT

  • @STACK_ALIGNMENT

  • @STACK_ALIGNMENT_BITS

  • @TEMPORARIES

  • @WORD_NAME

  • @WORDSIZE

  • @WORDSIZE_BITS

  • @AX, @BX, @CX, @DX, @BP, and @SP

Direct Known Subclasses

AMD64NasmGenerator, I386NasmGenerator

Instance Method Summary collapse

Methods inherited from CommonCodeGenerator

#add, #add_function, #align, #assymetric_binop?, #at_expr?, #binop?, #block, #count_locals, #default_alignment, #each_statement, #emit, #emit_voodoo, #export, #features, #function, #gensym, #global?, #has_feature?, #import, #in_section, #integer?, #label, #local_register, #number_of_register_arguments, #number_of_stack_arguments, #output_file_name, #output_file_suffix, #real_section_name, #register?, #register_arg?, #registers_for_locals, #restore_frame, #restore_locals, #restore_registers_from_frame, #save_frame, #save_frame_and_locals, #save_locals, #save_registers_to_frame, #saved_frame_size, #section, #section=, #section_alias, #stack_align, #substitute_number, #substitution?, #symbol?, #symmetric_binop?, #undefined_symbols, #with_temporaries, #with_temporary

Constructor Details

#initialize(params = {}) ⇒ NasmGenerator

Returns a new instance of NasmGenerator.



27
28
29
30
31
# File 'lib/voodoo/generators/nasm_generator.rb', line 27

def initialize params = {}
  super params
  @if_labels = []
  @output_file_suffix = '.asm'
end

Instance Method Details

#action_to_mnemonic(action) ⇒ Object

Translates a Voodoo action name to an x86 mnemonic



707
708
709
710
711
712
713
714
715
716
# File 'lib/voodoo/generators/nasm_generator.rb', line 707

def action_to_mnemonic action
  case action
  when :asr
    :sar
  when :bsr
    :shr
  else
    action
  end
end

#auto_bytes(n, register = @RETURN_REG) ⇒ Object

Allocates n bytes on the stack and stores a pointer to the allocated memory in the specified register. The number of bytes is rounded up to the nearest multiple of @STACK_ALIGNMENT.



187
188
189
190
191
192
193
194
# File 'lib/voodoo/generators/nasm_generator.rb', line 187

def auto_bytes n, register = @RETURN_REG
  if n.kind_of? Integer
    auto_bytes_immediate n, register
  else
    load_value_into_register n, register
    auto_bytes_register register, register
  end
end

#auto_bytes_immediate(nbytes, register) ⇒ Object

Implements auto_bytes where the number of bytes to allocate is given as an immediate value.



198
199
200
201
202
203
# File 'lib/voodoo/generators/nasm_generator.rb', line 198

def auto_bytes_immediate nbytes, register
  nbytes = ((nbytes + @STACK_ALIGNMENT - 1) >> @STACK_ALIGNMENT_BITS) <<
    @STACK_ALIGNMENT_BITS
  emit "sub #{@SP}, #{nbytes}\n"
  emit "mov #{register}, #{@SP}\n" if register != @SP
end

#auto_bytes_register(nbytes, register = @RETURN_REG) ⇒ Object

Implements auto_bytes where the number of bytes is supplied in a register.



207
208
209
210
211
212
213
# File 'lib/voodoo/generators/nasm_generator.rb', line 207

def auto_bytes_register nbytes, register = @RETURN_REG
  emit "add #{nbytes}, #{@STACK_ALIGNMENT - 1}\n"
  emit "shr #{nbytes}, #{@STACK_ALIGNMENT_BITS}\n"
  emit "shl #{nbytes}, #{@STACK_ALIGNMENT_BITS}\n"
  emit "sub #{@SP}, #{nbytes}\n"
  emit "mov #{register}, #{@SP}\n" if register != @SP
end

#auto_words(n, register = @RETURN_REG) ⇒ Object

Allocates n words on the stack and stores a pointer to the allocated memory in the specified register.



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/voodoo/generators/nasm_generator.rb', line 217

def auto_words n, register = @RETURN_REG
  if n.kind_of? Integer
    auto_bytes_immediate n * @WORDSIZE, register
  else
    load_value_into_register n, register
    if @STACK_ALIGNMENT_BITS > @WORDSIZE_BITS
      emit "add #{register}, " +
        "#{(1 << @STACK_ALIGNMENT_BITS >> @WORDSIZE_BITS) - 1}\n"
      emit "shr #{register}, #{@STACK_ALIGNMENT_BITS - @WORDSIZE_BITS}\n"
      emit "shl #{register}, #{STACK_ALIGNMENT_BITS}\n"
    else
      emit "shl #{register}, #{@WORDSIZE_BITS}\n"
    end
    emit "sub #{@SP}, #{register}\n"
    emit "mov #{register}, #{@SP}\n" if register != @SP
  end
end

#begin_block(*code) ⇒ Object

Begins a new block.



160
161
162
163
164
165
166
167
168
169
# File 'lib/voodoo/generators/nasm_generator.rb', line 160

def begin_block *code
  # If entering a block at top level,
  # Save @BP, then set @BP to @SP
  if @environment == @top_level
    emit "push #{@BP}\n"
    emit "mov #{@BP}, #{@SP}\n"
  end
  environment = Environment.new @environment
  @environment = environment
end

#byte(value) ⇒ Object

Define a byte with the given value



78
79
80
# File 'lib/voodoo/generators/nasm_generator.rb', line 78

def byte value
  emit "db #{value}\n"
end

#comment(text) ⇒ Object

Emit a comment



719
720
721
# File 'lib/voodoo/generators/nasm_generator.rb', line 719

def comment text
  emit "; #{text}\n"
end

#common_if(branch, x, y = nil) ⇒ Object

Start a conditional using the specified branch instruction after the comparison.



613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
# File 'lib/voodoo/generators/nasm_generator.rb', line 613

def common_if branch, x, y = nil
  # Inverses of branches. E.g.
  #   cmp x, y
  #   jle somewhere
  # is the same as
  #   cmp y, x
  #   jgt somewhere
  inverse_branch = {
    :je => :je,
    :jge => :jl,
    :jg => :jle,
    :jl => :jge,
    :jle => :jg,
    :jne => :jne,
  }

  y_ref = load_value y, @DX
  x_ref = load_value x, @AX
  if immediate_operand?(x_ref)
    # Can't have an immediate value as the first operand.
    if immediate_operand?(y_ref)
      # Both are immediates. Put the first in a register.
      emit "mov #{@AX}, #{x_ref}\n"
      x_ref = @AX
    else
      # y isn't immediate; swap x and y.
      x_ref, y_ref = [y_ref, x_ref]
      branch = inverse_branch[branch]
    end
  elsif memory_operand?(x_ref) && memory_operand?(y_ref)
    # Can't have two memory operands. Move the first into a register.
    emit "mov #{@AX}, #{x_ref}\n"
    x_ref = @AX
  end
  truelabel = @environment.gensym
  falselabel = @environment.gensym
  @if_labels.push falselabel

  emit "cmp #{@WORD_NAME} #{x_ref}, #{y_ref}\n"
  emit "#{branch} #{truelabel}\n"
  emit "jmp #{falselabel}\n"
  emit "#{truelabel}:\n"
end

#div(target, x, y) ⇒ Object

Divide x by y and store the quotient in target



449
450
451
452
453
# File 'lib/voodoo/generators/nasm_generator.rb', line 449

def div target, x, y
  eval_div x, y
  target_ref = load_value target, @BX
  emit "mov #{target_ref}, #{@AX}\n"
end

#div2(target, x) ⇒ Object

Divide target by x and store the quotient in target



456
457
458
# File 'lib/voodoo/generators/nasm_generator.rb', line 456

def div2 target, x
  div target, target, x
end

#dword(value) ⇒ Object

Define a dword with the given value



83
84
85
# File 'lib/voodoo/generators/nasm_generator.rb', line 83

def dword value
  emit "dd #{value}\n"
end

#emit_align(alignment) ⇒ Object

Alignment



123
124
125
# File 'lib/voodoo/generators/nasm_generator.rb', line 123

def emit_align alignment
  emit "align #{alignment}\n"
end

#emit_export(*symbols) ⇒ Object

Export symbols from the current section



38
39
40
41
42
43
44
45
# File 'lib/voodoo/generators/nasm_generator.rb', line 38

def emit_export *symbols
  case real_section_name(section)
  when ".text"
    symbols.each { |sym| emit "global #{sym}:function\n" }
  else
    symbols.each { |sym| emit "global #{sym}:data #{sym}.end-#{sym}\n" }
  end
end

#emit_function_epilogue(formals = []) ⇒ Object

Emits function epilogue.



132
133
134
# File 'lib/voodoo/generators/nasm_generator.rb', line 132

def emit_function_epilogue formals = []
  emit "leave\n"
end

#emit_import(*symbols) ⇒ Object

Emits code to declare symbols as imported from an external object.



56
57
58
# File 'lib/voodoo/generators/nasm_generator.rb', line 56

def emit_import *symbols
  emit "extern #{symbols.join ', '}\n"
end

#emit_label(name) ⇒ Object

Emits a label.



61
62
63
# File 'lib/voodoo/generators/nasm_generator.rb', line 61

def emit_label name
  emit "#{name}:\n"
end

#emit_label_size(name) ⇒ Object



65
66
67
# File 'lib/voodoo/generators/nasm_generator.rb', line 65

def emit_label_size name
  emit ".end:\n"
end

#emit_label_type(name, type) ⇒ Object



69
70
71
# File 'lib/voodoo/generators/nasm_generator.rb', line 69

def emit_label_type name, type
  # nothing to do
end

#emit_load_word(register, base, offset = 0) ⇒ Object

Loads a word into a register.



275
276
277
278
279
280
281
# File 'lib/voodoo/generators/nasm_generator.rb', line 275

def emit_load_word register, base, offset = 0
  if offset == 0
    emit "mov #{register}, [#{base}]\n"
  else
    emit "mov #{register}, [#{base} + #{offset} * #{@WORDSIZE}]\n"
  end
end

#emit_store_word(register, base, offset = 0) ⇒ Object

Stores the value of a register in memory.



397
398
399
400
401
402
403
# File 'lib/voodoo/generators/nasm_generator.rb', line 397

def emit_store_word register, base, offset = 0
  if offset == 0
    emit "mov [#{base}], #{register}\n"
  else
    emit "mov [#{base} + #{offset} * #{@WORDSIZE}], #{register}\n"
  end
end

#end_blockObject

Ends the current block.



172
173
174
175
176
177
178
# File 'lib/voodoo/generators/nasm_generator.rb', line 172

def end_block
  # Restore old value of @environment
  @environment = @environment.parent

  # If returning to top level, restore old @BP
  emit "leave\n" if @environment == @top_level
end

#end_functionObject

Ends a function body



137
138
139
140
141
142
143
# File 'lib/voodoo/generators/nasm_generator.rb', line 137

def end_function
  if @environment == @top_level
    raise "Cannot end function when not in a function"
  else
    @environment = @top_level
  end
end

#end_ifObject

End a conditional.



251
252
253
254
# File 'lib/voodoo/generators/nasm_generator.rb', line 251

def end_if
  label = @if_labels.pop
  emit "#{label}:\n"
end

#eval_div(x, y) ⇒ Object

Perform division. The quotient is stored in @AX, the remainder in @DX.



490
491
492
493
494
495
496
497
498
499
500
501
502
503
# File 'lib/voodoo/generators/nasm_generator.rb', line 490

def eval_div x, y
  with_temporary do |temporary|
    x_ref = load_value_into_register x, @AX
    y_ref = load_value y, temporary
    emit "mov #{@DX}, #{@AX}\n"
    emit "sar #{@DX}, #{@WORDSIZE * 8 - 1}\n"
    if immediate_operand?(y_ref)
      set_register @BX, y_ref
      emit "idiv #{@BX}\n"
    else
      emit "idiv #{@WORD_NAME} #{y_ref}\n"
    end
  end
end

#eval_expr(words, register = @RETURN_REG) ⇒ Object

Evaluate an expression. The result is stored in register (@RETURN_REG by default). The following registers may be clobbered: @AX, @BX, @CX, @DX



508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
# File 'lib/voodoo/generators/nasm_generator.rb', line 508

def eval_expr words, register = @RETURN_REG
  if words.length == 1
    if words[0] == 0
      emit "xor #{register}, #{register}\n"
    else
      load_value_into_register words[0], register
    end
  else
    op = words[0]
    case op
    when :asr, :bsr, :rol, :ror, :shl, :shr
      if integer? words[2]
        y_ref = words[2]
      else
        load_value_into_register words[2], @CX
        y_ref = :cl
      end
      load_value_into_register words[1], register
      emit "#{action_to_mnemonic op} #{register}, #{y_ref}\n"
    when :'auto-bytes'
      auto_bytes words[1], register
    when :'auto-words'
      auto_words words[1], register
    when :call
      call *words[1..-1]
      emit "mov #{register}, #{@RETURN_REG}\n" if register != @RETURN_REG
    when :div
      eval_div words[1], words[2]
      set_register register, @AX
    when :'get-byte'
      # Get address reference
      address_ref = load_address words[1], words[2], 1
      # Load byte from address
      case register
      when :eax, :rax
        set_register register, 0
        set_register :al, address_ref
      when :ebx, :rbx
        set_register register, 0
        set_register :bl, address_ref
      when :ecx, :rcx
        set_register register, 0
        set_register :cl, address_ref
      when :edx, :rdx
        set_register register, 0
        set_register :dl, address_ref
      else
        set_register @AX, 0
        set_register :al, address_ref
        set_register register, @AX
      end
    when :'get-word'
      address_ref = load_address words[1], words[2], @WORDSIZE
      set_register register, address_ref
    when :mod
      eval_div words[1], words[2]
      set_register register, @DX
    when :mul
      eval_mul words[1], words[2], register
    when :not
      load_value_into_register words[1], register
      emit "not #{register}\n"
    else
      if binop?(op)
        x_ref = load_value words[1], @DX
        y_ref = load_value words[2], @BX
        emit "mov #{register}, #{x_ref}\n" unless register == x_ref
        emit "#{op} #{register}, #{y_ref}\n"
      else
        raise "Not a magic word: #{words[0]}"
      end
    end
  end
end

#eval_mul(x, y, register = @AX) ⇒ Object

Multiply x by y. The result is stored in @AX by default, but a different register can be specified by passing a third argument.



587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
# File 'lib/voodoo/generators/nasm_generator.rb', line 587

def eval_mul x, y, register = @AX
  x_ref = load_value x, @DX
  y_ref = load_value y, @BX

  if immediate_operand? x_ref
    if immediate_operand? y_ref
      set_register register, x_ref * y_ref
    else
      emit "imul #{register}, #{y_ref}, #{x_ref}\n"
    end
  elsif immediate_operand? y_ref
    emit "imul #{register}, #{x_ref}, #{y_ref}\n"
  elsif y_ref != register
    emit "mov #{register}, #{x_ref}\n" unless x_ref == register
    emit "imul #{register}, #{y_ref}\n"
  else
    emit "imul #{register}, #{x_ref}\n"
  end
end

#goto(value) ⇒ Object

Continue execution at the given address



48
49
50
51
52
53
# File 'lib/voodoo/generators/nasm_generator.rb', line 48

def goto value
  with_temporary do |temporary|
    value_ref = load_value value, temporary
    emit "jmp #{value_ref}\n"
  end
end

#ifelseObject

Start the false path of a conditional.



664
665
666
667
668
669
670
# File 'lib/voodoo/generators/nasm_generator.rb', line 664

def ifelse
  newlabel = @environment.gensym
  emit "jmp #{newlabel}\n"
  label = @if_labels.pop
  emit "#{label}:\n"
  @if_labels.push newlabel
end

#ifeq(x, y) ⇒ Object

Test if x is equal to y



673
674
675
# File 'lib/voodoo/generators/nasm_generator.rb', line 673

def ifeq x, y
  common_if :je, x, y
end

#ifge(x, y) ⇒ Object

Test if x is greater than or equal to y



678
679
680
# File 'lib/voodoo/generators/nasm_generator.rb', line 678

def ifge x, y
  common_if :jge, x, y
end

#ifgt(x, y) ⇒ Object

Test if x is strictly greater than y



683
684
685
# File 'lib/voodoo/generators/nasm_generator.rb', line 683

def ifgt x, y
  common_if :jg, x, y
end

#ifle(x, y) ⇒ Object

Test if x is less than or equal to y



688
689
690
# File 'lib/voodoo/generators/nasm_generator.rb', line 688

def ifle x, y
  common_if :jle, x, y
end

#iflt(x, y) ⇒ Object

Test if x is strictly less than y



693
694
695
# File 'lib/voodoo/generators/nasm_generator.rb', line 693

def iflt x, y
  common_if :jl, x, y
end

#ifne(x, y) ⇒ Object

Test if x different from y



698
699
700
# File 'lib/voodoo/generators/nasm_generator.rb', line 698

def ifne x, y
  common_if :jne, x, y
end

#immediate_operand?(operand) ⇒ Boolean

Tests if an operand is an immediate operand

Returns:

  • (Boolean)


261
262
263
# File 'lib/voodoo/generators/nasm_generator.rb', line 261

def immediate_operand? operand
  integer?(operand)
end

#let(symbol, *words) ⇒ Object

Introduces a new local variable.



240
241
242
243
244
# File 'lib/voodoo/generators/nasm_generator.rb', line 240

def let symbol, *words
  loc = local_offset_or_register @environment.locals
  @environment.add_local symbol, loc
  set symbol, *words
end

#load_address(base, offset, scale) ⇒ Object

Create a value reference to an address. Invoking this code may clobber @BX and/or @CX



285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# File 'lib/voodoo/generators/nasm_generator.rb', line 285

def load_address base, offset, scale
  base_ref = load_value base, @BX
  offset_ref = load_value offset, @CX

  if offset_ref == 0
    if integer? base_ref
      # Only an integer base
      "[#{base_ref}]"
    else
      # Some complex base; load in @BX
      emit "mov #{@BX}, #{base_ref}\n"
      "[#{@BX}]"
    end
  elsif base_ref == 0
    if integer? offset_ref
      # Only a scaled offset
      "[#{offset_ref.to_i * scale}]"
    else
      # Some complex offset; load in @CX
      emit "mov #{@CX}, #{offset_ref}\n"
      "[#{@CX} * #{scale}]"
    end
  elsif integer? base_ref
    if integer? offset_ref
      # All integers, combine them together
      "[#{base_ref.to_i + (offset_ref.to_i * scale)}]"
    else
      # Complex offset; use @CX
      emit "mov #{@CX}, #{offset_ref}\n"
      "[#{base_ref} + #{@CX} * #{scale}]"
    end
  elsif integer? offset_ref
    # Complex base, integer offset; use @BX
    emit "mov #{@BX}, #{base_ref}\n"
    "[#{@BX} + #{offset_ref.to_i * scale}]"
  else
    # Both base and offset are complex
    # Use both @BX and @CX
    emit "mov #{@BX}, #{base_ref}\n"
    emit "mov #{@CX}, #{offset_ref}\n"
    "[#{@BX} + #{@CX} * #{scale}]"
  end
end

#load_at(address, reg) ⇒ Object

Load the value at the given address. Invoking this code may clobber @BX.



331
332
333
334
335
336
337
338
339
# File 'lib/voodoo/generators/nasm_generator.rb', line 331

def load_at address, reg
  if integer?(address) || (global?(address) && 
                           !@relocated_symbols.include?(address))
    "[#{address}]"
  else
    load_value_into_register address, @BX
    "[#{@BX}]"
  end
end

#load_symbol(symbol, reg) ⇒ Object

Loads the value associated with the given symbol.



342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'lib/voodoo/generators/nasm_generator.rb', line 342

def load_symbol symbol, reg
  x = @environment[symbol]
  if x.kind_of? Symbol
    x
  elsif x.kind_of? Integer
    offset_reference x
  else
    # Assume global
    @symbol_tracker.use symbol
    if @relocated_symbols.include? symbol
      load_symbol_from_got symbol, reg
    else
      symbol
    end
  end
end

#load_value(value, reg) ⇒ Object

Loads a value. Returns a string that can be used to refer to the loaded value.



361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
# File 'lib/voodoo/generators/nasm_generator.rb', line 361

def load_value value, reg
  if substitution? value
    value = substitute_number value[1]
  end

  if integer? value
    if @WORDSIZE > 4 && (value < -2147483648 || value > 2147483647)
      # AMD64 can load immediate values that are outside the range
      # that can be represented as a 32-bit signed integer, but
      # only with a mov instruction that loads the value into a
      # register.
      emit "mov #{@WORD_NAME} #{reg}, #{value}\n"
      reg
    else
      value
    end
  elsif symbol? value
    load_symbol value, reg
  elsif at_expr? value
    load_at value[1], reg
  else
    raise "Don't know how to load #{value.inspect}"
  end
end

#load_value_into_register(value, register) ⇒ Object

Loads a value into a register.



387
388
389
390
# File 'lib/voodoo/generators/nasm_generator.rb', line 387

def load_value_into_register value, register
  value_ref = load_value value, register
  set_register register, value_ref
end

#memory_operand?(operand) ⇒ Boolean

Tests if an operand is a memory operand

Returns:

  • (Boolean)


266
267
268
# File 'lib/voodoo/generators/nasm_generator.rb', line 266

def memory_operand? operand
  operand.kind_of?(String) && operand[0] == ?[
end

#mod(target, x, y) ⇒ Object

Divide x by y and store the remainder in target



461
462
463
464
465
# File 'lib/voodoo/generators/nasm_generator.rb', line 461

def mod target, x, y
  eval_div x, y
  target_ref = load_value target, @BX
  emit "mov #{target_ref}, #{@DX}\n"
end

#mod2(target, x) ⇒ Object

Divide target by x and store the remainder in target



468
469
470
# File 'lib/voodoo/generators/nasm_generator.rb', line 468

def mod2 target, x
  mod target, target, x
end

#mul(target, x, y) ⇒ Object

Multiply x by y and store the result in target



473
474
475
476
477
# File 'lib/voodoo/generators/nasm_generator.rb', line 473

def mul target, x, y
  eval_mul x, y
  target_ref = load_value target, @BX
  emit "mov #{target_ref}, #{@RETURN_REG}\n"      
end

#mul2(target, x) ⇒ Object

Multiply target by x and store the result in target



480
481
482
# File 'lib/voodoo/generators/nasm_generator.rb', line 480

def mul2 target, x
  mul target, target, x
end

#offset_reference(offset) ⇒ Object

Returns a memory reference for the address at the given offset from the frame pointer.



725
726
727
728
729
730
731
732
733
# File 'lib/voodoo/generators/nasm_generator.rb', line 725

def offset_reference offset
  if offset > 0
    "[#{@BP} + #{offset}]"
  elsif offset < 0
    "[#{@BP} - #{-offset}]"
  else
    "[#{@BP}]"
  end
end

#qword(value) ⇒ Object

Define a qword with the given value



88
89
90
# File 'lib/voodoo/generators/nasm_generator.rb', line 88

def qword value
  emit "dq #{value}\n"
end

#ret(*words) ⇒ Object

Returns from a function.

words may contain an expression to be evaluated. The result of the evaluation is returned from the function.



149
150
151
152
153
# File 'lib/voodoo/generators/nasm_generator.rb', line 149

def ret *words
  eval_expr(words) unless words.empty?
  emit_function_epilogue
  emit "ret\n"
end

#set(target, *words) ⇒ Object

Evaluate the expr in words and store the result in target



406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
# File 'lib/voodoo/generators/nasm_generator.rb', line 406

def set target, *words
  if integer? target
    raise "Cannot change value of integer #{target}"
  elsif global?(target)
    raise "Cannot change value of global #{target}"
  end

  if words.length != 1 || words[0] != target
    if symbol?(target) && symbol?(@environment[target])
      eval_expr words, @environment[target]
    else
      eval_expr words, @RETURN_REG
      target_ref = load_value target, @BX
      emit "mov #{target_ref}, #{@RETURN_REG}\n"
    end
  end
end

#set_byte(base, offset, value) ⇒ Object

Set the byte at base + offset to value



425
426
427
428
429
430
431
432
433
434
# File 'lib/voodoo/generators/nasm_generator.rb', line 425

def set_byte base, offset, value
  if immediate_operand?(value)
    value_ref = value
  else
    load_value_into_register value, @RETURN_REG
    value_ref = :al
  end
  addr_ref = load_address base, offset, 1
  emit "mov byte #{addr_ref}, #{value_ref}\n"
end

#set_register(register, value_ref) ⇒ Object

Set a register to a value. The value must be a valid operand to the mov instruction.



737
738
739
740
741
742
743
744
745
746
# File 'lib/voodoo/generators/nasm_generator.rb', line 737

def set_register register, value_ref
  case value_ref
  when register
    # Nothing to do
  when 0
    emit "xor #{register}, #{register}\n"
  else
    emit "mov #{register}, #{value_ref}\n"
  end
end

#set_word(base, offset, value) ⇒ Object

Set the word at base + offset * @WORDSIZE to value



437
438
439
440
441
442
443
444
445
446
# File 'lib/voodoo/generators/nasm_generator.rb', line 437

def set_word base, offset, value
  if immediate_operand?(value)
    value_ref = load_value value, @RETURN_REG
  else
    load_value_into_register value, @RETURN_REG
    value_ref = @RETURN_REG
  end
  addr_ref = load_address base, offset, @WORDSIZE
  emit "mov #{@WORD_NAME} #{addr_ref}, #{value_ref}\n"
end

#string(value) ⇒ Object

Define a string with the given value



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/voodoo/generators/nasm_generator.rb', line 93

def string value
  code = ''
  in_quote = false
  value.each_byte do |b|
    if b >= 32 && b < 127 && b != 39 
      if in_quote
        code << b.chr
      else
        code << ',' unless code.empty?
        code << "'" + b.chr
        in_quote = true
      end
    else
      if in_quote
        code << "',#{b}"
        in_quote = false
      else
        code << ',' unless code.empty?
        code << "#{b}"
      end
    end
  end
  code << "'" if in_quote
  emit "db #{code}\n"
end

#write(io) ⇒ Object

Write generated code to the given IO object.



753
754
755
756
757
758
759
760
761
762
# File 'lib/voodoo/generators/nasm_generator.rb', line 753

def write io
  io.puts "bits #{@WORDSIZE * 8}\n\n"
  @sections.each do |section,code|
    unless code.empty?
      io.puts "section #{section.to_s}"
      io.puts code
      io.puts
    end
  end
end