voodoo 1.1.3 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/voodoo/config.rb
CHANGED
@@ -162,13 +162,14 @@ module Voodoo
|
|
162
162
|
end
|
163
163
|
# Call function
|
164
164
|
with_temporary do |temporary|
|
165
|
-
|
166
|
-
emit "xor rax, rax\n"
|
167
|
-
# If value_ref is a symbol, use PLT-relative addressing
|
165
|
+
# If func is a global, use PLT-relative addressing
|
168
166
|
if global?(func)
|
169
167
|
@symbol_tracker.use func
|
168
|
+
emit "xor rax, rax\n"
|
170
169
|
emit "call #{func} wrt ..plt\n"
|
171
170
|
else
|
171
|
+
value_ref = load_value func, temporary
|
172
|
+
emit "xor rax, rax\n"
|
172
173
|
emit "call #{value_ref}\n"
|
173
174
|
end
|
174
175
|
end
|
@@ -181,14 +182,8 @@ module Voodoo
|
|
181
182
|
# Ends a function body.
|
182
183
|
def end_function
|
183
184
|
label @function_end_label
|
184
|
-
|
185
|
-
@saved_registers.each_with_index do |register,i|
|
186
|
-
ref = offset_reference saved_local_offset(i)
|
187
|
-
emit "mov #{register}, #{ref}\n"
|
188
|
-
end
|
189
|
-
# Destroy frame.
|
185
|
+
restore_saved_registers
|
190
186
|
emit "leave\n"
|
191
|
-
# Return.
|
192
187
|
emit "ret\n"
|
193
188
|
if @environment == @top_level
|
194
189
|
raise "Cannot end function when not in a function"
|
@@ -197,6 +192,14 @@ module Voodoo
|
|
197
192
|
end
|
198
193
|
end
|
199
194
|
|
195
|
+
# Restores saved registers.
|
196
|
+
def restore_saved_registers
|
197
|
+
@saved_registers.each_with_index do |register,i|
|
198
|
+
ref = offset_reference saved_local_offset(i)
|
199
|
+
emit "mov #{register}, #{ref}\n"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
200
203
|
# Returns from a function.
|
201
204
|
def ret *words
|
202
205
|
eval_expr words, @AX unless words.empty?
|
@@ -266,13 +269,16 @@ module Voodoo
|
|
266
269
|
end
|
267
270
|
|
268
271
|
# Tail call
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
272
|
+
with_temporary do |temporary|
|
273
|
+
# If func is a global, use PLT-relative addressing
|
274
|
+
if global?(func)
|
275
|
+
func_ref = "#{func} wrt ..plt\n"
|
276
|
+
else
|
277
|
+
func_ref = load_value func, temporary
|
278
|
+
end
|
279
|
+
restore_saved_registers
|
280
|
+
emit "leave\n"
|
281
|
+
set_register @AX, 0
|
276
282
|
emit "jmp #{func_ref}\n"
|
277
283
|
end
|
278
284
|
end
|
@@ -72,6 +72,7 @@ module Voodoo
|
|
72
72
|
#
|
73
73
|
class ARMGasGenerator < CommonCodeGenerator
|
74
74
|
def initialize params
|
75
|
+
@BYTES_PER_INSTRUCTION = 4
|
75
76
|
@WORDSIZE_BITS = 2
|
76
77
|
@WORDSIZE = 1 << @WORDSIZE_BITS
|
77
78
|
@CODE_ALIGNMENT = 4
|
@@ -90,12 +91,15 @@ module Voodoo
|
|
90
91
|
@SAVED_FRAME_LAYOUT = {}
|
91
92
|
@SAVE_FRAME_REGISTERS.each_with_index { |r,i| @SAVED_FRAME_LAYOUT[r] = i }
|
92
93
|
@INITIAL_FRAME_SIZE = 2 * @WORDSIZE
|
94
|
+
@MAX_CONSTANT_POOL_OFFSET = 4096
|
93
95
|
@NREGISTER_ARGS = 4
|
94
96
|
@NREGISTER_LOCALS = @LOCAL_REGISTERS.length
|
95
97
|
@FP = :r11
|
96
98
|
@RETURN = :r0
|
97
99
|
@TEMPORARIES = [:r12, :r3, :r2, :r1]
|
98
|
-
@
|
100
|
+
@bytes_emitted_since_constants = 0
|
101
|
+
@constants = {}
|
102
|
+
@emitting_constants = false
|
99
103
|
@frame_offset = 0
|
100
104
|
@frame_size = 0
|
101
105
|
@function_end_label = nil
|
@@ -114,9 +118,13 @@ module Voodoo
|
|
114
118
|
# returning the label that will refer to the constant.
|
115
119
|
# The value may be an integer or a label.
|
116
120
|
def add_constant value
|
117
|
-
|
118
|
-
|
119
|
-
|
121
|
+
# If the value is already in the constant pool, return its label.
|
122
|
+
# Else, add it to the pool with a new label and return that label.
|
123
|
+
@constants.fetch(value) do |value|
|
124
|
+
label = gensym
|
125
|
+
@constants[value] = label
|
126
|
+
label
|
127
|
+
end
|
120
128
|
end
|
121
129
|
|
122
130
|
# Returns the fp-relative offset for the nth (0-based) argument.
|
@@ -322,6 +330,22 @@ module Voodoo
|
|
322
330
|
emit_constants if ret
|
323
331
|
end
|
324
332
|
|
333
|
+
alias :_common_emit :emit
|
334
|
+
|
335
|
+
# Adds code to the current section.
|
336
|
+
def emit code
|
337
|
+
_common_emit code
|
338
|
+
if real_section_name(@section) == '.text'
|
339
|
+
@bytes_emitted_since_constants = @bytes_emitted_since_constants +
|
340
|
+
@BYTES_PER_INSTRUCTION
|
341
|
+
if !@emitting_constants &&
|
342
|
+
(@bytes_emitted_since_constants + @WORDSIZE * @constants.length) >
|
343
|
+
@MAX_CONSTANT_POOL_OFFSET - 2 * @BYTES_PER_INSTRUCTION
|
344
|
+
emit_constants_with_goto
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
325
349
|
# Aligns on the next multiple of +n+ bytes.
|
326
350
|
def emit_align n
|
327
351
|
emit ".align #{n}\n"
|
@@ -330,11 +354,31 @@ module Voodoo
|
|
330
354
|
# Writes any constants that need to be written to the instruction
|
331
355
|
# stream, and clears the list of constants that need to be written.
|
332
356
|
def emit_constants
|
333
|
-
|
334
|
-
|
335
|
-
|
357
|
+
old_emitting_constants = @emitting_constants
|
358
|
+
begin
|
359
|
+
@emitting_constants = true
|
360
|
+
@constants.each do |value,l|
|
361
|
+
label l
|
362
|
+
word value
|
363
|
+
end
|
364
|
+
@constants = {}
|
365
|
+
@bytes_emitted_since_constants = 0
|
366
|
+
ensure
|
367
|
+
@emitting_constants = old_emitting_constants
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
# Emits constants, and code that jumps over the constants pool.
|
372
|
+
def emit_constants_with_goto
|
373
|
+
old_emitting_constants = @emitting_constants
|
374
|
+
begin
|
375
|
+
@emitting_constants = true
|
376
|
+
lbl = gensym
|
377
|
+
goto lbl
|
378
|
+
label lbl
|
379
|
+
ensure
|
380
|
+
@emitting_constants = old_emitting_constants
|
336
381
|
end
|
337
|
-
@constants = []
|
338
382
|
end
|
339
383
|
|
340
384
|
# Declares symbols to be exported.
|
@@ -408,9 +452,7 @@ module Voodoo
|
|
408
452
|
|
409
453
|
# If we need to emit constants, do so now
|
410
454
|
unless @constants.empty?
|
411
|
-
|
412
|
-
goto lbl
|
413
|
-
label lbl
|
455
|
+
emit_constants_with_goto
|
414
456
|
end
|
415
457
|
end
|
416
458
|
|
@@ -686,7 +686,7 @@ module Voodoo
|
|
686
686
|
if @relocated_symbols.include? x
|
687
687
|
emit "lw #{register}, %got(#{x})(#{@GOT})\n"
|
688
688
|
else
|
689
|
-
emit "
|
689
|
+
emit "lw #{register}, %got(#{x})(#{@GOT})\n"
|
690
690
|
emit "addiu #{register}, %lo(#{x})\n"
|
691
691
|
end
|
692
692
|
return register
|
@@ -281,60 +281,60 @@ module Voodoo
|
|
281
281
|
end
|
282
282
|
|
283
283
|
# Create a value reference to an address.
|
284
|
-
# Invoking this code may
|
284
|
+
# Invoking this code may use a temporary and/or clobber @CX
|
285
285
|
def load_address base, offset, scale
|
286
|
-
|
287
|
-
|
286
|
+
with_temporary do |temporary|
|
287
|
+
base_ref = load_value base, temporary
|
288
|
+
offset_ref = load_value offset, @CX
|
288
289
|
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
290
|
+
if offset_ref == 0
|
291
|
+
if integer? base_ref
|
292
|
+
# Only an integer base
|
293
|
+
"[#{base_ref}]"
|
294
|
+
else
|
295
|
+
# Some complex base; load in temporary
|
296
|
+
emit "mov #{temporary}, #{base_ref}\n"
|
297
|
+
"[#{temporary}]"
|
298
|
+
end
|
299
|
+
elsif base_ref == 0
|
300
|
+
if integer? offset_ref
|
301
|
+
# Only a scaled offset
|
302
|
+
"[#{offset_ref.to_i * scale}]"
|
303
|
+
else
|
304
|
+
# Some complex offset; load in @CX
|
305
|
+
emit "mov #{@CX}, #{offset_ref}\n"
|
306
|
+
"[#{@CX} * #{scale}]"
|
307
|
+
end
|
308
|
+
elsif integer? base_ref
|
309
|
+
if integer? offset_ref
|
310
|
+
# All integers, combine them together
|
311
|
+
"[#{base_ref.to_i + (offset_ref.to_i * scale)}]"
|
312
|
+
else
|
313
|
+
# Complex offset; use @CX
|
314
|
+
emit "mov #{@CX}, #{offset_ref}\n"
|
315
|
+
"[#{base_ref} + #{@CX} * #{scale}]"
|
316
|
+
end
|
317
|
+
elsif integer? offset_ref
|
318
|
+
# Complex base, integer offset; use temporary
|
319
|
+
emit "mov #{temporary}, #{base_ref}\n"
|
320
|
+
"[#{temporary} + #{offset_ref.to_i * scale}]"
|
311
321
|
else
|
312
|
-
#
|
322
|
+
# Both base and offset are complex
|
323
|
+
# Use both temporary and @CX
|
324
|
+
emit "mov #{temporary}, #{base_ref}\n"
|
313
325
|
emit "mov #{@CX}, #{offset_ref}\n"
|
314
|
-
"[#{
|
326
|
+
"[#{temporary} + #{@CX} * #{scale}]"
|
315
327
|
end
|
316
|
-
elsif integer? offset_ref
|
317
|
-
# Complex base, integer offset; use @BX
|
318
|
-
emit "mov #{@BX}, #{base_ref}\n"
|
319
|
-
"[#{@BX} + #{offset_ref.to_i * scale}]"
|
320
|
-
else
|
321
|
-
# Both base and offset are complex
|
322
|
-
# Use both @BX and @CX
|
323
|
-
emit "mov #{@BX}, #{base_ref}\n"
|
324
|
-
emit "mov #{@CX}, #{offset_ref}\n"
|
325
|
-
"[#{@BX} + #{@CX} * #{scale}]"
|
326
328
|
end
|
327
329
|
end
|
328
330
|
|
329
331
|
# Load the value at the given address.
|
330
|
-
# Invoking this code may clobber @BX.
|
331
332
|
def load_at address, reg
|
332
|
-
if integer?(address)
|
333
|
-
!@relocated_symbols.include?(address))
|
333
|
+
if integer?(address)
|
334
334
|
"[#{address}]"
|
335
335
|
else
|
336
|
-
load_value_into_register address,
|
337
|
-
"[#{
|
336
|
+
load_value_into_register address, reg
|
337
|
+
"[#{reg}]"
|
338
338
|
end
|
339
339
|
end
|
340
340
|
|
@@ -415,8 +415,10 @@ module Voodoo
|
|
415
415
|
eval_expr words, @environment[target]
|
416
416
|
else
|
417
417
|
eval_expr words, @RETURN_REG
|
418
|
-
|
419
|
-
|
418
|
+
with_temporary do |temporary|
|
419
|
+
target_ref = load_value target, temporary
|
420
|
+
emit "mov #{target_ref}, #{@RETURN_REG}\n"
|
421
|
+
end
|
420
422
|
end
|
421
423
|
end
|
422
424
|
end
|
@@ -448,8 +450,10 @@ module Voodoo
|
|
448
450
|
# Divide x by y and store the quotient in target
|
449
451
|
def div target, x, y
|
450
452
|
eval_div x, y
|
451
|
-
|
452
|
-
|
453
|
+
with_temporary do |temporary|
|
454
|
+
target_ref = load_value target, temporary
|
455
|
+
emit "mov #{target_ref}, #{@AX}\n"
|
456
|
+
end
|
453
457
|
end
|
454
458
|
|
455
459
|
# Divide target by x and store the quotient in target
|
@@ -460,8 +464,10 @@ module Voodoo
|
|
460
464
|
# Divide x by y and store the remainder in target
|
461
465
|
def mod target, x, y
|
462
466
|
eval_div x, y
|
463
|
-
|
464
|
-
|
467
|
+
with_temporary do |temporary|
|
468
|
+
target_ref = load_value target, temporary
|
469
|
+
emit "mov #{target_ref}, #{@DX}\n"
|
470
|
+
end
|
465
471
|
end
|
466
472
|
|
467
473
|
# Divide target by x and store the remainder in target
|
@@ -472,8 +478,10 @@ module Voodoo
|
|
472
478
|
# Multiply x by y and store the result in target
|
473
479
|
def mul target, x, y
|
474
480
|
eval_mul x, y
|
475
|
-
|
476
|
-
|
481
|
+
with_temporary do |temporary|
|
482
|
+
target_ref = load_value target, temporary
|
483
|
+
emit "mov #{target_ref}, #{@RETURN_REG}\n"
|
484
|
+
end
|
477
485
|
end
|
478
486
|
|
479
487
|
# Multiply target by x and store the result in target
|
@@ -494,8 +502,8 @@ module Voodoo
|
|
494
502
|
emit "mov #{@DX}, #{@AX}\n"
|
495
503
|
emit "sar #{@DX}, #{@WORDSIZE * 8 - 1}\n"
|
496
504
|
if immediate_operand?(y_ref)
|
497
|
-
set_register
|
498
|
-
emit "idiv #{
|
505
|
+
set_register temporary, y_ref
|
506
|
+
emit "idiv #{temporary}\n"
|
499
507
|
else
|
500
508
|
emit "idiv #{@WORD_NAME} #{y_ref}\n"
|
501
509
|
end
|
@@ -504,7 +512,7 @@ module Voodoo
|
|
504
512
|
|
505
513
|
# Evaluate an expression.
|
506
514
|
# The result is stored in _register_ (@RETURN_REG by default).
|
507
|
-
# The following registers may be clobbered: @AX, @
|
515
|
+
# The following registers may be clobbered: @AX, @CX, @DX
|
508
516
|
def eval_expr words, register = @RETURN_REG
|
509
517
|
if words.length == 1
|
510
518
|
if words[0] == 0
|
@@ -569,10 +577,18 @@ module Voodoo
|
|
569
577
|
emit "not #{register}\n"
|
570
578
|
else
|
571
579
|
if binop?(op)
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
580
|
+
with_temporary do |t1|
|
581
|
+
x_ref = load_value words[1], @DX
|
582
|
+
y_ref = load_value words[2], t1
|
583
|
+
if register == y_ref
|
584
|
+
emit "mov #{@DX}, #{x_ref}\n"
|
585
|
+
emit "#{op} #{@DX}, #{y_ref}\n"
|
586
|
+
emit "mov #{register}, #{@DX}\n"
|
587
|
+
else
|
588
|
+
emit "mov #{register}, #{x_ref}\n" unless register == x_ref
|
589
|
+
emit "#{op} #{register}, #{y_ref}\n"
|
590
|
+
end
|
591
|
+
end
|
576
592
|
else
|
577
593
|
raise "Not a magic word: #{words[0]}"
|
578
594
|
end
|
@@ -585,22 +601,24 @@ module Voodoo
|
|
585
601
|
# a different register can be specified by passing
|
586
602
|
# a third argument.
|
587
603
|
def eval_mul x, y, register = @AX
|
588
|
-
|
589
|
-
|
604
|
+
with_temporary do |t1|
|
605
|
+
x_ref = load_value x, @DX
|
606
|
+
y_ref = load_value y, t1
|
590
607
|
|
591
|
-
|
592
|
-
|
593
|
-
|
608
|
+
if immediate_operand? x_ref
|
609
|
+
if immediate_operand? y_ref
|
610
|
+
set_register register, x_ref * y_ref
|
611
|
+
else
|
612
|
+
emit "imul #{register}, #{y_ref}, #{x_ref}\n"
|
613
|
+
end
|
614
|
+
elsif immediate_operand? y_ref
|
615
|
+
emit "imul #{register}, #{x_ref}, #{y_ref}\n"
|
616
|
+
elsif y_ref != register
|
617
|
+
emit "mov #{register}, #{x_ref}\n" unless x_ref == register
|
618
|
+
emit "imul #{register}, #{y_ref}\n"
|
594
619
|
else
|
595
|
-
emit "imul #{register}, #{
|
620
|
+
emit "imul #{register}, #{x_ref}\n"
|
596
621
|
end
|
597
|
-
elsif immediate_operand? y_ref
|
598
|
-
emit "imul #{register}, #{x_ref}, #{y_ref}\n"
|
599
|
-
elsif y_ref != register
|
600
|
-
emit "mov #{register}, #{x_ref}\n" unless x_ref == register
|
601
|
-
emit "imul #{register}, #{y_ref}\n"
|
602
|
-
else
|
603
|
-
emit "imul #{register}, #{x_ref}\n"
|
604
622
|
end
|
605
623
|
end
|
606
624
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: voodoo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-11-10 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ! 'The Voodoo compiler is an implementation of the Voodoo programming
|
15
15
|
|
@@ -30,28 +30,28 @@ extensions: []
|
|
30
30
|
extra_rdoc_files: []
|
31
31
|
files:
|
32
32
|
- bin/voodooc
|
33
|
+
- lib/voodoo.rb
|
34
|
+
- lib/voodoo/config.rb
|
35
|
+
- lib/voodoo/error.rb
|
36
|
+
- lib/voodoo/code_generator.rb
|
37
|
+
- lib/voodoo/parser.rb
|
33
38
|
- lib/voodoo/symbol_tracker.rb
|
34
|
-
- lib/voodoo/
|
35
|
-
- lib/voodoo/
|
36
|
-
- lib/voodoo/generators/
|
37
|
-
- lib/voodoo/generators/mips_elf_generator.rb
|
39
|
+
- lib/voodoo/validator.rb
|
40
|
+
- lib/voodoo/compiler.rb
|
41
|
+
- lib/voodoo/generators/nasm_generator.rb
|
38
42
|
- lib/voodoo/generators/dummy_generator.rb
|
39
|
-
- lib/voodoo/generators/
|
43
|
+
- lib/voodoo/generators/i386_nasm_generator.rb
|
40
44
|
- lib/voodoo/generators/arm_elf_generator.rb
|
45
|
+
- lib/voodoo/generators/nasm_elf_generator.rb
|
46
|
+
- lib/voodoo/generators/gas_elf_generator.rb
|
41
47
|
- lib/voodoo/generators/i386_elf_generator.rb
|
42
|
-
- lib/voodoo/generators/i386_nasm_generator.rb
|
43
48
|
- lib/voodoo/generators/amd64_nasm_generator.rb
|
44
|
-
- lib/voodoo/generators/
|
49
|
+
- lib/voodoo/generators/common_code_generator.rb
|
50
|
+
- lib/voodoo/generators/mips_gas_generator.rb
|
51
|
+
- lib/voodoo/generators/arm_gas_generator.rb
|
52
|
+
- lib/voodoo/generators/mips_elf_generator.rb
|
53
|
+
- lib/voodoo/generators/amd64_elf_generator.rb
|
45
54
|
- lib/voodoo/generators/command_postprocessor.rb
|
46
|
-
- lib/voodoo/generators/gas_elf_generator.rb
|
47
|
-
- lib/voodoo/generators/nasm_elf_generator.rb
|
48
|
-
- lib/voodoo/parser.rb
|
49
|
-
- lib/voodoo/config.rb
|
50
|
-
- lib/voodoo/error.rb
|
51
|
-
- lib/voodoo/validator.rb
|
52
|
-
- lib/voodoo/code_generator.rb
|
53
|
-
- lib/voodoo/compiler.rb
|
54
|
-
- lib/voodoo.rb
|
55
55
|
homepage: http://inglorion.net/software/voodoo/
|
56
56
|
licenses: []
|
57
57
|
post_install_message:
|