haxor 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +101 -335
- data/bin/{hcc → hc} +1 -9
- data/bin/hvm +13 -8
- data/examples/build.sh +1 -1
- data/examples/guess-the-number.hax +65 -76
- data/lib/haxor.rb +2 -14
- data/lib/haxor/compiler/core.rb +249 -18
- data/lib/haxor/consts.rb +4 -17
- data/lib/haxor/linker.rb +12 -4
- data/lib/haxor/token/cmd.rb +29 -2
- data/lib/haxor/utils.rb +24 -0
- data/lib/haxor/vm/core.rb +6 -9
- data/lib/haxor/vm/cpu/core.rb +214 -83
- data/lib/haxor/vm/mem.rb +1 -36
- data/lib/haxor/vm/os.rb +7 -13
- data/lib/haxor/vm/stack.rb +4 -4
- data/media/memory.png +0 -0
- metadata +5 -19
- data/lib/haxor/compiler/component/arithmetic.rb +0 -45
- data/lib/haxor/compiler/component/base.rb +0 -41
- data/lib/haxor/compiler/component/data.rb +0 -32
- data/lib/haxor/compiler/component/jumps.rb +0 -83
- data/lib/haxor/compiler/component/logical.rb +0 -35
- data/lib/haxor/compiler/component/other.rb +0 -21
- data/lib/haxor/compiler/component/transfer.rb +0 -25
- data/lib/haxor/compiler/component/various.rb +0 -30
- data/lib/haxor/vm/cpu/unit/arithmetic.rb +0 -78
- data/lib/haxor/vm/cpu/unit/base.rb +0 -46
- data/lib/haxor/vm/cpu/unit/jumps.rb +0 -118
- data/lib/haxor/vm/cpu/unit/logical.rb +0 -59
- data/lib/haxor/vm/cpu/unit/transfer.rb +0 -37
- data/lib/haxor/vm/cpu/unit/various.rb +0 -47
- data/media/vm.png +0 -0
data/lib/haxor/consts.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Haxor
|
2
2
|
class Consts
|
3
3
|
MAJOR = 0
|
4
|
-
MINOR =
|
4
|
+
MINOR = 4
|
5
5
|
PATCH = 0
|
6
6
|
GEM_VERSION = "#{MAJOR}.#{MINOR}.#{PATCH}"
|
7
7
|
VERSION = (MAJOR << 16) | (MINOR << 8) | PATCH
|
@@ -11,21 +11,8 @@ module Haxor
|
|
11
11
|
WORD_SIZE = 8 # 64bit
|
12
12
|
WORD_UNPACK = 'q<'
|
13
13
|
|
14
|
-
|
15
|
-
IVT_ADDR =
|
16
|
-
|
17
|
-
# OpCode
|
18
|
-
OPCODE_CMD_MASK = 0x0000_0000_0000_00ff
|
19
|
-
OPCODE_FLG_MASK = 0xffff_ffff_ffff_ff00 # << 8
|
20
|
-
OPCODE_FLG_OFFSET = 8
|
21
|
-
# 8 bits of flag - 1st operand
|
22
|
-
# 8 bits of flag - 2nd operand
|
23
|
-
|
24
|
-
OPERAND_FLAGS = 8 # how many bits per operand
|
25
|
-
OPERAND_DEREFERENCE = (1 << 0) # Dereference operand (aka *operand)
|
26
|
-
|
27
|
-
# Flags Registry Flags
|
28
|
-
FR_ZERO = 1 << 0 # a-b == 0
|
29
|
-
FR_SIGN = 1 << 1 # a-b < 0
|
14
|
+
IVT_MEM = 1024
|
15
|
+
IVT_ADDR = 0
|
16
|
+
RESERVED_MEM = IVT_MEM
|
30
17
|
end
|
31
18
|
end
|
data/lib/haxor/linker.rb
CHANGED
@@ -8,7 +8,7 @@ module Haxor
|
|
8
8
|
@cpu = Vm::Cpu::Core.new
|
9
9
|
@units = []
|
10
10
|
@tokens = []
|
11
|
-
@labels =
|
11
|
+
@labels = {}
|
12
12
|
@stack = 4096
|
13
13
|
end
|
14
14
|
|
@@ -56,9 +56,17 @@ module Haxor
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def unwind_pointers
|
59
|
-
walk_tokens(Token::
|
60
|
-
|
61
|
-
token.
|
59
|
+
walk_tokens(Token::Cmd) do |token|
|
60
|
+
next unless token.imm.is_a? String
|
61
|
+
fail "Label not found: #{token.imm}." unless @labels.key? token.imm
|
62
|
+
|
63
|
+
token.imm = @labels[token.imm].absolute_addr
|
64
|
+
|
65
|
+
if token.opts.include? :rel_imm
|
66
|
+
token.imm -= token.absolute_addr + Consts::WORD_SIZE
|
67
|
+
end
|
68
|
+
|
69
|
+
token.imm /= Consts::WORD_SIZE if token.opts.include? :x8
|
62
70
|
end
|
63
71
|
end
|
64
72
|
|
data/lib/haxor/token/cmd.rb
CHANGED
@@ -1,8 +1,35 @@
|
|
1
1
|
module Haxor
|
2
2
|
module Token
|
3
|
-
class Cmd <
|
3
|
+
class Cmd < Base
|
4
|
+
attr_accessor :cmd
|
5
|
+
attr_accessor :flags
|
6
|
+
attr_accessor :reg1
|
7
|
+
attr_accessor :reg2
|
8
|
+
attr_accessor :reg3
|
9
|
+
attr_accessor :imm
|
10
|
+
attr_accessor :opts
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@cmd = 0
|
14
|
+
@flags = 0
|
15
|
+
@reg1 = 0
|
16
|
+
@reg2 = 0
|
17
|
+
@reg3 = 0
|
18
|
+
@imm = 0
|
19
|
+
@opts = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def size
|
23
|
+
Consts::WORD_SIZE
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_bytecode
|
27
|
+
data = Utils.encode_opcode @cmd, @flags, @reg1, @reg2, @reg3, @imm
|
28
|
+
[data].pack Consts::WORD_UNPACK
|
29
|
+
end
|
30
|
+
|
4
31
|
def to_s
|
5
|
-
"
|
32
|
+
"CMD code:[0x#{@cmd.to_s(16)}], flags:[#{@flags.to_s(2)}], regs:[#{@reg1}, #{@reg2}, #{@reg3}], imm:[#{@imm}], opts:#{@opts}"
|
6
33
|
end
|
7
34
|
end
|
8
35
|
end
|
data/lib/haxor/utils.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module Haxor
|
2
|
+
module Utils
|
3
|
+
def self.encode_opcode(cmd = 0, flags = 0, reg1 = 0, reg2 = 0, reg3 = 0, imm = 0)
|
4
|
+
result = cmd
|
5
|
+
result |= flags << 7
|
6
|
+
result |= reg1 << 9
|
7
|
+
result |= reg2 << 15
|
8
|
+
result |= reg3 << 21
|
9
|
+
result |= imm << 27
|
10
|
+
result
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.decode_opcode(opcode)
|
14
|
+
r = OpenStruct.new
|
15
|
+
r.cmd = opcode & 0x7f
|
16
|
+
r.flags = (opcode >> 7) & 0x03
|
17
|
+
r.reg1 = (opcode >> 9) & 0x3f
|
18
|
+
r.reg2 = (opcode >> 15) & 0x3f
|
19
|
+
r.reg3 = (opcode >> 21) & 0x3f
|
20
|
+
r.imm = (opcode >> 27)
|
21
|
+
r
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/haxor/vm/core.rb
CHANGED
@@ -9,12 +9,7 @@ module Haxor
|
|
9
9
|
register_subsystem :mem, Mem.new(Consts::RESERVED_MEM)
|
10
10
|
register_subsystem :stack, Stack.new
|
11
11
|
register_subsystem :os, Os.new
|
12
|
-
register_subsystem :registers, Registers.new
|
13
|
-
|
14
|
-
subsystem(:cpu).labels.each do |_, label|
|
15
|
-
subsystem(:mem).add_label label.label, label.absolute_addr
|
16
|
-
subsystem(:registers).add_register label.label, label.absolute_addr
|
17
|
-
end
|
12
|
+
# register_subsystem :registers, Registers.new
|
18
13
|
|
19
14
|
@units = []
|
20
15
|
@opcodes = {}
|
@@ -41,14 +36,16 @@ module Haxor
|
|
41
36
|
@hdr = Header.new
|
42
37
|
@hdr.parse! exe
|
43
38
|
|
44
|
-
|
39
|
+
if @hdr.version != Consts::VERSION
|
40
|
+
fail 'Program is compiled for different version of Haxor VM Machine'
|
41
|
+
end
|
45
42
|
|
46
43
|
exe = exe[@hdr.size..-1] # cut off header
|
47
44
|
subsystem(:mem).replace_region Consts::RESERVED_MEM, exe
|
48
|
-
subsystem(:
|
45
|
+
subsystem(:cpu).ip = @hdr.entry_point # instruction pointer
|
49
46
|
subsystem(:mem).enlarge @hdr.bss_size
|
50
47
|
subsystem(:mem).enlarge @hdr.stack_size
|
51
|
-
subsystem(:
|
48
|
+
subsystem(:cpu).reg Vm::Cpu::Core::REG_STACK, subsystem(:mem).size
|
52
49
|
end
|
53
50
|
end
|
54
51
|
end
|
data/lib/haxor/vm/cpu/core.rb
CHANGED
@@ -2,126 +2,257 @@ module Haxor
|
|
2
2
|
module Vm
|
3
3
|
module Cpu
|
4
4
|
class Core < Subsystem
|
5
|
-
|
6
|
-
|
5
|
+
attr_accessor :ip
|
6
|
+
|
7
|
+
# Misc
|
8
|
+
OP_NOP = 0x00
|
9
|
+
OP_EXITI = 0x01
|
10
|
+
OP_SYSCALL = 0x02
|
11
|
+
|
12
|
+
# Arithmetic
|
13
|
+
OP_ADD = 0x10
|
14
|
+
OP_ADDI = 0x11
|
15
|
+
OP_SUB = 0x12
|
16
|
+
OP_MULT = 0x13
|
17
|
+
OP_DIV = 0x14
|
18
|
+
OP_MOD = 0x15
|
19
|
+
|
20
|
+
# Data transfer
|
21
|
+
OP_LW = 0x20
|
22
|
+
OP_SW = 0x21
|
23
|
+
OP_LUI = 0x22
|
24
|
+
|
25
|
+
# Logical
|
26
|
+
OP_AND = 0x30
|
27
|
+
OP_ANDI = 0x31
|
28
|
+
OP_OR = 0x32
|
29
|
+
OP_ORI = 0x33
|
30
|
+
OP_XOR = 0x34
|
31
|
+
OP_NOR = 0x35
|
32
|
+
OP_SLT = 0x36
|
33
|
+
OP_SLTI = 0x37
|
34
|
+
|
35
|
+
# Bitwise shift
|
36
|
+
OP_SLLI = 0x40
|
37
|
+
OP_SRLI = 0x41
|
38
|
+
OP_SLL = 0x42
|
39
|
+
OP_SRL = 0x43
|
40
|
+
|
41
|
+
# Branch/Jumps
|
42
|
+
OP_BEQ = 0x50
|
43
|
+
OP_BEQL = 0x51
|
44
|
+
OP_BNE = 0x52
|
45
|
+
OP_BNEL = 0x53
|
46
|
+
OP_J = 0x54
|
47
|
+
OP_JR = 0x55
|
48
|
+
OP_JAL = 0x56
|
49
|
+
|
50
|
+
REG_ZERO = 0
|
51
|
+
REG_STACK = 61
|
52
|
+
REG_RETURN = 62
|
53
|
+
REG_SYSCALL = 63
|
7
54
|
|
8
55
|
def initialize
|
56
|
+
@registers = Array.new(64, 0)
|
9
57
|
@units = []
|
10
58
|
@opcodes = {}
|
59
|
+
init_opcodes
|
60
|
+
end
|
11
61
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
62
|
+
def init_opcodes
|
63
|
+
bind_opcode OP_NOP, :op_nop
|
64
|
+
bind_opcode OP_ADD, :op_add
|
65
|
+
bind_opcode OP_ADDI, :op_addi
|
66
|
+
bind_opcode OP_SUB, :op_sub
|
67
|
+
bind_opcode OP_MULT, :op_mult
|
68
|
+
bind_opcode OP_DIV, :op_div
|
69
|
+
bind_opcode OP_MOD, :op_mod
|
70
|
+
bind_opcode OP_LW, :op_lw
|
71
|
+
bind_opcode OP_SW, :op_sw
|
72
|
+
bind_opcode OP_LUI, :op_lui
|
73
|
+
bind_opcode OP_AND, :op_and
|
74
|
+
bind_opcode OP_ANDI, :op_andi
|
75
|
+
bind_opcode OP_OR, :op_or
|
76
|
+
bind_opcode OP_ORI, :op_ori
|
77
|
+
bind_opcode OP_XOR, :op_xor
|
78
|
+
bind_opcode OP_NOR, :op_nor
|
79
|
+
bind_opcode OP_SLT, :op_slt
|
80
|
+
bind_opcode OP_SLTI, :op_slti
|
81
|
+
bind_opcode OP_SLLI, :op_slli
|
82
|
+
bind_opcode OP_SRLI, :op_srli
|
83
|
+
bind_opcode OP_SLL, :op_sll
|
84
|
+
bind_opcode OP_SRL, :op_srl
|
85
|
+
bind_opcode OP_BEQ, :op_beq
|
86
|
+
bind_opcode OP_BEQL, :op_beql
|
87
|
+
bind_opcode OP_BNE, :op_bne
|
88
|
+
bind_opcode OP_BNEL, :op_bnel
|
89
|
+
bind_opcode OP_J, :op_j
|
90
|
+
bind_opcode OP_JR, :op_jr
|
91
|
+
bind_opcode OP_JAL, :op_jal
|
92
|
+
bind_opcode OP_EXITI, :op_exiti
|
93
|
+
bind_opcode OP_SYSCALL, :op_syscall
|
94
|
+
end
|
17
95
|
|
18
|
-
|
96
|
+
def op_nop(info)
|
19
97
|
end
|
20
98
|
|
21
|
-
def
|
22
|
-
|
23
|
-
@opcodes[opcode] = {
|
24
|
-
object: object,
|
25
|
-
method: method
|
26
|
-
}
|
99
|
+
def op_add(info)
|
100
|
+
reg info.reg1, reg(info.reg2) + reg(info.reg3)
|
27
101
|
end
|
28
102
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
32
|
-
|
103
|
+
def op_addi(info)
|
104
|
+
reg info.reg1, reg(info.reg2) + info.imm
|
105
|
+
end
|
106
|
+
|
107
|
+
def op_sub(info)
|
108
|
+
reg info.reg1, reg(info.reg2) - reg(info.reg3)
|
109
|
+
end
|
110
|
+
|
111
|
+
def op_mult(info)
|
112
|
+
reg info.reg1, reg(info.reg2) * reg(info.reg3)
|
113
|
+
end
|
114
|
+
|
115
|
+
def op_div(info)
|
116
|
+
reg info.reg1, reg(info.reg2) / reg(info.reg3)
|
117
|
+
end
|
118
|
+
|
119
|
+
def op_mod(info)
|
120
|
+
reg info.reg1, reg(info.reg2) % reg(info.reg3)
|
121
|
+
end
|
122
|
+
|
123
|
+
# reg1 = memory[reg2+imm]
|
124
|
+
def op_lw(info)
|
125
|
+
addr = reg(info.reg2) + info.imm
|
126
|
+
reg info.reg1, subsystem(:mem).read(addr)
|
127
|
+
end
|
128
|
+
|
129
|
+
# memory[reg1+imm] = reg2
|
130
|
+
def op_sw(info)
|
131
|
+
addr = reg(info.reg1) + info.imm
|
132
|
+
subsystem(:mem).write addr, reg(info.reg2)
|
133
|
+
end
|
134
|
+
|
135
|
+
def op_lui(info)
|
136
|
+
reg info.reg1, (info.imm << 32)
|
137
|
+
end
|
138
|
+
|
139
|
+
def op_and(info)
|
140
|
+
reg info.reg1, reg(info.reg2) & reg(info.reg3)
|
141
|
+
end
|
142
|
+
|
143
|
+
def op_andi(info)
|
144
|
+
reg info.reg1, reg(info.reg2) & info.imm
|
145
|
+
end
|
33
146
|
|
34
|
-
|
35
|
-
|
36
|
-
# puts flg.to_s(16)
|
37
|
-
@opcodes[cmd][:object].send(@opcodes[cmd][:method])
|
147
|
+
def op_or(info)
|
148
|
+
reg info.reg1, reg(info.reg2) | reg(info.reg3)
|
38
149
|
end
|
39
150
|
|
40
|
-
def
|
41
|
-
|
151
|
+
def op_ori(info)
|
152
|
+
reg info.reg1, reg(info.reg2) | info.imm
|
42
153
|
end
|
43
154
|
|
44
|
-
def
|
45
|
-
|
46
|
-
unit.vm = self
|
47
|
-
unit.register
|
155
|
+
def op_xor(info)
|
156
|
+
reg info.reg1, reg(info.reg2) ^ reg(info.reg3)
|
48
157
|
end
|
49
158
|
|
50
|
-
def
|
51
|
-
|
159
|
+
def op_nor(info)
|
160
|
+
reg info.reg1, ~(reg(info.reg2) | reg(info.reg3))
|
52
161
|
end
|
53
162
|
|
54
|
-
def
|
55
|
-
|
56
|
-
|
163
|
+
def op_slt(info)
|
164
|
+
reg info.reg1, reg(info.reg2) < reg(info.reg3) ? 1 : 0
|
165
|
+
end
|
57
166
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
v = subsystem(:mem).read a if (flg & Consts::OPERAND_DEREFERENCE != 0)
|
62
|
-
result << v
|
63
|
-
flg << Consts::OPERAND_FLAGS
|
64
|
-
end
|
167
|
+
def op_slti(info)
|
168
|
+
reg info.reg1, reg(info.reg2) < info.imm ? 1 : 0
|
169
|
+
end
|
65
170
|
|
66
|
-
|
171
|
+
def op_slli(info)
|
172
|
+
reg info.reg1, reg(info.reg2) << info.imm
|
67
173
|
end
|
68
174
|
|
69
|
-
|
175
|
+
def op_srli(info)
|
176
|
+
reg info.reg1, reg(info.reg2) >> info.imm
|
177
|
+
end
|
70
178
|
|
71
|
-
def
|
72
|
-
|
179
|
+
def op_sll(info)
|
180
|
+
reg info.reg1, reg(info.reg2) << reg(info.reg3)
|
181
|
+
end
|
73
182
|
|
74
|
-
|
75
|
-
|
183
|
+
def op_srl(info)
|
184
|
+
reg info.reg1, reg(info.reg2) >> reg(info.reg3)
|
185
|
+
end
|
186
|
+
|
187
|
+
def op_beq(info)
|
188
|
+
branch(info.imm) if reg(info.reg1) == reg(info.reg2)
|
189
|
+
end
|
190
|
+
|
191
|
+
def op_beql(info)
|
192
|
+
return if reg(info.reg1) != reg(info.reg2)
|
193
|
+
|
194
|
+
reg REG_RETURN, @ip
|
195
|
+
branch(info.imm)
|
196
|
+
end
|
197
|
+
|
198
|
+
def op_bne(info)
|
199
|
+
branch info.imm if reg(info.reg1) != reg(info.reg2)
|
200
|
+
end
|
76
201
|
|
77
|
-
|
202
|
+
def op_bnel(info)
|
203
|
+
return if reg(info.reg1) == reg(info.reg2)
|
78
204
|
|
79
|
-
|
80
|
-
|
81
|
-
|
205
|
+
reg REG_RETURN, @ip
|
206
|
+
branch(info.imm)
|
207
|
+
end
|
82
208
|
|
83
|
-
|
84
|
-
|
85
|
-
|
209
|
+
def op_j(info)
|
210
|
+
jmp info.imm
|
211
|
+
end
|
86
212
|
|
87
|
-
|
88
|
-
@
|
89
|
-
|
213
|
+
def op_jr(info)
|
214
|
+
@ip = reg(info.reg1)
|
215
|
+
end
|
90
216
|
|
91
|
-
|
92
|
-
|
93
|
-
|
217
|
+
def op_jal(info)
|
218
|
+
reg REG_RETURN, @ip
|
219
|
+
jmp info.imm
|
220
|
+
end
|
94
221
|
|
95
|
-
|
96
|
-
|
97
|
-
|
222
|
+
def op_exiti(info)
|
223
|
+
exit info.imm
|
224
|
+
end
|
98
225
|
|
99
|
-
|
100
|
-
@
|
101
|
-
|
226
|
+
def op_syscall(_info)
|
227
|
+
@vm.subsystem(:os).syscall
|
228
|
+
end
|
102
229
|
|
103
|
-
|
104
|
-
@
|
105
|
-
|
230
|
+
def reg(id, value = nil)
|
231
|
+
return @registers[id] if value.nil?
|
232
|
+
return if id == REG_ZERO # $0 cannot be overwritten
|
233
|
+
@registers[id] = value
|
234
|
+
end
|
106
235
|
|
107
|
-
|
108
|
-
@
|
109
|
-
|
236
|
+
def jmp(addr)
|
237
|
+
@ip = addr * Consts::WORD_SIZE
|
238
|
+
end
|
110
239
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
@struct << Token::Int64.new(0)
|
115
|
-
end
|
240
|
+
def branch(rel_addr)
|
241
|
+
@ip += rel_addr * Consts::WORD_SIZE
|
242
|
+
end
|
116
243
|
|
117
|
-
|
118
|
-
|
119
|
-
@
|
120
|
-
|
121
|
-
|
244
|
+
def bind_opcode(opcode, method)
|
245
|
+
fail "OpCode already defined - #{opcode}." if @opcodes.key? opcode
|
246
|
+
@opcodes[opcode] = {
|
247
|
+
method: method
|
248
|
+
}
|
249
|
+
end
|
122
250
|
|
123
|
-
|
124
|
-
|
251
|
+
def iterate
|
252
|
+
opcode = subsystem(:mem).read @ip
|
253
|
+
@ip += Consts::WORD_SIZE
|
254
|
+
info = Utils.decode_opcode opcode
|
255
|
+
send @opcodes[info.cmd][:method], info
|
125
256
|
end
|
126
257
|
end
|
127
258
|
end
|