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, #features, #function, #gensym, #has_feature?, #in_section, #output_file_name, #output_file_suffix, #real_section_name, #section, #section=, #section_alias

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



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

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

#align(alignment = nil) ⇒ Object

Alignment



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/voodoo/generators/nasm_generator.rb', line 108

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)


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

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

#begin_block(*code) ⇒ Object

Begins a new block.



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

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



131
132
133
134
135
136
137
# File 'lib/voodoo/generators/nasm_generator.rb', line 131

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



437
438
439
440
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
# File 'lib/voodoo/generators/nasm_generator.rb', line 437

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



475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
# File 'lib/voodoo/generators/nasm_generator.rb', line 475

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)


217
218
219
220
# File 'lib/voodoo/generators/nasm_generator.rb', line 217

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



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

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

#comment(text) ⇒ Object

Emit a comment



726
727
728
# File 'lib/voodoo/generators/nasm_generator.rb', line 726

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.



644
645
646
647
648
649
650
651
652
653
654
655
# File 'lib/voodoo/generators/nasm_generator.rb', line 644

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



496
497
498
499
500
# File 'lib/voodoo/generators/nasm_generator.rb', line 496

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



503
504
505
# File 'lib/voodoo/generators/nasm_generator.rb', line 503

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

#dword(value) ⇒ Object

Define a dword with the given value



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

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

#emit_function_epilogue(formals = []) ⇒ Object

Emit function epilogue.



140
141
142
# File 'lib/voodoo/generators/nasm_generator.rb', line 140

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

#end_blockObject

Ends the current block.



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

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



145
146
147
148
149
150
151
152
# File 'lib/voodoo/generators/nasm_generator.rb', line 145

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.



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

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.



537
538
539
540
541
542
543
544
545
546
547
548
# File 'lib/voodoo/generators/nasm_generator.rb', line 537

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



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

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.



620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
# File 'lib/voodoo/generators/nasm_generator.rb', line 620

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



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

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

#global?(symbol) ⇒ Boolean

Test if a symbol refers to a global

Returns:

  • (Boolean)


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

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

#goto(value) ⇒ Object

Continue execution at the given address



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

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.



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

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



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

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



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

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



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

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



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

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



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

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



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

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)


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

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

#import(*symbols) ⇒ Object

Import labels into the current section



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

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

#integer?(value) ⇒ Boolean

Test if a value is an integer

Returns:

  • (Boolean)


223
224
225
# File 'lib/voodoo/generators/nasm_generator.rb', line 223

def integer? value
  value.kind_of? Integer
end

#label(name) ⇒ Object

Define a label in the current section



54
55
56
# File 'lib/voodoo/generators/nasm_generator.rb', line 54

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



259
260
261
262
263
264
265
266
267
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
# File 'lib/voodoo/generators/nasm_generator.rb', line 259

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.



305
306
307
308
309
310
311
312
# File 'lib/voodoo/generators/nasm_generator.rb', line 305

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.



316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
# File 'lib/voodoo/generators/nasm_generator.rb', line 316

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.



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

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



349
350
351
352
353
354
355
356
# File 'lib/voodoo/generators/nasm_generator.rb', line 349

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)


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

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

#mod(target, x, y) ⇒ Object

Divide x by y and store the remainder in target



508
509
510
511
512
# File 'lib/voodoo/generators/nasm_generator.rb', line 508

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



515
516
517
# File 'lib/voodoo/generators/nasm_generator.rb', line 515

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

#mul(target, x, y) ⇒ Object

Multiply x by y and store the result in target



520
521
522
523
524
# File 'lib/voodoo/generators/nasm_generator.rb', line 520

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



527
528
529
# File 'lib/voodoo/generators/nasm_generator.rb', line 527

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

#qword(value) ⇒ Object

Define a qword with the given value



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

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.



158
159
160
161
162
163
# File 'lib/voodoo/generators/nasm_generator.rb', line 158

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



363
364
365
366
367
368
369
370
371
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
# File 'lib/voodoo/generators/nasm_generator.rb', line 363

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



407
408
409
410
411
412
413
414
415
416
417
# File 'lib/voodoo/generators/nasm_generator.rb', line 407

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



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

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



420
421
422
423
424
425
426
427
428
429
430
# File 'lib/voodoo/generators/nasm_generator.rb', line 420

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



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/voodoo/generators/nasm_generator.rb', line 78

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)


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

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)


249
250
251
# File 'lib/voodoo/generators/nasm_generator.rb', line 249

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

#write(io) ⇒ Object

Write generated code to the given IO object.



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

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