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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +27 -0
- data/README.md +414 -0
- data/Rakefile +1 -0
- data/bin/hcc +21 -0
- data/bin/hld +38 -0
- data/bin/hvm +17 -0
- data/examples/build.sh +10 -0
- data/examples/guess-the-number.hax +100 -0
- data/haxor.gemspec +24 -0
- data/lib/haxor.rb +44 -0
- data/lib/haxor/compiler/component/arithmetic.rb +55 -0
- data/lib/haxor/compiler/component/base.rb +37 -0
- data/lib/haxor/compiler/component/data.rb +32 -0
- data/lib/haxor/compiler/component/jumps.rb +95 -0
- data/lib/haxor/compiler/component/logical.rb +43 -0
- data/lib/haxor/compiler/component/other.rb +21 -0
- data/lib/haxor/compiler/component/transfer.rb +29 -0
- data/lib/haxor/compiler/component/various.rb +33 -0
- data/lib/haxor/compiler/core.rb +134 -0
- data/lib/haxor/compiler/section.rb +6 -0
- data/lib/haxor/compiler/unit.rb +39 -0
- data/lib/haxor/consts.rb +28 -0
- data/lib/haxor/header.rb +40 -0
- data/lib/haxor/linker.rb +89 -0
- data/lib/haxor/token/base.rb +7 -0
- data/lib/haxor/token/cmd.rb +9 -0
- data/lib/haxor/token/data.rb +17 -0
- data/lib/haxor/token/int64.rb +17 -0
- data/lib/haxor/token/label.rb +23 -0
- data/lib/haxor/token/pointer.rb +13 -0
- data/lib/haxor/vm/core.rb +53 -0
- data/lib/haxor/vm/cpu/core.rb +129 -0
- data/lib/haxor/vm/cpu/unit/arithmetic.rb +92 -0
- data/lib/haxor/vm/cpu/unit/base.rb +46 -0
- data/lib/haxor/vm/cpu/unit/jumps.rb +123 -0
- data/lib/haxor/vm/cpu/unit/logical.rb +59 -0
- data/lib/haxor/vm/cpu/unit/transfer.rb +37 -0
- data/lib/haxor/vm/cpu/unit/various.rb +47 -0
- data/lib/haxor/vm/mem.rb +101 -0
- data/lib/haxor/vm/os.rb +115 -0
- data/lib/haxor/vm/stack.rb +31 -0
- data/lib/haxor/vm/subsystem.rb +16 -0
- data/media/memory.png +0 -0
- data/media/vm.png +0 -0
- metadata +122 -0
@@ -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,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
|