pavone@174
|
1 {
|
pavone@179
|
2 regnames <- #["rax" "rcx" "rdx" "rbx" "rsp" "rbp" "rsi" "rdi" "r8" "r9" "r10" "r11" "r12" "r13" "r14" "r15"]
|
pavone@179
|
3 uppernames <- #["ah" "ch" "dh" "bh"]
|
pavone@174
|
4 ireg <- :regnum {
|
pavone@174
|
5 #{
|
pavone@174
|
6 num <- { regnum }
|
pavone@174
|
7 reg <- { regnum and 7u8}
|
pavone@179
|
8 string <- { regnames get: regnum }
|
pavone@174
|
9 rm <- :tail { reg or 0xC0u8 | tail }
|
pavone@174
|
10 validforSize? <- :size { true }
|
pavone@174
|
11 isInteger? <- { false }
|
pavone@203
|
12 isString? <- { false }
|
pavone@174
|
13 register? <- { true }
|
pavone@181
|
14 label? <- { false }
|
pavone@198
|
15 upper? <- { false }
|
pavone@174
|
16 needsRex? <- { regnum >= 8u8 }
|
pavone@174
|
17 rexBitReg <- {
|
pavone@174
|
18 if: needsRex? {
|
pavone@174
|
19 4u8
|
pavone@174
|
20 } else: {
|
pavone@174
|
21 0u8
|
pavone@174
|
22 }
|
pavone@174
|
23 }
|
pavone@174
|
24 rexBitRM <- {
|
pavone@174
|
25 if: needsRex? {
|
pavone@174
|
26 1u8
|
pavone@174
|
27 } else: {
|
pavone@174
|
28 0u8
|
pavone@174
|
29 }
|
pavone@174
|
30 }
|
pavone@174
|
31 = <- :other {
|
pavone@174
|
32 (not: (other isInteger?)) && (other register?) && (not: (other upper?)) && regnum = (other num)
|
pavone@174
|
33 }
|
pavone@174
|
34 }
|
pavone@174
|
35 }
|
pavone@174
|
36
|
pavone@174
|
37 upper <- :regnum {
|
pavone@174
|
38 #{
|
pavone@174
|
39 num <- { regnum }
|
pavone@174
|
40 reg <- { regnum }
|
pavone@179
|
41 string <- { uppernames get: regnum - 4 }
|
pavone@174
|
42 rm <- :tail { regnum or 0xC0u8 | tail }
|
pavone@174
|
43 validforSize? <- :size {
|
pavone@174
|
44 size = byte
|
pavone@174
|
45 }
|
pavone@174
|
46 isInteger? <- { false }
|
pavone@174
|
47 register? <- { true }
|
pavone@181
|
48 label? <- { false }
|
pavone@174
|
49 upper? <- { true }
|
pavone@174
|
50 needsRex? <- { false }
|
pavone@174
|
51 = <- :other {
|
pavone@174
|
52 (not: (other isInteger?)) && (other register?) && (other upper?) && regnum = (other num)
|
pavone@174
|
53 }
|
pavone@174
|
54 }
|
pavone@174
|
55 }
|
pavone@174
|
56 fakesrc <- #{
|
pavone@174
|
57 needsRex? <- { false }
|
pavone@174
|
58 rexBitReg <- { 0u8 }
|
pavone@174
|
59 rexBitRM <- { 0u8 }
|
pavone@174
|
60 }
|
pavone@203
|
61 _size <- :s {
|
pavone@174
|
62 #{
|
pavone@174
|
63 num <- { s }
|
pavone@174
|
64 = <- :other {
|
pavone@174
|
65 s = (other num)
|
pavone@174
|
66 }
|
pavone@174
|
67 > <- :other {
|
pavone@174
|
68 s > (other num)
|
pavone@174
|
69 }
|
pavone@174
|
70 >= <- :other {
|
pavone@174
|
71 s >= (other num)
|
pavone@174
|
72 }
|
pavone@174
|
73 < <- :other {
|
pavone@174
|
74 s < (other num)
|
pavone@174
|
75 }
|
pavone@174
|
76 <= <- :other {
|
pavone@174
|
77 s <= (other num)
|
pavone@174
|
78 }
|
pavone@174
|
79 needsRex? <- { s = 3 }
|
pavone@174
|
80 rexBit <- {
|
pavone@174
|
81 if: needsRex? {
|
pavone@174
|
82 0x08u8
|
pavone@174
|
83 } else: {
|
pavone@174
|
84 0u8
|
pavone@174
|
85 }
|
pavone@174
|
86 }
|
pavone@174
|
87 }
|
pavone@174
|
88 }
|
pavone@203
|
89 byte <- _size: 0
|
pavone@203
|
90 word <- _size: 1
|
pavone@203
|
91 dword <- _size: 2
|
pavone@203
|
92 qword <- _size: 3
|
pavone@174
|
93
|
pavone@183
|
94 condition <- :num {
|
pavone@183
|
95 #{
|
pavone@183
|
96 cc <- { num }
|
pavone@183
|
97 }
|
pavone@183
|
98 }
|
pavone@183
|
99 _o <- condition: 0u8
|
pavone@183
|
100 _no <- condition: 1u8
|
pavone@183
|
101 _c <- condition: 2u8
|
pavone@183
|
102 _nc <- condition: 3u8
|
pavone@183
|
103 _z <- condition: 4u8
|
pavone@183
|
104 _nz <- condition: 5u8
|
pavone@183
|
105 _be <- condition: 6u8
|
pavone@183
|
106 _nbe <- condition: 7u8
|
pavone@183
|
107 _s <- condition: 8u8
|
pavone@183
|
108 _ns <- condition: 9u8
|
pavone@183
|
109 _p <- condition: 10u8
|
pavone@183
|
110 _np <- condition: 11u8
|
pavone@183
|
111 _l <- condition: 12u8
|
pavone@183
|
112 _nl <- condition: 13u8
|
pavone@183
|
113 _le <- condition: 14u8
|
pavone@183
|
114 _nle <- condition: 15u8
|
pavone@183
|
115
|
pavone@183
|
116
|
pavone@174
|
117 size_bit <- :opcode size {
|
pavone@174
|
118 if: size = byte {
|
pavone@174
|
119 opcode
|
pavone@174
|
120 } else: {
|
pavone@179
|
121 opcode or 1u8
|
pavone@174
|
122 }
|
pavone@174
|
123 }
|
pavone@174
|
124 opex <- :val {
|
pavone@174
|
125 #{
|
pavone@174
|
126 reg <- { val }
|
pavone@179
|
127 string <- { "opex " . val}
|
pavone@174
|
128 }
|
pavone@174
|
129 }
|
pavone@174
|
130
|
pavone@174
|
131 mod_rm:withTail <- :register regmem :end {
|
pavone@193
|
132 list <- regmem rm: end
|
pavone@193
|
133 (list value) or ( lshift: (register reg) by: 3u8) | (list tail)
|
pavone@174
|
134 }
|
pavone@174
|
135
|
pavone@174
|
136 mod_rm <- :reg rm {
|
pavone@174
|
137 mod_rm: reg rm withTail: []
|
pavone@174
|
138 }
|
pavone@174
|
139
|
pavone@175
|
140 int_op:withTail <- :value size :tail {
|
pavone@174
|
141 if: size >= dword {
|
pavone@179
|
142 tail <- (uint8: (rshift: value by: 16u64)) | (uint8: (rshift: value by: 24u64)) | tail
|
pavone@174
|
143 }
|
pavone@174
|
144 if: size >= word {
|
pavone@179
|
145 tail <- (uint8: (rshift: value by: 8u64)) | tail
|
pavone@174
|
146 }
|
pavone@174
|
147 (uint8: value) | tail
|
pavone@174
|
148 }
|
pavone@175
|
149 int_op <- :value size {
|
pavone@175
|
150 int_op: value size withTail: []
|
pavone@175
|
151 }
|
pavone@175
|
152 //used for mov instructions that support 64-bit immediate operands/offsets
|
pavone@175
|
153 int_op64 <- :value size {
|
pavone@175
|
154 tail <- []
|
pavone@183
|
155 value <- uint64: value
|
pavone@175
|
156 if: size = qword {
|
pavone@179
|
157 tail <- (uint8: (rshift: value by: 32u64)) | (uint8: (rshift: value by: 40u64)) | (uint8: (rshift: value by: 48u64)) | (uint8: (rshift: value by: 56u64)) | tail
|
pavone@175
|
158 }
|
pavone@175
|
159 int_op: value size withTail: tail
|
pavone@175
|
160 }
|
pavone@174
|
161
|
pavone@174
|
162 prefix:withInstruction <- :reg rm size :inst {
|
pavone@174
|
163 if: size = word {
|
pavone@174
|
164 inst <- 0x66u8 | inst
|
pavone@174
|
165 }
|
pavone@174
|
166 if: (size needsRex?) || (reg needsRex?) || (rm needsRex?) {
|
pavone@174
|
167 rex <- 0x40u8 or (size rexBit) or (reg rexBitReg) or (rm rexBitRM)
|
pavone@174
|
168 inst <- rex | inst
|
pavone@174
|
169 }
|
pavone@174
|
170 inst
|
pavone@174
|
171 }
|
pavone@174
|
172
|
pavone@174
|
173 _rax <- ireg: 0u8
|
pavone@174
|
174 _rcx <- ireg: 1u8
|
pavone@174
|
175 _rdx <- ireg: 2u8
|
pavone@174
|
176 _rbx <- ireg: 3u8
|
pavone@174
|
177 _rsp <- ireg: 4u8
|
pavone@174
|
178 _rbp <- ireg: 5u8
|
pavone@174
|
179 _rsi <- ireg: 6u8
|
pavone@174
|
180 _rdi <- ireg: 7u8
|
pavone@174
|
181 _r8 <- ireg: 8u8
|
pavone@174
|
182 _r9 <- ireg: 9u8
|
pavone@174
|
183 _r10 <- ireg: 10u8
|
pavone@174
|
184 _r11 <- ireg: 11u8
|
pavone@174
|
185 _r12 <- ireg: 12u8
|
pavone@174
|
186 _r13 <- ireg: 13u8
|
pavone@174
|
187 _r14 <- ireg: 14u8
|
pavone@174
|
188 _r15 <- ireg: 15u8
|
pavone@174
|
189 _ah <- upper: 4u8
|
pavone@174
|
190 _ch <- upper: 5u8
|
pavone@174
|
191 _dh <- upper: 6u8
|
pavone@174
|
192 _bh <- upper: 7u8
|
pavone@174
|
193
|
pavone@193
|
194 //AMD64 convention
|
pavone@193
|
195 _argregs <- #[
|
pavone@193
|
196 _rdi
|
pavone@193
|
197 _rsi
|
pavone@193
|
198 _rdx
|
pavone@193
|
199 _rcx
|
pavone@193
|
200 _r8
|
pavone@193
|
201 _r9
|
pavone@193
|
202 ]
|
pavone@193
|
203 _calleesave <- #[
|
pavone@193
|
204 _rbx
|
pavone@193
|
205 _rbp
|
pavone@193
|
206 _r12
|
pavone@193
|
207 _r13
|
pavone@193
|
208 _r14
|
pavone@193
|
209 _r15
|
pavone@193
|
210 ]
|
pavone@193
|
211 _tempregs <- #[
|
pavone@193
|
212 _r10
|
pavone@193
|
213 _r11
|
pavone@194
|
214 //TODO: Add rax back in once there's logic in il to properly
|
pavone@194
|
215 //allocate it for the instances in which it's live
|
pavone@194
|
216 //_rax
|
pavone@193
|
217 ]
|
pavone@193
|
218
|
pavone@193
|
219
|
pavone@180
|
220 inst <- :ilist {
|
pavone@180
|
221 #{
|
pavone@180
|
222 length <- { ilist length }
|
pavone@180
|
223 flattenTo:at <- :dest :idx {
|
pavone@180
|
224 ilist fold: idx with: :idx byte {
|
pavone@180
|
225 dest set: idx byte
|
pavone@180
|
226 idx + 1
|
pavone@180
|
227 }
|
pavone@180
|
228 }
|
pavone@180
|
229 }
|
pavone@180
|
230 }
|
pavone@204
|
231 multiInst <- :instarr {
|
pavone@204
|
232 #{
|
pavone@204
|
233 length <- {
|
pavone@204
|
234 instarr fold: 0 with: :acc inst {
|
pavone@204
|
235 acc + (inst length)
|
pavone@204
|
236 }
|
pavone@204
|
237 }
|
pavone@204
|
238 flattenTo:at <- :dest :idx {
|
pavone@204
|
239 instarr fold: idx with: :idx inst {
|
pavone@204
|
240 inst flattenTo: dest at: idx
|
pavone@204
|
241 }
|
pavone@204
|
242 }
|
pavone@204
|
243 }
|
pavone@204
|
244 }
|
pavone@180
|
245
|
pavone@175
|
246 op:withCode:withImmed:withOpEx <- :src dst size :normal :immed :myopex {
|
pavone@174
|
247 reg <- src
|
pavone@174
|
248 rm <- dst
|
pavone@174
|
249 base <- if: (src isInteger?) {
|
pavone@174
|
250 reg <- fakesrc
|
pavone@175
|
251 (size_bit: immed size) | (mod_rm: (opex: myopex) dst withTail: (int_op: src size))
|
pavone@174
|
252 } else: {
|
pavone@174
|
253 if: (src register?) {
|
pavone@174
|
254 (size_bit: normal size) | (mod_rm: src dst)
|
pavone@174
|
255 } else: {
|
pavone@174
|
256 reg <- dst
|
pavone@174
|
257 rm <- src
|
pavone@174
|
258 (size_bit: normal or 0x02u8 size) | (mod_rm: dst src)
|
pavone@174
|
259 }
|
pavone@174
|
260 }
|
pavone@180
|
261 inst: (prefix: reg rm size withInstruction: base)
|
pavone@174
|
262 }
|
pavone@174
|
263
|
pavone@175
|
264 op:withCode:withImmed:withImmedRax:withOpEx:withByteExtend <- :src dst size :normal :immed :immedRax :myopex :byteExt {
|
pavone@175
|
265 reg <- src
|
pavone@175
|
266 rm <- dst
|
pavone@175
|
267 if: (src isInteger?) {
|
pavone@175
|
268 reg <- fakesrc
|
pavone@175
|
269 base <- if: size > byte && (((src signed?) && src < 128 && src >= -128) || ((not: (src signed?)) && src < 256)) {
|
pavone@179
|
270 byteExt | (mod_rm: (opex: myopex) dst withTail: [(uint8: src)])
|
pavone@175
|
271 } else: {
|
pavone@175
|
272 if: dst = _rax {
|
pavone@175
|
273 (size_bit: immedRax size) | (int_op: src size)
|
pavone@175
|
274 } else: {
|
pavone@175
|
275 (size_bit: immed size) | (mod_rm: (opex: myopex) dst withTail: (int_op: src size))
|
pavone@175
|
276 }
|
pavone@175
|
277 }
|
pavone@180
|
278 inst: (prefix: reg rm size withInstruction: base)
|
pavone@175
|
279 } else: {
|
pavone@175
|
280 op: src dst size withCode: normal withImmed: immed withOpEx: myopex
|
pavone@175
|
281 }
|
pavone@175
|
282 }
|
pavone@175
|
283
|
pavone@204
|
284 shiftRot:withOpEx <- :amount dst size :myopex {
|
pavone@204
|
285 opcode <- 0u8
|
pavone@204
|
286 tail <- []
|
pavone@204
|
287 pre <- #[]
|
pavone@204
|
288 post <- #[]
|
pavone@204
|
289 base <- if: (amount isInteger?) {
|
pavone@204
|
290 if: amount = 1 {
|
pavone@204
|
291 opcode <- 0xD0u8
|
pavone@204
|
292 } else: {
|
pavone@204
|
293 opcode <- 0xC0u8
|
pavone@204
|
294 tail <- [uint8: amount]
|
pavone@204
|
295 }
|
pavone@204
|
296 } else: {
|
pavone@204
|
297 opcode <- 0xD2u8
|
pavone@204
|
298 if: (not: _rcx = amount) {
|
pavone@204
|
299 pre <- #[
|
pavone@204
|
300 x86 push: _rcx
|
pavone@204
|
301 x86 mov: amount _rcx byte
|
pavone@204
|
302 ]
|
pavone@204
|
303 post <- #[
|
pavone@204
|
304 x86 pop: _rcx
|
pavone@204
|
305 ]
|
pavone@204
|
306 }
|
pavone@204
|
307 }
|
pavone@204
|
308 bytes <- prefix: fakesrc dst withInstruction: (size_bit: 0xC0u8 size) | (mod_rm: (opex: myopex) dst withTail: tail)
|
pavone@204
|
309 myinst <- inst: bytes
|
pavone@204
|
310 if: (pre length) > 0 {
|
pavone@204
|
311 pre append: myinst
|
pavone@204
|
312 foreach: post :_ inst {
|
pavone@204
|
313 pre append: inst
|
pavone@204
|
314 }
|
pavone@204
|
315 multiInst: pre
|
pavone@204
|
316 } else: {
|
pavone@204
|
317 myinst
|
pavone@204
|
318 }
|
pavone@204
|
319 }
|
pavone@204
|
320
|
pavone@183
|
321 _jmprel <- :op jmpDest {
|
pavone@183
|
322 }
|
pavone@183
|
323
|
pavone@174
|
324 #{
|
pavone@174
|
325 rax <- { _rax }
|
pavone@174
|
326 rcx <- { _rcx }
|
pavone@174
|
327 rdx <- { _rdx }
|
pavone@174
|
328 rbx <- { _rbx }
|
pavone@174
|
329 rsp <- { _rsp }
|
pavone@174
|
330 rbp <- { _rbp }
|
pavone@174
|
331 rsi <- { _rsi }
|
pavone@174
|
332 rdi <- { _rdi }
|
pavone@174
|
333 r8 <- { _r8 }
|
pavone@174
|
334 r9 <- { _r9 }
|
pavone@174
|
335 r10 <- { _r10 }
|
pavone@174
|
336 r11 <- { _r11 }
|
pavone@174
|
337 r12 <- { _r12 }
|
pavone@174
|
338 r13 <- { _r13 }
|
pavone@174
|
339 r14 <- { _r14 }
|
pavone@174
|
340 r15 <- { _r15 }
|
pavone@174
|
341 ah <- { _ah }
|
pavone@174
|
342 ch <- { _ch }
|
pavone@174
|
343 dh <- { _dh }
|
pavone@174
|
344 bh <- { _bh }
|
pavone@174
|
345
|
pavone@174
|
346 b <- { byte }
|
pavone@174
|
347 w <- { word }
|
pavone@174
|
348 d <- { dword }
|
pavone@174
|
349 q <- { qword }
|
pavone@174
|
350
|
pavone@183
|
351 o <- { _o }
|
pavone@183
|
352 no <- { _no }
|
pavone@183
|
353 c <- { _c }
|
pavone@183
|
354 nc <- { _nc }
|
pavone@183
|
355 ae <- { _nc }
|
pavone@183
|
356 z <- { _z }
|
pavone@183
|
357 e <- { _z }
|
pavone@183
|
358 nz <- { _nz }
|
pavone@183
|
359 ne <- { _nz }
|
pavone@183
|
360 be <- { _be }
|
pavone@183
|
361 nbe <- { _nbe }
|
pavone@183
|
362 a <- { _nbe }
|
pavone@183
|
363 s <- { _s }
|
pavone@183
|
364 ns <- { _ns }
|
pavone@183
|
365 p <- { _p }
|
pavone@183
|
366 pe <- { _p }
|
pavone@183
|
367 np <- { _np }
|
pavone@183
|
368 po <- { _np }
|
pavone@183
|
369 l <- { _l }
|
pavone@183
|
370 nl <- { _nl }
|
pavone@183
|
371 ge <- { _nl }
|
pavone@183
|
372 le <- { _le }
|
pavone@183
|
373 nle <- { _nle }
|
pavone@183
|
374 g <- { _nle }
|
pavone@183
|
375
|
pavone@174
|
376 add <- :src dst size {
|
pavone@174
|
377 op: src dst size withCode: 0u8 withImmed: 0x80u8 withImmedRax: 0x04u8 withOpEx: 0u8 withByteExtend: 0x83u8
|
pavone@174
|
378 }
|
pavone@174
|
379
|
pavone@175
|
380 sub <- :src dst size {
|
pavone@175
|
381 op: src dst size withCode: 0x28u8 withImmed: 0x80u8 withImmedRax: 0x2Cu8 withOpEx: 5u8 withByteExtend: 0x83u8
|
pavone@175
|
382 }
|
pavone@175
|
383
|
pavone@204
|
384 cmp <- :src dst size {
|
pavone@204
|
385 op: src dst size withCode: 0x38u8 withImmed: 0x80u8 withImmedRax: 0x3Cu8 withOpEx: 7u8 withByteExtend: 0x83u8
|
pavone@204
|
386 }
|
pavone@204
|
387
|
pavone@204
|
388 and <- :src dst size {
|
pavone@204
|
389 op: src dst size withCode: 0x20u8 withImmed: 0x80u8 withImmedRax: 0x24u8 withOpEx: 4u8 withByteExtend: 0x83u8
|
pavone@204
|
390 }
|
pavone@204
|
391
|
pavone@204
|
392 or <- :src dst size {
|
pavone@204
|
393 op: src dst size withCode: 0x08u8 withImmed: 0x80u8 withImmedRax: 0x0Cu8 withOpEx: 1u8 withByteExtend: 0x83u8
|
pavone@204
|
394 }
|
pavone@204
|
395
|
pavone@204
|
396 xor <- :src dst size {
|
pavone@204
|
397 op: src dst size withCode: 0x30u8 withImmed: 0x80u8 withImmedRax: 0x34u8 withOpEx: 6u8 withByteExtend: 0x83u8
|
pavone@204
|
398 }
|
pavone@204
|
399
|
pavone@175
|
400 mov <- :src dst size {
|
pavone@175
|
401 rm <- dst
|
pavone@175
|
402 if: (src isInteger?) && (dst register?) {
|
pavone@175
|
403 opval <- if: size = byte { 0xB0u8 } else: { 0xB8u8 }
|
pavone@183
|
404 base <- opval or (dst reg) | (int_op64: src size)
|
pavone@180
|
405 inst: (prefix: fakesrc rm size withInstruction: base)
|
pavone@175
|
406 } else: {
|
pavone@175
|
407 op: src dst size withCode: 0x88u8 withImmed: 0xC6u8 withOpEx: 0u8
|
pavone@175
|
408 }
|
pavone@175
|
409 }
|
pavone@175
|
410
|
pavone@204
|
411 shl <- :shift dst size {
|
pavone@204
|
412 shiftRot: shift dst size withOpEx: 4u8
|
pavone@204
|
413 }
|
pavone@204
|
414
|
pavone@204
|
415 shr <- :shift dst size {
|
pavone@204
|
416 shiftRot: shift dst size withOpEx: 5u8
|
pavone@204
|
417 }
|
pavone@204
|
418
|
pavone@204
|
419 sar <- :shift dst size {
|
pavone@204
|
420 shiftRot: shift dst size withOpEx: 7u8
|
pavone@204
|
421 }
|
pavone@204
|
422
|
pavone@204
|
423 rol <- :shift dst size {
|
pavone@204
|
424 shiftRot: shift dst size withOpEx: 0u8
|
pavone@204
|
425 }
|
pavone@204
|
426
|
pavone@204
|
427 ror <- :shift dst size {
|
pavone@204
|
428 shiftRot: shift dst size withOpEx: 1u8
|
pavone@204
|
429 }
|
pavone@204
|
430
|
pavone@180
|
431 ret <- { inst: [ 0xC3u8 ] }
|
pavone@180
|
432
|
pavone@180
|
433 label <- {
|
pavone@180
|
434 _offset <- -1
|
pavone@180
|
435 _forwardRefs <- #[]
|
pavone@180
|
436 #{
|
pavone@180
|
437 length <- { 0 }
|
pavone@180
|
438 hasOffset? <- { _offset >= 0 }
|
pavone@180
|
439 offset <- { _offset }
|
pavone@180
|
440 register? <- { false }
|
pavone@181
|
441 label? <- { true }
|
pavone@180
|
442 flattenTo:at <- :dest :idx {
|
pavone@180
|
443 if: (not: hasOffset?) {
|
pavone@180
|
444 _offset <- idx
|
pavone@180
|
445 foreach: _forwardRefs :idx fun {
|
pavone@180
|
446 fun: _offset
|
pavone@180
|
447 }
|
pavone@180
|
448 _forwardRefs <- #[]
|
pavone@180
|
449 }
|
pavone@180
|
450 idx
|
pavone@180
|
451 }
|
pavone@180
|
452 withOffset:else <- :fun :elsefun {
|
pavone@180
|
453 if: hasOffset? {
|
pavone@180
|
454 fun: _offset
|
pavone@180
|
455 } else: {
|
pavone@180
|
456 _forwardRefs append: fun
|
pavone@180
|
457 elsefun:
|
pavone@180
|
458 }
|
pavone@180
|
459 }
|
pavone@180
|
460 }
|
pavone@180
|
461 }
|
pavone@180
|
462
|
pavone@180
|
463 jmp <- :jmpDest {
|
pavone@181
|
464 if: (jmpDest label?) {
|
pavone@180
|
465 _size <- -1
|
pavone@180
|
466 #{
|
pavone@180
|
467 length <- { if: _size < 0 { 5 } else: { _size } }
|
pavone@180
|
468 flattenTo:at <- :dest :idx {
|
pavone@180
|
469 jmpDest withOffset: :off {
|
pavone@180
|
470 if: _size < 0 {
|
pavone@180
|
471 rel <- off - (idx + 2)
|
pavone@180
|
472 if: rel < 128 && rel >= -128 {
|
pavone@180
|
473 _size <- 2
|
pavone@180
|
474 } else: {
|
pavone@180
|
475 rel <- rel - 2
|
pavone@180
|
476 if: rel < 32768 && rel >= -32768 {
|
pavone@180
|
477 _size <- 4
|
pavone@180
|
478 } else: {
|
pavone@180
|
479 _size <- 5
|
pavone@180
|
480 }
|
pavone@180
|
481 }
|
pavone@180
|
482 }
|
pavone@180
|
483 rel <- off - (idx + _size)
|
pavone@180
|
484 if: _size = 2 {
|
pavone@180
|
485 dest set: idx 0xEBu8
|
pavone@180
|
486 dest set: (idx + 1) (uint8: rel)
|
pavone@180
|
487 } else: {
|
pavone@180
|
488 if: _size = 4 {
|
pavone@180
|
489 dest set: idx 0x66u8
|
pavone@180
|
490 dest set: (idx + 1) 0xE9u8
|
pavone@180
|
491 dest set: (idx + 2) (uint8: rel)
|
pavone@180
|
492 dest set: (idx + 3) (uint8: (rshift: rel by: 8))
|
pavone@180
|
493 } else: {
|
pavone@180
|
494 dest set: idx 0xE9u8
|
pavone@180
|
495 dest set: (idx + 1) (uint8: rel)
|
pavone@180
|
496 dest set: (idx + 2) (uint8: (rshift: rel by: 8))
|
pavone@180
|
497 dest set: (idx + 3) (uint8: (rshift: rel by: 16))
|
pavone@180
|
498 dest set: (idx + 4) (uint8: (rshift: rel by: 24))
|
pavone@180
|
499 }
|
pavone@180
|
500 }
|
pavone@180
|
501 } else: {
|
pavone@180
|
502 _size <- 5
|
pavone@180
|
503 }
|
pavone@180
|
504 idx + _size
|
pavone@180
|
505 }
|
pavone@180
|
506 }
|
pavone@180
|
507 } else: {
|
pavone@180
|
508 inst: 0xFFu8 | (mod_rm: (opex: 5u8) jmpDest)
|
pavone@180
|
509 }
|
pavone@180
|
510 }
|
pavone@175
|
511
|
pavone@183
|
512 jcc <- :cond jmpDest {
|
pavone@183
|
513 _size <- -1
|
pavone@183
|
514 #{
|
pavone@183
|
515 length <- { if: _size < 0 { 5 } else: { _size } }
|
pavone@183
|
516 flattenTo:at <- :dest :idx {
|
pavone@183
|
517 jmpDest withOffset: :off {
|
pavone@183
|
518 if: _size < 0 {
|
pavone@183
|
519 rel <- off - (idx + 2)
|
pavone@183
|
520 if: rel < 128 && rel >= -128 {
|
pavone@183
|
521 _size <- 2
|
pavone@183
|
522 } else: {
|
pavone@183
|
523 _size <- 6
|
pavone@183
|
524 }
|
pavone@183
|
525 }
|
pavone@183
|
526 rel <- off - (idx + _size)
|
pavone@183
|
527 if: _size = 2 {
|
pavone@183
|
528 dest set: idx 0x70u8 or (cond cc)
|
pavone@183
|
529 dest set: (idx + 1) (uint8: rel)
|
pavone@183
|
530 } else: {
|
pavone@183
|
531 dest set: idx 0x0Fu8
|
pavone@183
|
532 dest set: (idx + 1) 0x80u8 or (cond cc)
|
pavone@183
|
533 dest set: (idx + 2) (uint8: rel)
|
pavone@183
|
534 dest set: (idx + 3) (uint8: (rshift: rel by: 8))
|
pavone@183
|
535 dest set: (idx + 4) (uint8: (rshift: rel by: 16))
|
pavone@183
|
536 dest set: (idx + 5) (uint8: (rshift: rel by: 24))
|
pavone@183
|
537 }
|
pavone@183
|
538 } else: {
|
pavone@183
|
539 _size <- 6
|
pavone@183
|
540 }
|
pavone@183
|
541 idx + _size
|
pavone@183
|
542 }
|
pavone@183
|
543 }
|
pavone@183
|
544 }
|
pavone@183
|
545
|
pavone@181
|
546 call <- :callDest {
|
pavone@181
|
547 if: (callDest label?) {
|
pavone@181
|
548 #{
|
pavone@181
|
549 length <- { 5 }
|
pavone@181
|
550 flattenTo:at <- :dest :idx {
|
pavone@181
|
551 dest set: idx 0xE8u8
|
pavone@181
|
552 callDest withOffset: :off {
|
pavone@181
|
553 rel <- off - (idx + 5)
|
pavone@181
|
554 dest set: (idx + 1) (uint8: rel)
|
pavone@181
|
555 dest set: (idx + 2) (uint8: (rshift: rel by: 8))
|
pavone@181
|
556 dest set: (idx + 3) (uint8: (rshift: rel by: 16))
|
pavone@181
|
557 dest set: (idx + 4) (uint8: (rshift: rel by: 24))
|
pavone@181
|
558 } else: {
|
pavone@181
|
559 }
|
pavone@181
|
560 idx + 5
|
pavone@181
|
561 }
|
pavone@181
|
562 }
|
pavone@181
|
563 } else: {
|
pavone@181
|
564 inst: 0xFFu8 | (mod_rm: (opex: 2u8) callDest)
|
pavone@181
|
565 }
|
pavone@181
|
566 }
|
pavone@174
|
567
|
pavone@183
|
568 push <- :src {
|
pavone@183
|
569 if: (src isInteger?) {
|
pavone@183
|
570 if: src < 128 && src > -128 {
|
pavone@183
|
571 inst: 0x6Au8 | (uint8: src)
|
pavone@183
|
572 } else: {
|
pavone@183
|
573 inst: 0x68u8 | (uint8: src) | (uint8: (rshift: src by: 8)) | (uint8: (rshift: src by: 16)) | (uint8: (rshift: src by: 24))
|
pavone@183
|
574 }
|
pavone@183
|
575 } else: {
|
pavone@183
|
576 base <- if: (src register?) {
|
pavone@183
|
577 [0x50u8 or (src reg)]
|
pavone@183
|
578 } else: {
|
pavone@183
|
579 0xFFu8 | (mod_rm: (opex: 6u8) src)
|
pavone@183
|
580 }
|
pavone@183
|
581 inst: (prefix: fakesrc src d withInstruction: base)
|
pavone@183
|
582 }
|
pavone@183
|
583 }
|
pavone@183
|
584
|
pavone@183
|
585 pop <- :dst {
|
pavone@183
|
586 base <- if: (dst register?) {
|
pavone@183
|
587 [0x58u8 or (dst reg)]
|
pavone@183
|
588 } else: {
|
pavone@183
|
589 0x8Fu8 | (mod_rm: (opex: 0u8) dst)
|
pavone@183
|
590 }
|
pavone@183
|
591 inst: (prefix: fakesrc dst d withInstruction: base)
|
pavone@183
|
592 }
|
pavone@183
|
593
|
pavone@204
|
594 bnot <- :dst size {
|
pavone@204
|
595 base <- (size_bit: 0xF6u8 size) | (mod_rm: (opex: 2u8) dst)
|
pavone@204
|
596 inst: (prefix: fakesrc dst size withInstruction: base)
|
pavone@204
|
597 }
|
pavone@204
|
598
|
pavone@193
|
599 //TODO: support multiple calling conventions
|
pavone@193
|
600 regSource <- {
|
pavone@193
|
601 _used <- 0
|
pavone@193
|
602 _usedAllTime <- 0
|
pavone@193
|
603 _nextStackOff <- 0
|
pavone@193
|
604 _findUnused <- :size reglists{
|
pavone@193
|
605 found <- -1
|
pavone@193
|
606 foundlist <- -1
|
pavone@193
|
607 curlist <- 0
|
pavone@193
|
608 ll <- reglists length
|
pavone@193
|
609 while: { found < 0 && curlist < ll } do: {
|
pavone@193
|
610 cur <- 0
|
pavone@193
|
611 regs <- reglists get: curlist
|
pavone@193
|
612 len <- regs length
|
pavone@193
|
613 while: { found < 0 && cur < len } do: {
|
pavone@195
|
614 bit <- lshift: 1 by: ((regs get: cur) num)
|
pavone@193
|
615 if: (_used and bit) = 0 {
|
pavone@193
|
616 found <- cur
|
pavone@193
|
617 foundlist <- regs
|
pavone@193
|
618 _used <- _used or bit
|
pavone@193
|
619 _usedAllTime <- _usedAllTime or bit
|
pavone@193
|
620 }
|
pavone@193
|
621 cur <- cur + 1
|
pavone@193
|
622 }
|
pavone@193
|
623 curlist <- curlist + 1
|
pavone@193
|
624 }
|
pavone@193
|
625 if: found >= 0 {
|
pavone@193
|
626 foundlist get: found
|
pavone@193
|
627 } else: {
|
pavone@193
|
628 myoff <- _nextStackOff
|
pavone@193
|
629 _nextStackOff <- _nextStackOff + size
|
pavone@193
|
630 il base: _rsp offset: myoff
|
pavone@193
|
631 }
|
pavone@193
|
632 }
|
pavone@193
|
633 #{
|
pavone@193
|
634 alloc <- :size {
|
pavone@193
|
635 _findUnused: size #[
|
pavone@193
|
636 _calleesave
|
pavone@193
|
637 _tempregs
|
pavone@193
|
638 _argregs
|
pavone@193
|
639 ]
|
pavone@193
|
640 }
|
pavone@193
|
641 //used to allocate a register
|
pavone@193
|
642 //that will be returned before a call
|
pavone@193
|
643 allocTemp <- :size {
|
pavone@193
|
644 _findUnused: size #[
|
pavone@193
|
645 _tempregs
|
pavone@193
|
646 _argregs
|
pavone@193
|
647 _calleesave
|
pavone@193
|
648 ]
|
pavone@193
|
649 }
|
pavone@193
|
650 //allocated the return register
|
pavone@194
|
651 allocRet <- {
|
pavone@193
|
652 bit <- (lshift: 1 by: (_rax num))
|
pavone@193
|
653 _used <- _used or bit
|
pavone@193
|
654 _usedAllTime <- _usedAllTime or bit
|
pavone@193
|
655 _rax
|
pavone@193
|
656 }
|
pavone@193
|
657 allocArg <- :argnum {
|
pavone@193
|
658 if: argnum < (_argregs length) {
|
pavone@193
|
659 reg <- _argregs get: argnum
|
pavone@193
|
660 bit <- (lshift: 1 by: (reg num))
|
pavone@193
|
661 _used <- _used or bit
|
pavone@193
|
662 _usedAllTime <- _usedAllTime or bit
|
pavone@194
|
663 reg
|
pavone@193
|
664 } else: {
|
pavone@193
|
665 il base: _rsp offset: _nextStackOff + 8 * (argnum - (_argregs length))
|
pavone@193
|
666 }
|
pavone@193
|
667 }
|
pavone@193
|
668 allocSpecific <- :reg {
|
pavone@193
|
669 if: (reg register?) {
|
pavone@193
|
670 bit <- (lshift: 1 by: (reg num))
|
pavone@193
|
671 _used <- _used or bit
|
pavone@193
|
672 }
|
pavone@193
|
673 }
|
pavone@193
|
674 stackSize <- { _nextStackOff }
|
pavone@193
|
675 return <- :reg {
|
pavone@193
|
676 _used <- _used and (0xF xor (lshift: 1 by: (reg num)))
|
pavone@193
|
677 }
|
pavone@198
|
678 returnAll <- { _used <- 0 }
|
pavone@193
|
679 needSaveProlog <- {
|
pavone@193
|
680 retval <- #[]
|
pavone@193
|
681 foreach: _calleesave :idx reg {
|
pavone@195
|
682 bit <- lshift: 1 by: (reg num)
|
pavone@195
|
683 if: (_usedAllTime and bit) != 0 {
|
pavone@193
|
684 retval append: reg
|
pavone@193
|
685 }
|
pavone@193
|
686 }
|
pavone@193
|
687 retval
|
pavone@193
|
688 }
|
pavone@193
|
689 needSaveForCall <- {
|
pavone@193
|
690 retval <- #[]
|
pavone@198
|
691 foreach: #[(_tempregs) (_argregs)] :_ regs {
|
pavone@193
|
692 foreach: regs :_ reg {
|
pavone@193
|
693 if: (_used and (lshift: 1 by: (reg num))) != 0 {
|
pavone@193
|
694 retval append: reg
|
pavone@193
|
695 }
|
pavone@193
|
696 }
|
pavone@193
|
697 }
|
pavone@193
|
698 retval
|
pavone@193
|
699 }
|
pavone@193
|
700 }
|
pavone@193
|
701 }
|
pavone@193
|
702
|
pavone@203
|
703 adjustIL <- :ilfun {
|
pavone@203
|
704 il to2Op: (il allocRegs: ilfun withSource: regSource)
|
pavone@203
|
705 }
|
pavone@203
|
706
|
pavone@203
|
707 convertIL:to:withLabels:withSaved <- :inst :outarr :labels :saved {
|
pavone@203
|
708 mapSize <- :ilsize {
|
pavone@203
|
709 if: (ilsize bytes) > 2 {
|
pavone@203
|
710 if: (ilsize bytes) = 8 { q } else: { d }
|
pavone@203
|
711 } else: {
|
pavone@203
|
712 if: (ilsize bytes) = 1 { b } else: { w }
|
pavone@203
|
713 }
|
pavone@203
|
714 }
|
pavone@203
|
715 mapcond <- :ilcond {
|
pavone@203
|
716 ccmap <- #[
|
pavone@203
|
717 e
|
pavone@203
|
718 ne
|
pavone@203
|
719 ge
|
pavone@203
|
720 le
|
pavone@203
|
721 g
|
pavone@203
|
722 l
|
pavone@203
|
723 ae
|
pavone@203
|
724 be
|
pavone@203
|
725 a
|
pavone@203
|
726 c
|
pavone@203
|
727 ]
|
pavone@203
|
728 ccmap get: (ilcond cc)
|
pavone@203
|
729 }
|
pavone@203
|
730 opmap <- #[
|
pavone@203
|
731 { outarr append: (add: (inst in) (inst out) (mapSize: (inst size))) }
|
pavone@204
|
732 { outarr append: (and: (inst in) (inst out) (mapSize: (inst size))) }
|
pavone@204
|
733 { outarr append: (or: (inst in) (inst out) (mapSize: (inst size))) }
|
pavone@204
|
734 { outarr append: (xor: (inst in) (inst out) (mapSize: (inst size))) }
|
pavone@203
|
735 { outarr append: (sub: (inst in) (inst out) (mapSize: (inst size))) }
|
pavone@204
|
736 { outarr append: (cmp: (inst in) (inst out) (mapSize: (inst size))) }
|
pavone@204
|
737 { outarr append: (bnot: (inst arg) (mapSize: (inst size))) }
|
pavone@204
|
738 { outarr append: (shl: (inst in) (inst out) (mapSize: (inst size))) } //sl
|
pavone@204
|
739 { outarr append: (sar: (inst in) (inst out) (mapSize: (inst size))) } //asr
|
pavone@204
|
740 { outarr append: (shr: (inst in) (inst out) (mapSize: (inst size))) } //lsr
|
pavone@204
|
741 { outarr append: (rol: (inst in) (inst out) (mapSize: (inst size))) }
|
pavone@204
|
742 { outarr append: (ror: (inst in) (inst out) (mapSize: (inst size))) }
|
pavone@203
|
743 { outarr append: (mov: (inst in) (inst out) (mapSize: (inst size))) }
|
pavone@203
|
744 {
|
pavone@203
|
745 //call
|
pavone@203
|
746 arguments <- inst args
|
pavone@203
|
747 cur <- (arguments length) - 1
|
pavone@203
|
748 while: { cur >= 0 } do: {
|
pavone@203
|
749 src <- (arguments get: cur)
|
pavone@203
|
750 if: cur < (_argregs length) {
|
pavone@203
|
751 dst <- _argregs get: cur
|
pavone@203
|
752 if: (not: dst = src) {
|
pavone@203
|
753 //TODO: Handle edge case in which src is a caller saved
|
pavone@203
|
754 //reg that has been pusehd onto the stack to preserve
|
pavone@203
|
755 //it across this call
|
pavone@203
|
756 outarr append: (mov: src dst q)
|
pavone@203
|
757 }
|
pavone@203
|
758 } else: {
|
pavone@203
|
759 outarr append: (push: src)
|
pavone@203
|
760 }
|
pavone@203
|
761 cur <- cur - 1
|
pavone@203
|
762 }
|
pavone@203
|
763 toCall <- inst target
|
pavone@203
|
764 if: (toCall isString?) {
|
pavone@203
|
765 //TODO: Handle call to undefined label
|
pavone@203
|
766 toCall <- labels get: toCall
|
pavone@203
|
767 }
|
pavone@203
|
768 outarr append: (call: toCall)
|
pavone@203
|
769 }
|
pavone@203
|
770 {
|
pavone@203
|
771 //return
|
pavone@203
|
772 if: (not: _rax = (inst arg)) {
|
pavone@203
|
773 outarr append: (mov: (inst arg) _rax q)
|
pavone@203
|
774 }
|
pavone@203
|
775 foreach: saved :_ reg {
|
pavone@203
|
776 outarr append: (pop: reg)
|
pavone@203
|
777 }
|
pavone@203
|
778 outarr append: (ret: )
|
pavone@203
|
779 }
|
pavone@203
|
780 {
|
pavone@203
|
781 //skipIf
|
pavone@203
|
782 endlab <- label:
|
pavone@203
|
783 outarr append: (jcc: (mapcond: (inst cond)) endlab)
|
pavone@203
|
784 foreach: (inst toskip) :_ inst {
|
pavone@203
|
785 convertIL: inst to: outarr withLabels: labels withSaved: saved
|
pavone@203
|
786 }
|
pavone@203
|
787 outarr append: endlab
|
pavone@203
|
788 }
|
pavone@203
|
789 {
|
pavone@203
|
790 //save
|
pavone@203
|
791 newsave <- []
|
pavone@203
|
792 foreach: (inst tosave) :_ reg {
|
pavone@203
|
793 outarr append: (push: reg)
|
pavone@203
|
794 newsave <- reg | newsave
|
pavone@203
|
795 }
|
pavone@203
|
796 foreach: (inst scope) :_ inst {
|
pavone@203
|
797 convertIL: inst to: outarr withLabels: labels withSaved: newsave
|
pavone@203
|
798 }
|
pavone@203
|
799 if: ((inst scope) length) = 0 || (((inst scope) get: ((inst scope) length) - 1) opcode) != 14 {
|
pavone@203
|
800 foreach: newsave :_ reg {
|
pavone@203
|
801 outarr append: (pop: reg)
|
pavone@203
|
802 }
|
pavone@203
|
803 }
|
pavone@203
|
804 }
|
pavone@203
|
805 ]
|
pavone@203
|
806 fun <- opmap get: (inst opcode)
|
pavone@203
|
807 fun:
|
pavone@203
|
808 outarr
|
pavone@203
|
809 }
|
pavone@203
|
810
|
pavone@203
|
811 convertIL:to:withLabels <- :inst :outarr :labels {
|
pavone@203
|
812 convertIL: inst to: outarr withLabels: labels withSaved: []
|
pavone@203
|
813 }
|
pavone@203
|
814
|
pavone@174
|
815 main <- {
|
pavone@183
|
816 fib <- label:
|
pavone@183
|
817 notbase <- label:
|
pavone@179
|
818 prog <- #[
|
pavone@183
|
819 fib
|
pavone@183
|
820 sub: 2 rdi q
|
pavone@183
|
821 jcc: ge notbase
|
pavone@183
|
822 mov: 1 rax q
|
pavone@183
|
823 ret:
|
pavone@183
|
824
|
pavone@183
|
825 notbase
|
pavone@183
|
826 push: rdi
|
pavone@183
|
827 call: fib
|
pavone@183
|
828 pop: rdi
|
pavone@183
|
829 push: rax
|
pavone@183
|
830 add: 1 rdi q
|
pavone@183
|
831 call: fib
|
pavone@183
|
832 pop: rdi
|
pavone@179
|
833 add: rdi rax q
|
pavone@181
|
834 ret:
|
pavone@179
|
835 ]
|
pavone@180
|
836
|
pavone@179
|
837 ba <- bytearray executableFromBytes: prog
|
pavone@183
|
838 res <- ba runWithArg: 30u64
|
pavone@179
|
839 print: (string: res) . "\n"
|
pavone@174
|
840 0
|
pavone@174
|
841 }
|
pavone@174
|
842 }
|
pavone@174
|
843 }
|