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?, #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



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

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.



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

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.



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

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.



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

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.



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

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.



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

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



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

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

#comment(text) ⇒ Object

Emit a comment



724
725
726
# File 'lib/voodoo/generators/nasm_generator.rb', line 724

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.



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
659
660
# File 'lib/voodoo/generators/nasm_generator.rb', line 618

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



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

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



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

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

#dword(value) ⇒ Object

Define a dword with the given value



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

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

#emit_align(alignment) ⇒ Object

Alignment



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

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

#emit_function_epilogue(formals = []) ⇒ Object

Emits function epilogue.



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

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

#emit_label(name) ⇒ Object

Emits a label.



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

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

#emit_label_size(name) ⇒ Object



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

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

#emit_label_type(name, type) ⇒ Object



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

def emit_label_type name, type
  # nothing to do
end

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

Loads a word into a register.



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

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.



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

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.



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

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



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

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.



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

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.



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

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



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
585
586
# File 'lib/voodoo/generators/nasm_generator.rb', line 513

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.



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

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.



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

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



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

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

#ifge(x, y) ⇒ Object

Test if x is greater than or equal to y



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

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

#ifgt(x, y) ⇒ Object

Test if x is strictly greater than y



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

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

#ifle(x, y) ⇒ Object

Test if x is less than or equal to y



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

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

#iflt(x, y) ⇒ Object

Test if x is strictly less than y



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

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

#ifne(x, y) ⇒ Object

Test if x different from y



703
704
705
# File 'lib/voodoo/generators/nasm_generator.rb', line 703

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

#immediate_operand?(operand) ⇒ Boolean

Tests if an operand is an immediate operand

Returns:

  • (Boolean)


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

def immediate_operand? operand
  integer?(operand)
end

#import(*symbols) ⇒ Object

Import labels into the current section



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

def import *symbols
  @symbol_tracker.define *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.



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

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



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
332
# File 'lib/voodoo/generators/nasm_generator.rb', line 290

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.



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

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.



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

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.



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

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.



392
393
394
395
# File 'lib/voodoo/generators/nasm_generator.rb', line 392

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)


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

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



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

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



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

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

#mul(target, x, y) ⇒ Object

Multiply x by y and store the result in target



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

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



485
486
487
# File 'lib/voodoo/generators/nasm_generator.rb', line 485

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.



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

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



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

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.



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

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



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

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



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

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.



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

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



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

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



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

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.



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

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