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.

Clone this repository (size: 68.5 KB): HTTPS / SSH
$ hg clone http://bitbucket.org/cheery/g386/

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