cheery / g386
A two-pass assembler for i386. Implements a subset of instruction encoders and implements more if benchmarks promote. Produces linux ELF binaries but isn't limited into them. Straightforward design.
| commit 15: | 34a7d7dbf537 |
| parent 14: | 79a43833457c |
| branch: | default |
factorial example
cheery
2 months ago
2 months ago
Changed (Δ2.7 KB):
raw changeset »
examples/factorial.py (77 lines added, 0 lines removed)
g386/__init__.py (57 lines added, 3 lines removed)
Up to file-list examples/factorial.py:
1 |
# -*- coding: utf-8 -*- |
|
2 |
""" |
|
3 |
slumber |
|
4 |
~~~~~~~ |
|
5 |
||
6 |
:copyright: 2009 by Henri Tuhola <henri.tuhola@gmail.com> |
|
7 |
||
8 |
Prints factorial of whatever item passed to it. |
|
9 |
""" |
|
10 |
from g386 import ( |
|
11 |
X86, Bytes, elf, |
|
12 |
r0,r1,r2,r3,r4,r5,r6,r7, |
|
13 |
Deref, |
|
14 |
) |
|
15 |
||
16 |
program = [] |
|
17 |
def include(node): |
|
18 |
program.append(node) |
|
19 |
return node |
|
20 |
||
21 |
unused_regs = [r0, r1, r2, r3, r6, r7] |
|
22 |
stack = r4 |
|
23 |
base = r5 |
|
24 |
||
25 |
entry = include(X86(unused_regs)) |
|
26 |
factorial = include(X86(unused_regs)) |
|
27 |
||
28 |
lib = elf.Dynamic(['libc.so.6']) |
|
29 |
def cfun(name): |
|
30 |
return Deref(lib[name]) |
|
31 |
||
32 |
def arg(gen, offset, node): |
|
33 |
gen.store(Deref(stack, offset), node) |
|
34 |
||
35 |
x = factorial |
|
36 |
retaddr = Deref(stack, 0) |
|
37 |
accum = Deref(stack, 4) |
|
38 |
k = Deref(stack, 8) |
|
39 |
||
40 |
repeat_factorial = include(X86(unused_regs)) |
|
41 |
x.jump(repeat_factorial) |
|
42 |
y = repeat_factorial |
|
43 |
y.store(accum, y.int_multiply(accum, k)) |
|
44 |
y.store(k, y.sub(k, 1)) |
|
45 |
y.ja(repeat_factorial) |
|
46 |
||
47 |
y.move(r0, accum) |
|
48 |
y.ret() |
|
49 |
||
50 |
x = entry |
|
51 |
x.move(base, stack) |
|
52 |
||
53 |
x.sub(stack, 12) |
|
54 |
||
55 |
arg(x, 0, 0) |
|
56 |
x.call(cfun('time')) |
|
57 |
||
58 |
arg(x, 0, r0) |
|
59 |
x.call(cfun('srand')) |
|
60 |
||
61 |
x.call(cfun('rand')) |
|
62 |
x.unused_gpr.discard(r0) |
|
63 |
||
64 |
arg(x, 4, |
|
65 |
x.int_modulus(r0, 16) |
|
66 |
) |
|
67 |
arg(x, 0, 1) |
|
68 |
x.call(factorial) |
|
69 |
arg(x, 4, r0) |
|
70 |
arg(x, 0, include(Bytes('%d\n\x00'))) |
|
71 |
x.call(cfun('printf')) |
|
72 |
||
73 |
arg(x, 0, 0) |
|
74 |
x.call(cfun('exit')) |
|
75 |
||
76 |
if __name__ == '__main__': |
|
77 |
elf.executable(open('factorial.app', 'w'), program, entry, lib) |
Up to file-list g386/__init__.py:
| … | … | @@ -116,6 +116,60 @@ def idiv(gen, divider): |
116 |
116 |
gen.emit('\xf7', ModRM(7, operand)) |
117 |
117 |
|
118 |
118 |
@X86.instruction |
119 |
def force_free(gen, *gprs): |
|
120 |
swaps = [] |
|
121 |
captured = [] |
|
122 |
for gpr in gprs: |
|
123 |
if gpr in gen.unused_gpr: |
|
124 |
gen.unused_gpr.discard(gpr) |
|
125 |
captured.append(gpr) |
|
126 |
else: |
|
127 |
saved_gpr = gen.get_gpr() |
|
128 |
gen.regswap(saved_gpr, gpr) |
|
129 |
swaps.append((saved_gpr, gpr)) |
|
130 |
||
131 |
def restore(result): |
|
132 |
for saved, gpr in swaps: |
|
133 |
gen.regswap(saved, gpr) |
|
134 |
if gpr == result: |
|
135 |
result = saved |
|
136 |
else: |
|
137 |
gen.free_gpr(saved) |
|
138 |
for gpr in captured: |
|
139 |
if gpr != result: |
|
140 |
gen.free_gpr(gpr) |
|
141 |
return result |
|
142 |
return restore |
|
143 |
||
144 |
@X86.instruction |
|
145 |
def int_modulus(gen, a, b): |
|
146 |
reg1 = gen.to_reg(a) |
|
147 |
reg2 = gen.to_reg(b) |
|
148 |
gen.free_gpr(reg1) |
|
149 |
gen.free_gpr(reg2) |
|
150 |
restore = gen.force_free(r0, r2) |
|
151 |
if reg2 in [r0, r2]: |
|
152 |
reg2 = gen.copy_reg(reg2) |
|
153 |
gen.move(r0, reg1) |
|
154 |
gen.move(r2, 0) |
|
155 |
gen.emit('\xf7', ModRM(7, reg2)) |
|
156 |
return restore(r2) |
|
157 |
||
158 |
@X86.instruction |
|
159 |
def int_division(gen, a, b): |
|
160 |
reg1 = gen.to_reg(a) |
|
161 |
reg2 = gen.to_reg(b) |
|
162 |
gen.free_gpr(reg1) |
|
163 |
gen.free_gpr(reg2) |
|
164 |
restore = gen.force_free(r0, r2) |
|
165 |
if reg2 in [r0, r2]: |
|
166 |
reg2 = gen.copy_reg(reg2) |
|
167 |
gen.move(r0, reg1) |
|
168 |
gen.move(r2, 0) |
|
169 |
gen.emit('\xf7', ModRM(7, reg2)) |
|
170 |
return restore(r0) |
|
171 |
||
172 |
@X86.instruction |
|
119 |
173 |
def mul(gen, mult): |
120 |
174 |
if isnum(mult): |
121 |
175 |
operand = gen.to_reg(mult) |
| … | … | @@ -176,7 +230,7 @@ def lognot(gen, a): |
176 |
230 |
def logand(gen, a, b): |
177 |
231 |
reg = gen.to_reg(a) |
178 |
232 |
if isnum(b): |
179 |
gen.emit('\x81', ModRM(4, reg), Imm32(b) |
|
233 |
gen.emit('\x81', ModRM(4, reg), Imm32(b)) |
|
180 |
234 |
else: |
181 |
235 |
gen.emit('\x23', ModRM(a, gen.free_gpr(gen.to_indirect(b)))) |
182 |
236 |
return reg |
| … | … | @@ -185,7 +239,7 @@ def logand(gen, a, b): |
185 |
239 |
def logxor(gen, a, b): |
186 |
240 |
reg = gen.to_reg(a) |
187 |
241 |
if isnum(b): |
188 |
gen.emit('\x81', ModRM(6, reg), Imm32(b) |
|
242 |
gen.emit('\x81', ModRM(6, reg), Imm32(b)) |
|
189 |
243 |
else: |
190 |
244 |
gen.emit('\x33', ModRM(a, gen.free_gpr(gen.to_indirect(b)))) |
191 |
245 |
return reg |
| … | … | @@ -194,7 +248,7 @@ def logxor(gen, a, b): |
194 |
248 |
def logor(gen, a, b): |
195 |
249 |
reg = gen.to_reg(a) |
196 |
250 |
if isnum(b): |
197 |
gen.emit('\x81', ModRM(1, reg), Imm32(b) |
|
251 |
gen.emit('\x81', ModRM(1, reg), Imm32(b)) |
|
198 |
252 |
else: |
199 |
253 |
gen.emit('\x0b', ModRM(a, gen.free_gpr(gen.to_indirect(b)))) |
200 |
254 |
return reg |
