voodoo 1.1.3 → 1.1.4
Sign up to get free protection for your applications and to get access to all the features.
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:
|