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