text: """A class for reading and writing ELF format binaries (esp. Amiga m68k ones)"""
  
  import struct
  import os
  from .ELF import *
  from .ELFFile import *
  
  
  class ELFReader:
      def _load_section_headers(self, f, ef):
          shoff = ef.header.shoff
          shentsize = ef.header.shentsize
          f.seek(shoff, os.SEEK_SET)
          shnum = ef.header.shnum
          for i in range(shnum):
              sh = ELFSectionHeader()
              sh_data = f.read(shentsize)
              sh.parse(sh_data)
              ef.section_hdrs.append(sh)
  
      def _load_sections(self, f, ef):
          sect_hdrs = ef.section_hdrs
          idx = 0
          for sect_hdr in sect_hdrs:
              idx += 1
              sect = self._load_section(f, sect_hdr, idx)
              ef.sections.append(sect)
  
      def _load_section(self, f, sect_hdr, idx):
          t = sect_hdr.type_
          size = sect_hdr.size
          if t == SHT_NOBITS or size == 0:
              sect = ELFSection(sect_hdr, idx)
          else:
              # read data
              offset = sect_hdr.offset
              f.seek(offset, os.SEEK_SET)
              data = f.read(size)
              # decode?
              if t == SHT_STRTAB:
                  sect = ELFSectionStringTable(sect_hdr, idx, data)
                  sect.decode()
              elif t == SHT_SYMTAB:
                  sect = ELFSectionSymbolTable(sect_hdr, idx, data)
                  sect.decode()
              elif t == SHT_RELA:
                  sect = ELFSectionRelocationsWithAddend(sect_hdr, idx, data)
                  sect.decode()
              else:
                  sect = ELFSectionWithData(sect_hdr, idx, data)
  
          return sect
  
      def _name_section(self, section, strtab):
          off = section.header.name
          section.name_str = strtab.get_string(off)
  
      def _resolve_symtab_names(self, sect, sections):
          # get linked string table
          strtab_seg_num = sect.header.link
          if strtab_seg_num < 1 or strtab_seg_num >= len(sections):
              raise ELFParseError("Invalid strtab for symtab: " + strtab_seg_num)
          strtab = sections[strtab_seg_num]
          if strtab.__class__ != ELFSectionStringTable:
              raise ELFParserError("Invalid strtab segment for symtab")
          # resolve all symbol names
          for sym in sect.symtab:
              sym.name_str = strtab.get_string(sym.name)
  
      def _resolve_symtab_indices(self, sect, sections):
          for sym in sect.symtab:
              if sym.shndx_str == None:
                  # refers a valid section
                  idx = sym.shndx
                  sym.section = sections[idx]
  
      def _assign_symbols_to_sections(self, sect):
          src_file_sym = None
          all_symbols = []
          for sym in sect.symtab:
              sym_type = sym.type_str
              if sym_type == "FILE":
                  # store file symbol for following symbols
                  src_file_sym = sym
              elif sym_type in ("OBJECT", "FUNC", "NOTYPE"):
                  # add containing file symbol and its name
                  if src_file_sym != None:
                      sym.file_sym = src_file_sym
                  else:
                      sym.file_sym = None
                  # add symbol to segment
                  sym_sect = sym.section
                  if sym_sect is not None:
                      sym_sect.symbols.append(sym)
                      # list of all symbols assigned
                      all_symbols.append(sym_sect.symbols)
          # now sort all symbol lists
          for symbols in all_symbols:
              symbols.sort(key=lambda x: x.value)
  
      def _resolve_rela_links(self, sect, sections):
          link = sect.header.link
          info = sect.header.info
          num_sects = len(sections)
          if link == 0 or link >= num_sects:
              raise ELFParseError("Invalid rela link!")
          if info == 0 or info >= num_sects:
              raise ELFParseError("Invalid rela info!")
  
          # info_seg -> src segment we will apply rela on
          src_sect = sections[info]
          sect.reloc_section = src_sect
  
          # link_seg -> symbol table
          sect.symtab = sections[link]
  
          # store link in segment for this relocation
          src_sect.relocations = sect
  
          # a map for rela by tgt segment
          by_sect = {}
          src_sect.reloc_by_sect = by_sect
  
          # now process all rela entries
          symtab = sect.symtab
          for entry in sect.rela:
              # look up symbol of rela entry
              sym_idx = entry.sym
              sym = symtab.get_symbol(sym_idx)
              entry.symbol = sym
              # copy section we relocate from
              entry.section = sym.section
              # calc addend in segment
              entry.section_addend = entry.addend + sym.value
  
              # clear symbol if its empty
              if sym.name_str == "":
                  entry.symbol = None
  
              # add entry to section list
              tgt_sect = entry.section
              if tgt_sect in by_sect:
                  by_sect_list = by_sect[tgt_sect]
              else:
                  by_sect_list = []
                  by_sect[tgt_sect] = by_sect_list
              by_sect_list.append(entry)
  
          # sort all by_seg entries
          for sect in by_sect:
              by_sect_list = by_sect[sect]
              by_sect_list.sort(key=lambda x: x.offset)
  
      def load(self, f):
          """load an ELF file from the given file object f
         and return an ELFFile instance or None if loading failed"""
  
          ef = ELFFile()
  
          # read identifier
          ident = ELFIdentifier()
          ident_data = f.read(16)
          ident.parse(ident_data)
          ef.identifier = ident
  
          # read header
          hdr = ELFHeader()
          hdr_data = f.read(36)
          hdr.parse(hdr_data)
          ef.header = hdr
  
          # expect a non-empty section header
          if hdr.shnum == 0:
              raise ELFParseError("No segment header defined!")
  
          # load all section headers
          self._load_section_headers(f, ef)
  
          # load and decode sections
          self._load_sections(f, ef)
  
          # get string table with segment names
          strtab_idx = ef.header.shstrndx
          strtab = ef.sections[strtab_idx]
          if strtab.__class__ != ELFSectionStringTable:
              raise ELFParseError("No strtab for segment header found! ")
  
          # process sections
          for sect in ef.sections:
              # name all sections by using the string table
              self._name_section(sect, strtab)
              # resolve symbol table names
              if sect.header.type_ == SHT_SYMTAB:
                  # store in file symtabs
                  ef.symtabs.append(sect)
                  # get names in symtab
                  self._resolve_symtab_names(sect, ef.sections)
                  # link sections to symbols
                  self._resolve_symtab_indices(sect, ef.sections)
                  # assign symbols to sections
                  self._assign_symbols_to_sections(sect)
  
          # resolve rela links and symbols
          for sect in ef.sections:
              if sect.header.type_ == SHT_RELA:
                  self._resolve_rela_links(sect, ef.sections)
                  ef.relas.append(sect)
  
          return ef
  
  
  # mini test
  if __name__ == "__main__":
      import sys
  
      reader = ELFReader()
      for a in sys.argv[1:]:
          f = open(a, "rb")
          ef = reader.load(f)
  