X-Git-Url: https://git.alrj.org/?p=bold.git;a=blobdiff_plain;f=bold.py;h=02f6626611aa4fdaca94ee2e6c6f2100b9ce7416;hp=74a8ba2c48c1f2cb45541e45b2e379373073bc48;hb=7eeaa837d3a6f29f9312bf29962214e709663e52;hpb=aa036795cb0ab7f31b9d78cfa562ccb603bc977a diff --git a/bold.py b/bold.py index 74a8ba2..02f6626 100755 --- a/bold.py +++ b/bold.py @@ -5,195 +5,117 @@ # Copyright (C) 2009 Amand 'alrj' Tihon # # This file is part of bold, the Byte Optimized Linker. -# Heavily inspired by elf.h from the GNU C Library. # # You can redistribute this file and/or modify it under the terms of the # GNU Lesser General Public License as published by the Free Software # Foundation, version 2.1. -from elf.BinArray import BinArray -from elf.constants import * -from elf.elf import Elf64, Elf64_Phdr, TextSegment, DataSegment, Dynamic, Interpreter -import struct, sys - -infiles = [Elf64(n) for n in sys.argv[1:]] -for i in infiles: - i.resolve_names() - i.find_symbols() - -#h = infile.header -#print "Class: %s" % h.e_ident.ei_class -#print "Data: %s" % h.e_ident.ei_data -#print "Version: %s" % h.e_ident.ei_version -#print "OS/ABI: %s" % h.e_ident.ei_osabi -#print "ABI Version: %s" % h.e_ident.ei_abiversion -#print "Type: %s" % h.e_type -#print "Machine: %s" % h.e_machine -#print "Version: %s" % h.e_version -#print "Entry point address: 0x%x" % h.e_entry -#print "Start of program headers: %i (bytes into file)" % h.e_phoff -#print "Start of section headers: %i (bytes into file)" % h.e_shoff -#print "Flags: 0x%x" % h.e_flags -#print "Size of this header: %i (bytes)" % h.e_ehsize -#print "Size of program headers: %i (bytes)" % h.e_phentsize -#print "Number of program headers: %i" % h.e_phnum -#print "Size of section headers: %i (bytes)" % h.e_shentsize -#print "Number of section headers: %i" % h.e_shnum - -#print "Section header string table index: %s" % h.e_shstrndx - -#print - -#print "Section Headers:" -#for sh in infile.shdrs: - #print "[%2i] %-16s %-16s %016x %08x" % (sh.index, sh.name, sh.sh_type, - #sh.sh_addr, sh.sh_offset) - #print " %016x %016x %-5s %4i %4i %4i" % (sh.sh_size, sh.sh_entsize, - #sh.sh_flags, sh.sh_link, sh.sh_info, sh.sh_addralign) -#print - -#for sh in infile.shdrs : - #if sh.sh_type == SHT_STRTAB: - ##print "Section %i is a string table with entries :" % sh.index - ##for i, name in sh.content.iteritems(): - ## print "%4i %s" % (i, name) - #print - #elif sh.sh_type == SHT_SYMTAB: - #print "Section %i is a symbol table with entries :" % sh.index - #print " Num: Value Size Type Bind Vis Ndx Name" - #for i, sym in enumerate(sh.content.symtab): - #print "%6i: %016x %5s %-7s %-6s %-7s %4s %s" % (i, - #sym.st_value, sym.st_size, sym.st_type, sym.st_binding, - #sym.st_visibility, sym.st_shndx, sym.name) - #print - #elif sh.sh_type == SHT_RELA: - #print "Section %s is a RELA that applies to %s:" % (sh.name, sh.target.name) - #print " Offset Info Type Sym. Value Sym. Name + Addend" - #for i in sh.content.relatab: - #print "%012x %012x %-16s %016x %s%s + %x" % (i.r_offset, i.r_info, - #i.r_type, i.symbol.st_value, i.symbol.name, - #sh.owner.shdrs[i.symbol.st_shndx].name, - #i.r_addend) - #print - - - -outfile = Elf64() - -text_segment = TextSegment() -data_segment = DataSegment(align=0x100000) - -outfile.add_segment(text_segment) -outfile.add_segment(data_segment) - - -outfile.header.e_ident.make_default_amd64() -outfile.header.e_phoff = outfile.header.size -outfile.header.e_type = ET_EXEC -text_segment.add_content(outfile.header) - -ph_text = Elf64_Phdr() -ph_text.p_type = PT_LOAD -ph_text.p_align = 0x100000 -outfile.add_phdr(ph_text) -text_segment.add_content(ph_text) - -ph_data = Elf64_Phdr() -ph_data.p_type = PT_LOAD -ph_data.p_align = 0x100000 -outfile.add_phdr(ph_data) -text_segment.add_content(ph_data) - -ph_dynamic = Elf64_Phdr() -ph_dynamic.p_type = PT_DYNAMIC -outfile.add_phdr(ph_dynamic) -text_segment.add_content(ph_dynamic) - -ph_interp = Elf64_Phdr() -ph_interp.p_type = PT_INTERP -outfile.add_phdr(ph_interp) -text_segment.add_content(ph_interp) - -interp = Interpreter() -text_segment.add_content(interp) - -dynamic = Dynamic() -dynamic.add_shlib("libGL.so.1") -dynamic.add_shlib("libSDL-1.2.so.0") -dynamic.add_symtab(0) -dynamic.add_debug() -data_segment.add_content(dynamic) -text_segment.add_content(dynamic.strtab) - - -# Find interresting sections in input file -for i in infiles: - for sh in i.shdrs: - if (sh.sh_flags & SHF_ALLOC): - if (sh.sh_flags & SHF_EXECINSTR): - text_segment.add_content(sh.content) - else: # No exec, it's for .data - if (sh.sh_type == SHT_NOBITS): - data_segment.add_nobits(sh.content) - else: - data_segment.add_content(sh.content) - - -outfile.layout(base_vaddr=0x400000) - - -# Set addresses, sizes, etc. where known -outfile.header.e_phnum = len(outfile.phdrs) -outfile.header.e_phoff = outfile.phdrs[0].file_offset - -ph_text.p_offset = text_segment.file_offset -ph_text.p_vaddr = text_segment.virt_addr -ph_text.p_filesz = text_segment.physical_size -ph_text.p_memsz = text_segment.logical_size - -ph_data.p_offset = data_segment.file_offset -ph_data.p_vaddr = data_segment.virt_addr -ph_data.p_filesz = data_segment.physical_size -ph_data.p_memsz = data_segment.logical_size - -ph_interp.p_offset = interp.file_offset -ph_interp.p_vaddr = interp.virt_addr -ph_interp.p_filesz = interp.physical_size -ph_interp.p_memsz = interp.logical_size - -ph_dynamic.p_offset = dynamic.file_offset -ph_dynamic.p_vaddr = dynamic.virt_addr -ph_dynamic.p_filesz = dynamic.physical_size -ph_dynamic.p_memsz = dynamic.logical_size - -for i in infiles: - outfile.undefined_symbols.extend(i.undefined_symbols) - -dt_dbg = dynamic.dt_debug_address -outfile.global_symbols["_dt_debug"] = dt_dbg -outfile.global_symbols["_DYNAMIC"] = dynamic.virt_addr - -# Take all globally declared symbols, and put them in outfile's dict -for i in infiles: - for s in i.global_symbols: - section_addr = i.global_symbols[s][0].content.virt_addr - addr = section_addr + i.global_symbols[s][1] - if s in outfile.global_symbols: - print "Symbol '%s' defined more than once." - exit(1) - outfile.global_symbols[s] = addr - -for i in infiles: - i.apply_relocation(outfile.global_symbols) - -_start = outfile.global_symbols["_start"] -outfile.header.e_entry = _start - -# outfile.apply_global_relocation() - -f = open("prout", "wb") -outfile.toBinArray().tofile(f) -f.close() - - +#from bold.constants import * +#from bold.elf import Elf64, Elf64_Phdr, TextSegment, DataSegment, Dynamic, Interpreter + +__author__ = "Amand Tihon " +__version__ = "0.0.1" + + +from Bold.linker import BoldLinker +from Bold.errors import * +from optparse import OptionParser +import os, sys + +class BoldOptionParser(OptionParser): + """Bold option parser.""" + global __version__ + _usage_message = "%prog [options] file..." + _version_message = "%%prog version %s" % __version__ + _description_message = """A limited ELF linker for x86_64. It is +intended to create very small executables with the least possible overhead.""" + + def __init__(self): + OptionParser.__init__(self, usage=self._usage_message, + version=self._version_message, description=self._description_message, + add_help_option=True, prog="bold") + + self.set_defaults(entry="_start", outfile="a.out") + + self.add_option("-e", "--entry", action="store", dest="entry", + metavar="SYMBOL", help="Set the entry point (default: _start)") + self.add_option("-l", "--library", action="append", dest="shlibs", + metavar="LIBNAME", help="Search for library LIBNAME") + self.add_option("-o", "--output", action="store", dest="outfile", + metavar="FILE", help="Set output file name (default: a.out)") + + +def main(): + parser = BoldOptionParser() + options, args = parser.parse_args() + + linker = BoldLinker() + + if options.shlibs: + for shlib in options.shlibs: + try: + linker.add_shlib(shlib) + except LibNotFound, e: + print >>sys.stderr, e + return 1 + + if not args: + print >>sys.stderr, "No input files" + return 1 + + for infile in args: + try: + linker.add_object(infile) + except UnsupportedObject, e: + print >>sys.stderr, e + return 1 + except IOError, e: + print >>sys.stderr, e + return 1 + + linker.entry_point = options.entry + + try: + linker.link() + except UndefinedSymbol, e: + print >>sys.stderr, e + return 1 + except RedefinedSymbol, e: + print >>sys.stderr, e + return 1 + + # Remove the file if it was present + try: + os.unlink(options.outfile) + except os.error, e: + if e.errno == 2: # No such file + pass + + try: + o = open(options.outfile, "wb") + except IOError, e: + print >>sys.stderr, e + return 1 + + linker.tofile(o) + o.close() + + try: + os.chmod(options.outfile, 0755) + except IOError, e: + print >>sys.stderr, e + return 1 + + return 0 + + +if __name__ == "__main__": + try: + rcode = main() + except Exception, e: + raise + print >>sys.stderr, "Unhandled error:", e + rcode = 1 + + exit(rcode)