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:

  • #emit_function_prologue

  • #load_arg

  • #load_local

  • @CODE_ALIGNMENT

  • @DATA_ALIGNMENT

  • @FUNCTION_ALIGNMENT

  • @SCRATCH_REG

  • @WORD_NAME

  • @WORDSIZE

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

Direct Known Subclasses

AMD64NasmGenerator, I386NasmGenerator

Instance Method Summary collapse

Methods inherited from CommonCodeGenerator

#add, #add_function, #block, #each_statement, #emit, #function, #gensym, #in_section, #output_file_name, #output_file_suffix, #real_section_name, #section, #section=, #section_alias

Methods included from GeneratorApi1

#add_code, #add_code_label, #add_data, #add_data_label, #add_function_label, #align_code, #align_data, #align_function

Constructor Details

#initialize(params = {}) ⇒ NasmGenerator

Returns a new instance of NasmGenerator.



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

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



718
719
720
721
722
723
724
725
726
727
# File 'lib/voodoo/generators/nasm_generator.rb', line 718

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

#align(alignment = nil) ⇒ Object

Alignment



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/voodoo/generators/nasm_generator.rb', line 117

def align alignment = nil
  unless alignment
    # Get default alignment
    case @section
    when :code
      alignment = @CODE_ALIGNMENT
    when :data
      alignment = @DATA_ALIGNMENT
    when :function
      alignment = @FUNCTION_ALIGNMENT
    else
      # Use data alignment as default
      alignment = @DATA_ALIGNMENT
    end
  end
  emit "align #{alignment}\n" unless alignment == 0
end

#at_expr?(value) ⇒ Boolean

Test if a value is an at-expression

Returns:

  • (Boolean)


221
222
223
# File 'lib/voodoo/generators/nasm_generator.rb', line 221

def at_expr? value
  value.respond_to?(:[]) && value[0] == :'@'
end

#begin_block(*code) ⇒ Object

Begins a new block.



179
180
181
182
183
184
185
186
187
188
189
# File 'lib/voodoo/generators/nasm_generator.rb', line 179

def begin_block *code
  emit "; begin block\n"
  # 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

#begin_function(*formals) ⇒ Object

Emit function preamble and declare formals as function arguments



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

def begin_function *formals
  emit "; function #{formals.join ' '}\n"
  environment = Environment.new @environment
  environment.add_args formals
  @environment = environment
  emit_function_prologue formals
end

#binop(op, target, x, y) ⇒ Object

Emit code for a binary operation



441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
# File 'lib/voodoo/generators/nasm_generator.rb', line 441

def binop op, target, x, y
  if target == x
    binop2 op, target, y
  elsif symmetric_operation?(op) && y == target
    binop2 op, target, x
  else
    # Cases that are handled specially
    return div(target, x, y) if op == :div
    return mod(target, x, y) if op == :mod
    return mul(target, x, y) if op == :mul

    target_ref = load_value target, @BX
    x_ref = load_value x, @DX
    y_ref = load_value y, @CX

    mnemonic = action_to_mnemonic op
    if [:asr, :bsr, :rol, :ror, :shl, :shr].member? op
      emit "mov cl, #{y_ref}\n" unless y_ref == @CX
      y_ref = 'cl'
    end

    if memory_operand?(target_ref)
      if memory_operand?(x_ref) || memory_operand?(y_ref)
        emit "mov #{@AX}, #{x_ref}\n"
        emit "#{mnemonic} #{@AX}, #{y_ref}\n"
        emit "mov #{target_ref}, #{@AX}\n"
      else
        emit "mov #{@WORD_NAME} #{target_ref}, #{x_ref}\n"
        emit "#{mnemonic} #{@WORD_NAME} #{target_ref}, #{y_ref}\n"
      end
    else
      raise "Can't happen: target_ref is #{target_ref.inspect}"
    end
  end
end

#binop2(op, target, y) ⇒ Object

Emit code for a binary operation where the first operand is also the target



479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
# File 'lib/voodoo/generators/nasm_generator.rb', line 479

def binop2 op, target, y
  # Cases that are handled specially
  return div2(target, target, y) if op == :div
  return mod2(target, y) if op == :mod
  return mul2(target, y) if op == :mul

  target_ref = load_value target, @AX
  y_ref = load_value y, @CX
  mnemonic = action_to_mnemonic op
  if [:asr, :bsr, :rol, :ror, :shl, :shr].member? op
    emit "mov cl, #{y_ref}\n" unless y_ref == @CX
    emit "#{mnemonic} #{@WORD_NAME} #{target_ref}, cl\n"
  elsif memory_operand?(target_ref) && memory_operand?(y_ref)
    emit "mov #{@CX}, #{y_ref}\n"
    emit "#{mnemonic} #{target_ref}, #{@CX}\n"
  else
    emit "#{mnemonic} #{@WORD_NAME} #{target_ref}, #{y_ref}\n"
  end
end

#binop?(op) ⇒ Boolean

Test if op is a binary operation

Returns:

  • (Boolean)


226
227
228
229
# File 'lib/voodoo/generators/nasm_generator.rb', line 226

def binop? op
  [:asr, :bsr, :div, :mod, :rol, :ror, :shl, :shr, :sub].member?(op) ||
    symmetric_operation?(op)
end

#byte(value) ⇒ Object

Define a byte with the given value



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

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

#comment(text) ⇒ Object

Emit a comment



730
731
732
# File 'lib/voodoo/generators/nasm_generator.rb', line 730

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.



648
649
650
651
652
653
654
655
656
657
658
659
# File 'lib/voodoo/generators/nasm_generator.rb', line 648

def common_if branch, x, y = nil
  load_value_into_register y, @DX if y
  load_value_into_register x, @AX
  truelabel = @environment.gensym
  falselabel = @environment.gensym
  @if_labels.push falselabel

  emit "cmp #{@AX}, #{@DX}\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



500
501
502
503
504
# File 'lib/voodoo/generators/nasm_generator.rb', line 500

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



507
508
509
# File 'lib/voodoo/generators/nasm_generator.rb', line 507

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

#dword(value) ⇒ Object

Define a dword with the given value



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

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

#emit_function_epilogue(formals = []) ⇒ Object

Emit function epilogue.



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

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

#end_blockObject

Ends the current block.



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

def end_block
  emit "; end block\n"

  # De-allocate block's variables
  nvars = @environment.locals - @environment.parent.locals
  emit "add #{@SP}, #{nvars * @WORDSIZE}\n" unless nvars == 0

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

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

#end_functionObject

End a function body



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

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

#end_ifObject

End a conditional.



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

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.



541
542
543
544
545
546
547
548
549
550
551
552
# File 'lib/voodoo/generators/nasm_generator.rb', line 541

def eval_div x, y
  x_ref = load_value_into_register x, @AX
  y_ref = load_value y, @SCRATCH_REG
  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

#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



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
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
# File 'lib/voodoo/generators/nasm_generator.rb', line 557

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
      load_value_into_register words[2], @CX
      load_value_into_register words[1], register
      emit "#{action_to_mnemonic op} #{register}, cl\n"
    when :call
      call *words[1..-1]
    when :div
      eval_div words[1], words[2]
      set_register register, @AX
    when :'get-byte'
      # Clear register
      set_register register, 0
      # Get address reference
      address_ref = load_address words[1], words[2], 1
      # Load byte from address
      case register
      when 'eax', 'rax'
        set_register 'al', address_ref
      when 'ebx', 'rbx'
        set_register 'bl', address_ref
      when 'ecx', 'rcx'
        set_register 'cl', address_ref
      when 'edx', 'rdx'
        set_register 'dl', address_ref
      else
        set_register @BX, 0
        set_register 'bl', address_ref
        set_register register, @BX
      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"
        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.



624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
# File 'lib/voodoo/generators/nasm_generator.rb', line 624

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"
  else
    emit "mov #{register}, #{x_ref}\n"
    emit "imul #{register}, #{y_ref}\n"
  end
end

#export(*symbols) ⇒ Object

Export symbols from the current section



46
47
48
# File 'lib/voodoo/generators/nasm_generator.rb', line 46

def export *symbols
  emit "global #{symbols.join ', '}\n"
end

#global?(symbol) ⇒ Boolean

Test if a symbol refers to a global

Returns:

  • (Boolean)


237
238
239
# File 'lib/voodoo/generators/nasm_generator.rb', line 237

def global? symbol
  symbol?(symbol) && @environment[symbol] == nil
end

#goto(value) ⇒ Object

Continue execution at the given address



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

def goto value
  emit "; goto #{value}\n"
  value_ref = load_value value, @SCRATCH_REG
  emit "jmp #{value_ref}\n"
end

#ifelseObject

Start the false path of a conditional.



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

def ifelse
  emit "; else\n"
  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
681
# File 'lib/voodoo/generators/nasm_generator.rb', line 678

def ifeq x, y
  emit "; ifeq #{x} #{y}\n"
  common_if 'je', x, y
end

#ifge(x, y) ⇒ Object

Test if x is greater than or equal to y



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

def ifge x, y
  emit "; ifge #{x} #{y}\n"
  common_if 'jge', x, y
end

#ifgt(x, y) ⇒ Object

Test if x is strictly greater than y



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

def ifgt x, y
  emit "; ifgt #{x} #{y}\n"
  common_if 'jg', x, y
end

#ifle(x, y) ⇒ Object

Test if x is less than or equal to y



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

def ifle x, y
  emit "; ifle #{x} #{y}\n"
  common_if 'jle', x, y
end

#iflt(x, y) ⇒ Object

Test if x is strictly less than y



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

def iflt x, y
  emit "; iflt #{x} #{y}\n"
  common_if 'jl', x, y
end

#ifne(x, y) ⇒ Object

Test if x different from y



708
709
710
711
# File 'lib/voodoo/generators/nasm_generator.rb', line 708

def ifne x, y
  emit "; ifne #{x} #{y}\n"
  common_if 'jne', x, y
end

#immediate_operand?(operand) ⇒ Boolean

Tests if an operand is an immediate operand

Returns:

  • (Boolean)


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

def immediate_operand? operand
  integer?(operand) || global?(operand)
end

#import(*symbols) ⇒ Object

Import labels into the current section



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

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

#integer?(value) ⇒ Boolean

Test if a value is an integer

Returns:

  • (Boolean)


232
233
234
# File 'lib/voodoo/generators/nasm_generator.rb', line 232

def integer? value
  value.kind_of? Integer
end

#label(name) ⇒ Object

Define a label in the current section



63
64
65
# File 'lib/voodoo/generators/nasm_generator.rb', line 63

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

#load_address(base, offset, scale) ⇒ Object

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



268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
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
# File 'lib/voodoo/generators/nasm_generator.rb', line 268

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 = @SCRATCH_REG) ⇒ Object

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



314
315
316
317
318
319
320
321
# File 'lib/voodoo/generators/nasm_generator.rb', line 314

def load_at address, reg = @SCRATCH_REG
  if integer?(address) || global?(address)
    "[#{address}]"
  else
    load_value_into_register address, @BX
    "[#{@BX}]"
  end
end

#load_symbol(symbol, reg = @SCRATCH_REG) ⇒ Object

Load the value associated with the given symbol. Returns a string that can be used to refer to the loaded value.



325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# File 'lib/voodoo/generators/nasm_generator.rb', line 325

def load_symbol symbol, reg = @SCRATCH_REG
  x = @environment[symbol]
  if x
    case x[0]
    when :arg
      load_arg x[1], reg
    when :local
      load_local x[1], reg
    else
      raise "Invalid variable type: #{x[0]}"
    end
  else
    # Assume global
    symbol.to_s
  end
end

#load_value(value, reg = @SCRATCH_REG) ⇒ Object

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



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

def load_value value, reg = @SCRATCH_REG
  if integer? value
    # Integers can be used as is
    value
  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

Load a value into a register



358
359
360
361
362
363
364
365
# File 'lib/voodoo/generators/nasm_generator.rb', line 358

def load_value_into_register value, register
  load_code = load_value(value), register
  if load_code == register.to_s
    load_code
  else
    "mov #{register}, #{load_code}\n"
  end
end

#memory_operand?(operand) ⇒ Boolean

Tests if an operand is a memory operand

Returns:

  • (Boolean)


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

def memory_operand? operand
  operand[0] == ?[
end

#mod(target, x, y) ⇒ Object

Divide x by y and store the remainder in target



512
513
514
515
516
# File 'lib/voodoo/generators/nasm_generator.rb', line 512

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



519
520
521
# File 'lib/voodoo/generators/nasm_generator.rb', line 519

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

#mul(target, x, y) ⇒ Object

Multiply x by y and store the result in target



524
525
526
527
528
# File 'lib/voodoo/generators/nasm_generator.rb', line 524

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



531
532
533
# File 'lib/voodoo/generators/nasm_generator.rb', line 531

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

#qword(value) ⇒ Object

Define a qword with the given value



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

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

#ret(*words) ⇒ Object

Return a from a function.

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



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

def ret *words
  emit "; return #{words.join ' '}\n"
  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



372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
# File 'lib/voodoo/generators/nasm_generator.rb', line 372

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

  emit "; set #{target} #{words.join ' '}\n"
  if words.length == 1
    if words[0] == target
      emit "; nothing to do; destination equals source\n"
    else
      target_ref = load_value target, @BX
      if integer?(words[0])
        if words[0].to_i == 0
          # Set destination to 0
          emit "xor #{@AX}, #{@AX}\n"
          emit "mov #{target_ref}, #{@AX}\n"
        else
          # Load immediate
          emit "mov #{@WORD_NAME} #{target_ref}, #{words[0]}\n"
        end
      else
        # Copy source to destination
        eval_expr words, @RETURN_REG
        emit "mov #{target_ref}, #{@RETURN_REG}\n"
      end
    end
  else
    op = words[0]

    if words.length == 3 && binop?(op)
      # Binary operation
      binop op, target, words[1], words[2]
    else
      # Not a binary operation
      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



416
417
418
419
420
421
# File 'lib/voodoo/generators/nasm_generator.rb', line 416

def set_byte base, offset, value
  emit "; set-byte #{base} #{offset} #{value}\n"
  value_ref = load_value value, @RETURN_REG
  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



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

def set_word base, offset, value
  emit "; set-word #{base} #{offset} #{value}\n"
  if immediate_operand?(value)
    value_ref = value
  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



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/voodoo/generators/nasm_generator.rb', line 87

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

#symbol?(value) ⇒ Boolean

Test if a value is a symbol

Returns:

  • (Boolean)


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

def symbol? value
  value.kind_of? Symbol
end

#symmetric_operation?(op) ⇒ Boolean

Test if op is a symmetric operation (i.e. it will yield the same result if the order of its source operands is changed).

Returns:

  • (Boolean)


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

def symmetric_operation? op
  [:add, :and, :mul, :or, :xor].member? op
end

#wordsizeObject

Returns the number of bits per word for this code generator.



37
38
39
# File 'lib/voodoo/generators/nasm_generator.rb', line 37

def wordsize
  @WORDSIZE * 8
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