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,43 @@
1
+ module Haxor
2
+ module Compiler
3
+ module Component
4
+ class Logical < Base
5
+ def register
6
+ bind_cmd 'and', :cmd_and
7
+ bind_cmd 'neg', :cmd_neg
8
+ bind_cmd 'not', :cmd_not
9
+ bind_cmd 'or', :cmd_or
10
+ bind_cmd 'xor', :cmd_xor
11
+ end
12
+
13
+ def cmd_and(a, b)
14
+ add Token::Cmd.new(Vm::Cpu::Unit::Logical::OP_AND | offset_flags(a, b))
15
+ parse_value a
16
+ parse_value b
17
+ end
18
+
19
+ def cmd_neg(a)
20
+ add Token::Cmd.new(Vm::Cpu::Unit::Logical::OP_NEG | offset_flags(a))
21
+ parse_value a
22
+ end
23
+
24
+ def cmd_not(a)
25
+ add Token::Cmd.new(Vm::Cpu::Unit::Logical::OP_NOT | offset_flags(a))
26
+ parse_value a
27
+ end
28
+
29
+ def cmd_or(a, b)
30
+ add Token::Cmd.new(Vm::Cpu::Unit::Logical::OP_OR | offset_flags(a, b))
31
+ parse_value a
32
+ parse_value b
33
+ end
34
+
35
+ def cmd_xor(a, b)
36
+ add Token::Cmd.new(Vm::Cpu::Unit::Logical::OP_XOR | offset_flags(a, b))
37
+ parse_value a
38
+ parse_value b
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ module Haxor
2
+ module Compiler
3
+ module Component
4
+ class Other < Base
5
+ def register
6
+ bind_cmd 'label', :cmd_label
7
+ bind_cmd 'rem', :cmd_rem
8
+ bind_cmd '#', :cmd_rem
9
+ end
10
+
11
+ def cmd_rem(*_args)
12
+ # nothing
13
+ end
14
+
15
+ def cmd_label(*args)
16
+ add Token::Label.new(args[0])
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,29 @@
1
+ module Haxor
2
+ module Compiler
3
+ module Component
4
+ class Transfer < Base
5
+ def register
6
+ bind_cmd 'mov', :cmd_mov
7
+ bind_cmd 'push', :cmd_push
8
+ bind_cmd 'pop', :cmd_pop
9
+ end
10
+
11
+ def cmd_push(a)
12
+ add Token::Cmd.new(Vm::Cpu::Unit::Transfer::OP_PUSH | offset_flags(a))
13
+ parse_value a
14
+ end
15
+
16
+ def cmd_pop(a)
17
+ add Token::Cmd.new(Vm::Cpu::Unit::Transfer::OP_POP | offset_flags(a))
18
+ parse_value a
19
+ end
20
+
21
+ def cmd_mov(a, b)
22
+ add Token::Cmd.new(Vm::Cpu::Unit::Transfer::OP_MOV | offset_flags(a, b))
23
+ parse_value a
24
+ parse_value b
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,33 @@
1
+ module Haxor
2
+ module Compiler
3
+ module Component
4
+ class Various < Base
5
+ def register
6
+ bind_cmd 'nop', :cmd_nop
7
+ bind_cmd 'lea', :cmd_lea
8
+ bind_cmd 'int', :cmd_int
9
+ bind_cmd 'syscall', :cmd_syscall
10
+ end
11
+
12
+ def cmd_nop(*_args)
13
+ add Token::Cmd.new(Vm::Cpu::Unit::Various::OP_NOP)
14
+ end
15
+
16
+ def cmd_lea(a, b)
17
+ add Token::Cmd.new(Vm::Cpu::Unit::Various::OP_LEA | offset_flags(a, b))
18
+ parse_value a
19
+ parse_value b
20
+ end
21
+
22
+ def cmd_int(a)
23
+ add Token::Cmd.new(Vm::Cpu::Unit::Various::OP_INT)
24
+ parse_value a
25
+ end
26
+
27
+ def cmd_syscall
28
+ add Token::Cmd.new(Vm::Cpu::Unit::Various::OP_SYSCALL)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,134 @@
1
+ module Haxor
2
+ module Compiler
3
+ class Core
4
+ def initialize
5
+ @units = []
6
+ @cmds = {}
7
+ @autolabel = 0
8
+ @prev_sections = []
9
+
10
+ bind_cmd 'section', self, :cmd_section
11
+ end
12
+
13
+ def register_unit(unit)
14
+ @units << unit
15
+ unit.compiler = self
16
+ unit.register
17
+ end
18
+
19
+ def bind_cmd(cmd, object, method)
20
+ @cmds[cmd] = {
21
+ object: object,
22
+ method: method
23
+ }
24
+ end
25
+
26
+ def cmd_section(name)
27
+ @unit.section = name[1..-1].to_sym
28
+ end
29
+
30
+ # this is ugly and must be reworked
31
+ def split_arguments(string)
32
+ inside_quotes = false
33
+ splits = []
34
+ string.each_char.with_index(0) do |x, i|
35
+ if x == '"' && string[i - 1] != '\\'
36
+ inside_quotes ^= true
37
+ end
38
+
39
+ if x == ',' && !inside_quotes
40
+ splits << i
41
+ end
42
+ end
43
+
44
+ splits << string.size
45
+
46
+ last_x = 0
47
+ args = []
48
+ splits.each do |x|
49
+ args << string[last_x...x]
50
+ last_x = x + 1
51
+ end
52
+ args.map!(&:strip).delete_if { |x| x.length == 0 }
53
+ end
54
+
55
+ def compile(filename)
56
+ input = File.read(filename, encoding: 'ASCII-8BIT')
57
+
58
+ @unit = Unit.new
59
+
60
+ input.lines.map(&:chomp).each_with_index do |line, index|
61
+ next if line.empty?
62
+
63
+ tmp = line.split ' ', 2
64
+ cmd = tmp[0]
65
+ args = split_arguments(tmp[1] || '')
66
+
67
+ fail "Unknown command #{cmd} in line #{index}." unless @cmds.key? cmd
68
+
69
+ @cmds[cmd][:object].send(@cmds[cmd][:method], *args)
70
+ end
71
+
72
+ @unit.save(filename + '.u')
73
+ end
74
+
75
+ def add(token)
76
+ @unit.add token
77
+ end
78
+
79
+ def parse_number(value)
80
+ md = value.match(/\A([-+]?[0-9]+[0-9A-F]*)([bhd]?)\z/)
81
+ fail if md.nil?
82
+
83
+ case md[2]
84
+ when 'b'
85
+ base = 2
86
+ when 'h'
87
+ base = 16
88
+ when 'd'
89
+ else
90
+ base = 10
91
+ end
92
+
93
+ md[1].to_i(base)
94
+ end
95
+
96
+ def parse_value(value)
97
+ value = strip_offset value
98
+
99
+ begin
100
+ number = parse_number(value)
101
+ @autolabel += 1
102
+ label = "__autolabel_#{@autolabel}"
103
+
104
+ old_section = @unit.section
105
+ @unit.section = :data
106
+ add Token::Label.new(label)
107
+ add Token::Int64.new(number)
108
+ @unit.section = old_section
109
+
110
+ add Token::Pointer.new(label)
111
+ rescue
112
+ add Token::Pointer.new(value)
113
+ end
114
+ end
115
+
116
+ def offset_flags(a, b = nil)
117
+ result = 0
118
+ result |= Consts::OPCODE_FLG_DA if offset?(a)
119
+ result |= Consts::OPCODE_FLG_DB if offset?(b)
120
+ result
121
+ end
122
+
123
+ def offset?(value)
124
+ return false unless value.is_a? String
125
+ value.start_with?('[') && value.end_with?(']')
126
+ end
127
+
128
+ def strip_offset(value)
129
+ return value[1...-1] if offset?(value)
130
+ value
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,6 @@
1
+ module Haxor
2
+ module Compiler
3
+ class Section
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,39 @@
1
+ module Haxor
2
+ module Compiler
3
+ class Unit
4
+ attr_reader :section
5
+
6
+ def initialize
7
+ @section = :text
8
+ @sections = {
9
+ text: [],
10
+ data: [],
11
+ bss: []
12
+ }
13
+ end
14
+
15
+ def add(item)
16
+ @sections[@section] << item
17
+ end
18
+
19
+ def section=(section)
20
+ fail unless @sections.key? section
21
+ @section = section
22
+ end
23
+
24
+ def tokens
25
+ @sections[@section]
26
+ end
27
+
28
+ def self.load(filename)
29
+ Marshal.load File.read(filename)
30
+ end
31
+
32
+ def save(filename)
33
+ fd = File.open(filename, 'wb')
34
+ fd.write Marshal.dump(self)
35
+ fd.close
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,28 @@
1
+ module Haxor
2
+ class Consts
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ PATCH = 0
6
+ GEM_VERSION = "#{MAJOR}.#{MINOR}.#{PATCH}"
7
+ VERSION = (MAJOR << 16) | (MINOR << 8) | PATCH
8
+
9
+ ROOT_PATH = __dir__ + '/../..'
10
+
11
+ WORD_SIZE = 8 # 64bit
12
+ WORD_UNPACK = 'q<'
13
+
14
+ RESERVED_MEM = 2048 # 1024 for CPU, 1024 for IVT
15
+ IVT_ADDR = 1024
16
+
17
+ # OpCode
18
+ OPCODE_CMD_MASK = 0x0000_0000_0000_00ff
19
+ OPCODE_FLG_MASK = 0xffff_ffff_ffff_ff00
20
+ OPCODE_FLG_OFFSET = 8
21
+ OPCODE_FLG_DA = 1 << OPCODE_FLG_OFFSET # dereference A operand
22
+ OPCODE_FLG_DB = 2 << OPCODE_FLG_OFFSET # dereference B operand
23
+
24
+ # Flags Registry Flags
25
+ FR_ZERO = 1 << 0 # a-b == 0
26
+ FR_SIGN = 1 << 1 # a-b < 0
27
+ end
28
+ end
@@ -0,0 +1,40 @@
1
+ module Haxor
2
+ class Header
3
+ MAGIC = 0x72_65_88_79_82 # HAXOR (ASCII)
4
+ SIZE = 64 # max 8 values (64bit per entry)
5
+
6
+ attr_accessor :version
7
+ attr_accessor :entry_point
8
+ attr_accessor :bss_size
9
+ attr_accessor :stack_size
10
+
11
+ def initialize
12
+ @magic = MAGIC
13
+ end
14
+
15
+ def dump
16
+ result = ''
17
+ result << [
18
+ @magic,
19
+ @version,
20
+ @entry_point,
21
+ @bss_size,
22
+ @stack_size
23
+ ].pack('q<*')
24
+ result.ljust(SIZE)
25
+ end
26
+
27
+ def parse!(data)
28
+ data = data.unpack('q<*')
29
+ @magic = data.shift
30
+ @version = data.shift
31
+ @entry_point = data.shift
32
+ @bss_size = data.shift
33
+ @stack_size = data.shift
34
+ end
35
+
36
+ def size
37
+ SIZE
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,89 @@
1
+ module Haxor
2
+ class Linker
3
+ attr_accessor :stack
4
+
5
+ SECTIONS = [:text, :data, :bss]
6
+
7
+ def initialize
8
+ @cpu = Vm::Cpu::Core.new
9
+ @units = []
10
+ @tokens = []
11
+ @labels = @cpu.labels.clone
12
+ @stack = 4096
13
+ end
14
+
15
+ def load_unit(filename)
16
+ @units << Haxor::Compiler::Unit.load(filename)
17
+ end
18
+
19
+ def link(filename)
20
+ calc_absolute_addr
21
+ collect_labels
22
+ unwind_pointers
23
+
24
+ output = File.open(filename, 'wb')
25
+ output.write build
26
+ output.close
27
+ end
28
+
29
+ private
30
+
31
+ def walk_tokens(type = nil)
32
+ SECTIONS.each do |section|
33
+ @units.each do |unit|
34
+ unit.section = section
35
+ unit.tokens.each do |token|
36
+ next unless type.nil? || token.is_a?(type)
37
+ yield token, section
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def calc_absolute_addr
44
+ addr = Consts::RESERVED_MEM
45
+ walk_tokens do |token|
46
+ token.absolute_addr = addr
47
+ addr += token.size
48
+ end
49
+ end
50
+
51
+ def collect_labels
52
+ walk_tokens(Token::Label) do |token|
53
+ fail "Label already exists: #{token.label}." if @labels.key? token.label
54
+ @labels[token.label] = token
55
+ end
56
+ end
57
+
58
+ def unwind_pointers
59
+ walk_tokens(Token::Pointer) do |token|
60
+ fail "Label not found: #{token.label}." unless @labels.key? token.label
61
+ token.data = @labels[token.label].absolute_addr
62
+ end
63
+ end
64
+
65
+ def build_header
66
+ bss_size = 0
67
+ walk_tokens do |token, section|
68
+ bss_size += token.size if section == :bss
69
+ end
70
+
71
+ hdr = Header.new
72
+ hdr.version = Consts::VERSION
73
+ hdr.entry_point = @labels['main'].absolute_addr
74
+ hdr.stack_size = @stack
75
+ hdr.bss_size = bss_size
76
+ hdr
77
+ end
78
+
79
+ def build
80
+ result = build_header.dump
81
+ walk_tokens do |token, section|
82
+ next unless [:text, :data].include? section
83
+ puts "[#{section}] [#{token.absolute_addr}] #{token}"
84
+ result << token.to_bytecode
85
+ end
86
+ result
87
+ end
88
+ end
89
+ end