haxor 0.1.0

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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.travis.yml +4 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +27 -0
  6. data/README.md +414 -0
  7. data/Rakefile +1 -0
  8. data/bin/hcc +21 -0
  9. data/bin/hld +38 -0
  10. data/bin/hvm +17 -0
  11. data/examples/build.sh +10 -0
  12. data/examples/guess-the-number.hax +100 -0
  13. data/haxor.gemspec +24 -0
  14. data/lib/haxor.rb +44 -0
  15. data/lib/haxor/compiler/component/arithmetic.rb +55 -0
  16. data/lib/haxor/compiler/component/base.rb +37 -0
  17. data/lib/haxor/compiler/component/data.rb +32 -0
  18. data/lib/haxor/compiler/component/jumps.rb +95 -0
  19. data/lib/haxor/compiler/component/logical.rb +43 -0
  20. data/lib/haxor/compiler/component/other.rb +21 -0
  21. data/lib/haxor/compiler/component/transfer.rb +29 -0
  22. data/lib/haxor/compiler/component/various.rb +33 -0
  23. data/lib/haxor/compiler/core.rb +134 -0
  24. data/lib/haxor/compiler/section.rb +6 -0
  25. data/lib/haxor/compiler/unit.rb +39 -0
  26. data/lib/haxor/consts.rb +28 -0
  27. data/lib/haxor/header.rb +40 -0
  28. data/lib/haxor/linker.rb +89 -0
  29. data/lib/haxor/token/base.rb +7 -0
  30. data/lib/haxor/token/cmd.rb +9 -0
  31. data/lib/haxor/token/data.rb +17 -0
  32. data/lib/haxor/token/int64.rb +17 -0
  33. data/lib/haxor/token/label.rb +23 -0
  34. data/lib/haxor/token/pointer.rb +13 -0
  35. data/lib/haxor/vm/core.rb +53 -0
  36. data/lib/haxor/vm/cpu/core.rb +129 -0
  37. data/lib/haxor/vm/cpu/unit/arithmetic.rb +92 -0
  38. data/lib/haxor/vm/cpu/unit/base.rb +46 -0
  39. data/lib/haxor/vm/cpu/unit/jumps.rb +123 -0
  40. data/lib/haxor/vm/cpu/unit/logical.rb +59 -0
  41. data/lib/haxor/vm/cpu/unit/transfer.rb +37 -0
  42. data/lib/haxor/vm/cpu/unit/various.rb +47 -0
  43. data/lib/haxor/vm/mem.rb +101 -0
  44. data/lib/haxor/vm/os.rb +115 -0
  45. data/lib/haxor/vm/stack.rb +31 -0
  46. data/lib/haxor/vm/subsystem.rb +16 -0
  47. data/media/memory.png +0 -0
  48. data/media/vm.png +0 -0
  49. metadata +122 -0
@@ -0,0 +1,7 @@
1
+ module Haxor
2
+ module Token
3
+ class Base
4
+ attr_accessor :absolute_addr
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ module Haxor
2
+ module Token
3
+ class Cmd < Int64
4
+ def to_s
5
+ "Cmd -> 0x#{@data.to_s(16)}"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ module Haxor
2
+ module Token
3
+ class Data < Base
4
+ def initialize(data)
5
+ @data = data
6
+ end
7
+
8
+ def size
9
+ @data.size
10
+ end
11
+
12
+ def to_s
13
+ @data.to_s
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Haxor
2
+ module Token
3
+ class Int64 < Data
4
+ def to_bytecode
5
+ [@data].pack('q<')
6
+ end
7
+
8
+ def size
9
+ 8
10
+ end
11
+
12
+ def to_s
13
+ "int64 -> #{@data}"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ module Haxor
2
+ module Token
3
+ class Label < Base
4
+ attr_reader :label
5
+
6
+ def initialize(label)
7
+ @label = label
8
+ end
9
+
10
+ def to_bytecode
11
+ ''
12
+ end
13
+
14
+ def to_s
15
+ "Label -> #{@label}"
16
+ end
17
+
18
+ def size
19
+ 0
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ module Haxor
2
+ module Token
3
+ class Pointer < Int64
4
+ attr_accessor :data
5
+ attr_reader :label
6
+
7
+ def initialize(label)
8
+ super(-1) # invalid pointer
9
+ @label = label
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,53 @@
1
+ module Haxor
2
+ module Vm
3
+ class Core
4
+ attr_reader :mem
5
+
6
+ def initialize
7
+ @subsystems = {}
8
+ register_subsystem :cpu, Cpu::Core.new
9
+ register_subsystem :mem, Mem.new(Consts::RESERVED_MEM)
10
+ register_subsystem :stack, Stack.new
11
+ register_subsystem :os, Os.new
12
+
13
+ subsystem(:cpu).labels.each do |_, label|
14
+ subsystem(:mem).add_label label.label, label.absolute_addr
15
+ end
16
+
17
+ @units = []
18
+ @opcodes = {}
19
+ end
20
+
21
+ def register_subsystem(id, object)
22
+ @subsystems[id] = object
23
+ object.vm = self
24
+ end
25
+
26
+ def subsystem(id)
27
+ @subsystems[id]
28
+ end
29
+
30
+ def execute
31
+ loop do
32
+ subsystem(:cpu).iterate
33
+ end
34
+ end
35
+
36
+ def load_program(filename)
37
+ exe = File.read(filename, encoding: 'ASCII-8BIT')
38
+
39
+ @hdr = Header.new
40
+ @hdr.parse! exe
41
+
42
+ fail if @hdr.version != Consts::VERSION
43
+
44
+ exe = exe[@hdr.size..-1] # cut off header
45
+ subsystem(:mem).replace_region Consts::RESERVED_MEM, exe
46
+ subsystem(:mem).write 'ip', @hdr.entry_point # instruction pointer
47
+ subsystem(:mem).enlarge @hdr.bss_size
48
+ subsystem(:mem).enlarge @hdr.stack_size
49
+ subsystem(:mem).write 'sp', subsystem(:mem).size
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,129 @@
1
+ module Haxor
2
+ module Vm
3
+ module Cpu
4
+ class Core < Subsystem
5
+ attr_reader :struct
6
+ attr_reader :labels
7
+
8
+ def initialize
9
+ @units = []
10
+ @opcodes = {}
11
+
12
+ register_unit Unit::Arithmetic.new
13
+ register_unit Unit::Jumps.new
14
+ register_unit Unit::Logical.new
15
+ register_unit Unit::Transfer.new
16
+ register_unit Unit::Various.new
17
+
18
+ build_struct
19
+ end
20
+
21
+ def bind_opcode(opcode, object, method)
22
+ fail "OpCode already defined - #{opcode}." if @opcodes.key? opcode
23
+ @opcodes[opcode] = {
24
+ object: object,
25
+ method: method
26
+ }
27
+ end
28
+
29
+ def iterate
30
+ opcode = subsystem(:mem).next_cell
31
+ cmd = opcode & Consts::OPCODE_CMD_MASK
32
+ subsystem(:mem).write 'op', opcode
33
+
34
+ fail "Call to not existing opcode #{cmd}." unless @opcodes.key? cmd
35
+ # puts 'cmd = ' + cmd.to_s(16)
36
+ # puts flg.to_s(16)
37
+ @opcodes[cmd][:object].send(@opcodes[cmd][:method])
38
+ end
39
+
40
+ def reserved_mem
41
+ 1024
42
+ end
43
+
44
+ def register_unit(unit)
45
+ @units << unit
46
+ unit.vm = self
47
+ unit.register
48
+ end
49
+
50
+ def operand
51
+ flg = (subsystem(:mem).read 'op') & Consts::OPCODE_FLG_MASK
52
+ a = subsystem(:mem).next_cell
53
+ a = subsystem(:mem).read a if (flg & Consts::OPCODE_FLG_DA != 0)
54
+ a
55
+ end
56
+
57
+ def operands
58
+ flg = (subsystem(:mem).read 'op') & Consts::OPCODE_FLG_MASK
59
+
60
+ a = subsystem(:mem).next_cell
61
+ a = subsystem(:mem).read a if (flg & Consts::OPCODE_FLG_DA != 0)
62
+
63
+ b = subsystem(:mem).next_cell
64
+ b = subsystem(:mem).read b if (flg & Consts::OPCODE_FLG_DB != 0)
65
+
66
+ [a, b]
67
+ end
68
+
69
+ private
70
+
71
+ def build_struct
72
+ @struct = []
73
+
74
+ @struct << Token::Label.new('null')
75
+ @struct << Token::Int64.new(0)
76
+
77
+ @struct << Token::Label.new('registers')
78
+
79
+ # instruction pointer
80
+ @struct << Token::Label.new('ip')
81
+ @struct << Token::Int64.new(0)
82
+
83
+ # stack pointer
84
+ @struct << Token::Label.new('sp')
85
+ @struct << Token::Int64.new(0)
86
+
87
+ # base pointer
88
+ @struct << Token::Label.new('bp')
89
+ @struct << Token::Int64.new(0)
90
+
91
+ # arithmetic registry I
92
+ @struct << Token::Label.new('ar')
93
+ @struct << Token::Int64.new(0)
94
+
95
+ # arithmetic registry II
96
+ @struct << Token::Label.new('dr')
97
+ @struct << Token::Int64.new(0)
98
+
99
+ # flags registry
100
+ @struct << Token::Label.new('fr')
101
+ @struct << Token::Int64.new(0)
102
+
103
+ # currently processed opcode (with opcode flags)
104
+ @struct << Token::Label.new('op')
105
+ @struct << Token::Int64.new(0)
106
+
107
+ # system call
108
+ @struct << Token::Label.new('sc')
109
+ @struct << Token::Int64.new(0)
110
+
111
+ # general usage registers
112
+ (1..10).each do |i|
113
+ @struct << Token::Label.new(format('r%02d', i))
114
+ @struct << Token::Int64.new(0)
115
+ end
116
+
117
+ addr = 0
118
+ @labels = {}
119
+ @struct.each do |token|
120
+ token.absolute_addr = addr
121
+ addr += token.size
122
+
123
+ @labels[token.label] = token if token.is_a? Token::Label
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,92 @@
1
+ module Haxor
2
+ module Vm
3
+ module Cpu
4
+ module Unit
5
+ class Arithmetic < Base
6
+ # 0x00 (not used)
7
+ OP_ADD = 0x01 # add a, b
8
+ OP_SUB = 0x02 # sub a, b
9
+ OP_DIV = 0x03 # div a
10
+ OP_MUL = 0x04 # mul a
11
+ OP_INC = 0x05 # inc a
12
+ OP_DEC = 0x06 # dec a
13
+ OP_CMP = 0x07 # cmp a, b
14
+ # 0x1f
15
+
16
+ def register
17
+ bind_opcode OP_ADD, :op_add
18
+ bind_opcode OP_SUB, :op_sub
19
+ bind_opcode OP_DIV, :op_div
20
+ bind_opcode OP_MUL, :op_mul
21
+ bind_opcode OP_INC, :op_inc
22
+ bind_opcode OP_DEC, :op_dec
23
+ bind_opcode OP_CMP, :op_cmp
24
+ end
25
+
26
+ def op_add
27
+ a, b = operands
28
+ c = @vm.subsystem(:mem).read(a) + @vm.subsystem(:mem).read(b)
29
+ @vm.subsystem(:mem).write a, c
30
+ end
31
+
32
+ def op_sub
33
+ a, b = operands
34
+ c = @vm.subsystem(:mem).read(a) - @vm.subsystem(:mem).read(b)
35
+ @vm.subsystem(:mem).write a, c
36
+ end
37
+
38
+ def op_div
39
+ a = operand
40
+ av = @vm.subsystem(:mem).read a
41
+ arv = @vm.subsystem(:mem).read 'ar'
42
+ @vm.subsystem(:mem).write 'ar', (arv / av)
43
+ @vm.subsystem(:mem).write 'dr', (arv % av)
44
+ end
45
+
46
+ def op_mul
47
+ a = operand
48
+ av = @vm.subsystem(:mem).read a
49
+ arv = @vm.subsystem(:mem).read 'ar'
50
+ @vm.subsystem(:mem).write 'ar', (arv * av)
51
+ end
52
+
53
+ def op_inc
54
+ a = operand
55
+ av = @vm.subsystem(:mem).read a
56
+ @vm.subsystem(:mem).write a, (av + 1)
57
+ end
58
+
59
+ def op_dec
60
+ a = operand
61
+ av = @vm.subsystem(:mem).read a
62
+ @vm.subsystem(:mem).write a, (av - 1)
63
+ end
64
+
65
+ def op_cmp
66
+ a, b = operands
67
+ av = @vm.subsystem(:mem).read a
68
+ bv = @vm.subsystem(:mem).read b
69
+ v = av - bv
70
+ fr_set Consts::FR_ZERO, (v == 0)
71
+ fr_set Consts::FR_SIGN, v < 0
72
+ end
73
+
74
+ def fr_set(b, enable)
75
+ flags = fetch_cell 'fr'
76
+ if enable
77
+ flags |= b
78
+ else
79
+ flags &= ~b
80
+ end
81
+ replace_cell 'fr', flags
82
+ end
83
+
84
+ def fr_if(b)
85
+ flags = fetch_cell 'fr'
86
+ (flags & b) > 0
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,46 @@
1
+ module Haxor
2
+ module Vm
3
+ module Cpu
4
+ module Unit
5
+ class Base
6
+ attr_accessor :vm
7
+
8
+ def register
9
+ fail 'this method must be implemented.'
10
+ end
11
+
12
+ def bind_opcode(opcode, method)
13
+ @vm.bind_opcode opcode, self, method
14
+ end
15
+
16
+ # TODO: BC
17
+ def next_cell
18
+ @vm.subsystem(:mem).next_word
19
+ end
20
+
21
+ # TODO: BC
22
+ def fetch_cell(addr)
23
+ @vm.subsystem(:mem).read addr
24
+ end
25
+
26
+ def dereference(addr)
27
+ @vm.subsystem(:mem).read addr
28
+ end
29
+
30
+ # TODO: BC
31
+ def replace_cell(addr, value)
32
+ @vm.subsystem(:mem).write addr, value
33
+ end
34
+
35
+ def operand
36
+ @vm.operand
37
+ end
38
+
39
+ def operands
40
+ @vm.operands
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,123 @@
1
+ module Haxor
2
+ module Vm
3
+ module Cpu
4
+ module Unit
5
+ class Jumps < Base
6
+ # 0x20
7
+ OP_CALL = 0x20 # call a
8
+ OP_JMP = 0x21 # jmp a
9
+ OP_JE = 0x22 # je a
10
+ OP_JG = 0x23 # jg a
11
+ OP_JGE = 0x24 # jge a
12
+ OP_JL = 0x25 # jl a
13
+ OP_JLE = 0x26 # jle a
14
+ OP_JNE = 0x27 # jne a
15
+ OP_JNG = 0x28 # jng a
16
+ OP_JNGE = 0x29 # jnge a
17
+ OP_JNL = 0x2a # jnl a
18
+ OP_JNLE = 0x2b # jnle a
19
+ OP_RET = 0x2c # ret
20
+ OP_IRET = 0x2d # iret
21
+ # 0x3f
22
+
23
+ def register
24
+ bind_opcode OP_CALL, :op_call
25
+ bind_opcode OP_JMP, :op_jmp
26
+ bind_opcode OP_JE, :op_je
27
+ bind_opcode OP_JG, :op_jg
28
+ bind_opcode OP_JGE, :op_jge
29
+ bind_opcode OP_JL, :op_jl
30
+ bind_opcode OP_JLE, :op_jle
31
+ bind_opcode OP_JNE, :op_jne
32
+ bind_opcode OP_JNG, :op_jng
33
+ bind_opcode OP_JNGE, :op_jnge
34
+ bind_opcode OP_JNL, :op_jnl
35
+ bind_opcode OP_JNLE, :op_jnle
36
+ bind_opcode OP_RET, :op_ret
37
+ bind_opcode OP_IRET, :op_iret
38
+ end
39
+
40
+ def fr_if(b)
41
+ flags = fetch_cell 'fr'
42
+ (flags & b) > 0
43
+ end
44
+
45
+ def op_call
46
+ a = operand
47
+ @vm.subsystem(:stack).push 'ip'
48
+ jmp a
49
+ end
50
+
51
+ def op_jmp
52
+ a = operand
53
+ jmp a
54
+ end
55
+
56
+ def op_je
57
+ a = operand
58
+ jmp a if fr_if Consts::FR_ZERO
59
+ end
60
+
61
+ def op_jg
62
+ a = operand
63
+ jmp a if !fr_if(Consts::FR_ZERO) && !fr_if(Consts::FR_SIGN)
64
+ end
65
+
66
+ def op_jge
67
+ a = operand
68
+ jmp a if !fr_if(Consts::FR_SIGN) || fr_if(Consts::FR_ZERO)
69
+ end
70
+
71
+ def op_jl
72
+ a = operand
73
+ jmp a if !fr_if(Consts::FR_ZERO) && fr_if(Consts::FR_SIGN)
74
+ end
75
+
76
+ def op_jle
77
+ a = operand
78
+ jmp a if fr_if(Consts::FR_SIGN) || fr_if(Consts::FR_ZERO)
79
+ end
80
+
81
+ def op_jne
82
+ a = operand
83
+ jmp a unless fr_if Consts::FR_ZERO
84
+ end
85
+
86
+ def op_jng
87
+ a = operand
88
+ jmp a unless !fr_if(Consts::FR_ZERO) && !fr_if(Consts::FR_SIGN)
89
+ end
90
+
91
+ def op_jnge
92
+ a = operand
93
+ jmp a unless !fr_if(Consts::FR_SIGN) || fr_if(Consts::FR_ZERO)
94
+ end
95
+
96
+ def op_jnl
97
+ a = operand
98
+ jmp a unless !fr_if(Consts::FR_ZERO) && fr_if(Consts::FR_SIGN)
99
+ end
100
+
101
+ def op_jnle
102
+ a = operand
103
+ jmp a unless fr_if(Consts::FR_SIGN) || fr_if(Consts::FR_ZERO)
104
+ end
105
+
106
+ def op_ret
107
+ @vm.subsystem(:stack).pop 'ip'
108
+ end
109
+
110
+ def op_iret
111
+ @vm.subsystem(:stack).pop 'ip'
112
+ end
113
+
114
+ private
115
+
116
+ def jmp(addr)
117
+ @vm.subsystem(:mem).write 'ip', addr
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end