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 17: | 4ce524aa90f3 |
| parent 16: | 9750486c98ad |
| branch: | default |
Changed (Δ2.7 KB):
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)
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 |
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, I |
|
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) |
| … | … | @@ -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 |
| … | … | @@ -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 |
|
|
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. |
|
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. |
|
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. |
|
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( |
|
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 |
} |
