haxor 0.3.0 → 0.4.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 +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
|