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, #features, #function, #gensym, #global?, #has_feature?, #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?, #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



710
711
712
713
714
715
716
717
718
719
# File 'lib/voodoo/generators/nasm_generator.rb', line 710

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.



191
192
193
194
195
196
197
198
# File 'lib/voodoo/generators/nasm_generator.rb', line 191

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.



202
203
204
205
206
207
# File 'lib/voodoo/generators/nasm_generator.rb', line 202

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.



211
212
213
214
215
216
217
# File 'lib/voodoo/generators/nasm_generator.rb', line 211

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.



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/voodoo/generators/nasm_generator.rb', line 221

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.



164
165
166
167
168
169
170
171
172
173
# File 'lib/voodoo/generators/nasm_generator.rb', line 164

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



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

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

#comment(text) ⇒ Object

Emit a comment



722
723
724
# File 'lib/voodoo/generators/nasm_generator.rb', line 722

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.



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
656
657
658
# File 'lib/voodoo/generators/nasm_generator.rb', line 616

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



452
453
454
455
456
# File 'lib/voodoo/generators/nasm_generator.rb', line 452

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



459
460
461
# File 'lib/voodoo/generators/nasm_generator.rb', line 459

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

#dword(value) ⇒ Object

Define a dword with the given value



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

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

#emit_align(alignment) ⇒ Object

Alignment



127
128
129
# File 'lib/voodoo/generators/nasm_generator.rb', line 127

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

#emit_function_epilogue(formals = []) ⇒ Object

Emits function epilogue.



136
137
138
# File 'lib/voodoo/generators/nasm_generator.rb', line 136

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

#emit_label(name) ⇒ Object

Emits a label.



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

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

#emit_label_size(name) ⇒ Object



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

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

#emit_label_type(name, type) ⇒ Object



73
74
75
# File 'lib/voodoo/generators/nasm_generator.rb', line 73

def emit_label_type name, type
  # nothing to do
end

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

Loads a word into a register.



279
280
281
282
283
284
285
# File 'lib/voodoo/generators/nasm_generator.rb', line 279

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.



400
401
402
403
404
405
406
# File 'lib/voodoo/generators/nasm_generator.rb', line 400

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.



176
177
178
179
180
181
182
# File 'lib/voodoo/generators/nasm_generator.rb', line 176

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



141
142
143
144
145
146
147
# File 'lib/voodoo/generators/nasm_generator.rb', line 141

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.



255
256
257
258
# File 'lib/voodoo/generators/nasm_generator.rb', line 255

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.



493
494
495
496
497
498
499
500
501
502
503
504
505
506
# File 'lib/voodoo/generators/nasm_generator.rb', line 493

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



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
582
583
584
# File 'lib/voodoo/generators/nasm_generator.rb', line 511

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.



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

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

#export(*symbols) ⇒ Object

Export symbols from the current section



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

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

#goto(value) ⇒ Object

Continue execution at the given address



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

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.



667
668
669
670
671
672
673
# File 'lib/voodoo/generators/nasm_generator.rb', line 667

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



676
677
678
# File 'lib/voodoo/generators/nasm_generator.rb', line 676

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

#ifge(x, y) ⇒ Object

Test if x is greater than or equal to y



681
682
683
# File 'lib/voodoo/generators/nasm_generator.rb', line 681

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

#ifgt(x, y) ⇒ Object

Test if x is strictly greater than y



686
687
688
# File 'lib/voodoo/generators/nasm_generator.rb', line 686

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

#ifle(x, y) ⇒ Object

Test if x is less than or equal to y



691
692
693
# File 'lib/voodoo/generators/nasm_generator.rb', line 691

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

#iflt(x, y) ⇒ Object

Test if x is strictly less than y



696
697
698
# File 'lib/voodoo/generators/nasm_generator.rb', line 696

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

#ifne(x, y) ⇒ Object

Test if x different from y



701
702
703
# File 'lib/voodoo/generators/nasm_generator.rb', line 701

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

#immediate_operand?(operand) ⇒ Boolean

Tests if an operand is an immediate operand

Returns:

  • (Boolean)


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

def immediate_operand? operand
  integer?(operand)
end

#import(*symbols) ⇒ Object

Import labels into the current section



57
58
59
60
61
62
# File 'lib/voodoo/generators/nasm_generator.rb', line 57

def import *symbols
  if real_section_name(section) != ".text"
    @relocated_symbols.merge symbols
  end
  emit "extern #{symbols.join ', '}\n"
end

#let(symbol, *words) ⇒ Object

Introduces a new local variable.



244
245
246
247
248
# File 'lib/voodoo/generators/nasm_generator.rb', line 244

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



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
328
329
330
331
# File 'lib/voodoo/generators/nasm_generator.rb', line 289

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.



335
336
337
338
339
340
341
342
343
# File 'lib/voodoo/generators/nasm_generator.rb', line 335

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.



346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
# File 'lib/voodoo/generators/nasm_generator.rb', line 346

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
    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.



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

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.



390
391
392
393
# File 'lib/voodoo/generators/nasm_generator.rb', line 390

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)


270
271
272
# File 'lib/voodoo/generators/nasm_generator.rb', line 270

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



464
465
466
467
468
# File 'lib/voodoo/generators/nasm_generator.rb', line 464

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



471
472
473
# File 'lib/voodoo/generators/nasm_generator.rb', line 471

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

#mul(target, x, y) ⇒ Object

Multiply x by y and store the result in target



476
477
478
479
480
# File 'lib/voodoo/generators/nasm_generator.rb', line 476

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



483
484
485
# File 'lib/voodoo/generators/nasm_generator.rb', line 483

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.



728
729
730
731
732
733
734
735
736
# File 'lib/voodoo/generators/nasm_generator.rb', line 728

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



92
93
94
# File 'lib/voodoo/generators/nasm_generator.rb', line 92

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.



153
154
155
156
157
# File 'lib/voodoo/generators/nasm_generator.rb', line 153

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



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

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



428
429
430
431
432
433
434
435
436
437
# File 'lib/voodoo/generators/nasm_generator.rb', line 428

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.



740
741
742
743
744
745
746
747
748
749
# File 'lib/voodoo/generators/nasm_generator.rb', line 740

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



440
441
442
443
444
445
446
447
448
449
# File 'lib/voodoo/generators/nasm_generator.rb', line 440

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



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

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.



756
757
758
759
760
761
762
763
764
765
# File 'lib/voodoo/generators/nasm_generator.rb', line 756

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