haxor 0.1.0

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