smol.py 3.11 KB
Newer Older
PoroCYon's avatar
PoroCYon committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/env python3

import argparse
import glob
import itertools
import os.path
import shutil
import subprocess
import sys

from smolshared import *
from smolparse  import *
from smolemit   import *

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-m', '--target', default='', \
        help='architecture to generate asm code for (default: auto)')
    parser.add_argument('-l', '--library', metavar='LIB', action='append', \
        help='libraries to link against')
    parser.add_argument('-L', '--libdir', metavar='DIR', action='append', \
        help="directories to search libraries in")

    parser.add_argument('--nasm', default=shutil.which('nasm'), \
        help="which nasm binary to use")
    parser.add_argument('--cc', default=shutil.which('cc'), \
        help="which cc binary to use")
    parser.add_argument('--scanelf', default=shutil.which('scanelf'), \
        help="which scanelf binary to use")
    parser.add_argument('--readelf', default=shutil.which('readelf'), \
        help="which readelf binary to use")
32

33
34
    parser.add_argument('-s', '--hash16', default=False, action='store_true', \
        help="Use 16-bit (BSD) hashes instead of 32-bit djb2 hashes. "\
35
            +"Must be used with -DUSE_DNLOAD_LOADER")
36
37
38
    parser.add_argument('-n', '--nx', default=False, action='store_true', \
        help="Use NX (i.e. don't use RWE pages). Costs the size of one phdr, "\
        +"plus some extra bytes on i386.")
39
40
41
    parser.add_argument('-d', '--det', default=False, action='store_true', \
        help="Make the order of imports deterministic (default: just use on "+\
        "whatever binutils throws at us)")
42

PoroCYon's avatar
PoroCYon committed
43
44
45
46
47
48
    parser.add_argument('input', nargs='+', help="input object file")
    parser.add_argument('output', type=argparse.FileType('w'), \
        help="output nasm file", default=sys.stdout)

    args = parser.parse_args()

49
50
51
52
53
54
55
    for x in ['nasm','cc','scanelf','readelf']:
        val = args.__dict__[x]
        if val is None or not os.path.isfile(val):
            eprintf("'" + x + "' binary" + (" " if val is None
                                            else " ('" + val + "')") + " not found")
            sys.exit(1)

PoroCYon's avatar
PoroCYon committed
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
    if args.libdir is None: args.libdir = []
    arch = args.target.tolower() if len(args.target)!=0 \
                                 else decide_arch(args.input)
    if arch not in archmagic:
        eprintf("Unknown architecture '" + str(arch) + "'")
        sys.exit(1)

    syms = get_needed_syms(args.readelf, args.input)

    paths = get_cc_paths(args.cc)

    spaths = args.libdir + paths['libraries']
    libraries=paths['libraries']
    libnames = args.library
    libs = list(find_libs(spaths, libnames))
    symbols = {}
PoroCYon's avatar
PoroCYon committed
72
    #print("libs = " + str(libs))
PoroCYon's avatar
PoroCYon committed
73

74
    for symbol, reloc in syms:
PoroCYon's avatar
PoroCYon committed
75
76
77
78
79
        library = find_symbol(args.scanelf, libs, libnames, symbol)
        if not library:
            eprintf("could not find symbol: {}".format(symbol))
            sys.exit(1)
        symbols.setdefault(library, [])
80
        symbols[library].append((symbol, reloc))
PoroCYon's avatar
PoroCYon committed
81

82
    output(arch, symbols, args.nx, args.hash16, args.output, args.det)
PoroCYon's avatar
PoroCYon committed
83
84
85
86

if __name__ == '__main__':
    main()