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 »

dev/shared.asm (10 lines added, 0 lines removed)

examples/shared.py (37 lines added, 0 lines removed)

g386/__init__.py (11 lines added, 1 lines removed)

g386/core.py (12 lines added, 0 lines removed)

g386/elf.py (40 lines added, 18 lines removed)

usage_example.c (13 lines added, 0 lines removed)

usage_example2.c (22 lines added, 0 lines removed)

Up to file-list dev/shared.asm:

1
bits 32
2
; nasm -f elf shared.asm
3
; ld shared.o -melf_i386 -o libshared.so -shared
4
5
extern _GLOBAL_OFFSET_TABLE_
6
global example_function:function
7
8
example_function:
9
    mov eax, 5000
10
    ret

Up to file-list examples/shared.py:

1
# -*- coding: utf-8 -*-
2
"""
3
    shared
4
    ~~~~~~
5
6
    :copyright: 2010 by Henri Tuhola <henri.tuhola@gmail.com>
7
8
    Produces a position independent executable.
9
"""
10
from g386 import (
11
    X86, Bytes, elf,
12
    r0,r1,r2,r3,r4,r5,r6,r7,
13
    Deref, Index,
14
)
15
16
unused_regs = [r0, r1, r2, r3, r6, r7]
17
18
program = []
19
def code():
20
    x86 = X86(unused_regs)
21
    program.append(x86)
22
    return x86
23
24
x = example_function = code()
25
x.move(r0, 1234)
26
x.ret()
27
28
lib = elf.Dynamic(['libc.so.6'], shared=True)
29
30
x = entry = code()
31
x.store(Deref(r4), 1)
32
x.call(Deref(x.pic(lib['exit'])))
33
34
lib.export('example_function', example_function)
35
36
if __name__ == '__main__':
37
    elf.executable(open('libshared.so', 'w'), program, entry, lib)

Up to file-list g386/__init__.py:

7
7
"""
8
8
from core import (
9
9
    Assembly, Instruction, Register,
10
    Imm32, Imm8, Rel32, Indirect,
10
    Imm32, Imm8, Rel32, IPR32, Indirect,
11
11
    ModRM, Bytes,
12
12
    isconst, isnum, isreg,
13
13
)
@@ -25,6 +25,16 @@ ccs = [
25
25
]
26
26
27
27
@X86.instruction
28
def pic(gen, source):
29
    reg = gen.get_gpr()
30
    gen.emit('\xe8\x00\x00\x00\x00')
31
    gen.emit(
32
        '\x8f', ModRM(0, reg),
33
        '\x81', ModRM(0, reg), IPR32(source)
34
    )
35
    return reg
36
37
@X86.instruction
28
38
def cmov(gen, mode, dst, src):
29
39
    dst = gen.to_reg(dst)
30
40
    src = gen.to_indirect(src)

Up to file-list g386/core.py:

@@ -94,6 +94,18 @@ class Rel32(object):
94
94
    def __repr__(self):
95
95
        return "Rel32(%r)" % self.value
96
96
97
class IPR32(object):
98
    size = 4
99
    def __init__(self, value):
100
        self.value = value
101
102
    def compose(self, instr):
103
        origin = instr.address
104
        return struct.pack('i', self.value.address - origin)
105
106
    def __repr__(self):
107
        return "Rel32(%r)" % self.value
108
97
109
class Register(object):
98
110
    def __init__(self, index):
99
111
        self.index = index

Up to file-list g386/elf.py:

@@ -34,8 +34,8 @@ def buildheader(**data):
34
34
        data.get('ehdrsize', headersize),
35
35
        data.get('phdrsize', loadersize),
36
36
        data.get('phdrnum', 1),
37
        data.get('shdrsize', 0),
38
        data.get('shdrnum', 1),
37
        data.get('shdrsize', 40),
38
        data.get('shdrnum', 0),
39
39
        data.get('shstrndx', 0),
40
40
    )
41
41
@@ -73,9 +73,10 @@ class Strings(object):
73
73
class SymbolTable(object):
74
74
    first_sym = 2
75
75
    entsize = struct.calcsize('3i2H')
76
    def __init__(self, strtab, symbols):
76
    def __init__(self, strtab, symbols, exports):
77
77
        self.strtab = strtab
78
78
        self.symbols = symbols
79
        self.exports = exports
79
80
        self.indices = dict(
80
81
            (sym, i+self.first_sym)
81
82
            for i, sym in enumerate(symbols)
@@ -89,7 +90,12 @@ class SymbolTable(object):
89
90
            self.strtab['_DYNAMIC'], self.dynamic.address, 0, 0x11, 0xfff1
90
91
        )
91
92
        for symbol in self.symbols:
92
            entries += struct.pack('3i2H', self.strtab[symbol], 0, 0, 0x12, 0)
93
            value = 0
94
            ndx = 0
95
            if symbol in self.exports:
96
                value = self.exports[symbol].address
97
                ndx = 0xfff1
98
            entries += struct.pack('3i2H', self.strtab[symbol], value, 0, 0x12, ndx)
93
99
        return entries
94
100
95
101
class DynTab(object):
@@ -154,23 +160,33 @@ class Dynamic(object):
154
160
    You can think of it as an address of a location that tells where
155
161
    the 'sleep' -function is in your process image.
156
162
    """
157
    def __init__(self, libraries):
163
    def __init__(self, libraries, shared=False):
158
164
        self.libraries = libraries
159
        self.keys = dict()
165
        self.shared = shared
166
        self.globals = dict()
167
        self.exports = dict()
160
168
161
169
    def __getitem__(self, key):
162
        if key in self.keys:
163
            return self.keys[key]
170
        if key in self.globals:
171
            return self.globals[key]
164
172
        else:
165
173
            cell = core.Bytes('\x00'*4)
166
            self.keys[key] = cell
174
            self.globals[key] = cell
167
175
            return cell
176
177
    def export(self, name, assembly):
178
        self.exports[name] = assembly
179
        self.shared = True
168
180
    
169
181
    def build(self):
170
        externals = self.keys.keys()
171
        dynstr = Strings(self.libraries + externals + ['_DYNAMIC'])
172
        dynsym = SymbolTable(dynstr, externals)
173
        reltext = RelTab(dynsym, self.keys.items())
182
        symbol_names = set()
183
        symbol_names.update(self.globals)
184
        symbol_names.update(self.exports)
185
        symbol_names = list(symbol_names)
186
187
        dynstr = Strings(self.libraries + symbol_names + ['_DYNAMIC'])
188
        dynsym = SymbolTable(dynstr, symbol_names, self.exports)
189
        reltext = RelTab(dynsym, self.globals.items())
174
190
        needed = [[1, dynstr[library]] for library in self.libraries]
175
191
        hashtab = HashTable(dynsym)
176
192
        dynamic = DynTab(needed + [
@@ -184,7 +200,7 @@ class Dynamic(object):
184
200
            [19, reltext.entsize], # relent
185
201
        ])
186
202
        dynsym.dynamic = dynamic # hack used to complete the vicious ELF cycle.
187
        librarytab = core.Assembly(self.keys.values())
203
        librarytab = core.Assembly(self.globals.values())
188
204
        self.section = dynamic
189
205
        return core.Assembly([
190
206
            hashtab, dynamic, dynsym, reltext, librarytab, dynstr,
@@ -198,6 +214,9 @@ def executable(file, program, entry, dyn
198
214
    entry: program entry, object with an offset.
199
215
    dynamic: optional dynamic library extension.
200
216
    """
217
    physaddr = 0x800000
218
    exec_type = 2
219
201
220
    phdr_count = 1
202
221
    if dynamic:
203
222
        phdr_count = 3
@@ -205,14 +224,17 @@ def executable(file, program, entry, dyn
205
224
        program = [
206
225
            dynamic.build(),
207
226
            interp,
208
            core.Assembly(program)
209
        ]
227
        ] + program
228
        if dynamic.shared == True:
229
            exec_type = 3
210
230
211
    physaddr = 0x800000
212
231
    headers = headersize + phdr_count*loadersize
213
232
    textsize = core.pass0(program, physaddr + headers)
214
233
    filesize = textsize + headers
215
    file.write(buildheader(entry = entry.address, phdrnum = phdr_count))
234
    file.write(buildheader(
235
        entry = entry.address, phdrnum = phdr_count,
236
        type = exec_type,
237
    ))
216
238
217
239
    if dynamic:
218
240
        file.write(buildloader(

Up to file-list usage_example.c:

1
/*
2
gcc usage_example.c -o usage_example ./libshared.so -m32
3
LD_LIBRARY_PATH=. ./usage_example
4
*/
5
#include <stdio.h>
6
#include <stdlib.h>
7
#include <dlfcn.h>
8
9
extern int example_function();
10
11
int main(){
12
    printf("hello %d\n", example_function());
13
}

Up to file-list usage_example2.c:

1
/*
2
gcc usage_example2.c -o usage_example2 -m32 -ldl
3
./usage_example
4
*/
5
#include <stdio.h>
6
#include <stdlib.h>
7
#include <dlfcn.h>
8
9
int (*example_function)();
10
11
int main(){
12
    void* handle = dlopen("./libshared.so", RTLD_LAZY);
13
    if (!handle)
14
    {
15
        fprintf(stderr, "Cannot open libshared.so: %s\n", dlerror());
16
        exit(1);
17
    }
18
    example_function = dlsym(handle, "example_function");
19
20
21
    printf("hello %d\n", example_function());
22
}