示例#1
0
文件: test_core.py 项目: paromix/okl4
 def test_prepare(self):
     ef = UnpreparedElfFile()
     segment = SectionedElfSegment(None, align=0x1)
     new_sect = UnpreparedElfSection(None, "pants")
     ef.add_section(new_sect)
     segment.add_section(new_sect)
     ef.add_segment(segment)
     ef.add_segment(HeaderElfSegment(None))
     ef = ef.prepare(32, '<')
示例#2
0
文件: test_core.py 项目: gapry/L4OS
 def test_prepare(self):
     ef = UnpreparedElfFile()
     segment = SectionedElfSegment(align=0x1)
     new_sect = UnpreparedElfSection("pants")
     ef.add_section(new_sect)
     segment.add_section(new_sect)
     ef.add_segment(segment)
     ef.add_segment(HeaderElfSegment())
     ef = ef.prepare(32, "<")
示例#3
0
文件: test_core.py 项目: gapry/L4OS
    def test_remove_section(self):
        ef = UnpreparedElfFile()
        sect = UnpreparedElfSection()
        self.assertRaises(InvalidArgument, ef.remove_section, sect)
        ef.add_section(sect)
        self.assertEqual(sect in ef.sections, True)
        ef.remove_section(sect)
        self.assertEqual(sect in ef.sections, False)

        seg = SectionedElfSegment()
        ef.add_segment(seg)
        ef.add_section(sect)
        seg.add_section(sect)
        self.assertEqual(sect in ef.sections, True)
        self.assertEqual(sect in seg.sections, True)
        ef.remove_section(sect)
        self.assertEqual(sect in ef.sections, False)
        self.assertEqual(sect in seg.sections, False)
示例#4
0
文件: test_core.py 项目: paromix/okl4
    def test_remove_section(self):
        ef = UnpreparedElfFile()
        sect = UnpreparedElfSection(None)
        self.assertRaises(InvalidArgument, ef.remove_section, sect)
        ef.add_section(sect)
        self.assertEqual(sect in ef.sections, True)
        ef.remove_section(sect)
        self.assertEqual(sect in ef.sections, False)

        seg = SectionedElfSegment(None)
        ef.add_segment(seg)
        ef.add_section(sect)
        seg.add_section(sect)
        self.assertEqual(sect in ef.sections, True)
        self.assertEqual(sect in seg.sections, True)  
        ef.remove_section(sect)
        self.assertEqual(sect in ef.sections, False)
        self.assertEqual(sect in seg.sections, False)  
示例#5
0
文件: link.py 项目: BruceYi/okl4
def link(files, section_vaddr = None, kernel_soc = True, rvct = False,
         verbose = False, verbose_merge = False, verbose_script = False,
         verbose_relocs = False):
    """
    Perform the actual link, split so that elfweaver merge can call this easily.
    """

    # Handle merging of multiple files.
    # Use the first provided elf file as the base file.  For each additonal file
    # merge the sections (.text -> .text) but do no other merging i.e. do not
    # merge any .text.foo into .text.  Update the symbol table and any relocs
    # to take into account the merging then merge in the symbol table and
    # relocation sections.
    base_elf = UnpreparedElfFile(files[0])
    base_elf.sections = []

    if verbose:
        print "Using %s as base file" % files[0]

    base_sym_tab = None

    for merge_file in files:
        merge_elf = UnpreparedElfFile(merge_file)

        if verbose:
            print "Merging in file %s" % merge_file

        sym_tab = [sym_tab for sym_tab in merge_elf.sections
                   if sym_tab.type == SHT_SYMTAB]

        # Things get really, really ugly if there is more than one symbol table,
        # fortunately sane compilers / linkers appear to only have one anyway.
        assert len(sym_tab) == 1

        sym_tab = sym_tab[0]

        merged_sects = []
        reloc_sects = []

        ind = 1
        if base_elf.sections == []:
            ind = 0

        for sect in merge_elf.sections[ind:]:
            # Symbol table and relocations require more specific magic and get
            # handled later on
            if sect.type == SHT_SYMTAB:
                continue
            elif sect.type in (SHT_REL, SHT_RELA):
                reloc_sects.append(sect)
                continue

            found_sect = base_elf.find_section_named(sect.name)
            if found_sect == None:
                # Don't need to merge this section as there is no corrosponding
                # entry in the base file, so just go ahead and add it.
                base_elf.add_section(sect)

                if verbose_merge:
                    print "\tAdding section %s" % sect.name

                continue

            merge_sections(found_sect, sect, merged_sects, None,
                           verbose_merge)

        # Update any symbols or relocations that relied on a merged section
        # to correctly point at the new section at the correct offset
        if verbose:
            print "\tUpdating relocation sections with merged data"

        sym_tab.update_merged_sections(merged_sects)
        for sect in reloc_sects:
            sect.update_merged_sections(merged_sects)

        # Merge the symbol tables, this is more just tricky than any deep magic
        # * For each undefined symbol in the base file try to find a match
        #   in the input file.  If we find one then replace the base file's
        #   symbol with the defined one.  Keep a list of the mappings from the
        #   input files symbols to the new base file symbol index.
        # * Merge the two symbol tables.  For each symbol in the input file's
        #   symbol table;
        #   * If it is undefined, try to find a match in the base file's symbol
        #     table.  If found record the mapping from old symbol to new index.
        #   * If it is defined or there is no match copy it over, again keeping
        #     a mapping from old symbol to new index.
        # * Update all the relocations in the input file to correctly point at
        #   the new symbol table and the correct symbol index.  And merge in
        #   the relocations sections if a section already exists or add them.
        if base_sym_tab:
            if verbose:
                print "\tMerging symbol tables"

            merged_syms = base_sym_tab.resolve(sym_tab)
            merged_syms += base_sym_tab.merge(sym_tab)

            for sect in reloc_sects:
                sect.update_merged_symbols(base_sym_tab, merged_syms)
        else:
            if verbose:
                print "\tAdding symbol table"

            base_elf.add_section(sym_tab)
            base_sym_tab = sym_tab

        for sect in reloc_sects:
            found_sect = base_elf.find_section_named(sect.name)

            if found_sect == None:
                base_elf.add_section(sect)

                if verbose_merge:
                    print "\tAdding relocation section %s" % sect.name
            else:
                found_sect.append_relocs(sect.get_relocs())

                if verbose_merge:
                    print "\tMerging in relocation section %s" % sect.name

    # Now before we lay everything out we need to adjust the size of any
    # sections (such as the .bss or .got) that may increase in size due
    # to allocation of symbols, etc.
    if verbose:
        print "Allocating symbol and relocation data"

    base_sym_tab.allocate_symbols()

    reloc_sects = []
    for sect in base_elf.sections:
        if sect.type in (SHT_REL, SHT_RELA):
            #pylint: disable-msg=E1103
            sect.set_verbose(verbose_relocs)
            sect.allocate_relocs()
            reloc_sects.append(sect)

    # Do any linker scripty things we need to do.  For the moment we either do
    # a standard link or a kernel+soc link, the actions performed are in python
    # functions currently but may be moved into external scripts later.
    if kernel_soc:
        if verbose:
            print "Performing a kernel + soc link, rvct", rvct

        kernel_link_func_types = KERNEL_SOC_LINKER_SCRIPT[base_elf.machine]
        if not rvct:
            kernel_link_func = kernel_link_func_types['gnu']
        else:
            kernel_link_func = kernel_link_func_types['rvct']

        segments, merged_sects, discarded_sects = \
                perform_link(base_elf, base_sym_tab, kernel_link_func,
                             section_vaddr, verbose_script)
    else:
        if verbose:
            print "Performing standard link"

        segments, merged_sects, discarded_sects = \
                perform_link(base_elf, base_sym_tab, standard_link,
                             section_vaddr, verbose_script)

    # Remove any symbols relating to discarded sections and update for any of
    # the merged sections
    if verbose:
        print "Updating symbols for discarded and merged sections"

    discarded_syms = base_sym_tab.update_discarded_sections(discarded_sects)
    base_sym_tab.update_merged_sections(merged_sects)

    if verbose:
        print "Updating relocation sections with new symbols"

    for sect in reloc_sects:
        sect.update_discarded_symbols(discarded_syms)
        sect.update_discarded_sections(discarded_sects)
        sect.update_merged_sections(merged_sects)

    # Segments don't have the correct flags yet, go through and update them
    # based on the types of the included sections.
    for seginfo in segments:
        flags = PF_R

        for sect in seginfo[2]:
            if sect.flags & SHF_WRITE:
                flags |= PF_W
            if sect.flags & SHF_EXECINSTR:
                flags |= PF_X

        seginfo[0] = flags

    for flags, base_addr, sects in segments:
        if len(sects) == 0:
            continue

        new_seg = SectionedElfSegment(base_elf, PT_LOAD, base_addr, base_addr,
                                 flags, SEGMENT_ALIGN, sections=sects)
        base_elf.add_segment(new_seg)

        if verbose:
            print "Adding segment to file"
            print "\tFlags %d (R %d, W %d, X %d)" % (flags, flags & PF_R > 0,
                                                     flags & PF_W > 0,
                                                     flags & PF_X > 0)
            print "\tBase address %x" % base_addr
            print "\tSections", [sect.name for sect in sects]

    # All sections are laid out and at their final size, go through and update
    # symbol values to their final position
    if verbose:
        print "Updating symbols"

    base_sym_tab.update_symbols()

    relocated_all = True
    # Apply all the relocs we know how to handle
    relocs_remove = []

    if verbose:
        print "Applying relocations"

    for sect in reloc_sects:
        if sect.apply():
            relocs_remove.append(sect)
        else:
            relocated_all = False

    if verbose:
        print "Applied all relocations", relocated_all

    for sect in relocs_remove:
        base_elf.remove_section(sect)

    if relocated_all:
        # Set the ELF entry point to _start
        base_elf.entry_point = base_elf.find_symbol("_start").value
        # Set ELF type to an executable
        base_elf.elf_type = ET_EXEC

        if verbose:
            print "Setting entry point to %x" % base_elf.entry_point

    return base_elf
示例#6
0
class Image:
    """Representation of the contents of the final image."""
    # Different types of segments.
    # NOTE:  PROGRAM and EXTENSION must have the values 1 and 2 to
    # maintain binary compatibility with the iguana library function
    # get_elf_info().
    PROGRAM      = 1
    EXTENSION    = 2
    KERNEL       = 3
    ROOT_PROGRAM = 4

    class Patch:
        """A Class for describing patches to segments."""
        def __init__(self, addr, size, value):
            self.addr    = addr
            self.size    = size
            self.value   = value

        def get_addr(self):
            """Return the address to patch."""
            return self.addr

        def get_size(self):
            """Return the number of bytes to change."""
            return self.size

        def get_value(self):
            """Return the value to patch in."""
            return self.value

    class AttrStack:
        """
        Class for holding a stack of attribute values.  Virtpool,
        physpool and pagers operate in that way.

        These stacks differ from regular stacks in that the top of the
        stack is defined to be the last non-None entry in the list.
        """
        def __init__(self):
            self.stack = []
            self.top   = None

        def __getitem__(self, index):
            return self.stack[index]

        def set(self, value):
            """
            Set the stack to only contain the given value.
            """
            assert value is not None

            self.stack = [value]
            self.top   = 0

            assert self.top is None or self.top < len(self.stack)

        def push(self, value):
            """
            Push an item onto the stack.  If the item is not None,
            then then will become the top of the stack.
            """
            self.stack.append(value)

            if value is not None:
                self.top = len(self.stack) - 1

                if self.top < 0:
                    self.top = None
        
            assert self.top is None or \
                   (self.top < len(self.stack) and \
                    self.stack[self.top] is not None)

        def pop(self):
            """
            Pop on item off the stack.  If the item is non-None,
            then the top of the stack is moved to the last non-None
            value in the list.
            """
            value = self.stack.pop()

            if value is not None:
                # Recalculate the top of the stack.
                self.top = None
                i        = 0

                for item in self.stack:
                    if item is not None:
                        self.top = i
                    i += 1

                assert self.top is None or \
                       self.stack[self.top] is not None

            assert self.top is None or self.top < len(self.stack)

        def tos(self):
            """
            Return the item at the top of the stack, or None if there
            is no such item.
            """
            if self.top is None:
                return None
            else:
                return self.stack[self.top]


    def __init__(self, ph_offset):
        self.ph_offset = ph_offset
        self.kconfig = KernelInit()
        self.objects = None
        self.kernel_segments = []
        self.kernel_heap     = None
        self.kernel_arrays     = []
        self.segments    = []
        self.memsections = []
        self.zones       = []
        self.elf     = None
        self.endianess = None
        self.wordsize = None
        self.patches = []
        self.virt_pool_stack = Image.AttrStack()
        self.phys_pool_stack = Image.AttrStack()
        self.pager_stack     = Image.AttrStack()
        self.direct_stack    = Image.AttrStack()
        self.protected_segment = None
        self.groups = []

    def get_elf(self):
        """Return the ELF file that will contain the image."""
        return self.elf

    def remove_section_headers(self):
        self.elf.remove_section_headers()

    def current_pools(self):
        """Return the current virtual and physical pools."""
        return (self.virt_pool_stack.tos(),
                self.phys_pool_stack.tos())

    def new_attrs(self, namespace, for_segment = False):
        """
        Create a new attribute object.

        The attributes are initialised with the current values from
        the attribute stack and the supplied namespace.
        """
        def_direct = False

        if for_segment:
            def_direct = self.direct_stack.tos()

        if namespace is None:
            path = '/'
        else:
            path = namespace.abs_name('.')

        return ImageAttrs(path     = path,
                          virtpool = self.virt_pool_stack.tos(),
                          physpool = self.phys_pool_stack.tos(),
                          pager    = self.pager_stack.tos(),
                          direct   = def_direct)

    def set_attrs_stack(self, def_virt = None, def_phys = None,
                        def_pager = None, def_direct = None):
        """
        Prime the attribute stack with initial values.
        """
        if def_virt is not None:
            self.virt_pool_stack.set(def_virt)

        if def_phys is not None:
            self.phys_pool_stack.set(def_phys)

        if def_pager is not None:
            self.pager_stack.set(def_pager)

        if def_direct is not None:
            self.direct_stack.set(def_direct)

    def push_attrs(self, virtual = None, physical = None,
                   pager = None, direct = None):
        """Push values onto the attribute stack."""
        self.virt_pool_stack.push(virtual)
        self.phys_pool_stack.push(physical)
        self.pager_stack.push(pager)
        self.direct_stack.push(direct)

    def pop_attrs(self):
        """Pop values from the attribute stack."""
        self.virt_pool_stack.pop()
        self.phys_pool_stack.pop()
        self.pager_stack.pop()
        self.direct_stack.pop()

    def prepare(self, machine):
        """Prepare the ELF file for writing to disk."""
        self.elf = self.elf.prepare(self.wordsize, self.endianess)

    def set_rootserver_stack(self, stack):
        """Record the root-servers stack pointer."""
        self.kconfig.set_rootserver_stack(stack)

    def write_out_image(self, output_file, machine):
        """Write out the final ELF file."""
        # Record the physical properties of the root server.
        # Note: Groovy functional programming!
        root_mappings = [o.root_mappings() for o in self.objects
                         if o.root_mappings() is not None]
        assert len(root_mappings) > 0
        self.kconfig.set_rootserver_mappings(root_mappings)

        # Record memory descriptors for those objects that need them.
        for obj in self.objects:
            descs = obj.make_memdesc()

            if descs is not None:
                for desc in descs:
                    self.kconfig.add_mem_descriptor(desc)

        # Now write out the data.
        self.kconfig.update_elf(self.elf, machine)
        #self.elf = self.elf.prepare(self.wordsize, self.endianess)
        self.elf.to_filename(output_file)
        
    def make_single_list(self):
        """
        Place all of the objects into a single list to generate a good
        layout.

        Items that will be written to the ELF file are placed together
        to try and reduce the size of the image.
        """
        #
        # Approximate proper support for proximity by placing the
        # kernel heap close to the kernel and memsections with data
        # close to the segments.
        #
        # Proper support should be added to ensure that wombat's
        # vmlinux memsection is close to the wombat text.
        #
        self.objects = []
        self.objects.extend(self.kernel_segments)
        self.objects.extend(self.kernel_arrays)
        self.objects.append(self.kernel_heap)
        self.objects.extend(self.segments)
        self.objects.extend(self.memsections)

    def layout(self, machine, pools):
        """Layout the image in memory."""
        self.make_single_list()

        for obj in self.zones:
            obj.prime(self.virt_pool_stack[0],
                      self.phys_pool_stack[0],
                      pools)

        for obj in self.groups:
            obj.layout(self.virt_pool_stack[0],
                       self.phys_pool_stack[0],
                       machine,
                       pools)

    def apply_patches(self):
        """Apply registered patches."""
        for segment in self.elf.segments:
            for section in segment.sections:
                patches = [patch for patch in self.patches
                           if patch.addr >= section.address and
                           patch.addr < section.address + section.get_size()]
                for patch in patches:
                    offset = patch.addr - section.address
                    if isinstance(patch.value, weaver.image.ImageObject):
                        value = patch.value.attrs.phys_addr
                    else:
                        value = patch.value
                    section.get_data().set_data(offset, value, 
                                                patch.size, self.endianess)

    def get_value(self, address, size, endianess=None):
        """get a value from the image."""
        if self.elf.machine == ElfMachine(8):
            if self.elf.flags & EF_MIPS_ABI_O64:
                if address & 0x80000000:
                    address |= 0xffffffff00000000L

        for segment in self.elf.segments:
            for section in segment.get_sections():
                if address > section.address and \
                       address < (section.address + section.get_size()):
                    offset = address - section.address
                    if endianess is None:
                        endianess = self.elf.endianess
                    return section.get_data().get_data(offset, size, endianess)

        raise MergeError, "Could not find address %x in Image." % address

    def set_kernel(self, kernel):
        """ Record the kernel."""
        self.elf = UnpreparedElfFile()
        self.endianess = kernel.endianess
        self.wordsize = kernel.wordsize

        self.elf.elf_type = ET_EXEC
        self.elf.machine = kernel.machine
        self.elf.osabi = kernel.osabi
        self.elf.abiversion = kernel.abiversion
        self.elf.flags = kernel.flags
        self.elf.entry_point = kernel.entry_point
        if self.ph_offset is not None:
            self.elf.set_ph_offset(self.ph_offset, fixed=True)

    def patch(self, addr, size, value):
        """Record the details of a patch to a segment."""
        if self.elf.machine == ElfMachine(8):
            if self.elf.flags & EF_MIPS_ABI_O64:
                if addr & 0x80000000:
                    addr |= 0xffffffff00000000L
        self.patches.append(self.Patch(addr, size, value))

    def set_kernel_heap(self, attrs, pools):

        """
        Record the details of the kernel heap.
        """
        self.kernel_heap = ImageKernelHeap(attrs, pools)
        return self.kernel_heap

    def add_kernel_array(self, attrs, pools):
        """Record the details of the kernel array."""
        array = ImageKernelArray(attrs, pools)
        self.kernel_arrays.append(array)
        return array

    def add_segment(self, segment_index, section_prefix,
                    segment, file_type, attrs, machine, pools):
        """Create a segment for inclusion in the image."""
        if not valid_segment(segment):
            return None

        # Remove any pathname components from the prefix.
        section_prefix = os.path.basename(section_prefix)

        # Prepare the image for inclusion.
        new_segment = segment.copy()

        # Align segments to the page boundary if is safe to do so.
        # RVCT tends to give very conservative alignment (1 word) to
        # segments that could be paged aligned.
        if new_segment.vaddr % machine.min_page_size() == 0 and \
               new_segment.align < machine.min_page_size():
            new_segment.align = machine.min_page_size()

        # Rename the sections in the segment, giving each the supplied
        # prefix
        if new_segment.has_sections():
            for section in new_segment.get_sections():
                assert section.link is None

                sec_name = section.name
                #strip GNU leading dots in section names
                if sec_name[0] == ".":
                    sec_name = sec_name[1:]

                section.name = "%s.%s" % (section_prefix, sec_name)
                if section_prefix != "kernel":
                    for symbol in section.symbols:
                        symbol.name = "%s-%s" % (section_prefix, symbol.name)
                self.elf.add_section(section)

        iseg = ImageSegment(new_segment, segment_index, file_type,
                            attrs, pools)

        if attrs.protected:
            if self.protected_segment is not None:
                raise MergeError, \
                      'Only one segment can be declared protected.  ' \
                      'Found "%s" and  "%s".' % \
                      (self.protected_segment.get_attrs().abs_name(),
                      attrs.abs_name())

            self.protected_segment = iseg

        # Kernel segments need to be at the start of the memory pools
        # to place them in a different list to keep track of them.
        if file_type == Image.KERNEL:
            self.kernel_segments.append(iseg)
        else:
            self.segments.append(iseg)

        self.elf.add_segment(new_segment)
        return iseg
        

    def add_memsection(self, attrs, machine, pools):
        """
        Create a memsection for inclusion in the image.

        If the data or file attributes of 'attr' are non-None, then a
        ELF segment will be created, otherwise the memsection will
        will be included in the address layout process, but will be
        created at runtime by Iguana server.
        """
        new_segment = None
        in_image = False

        if attrs.file is not None or attrs.data is not None:
            if attrs.file is not None:
                the_file = open(attrs.file, 'r')
                data = ByteArray(the_file.read())
                the_file.close()
            else:
                data = attrs.data
                
            if attrs.size is not None and len(data) < attrs.size:
                data.extend([0] * (attrs.size - len(data)))

            attrs.size = data.buffer_info()[1] * data.itemsize

            sect = UnpreparedElfSection(attrs.name, SHT_PROGBITS,
                                        attrs.virt_addr,
                                        data = data,
                                        flags = SHF_WRITE | SHF_ALLOC)
            self.elf.add_section(sect)
            new_segment = SectionedElfSegment(PT_LOAD, attrs.virt_addr,
                                              attrs.phys_addr, PF_R | PF_W,
                                              machine.min_page_size(),
                                              sections=[sect])
            self.elf.add_segment(new_segment)
            in_image = True
            
        obj = ImageMemsection(new_segment, attrs, pools)

        # If the memsection has data that goes into the image, then
        # put it at the front of the list so that it will be near the
        # code segments.
        if in_image:
            self.memsections = [obj] + self.memsections
        else:
            self.memsections.append(obj)

        return obj

    def add_zone(self, attrs, zone):
        """Create a zone for inclusion in the image."""
        izone = ImageZone(attrs, zone)
        self.zones.append(izone)

        return izone

    def add_group(self, distance, items, error_message = None):
        """Add an image group."""

        # Generate a static group for virtual addresses.
        virt_group = [i.get_allocator_item(is_virtual = True)
                      for i in items
                      if i.get_allocator_item(is_virtual = True) is not None]

        if len(virt_group) != 0:
            group = ImageGroup(distance, virt_group, error_message,
                               is_virtual = True)
            self.groups.append(group)

        # Generate a static group for physical addresses.
        phys_group = [i.get_allocator_item(is_virtual = False)
                      for i in items
                      if i.get_allocator_item(is_virtual = False) is not None]

        if len(phys_group) != 0:
            group = ImageGroup(distance, phys_group, error_message,
                               is_virtual = False)
            self.groups.append(group)

    def dump(self):
        """
        Print out a virtual and physical memory map of the final
        image.
        """
        virtual_objects = {}
        physical_objects = {}

        for obj in self.objects:
            if obj.attrs.virt_addr is not None:
                vbase = obj.attrs.virt_addr
                vend = vbase + obj.attrs.size - 1
                virtual_objects[vbase, vend] = obj.attrs.abs_name()
            if obj.attrs.phys_addr is not None:
                pbase = obj.attrs.phys_addr
                pend = pbase + obj.attrs.size - 1
                physical_objects[pbase, pend] = obj.attrs.abs_name()

        print "VIRTUAL:"
        for (base, end), name in sorted(virtual_objects.items()):
            print "  <%08x:%08x> %s" % (base, end, name)

        print "PHYSICAL:"
        for (base, end), name in sorted(physical_objects.items()):
            print "  <%08x:%08x> %s" % (base, end, name)
示例#7
0
文件: link.py 项目: openbox00/oktest
def link(files,
         section_vaddr=None,
         kernel_soc=True,
         rvct=False,
         verbose=False,
         verbose_merge=False,
         verbose_script=False,
         verbose_relocs=False):
    """
    Perform the actual link, split so that elfweaver merge can call this easily.
    """

    # Handle merging of multiple files.
    # Use the first provided elf file as the base file.  For each additonal file
    # merge the sections (.text -> .text) but do no other merging i.e. do not
    # merge any .text.foo into .text.  Update the symbol table and any relocs
    # to take into account the merging then merge in the symbol table and
    # relocation sections.
    base_elf = UnpreparedElfFile(files[0])
    base_elf.sections = []

    if verbose:
        print "Using %s as base file" % files[0]

    base_sym_tab = None

    for merge_file in files:
        merge_elf = UnpreparedElfFile(merge_file)

        if verbose:
            print "Merging in file %s" % merge_file

        sym_tab = [
            sym_tab for sym_tab in merge_elf.sections
            if sym_tab.type == SHT_SYMTAB
        ]

        # Things get really, really ugly if there is more than one symbol table,
        # fortunately sane compilers / linkers appear to only have one anyway.
        assert len(sym_tab) == 1

        sym_tab = sym_tab[0]

        merged_sects = []
        reloc_sects = []

        ind = 1
        if base_elf.sections == []:
            ind = 0

        for sect in merge_elf.sections[ind:]:
            # Symbol table and relocations require more specific magic and get
            # handled later on
            if sect.type == SHT_SYMTAB:
                continue
            elif sect.type in (SHT_REL, SHT_RELA):
                reloc_sects.append(sect)
                continue

            found_sect = base_elf.find_section_named(sect.name)
            if found_sect == None:
                # Don't need to merge this section as there is no corrosponding
                # entry in the base file, so just go ahead and add it.
                base_elf.add_section(sect)

                if verbose_merge:
                    print "\tAdding section %s" % sect.name

                continue

            merge_sections(found_sect, sect, merged_sects, None, verbose_merge)

        # Update any symbols or relocations that relied on a merged section
        # to correctly point at the new section at the correct offset
        if verbose:
            print "\tUpdating relocation sections with merged data"

        sym_tab.update_merged_sections(merged_sects)
        for sect in reloc_sects:
            sect.update_merged_sections(merged_sects)

        # Merge the symbol tables, this is more just tricky than any deep magic
        # * For each undefined symbol in the base file try to find a match
        #   in the input file.  If we find one then replace the base file's
        #   symbol with the defined one.  Keep a list of the mappings from the
        #   input files symbols to the new base file symbol index.
        # * Merge the two symbol tables.  For each symbol in the input file's
        #   symbol table;
        #   * If it is undefined, try to find a match in the base file's symbol
        #     table.  If found record the mapping from old symbol to new index.
        #   * If it is defined or there is no match copy it over, again keeping
        #     a mapping from old symbol to new index.
        # * Update all the relocations in the input file to correctly point at
        #   the new symbol table and the correct symbol index.  And merge in
        #   the relocations sections if a section already exists or add them.
        if base_sym_tab:
            if verbose:
                print "\tMerging symbol tables"

            merged_syms = base_sym_tab.resolve(sym_tab)
            merged_syms += base_sym_tab.merge(sym_tab)

            for sect in reloc_sects:
                sect.update_merged_symbols(base_sym_tab, merged_syms)
        else:
            if verbose:
                print "\tAdding symbol table"

            base_elf.add_section(sym_tab)
            base_sym_tab = sym_tab

        for sect in reloc_sects:
            found_sect = base_elf.find_section_named(sect.name)

            if found_sect == None:
                base_elf.add_section(sect)

                if verbose_merge:
                    print "\tAdding relocation section %s" % sect.name
            else:
                found_sect.append_relocs(sect.get_relocs())

                if verbose_merge:
                    print "\tMerging in relocation section %s" % sect.name

    # Now before we lay everything out we need to adjust the size of any
    # sections (such as the .bss or .got) that may increase in size due
    # to allocation of symbols, etc.
    if verbose:
        print "Allocating symbol and relocation data"

    base_sym_tab.allocate_symbols()

    reloc_sects = []
    for sect in base_elf.sections:
        if sect.type in (SHT_REL, SHT_RELA):
            #pylint: disable-msg=E1103
            sect.set_verbose(verbose_relocs)
            sect.allocate_relocs()
            reloc_sects.append(sect)

    # Do any linker scripty things we need to do.  For the moment we either do
    # a standard link or a kernel+soc link, the actions performed are in python
    # functions currently but may be moved into external scripts later.
    if kernel_soc:
        if verbose:
            print "Performing a kernel + soc link, rvct", rvct

        kernel_link_func_types = KERNEL_SOC_LINKER_SCRIPT[base_elf.machine]
        if not rvct:
            kernel_link_func = kernel_link_func_types['gnu']
        else:
            kernel_link_func = kernel_link_func_types['rvct']

        segments, merged_sects, discarded_sects = \
                perform_link(base_elf, base_sym_tab, kernel_link_func,
                             section_vaddr, verbose_script)
    else:
        if verbose:
            print "Performing standard link"

        segments, merged_sects, discarded_sects = \
                perform_link(base_elf, base_sym_tab, standard_link,
                             section_vaddr, verbose_script)

    # Remove any symbols relating to discarded sections and update for any of
    # the merged sections
    if verbose:
        print "Updating symbols for discarded and merged sections"

    discarded_syms = base_sym_tab.update_discarded_sections(discarded_sects)
    base_sym_tab.update_merged_sections(merged_sects)

    if verbose:
        print "Updating relocation sections with new symbols"

    for sect in reloc_sects:
        sect.update_discarded_symbols(discarded_syms)
        sect.update_discarded_sections(discarded_sects)
        sect.update_merged_sections(merged_sects)

    # Segments don't have the correct flags yet, go through and update them
    # based on the types of the included sections.
    for seginfo in segments:
        flags = PF_R

        for sect in seginfo[2]:
            if sect.flags & SHF_WRITE:
                flags |= PF_W
            if sect.flags & SHF_EXECINSTR:
                flags |= PF_X

        seginfo[0] = flags

    for flags, base_addr, sects in segments:
        if len(sects) == 0:
            continue

        new_seg = SectionedElfSegment(base_elf,
                                      PT_LOAD,
                                      base_addr,
                                      base_addr,
                                      flags,
                                      SEGMENT_ALIGN,
                                      sections=sects)
        base_elf.add_segment(new_seg)

        if verbose:
            print "Adding segment to file"
            print "\tFlags %d (R %d, W %d, X %d)" % (
                flags, flags & PF_R > 0, flags & PF_W > 0, flags & PF_X > 0)
            print "\tBase address %x" % base_addr
            print "\tSections", [sect.name for sect in sects]

    # All sections are laid out and at their final size, go through and update
    # symbol values to their final position
    if verbose:
        print "Updating symbols"

    base_sym_tab.update_symbols()

    relocated_all = True
    # Apply all the relocs we know how to handle
    relocs_remove = []

    if verbose:
        print "Applying relocations"

    for sect in reloc_sects:
        if sect.apply():
            relocs_remove.append(sect)
        else:
            relocated_all = False

    if verbose:
        print "Applied all relocations", relocated_all

    for sect in relocs_remove:
        base_elf.remove_section(sect)

    if relocated_all:
        # Set the ELF entry point to _start
        base_elf.entry_point = base_elf.find_symbol("_start").value
        # Set ELF type to an executable
        base_elf.elf_type = ET_EXEC

        if verbose:
            print "Setting entry point to %x" % base_elf.entry_point

    return base_elf
示例#8
0
文件: test_core.py 项目: gapry/L4OS
 def test_add_segment(self):
     ef = UnpreparedElfFile()
     seg = DataElfSegment(data=ByteArray("pants"))
     ef.add_segment(seg)
     self.assertEqual(ef.segments[-1], seg)
示例#9
0
文件: image.py 项目: openbox00/oktest
class Image:
    """Representation of the contents of the final image."""
    # Different types of segments.
    # NOTE:  PROGRAM and EXTENSION must have the values 1 and 2 to
    # maintain binary compatibility with the iguana library function
    # get_elf_info().
    PROGRAM = 1
    EXTENSION = 2
    KERNEL = 3
    ROOT_PROGRAM = 4

    class Patch:
        """A Class for describing patches to segments."""
        def __init__(self, addr, size, value, offset=0):
            self.addr = addr
            self.size = size
            self.value = value
            self.offset = offset

    class AttrStack:
        """
        Class for holding a stack of attribute values.  Virtpool,
        physpool and pagers operate in that way.

        These stacks differ from regular stacks in that the top of the
        stack is defined to be the last non-None entry in the list.
        """
        def __init__(self):
            self.stack = []
            self.top = None

        def __getitem__(self, index):
            return self.stack[index]

        def set(self, value):
            """
            Set the stack to only contain the given value.
            """
            assert value is not None

            self.stack = [value]
            self.top = 0

            assert self.top is None or self.top < len(self.stack)

        def push(self, value):
            """
            Push an item onto the stack.  If the item is not None,
            then then will become the top of the stack.
            """
            self.stack.append(value)

            if value is not None:
                self.top = len(self.stack) - 1

                if self.top < 0:
                    self.top = None

            assert self.top is None or \
                   (self.top < len(self.stack) and \
                    self.stack[self.top] is not None)

        def pop(self):
            """
            Pop on item off the stack.  If the item is non-None,
            then the top of the stack is moved to the last non-None
            value in the list.
            """
            value = self.stack.pop()

            if value is not None:
                # Recalculate the top of the stack.
                self.top = None
                i = 0

                for item in self.stack:
                    if item is not None:
                        self.top = i
                    i += 1

                assert self.top is None or \
                       self.stack[self.top] is not None

            assert self.top is None or self.top < len(self.stack)

        def tos(self):
            """
            Return the item at the top of the stack, or None if there
            is no such item.
            """
            if self.top is None:
                return None
            else:
                return self.stack[self.top]

        def bot(self):
            """
            Return the item at the bottom of the stack, or None if the
            stack is empty.
            """
            if len(self.stack) == 0:
                return None
            else:
                return self.stack[0]

    def __init__(self, ph_offset):
        self.ph_offset = ph_offset
        self.objects = None
        self.kernel_segments = []
        self.kernel_heap = None
        self.kernel_arrays = []
        self.utcb_areas = []
        self.utcb_size = 0
        self.segments = []
        self.memsections = []
        self.zones = []
        self.elf = None
        self.endianess = None
        self.wordsize = None
        self.patches = []
        self.virt_pool_stack = Image.AttrStack()
        self.phys_pool_stack = Image.AttrStack()
        self.pager_stack = Image.AttrStack()
        self.direct_stack = Image.AttrStack()
        self.protected_segment = None
        self.groups = []

    def get_elf(self):
        """Return the ELF file that will contain the image."""
        return self.elf

    def current_pools(self):
        """Return the current virtual and physical pools."""
        return (self.virt_pool_stack.tos(), self.phys_pool_stack.tos())

    def new_attrs(self, ns_node, for_segment=False):
        """
        Create a new attribute object.

        The attributes are initialised with the current values from
        the attribute stack and the supplied namespace.
        """
        def_direct = False

        if for_segment:
            def_direct = self.direct_stack.tos()

        return ImageAttrs(ns_node=ns_node,
                          virtpool=self.virt_pool_stack.tos(),
                          physpool=self.phys_pool_stack.tos(),
                          pager=self.pager_stack.tos(),
                          direct=def_direct)

    def set_attrs_stack(self,
                        def_virt=None,
                        def_phys=None,
                        def_pager=None,
                        def_direct=None):
        """
        Prime the attribute stack with initial values.
        """
        if def_virt is not None:
            self.virt_pool_stack.set(def_virt)

        if def_phys is not None:
            self.phys_pool_stack.set(def_phys)

        if def_pager is not None:
            self.pager_stack.set(def_pager)

        if def_direct is not None:
            self.direct_stack.set(def_direct)

    def push_attrs(self, virtual=None, physical=None, pager=None, direct=None):
        """Push values onto the attribute stack."""
        self.virt_pool_stack.push(virtual)
        self.phys_pool_stack.push(physical)
        self.pager_stack.push(pager)
        self.direct_stack.push(direct)

    def pop_attrs(self):
        """Pop values from the attribute stack."""
        self.virt_pool_stack.pop()
        self.phys_pool_stack.pop()
        self.pager_stack.pop()
        self.direct_stack.pop()

    def prepare(self):
        """Prepare the ELF file for writing to disk."""
        self.elf = self.elf.prepare(self.wordsize, self.endianess)

    def write_out_image(self, output_file, image, kernel, machine):
        """Write out the final ELF file."""
        kernel.update_elf(self.elf, image, machine)
        #self.elf = self.elf.prepare(self.wordsize, self.endianess)
        self.elf.to_filename(output_file)

    def make_single_list(self):
        """
        Place all of the objects into a single list to generate a good
        layout.

        Items that will be written to the ELF file are placed together
        to try and reduce the size of the image.
        """
        #
        # Approximate proper support for proximity by placing the
        # kernel heap close to the kernel and memsections with data
        # close to the segments.
        #
        # Proper support should be added to ensure that wombat's
        # vmlinux memsection is close to the wombat text.
        #
        self.objects = []
        self.objects.extend(self.kernel_segments)
        self.objects.extend(self.kernel_arrays)
        self.objects.append(self.kernel_heap)
        self.objects.extend(self.utcb_areas)
        self.objects.extend(self.segments)
        self.objects.extend(self.memsections)

    def layout(self, machine, pools):
        """Layout the image in memory."""
        self.make_single_list()

        for obj in self.zones:
            obj.prime(self.virt_pool_stack[0], self.phys_pool_stack[0], pools)

        for obj in self.groups:
            obj.layout(self.virt_pool_stack[0], self.phys_pool_stack[0],
                       machine, pools)

    def apply_patches(self):
        """Apply registered patches."""
        for segment in self.elf.segments:
            for section in segment.sections:
                patches = [
                    patch for patch in self.patches
                    if patch.addr >= section.address
                    and patch.addr < section.address + section.get_size()
                ]
                for patch in patches:
                    offset = patch.addr - section.address
                    if isinstance(patch.value, weaver.image.ImageObject):
                        value = patch.value.attrs.phys_addr + patch.offset
                    else:
                        value = patch.value + patch.offset
                    section.get_data().set_data(offset, value, patch.size,
                                                self.endianess)

    def get_value(self, address, size, endianess=None):
        """get a value from the image."""

        # Refactored into elf/core.py
        ret = self.elf.get_value(address, size, endianess)
        if ret != None:
            return ret

        raise MergeError, "Could not find address %x in Image." % address

    def set_kernel(self, kernel):
        """ Record the kernel."""
        self.elf = UnpreparedElfFile()
        self.endianess = kernel.endianess
        self.wordsize = kernel.wordsize

        self.elf.elf_type = ET_EXEC
        self.elf.machine = kernel.machine
        self.elf.osabi = kernel.osabi
        self.elf.abiversion = kernel.abiversion
        self.elf.flags = kernel.flags
        self.elf.entry_point = kernel.entry_point
        if self.ph_offset is not None:
            self.elf.set_ph_offset(self.ph_offset, fixed=True)

    def patch(self, addr, size, value, offset=0):
        """Record the details of a patch to a segment."""
        if self.elf.machine == ElfMachine(8):
            if self.elf.flags & EF_MIPS_ABI_O64:
                if addr & 0x80000000:
                    addr |= 0xffffffff00000000L
        self.patches.append(self.Patch(addr, size, value, offset))

    def set_kernel_heap(self, attrs, machine, pools, kern_seg, is_backed):
        """
        Record the details of the kernel heap.
        """
        if is_backed:
            self.kernel_heap = ImageKernelHeapBacked(attrs, self.elf, machine,
                                                     pools, kern_seg)
        else:
            self.kernel_heap = ImageKernelHeap(attrs, pools)

        return self.kernel_heap

    def add_utcb_area(self, attrs):
        """Record the details of an UTCB area"""
        area = ImageUtcbArea(attrs)
        self.utcb_areas.append(area)
        return area

    def add_segment(self, segment_index, section_prefix, segment, file_type,
                    attrs, machine, pools):
        """Create a segment for inclusion in the image."""
        if not valid_segment(segment):
            return None

        # Remove any pathname components from the prefix.
        section_prefix = os.path.basename(section_prefix)

        # Prepare the image for inclusion.
        new_segment = segment.copy_into(self.elf)

        # Align segments to the page boundary if is safe to do so.
        # RVCT tends to give very conservative alignment (1 word) to
        # segments that could be paged aligned.
        if new_segment.vaddr % machine.min_page_size() == 0 and \
               new_segment.align < machine.min_page_size():
            new_segment.align = machine.min_page_size()

        # Rename the sections in the segment, giving each the supplied
        # prefix
        if new_segment.has_sections():
            for section in new_segment.get_sections():
                assert section.link is None

                sec_name = section.name
                #strip GNU leading dots in section names
                if sec_name[0] == ".":
                    sec_name = sec_name[1:]

                section.name = "%s.%s" % (section_prefix, sec_name)
                # Add the program name as a prefix to all non-kernel
                # symbols, except for those symbols that can't have a
                # prefix added.
                if section_prefix != "kernel":
                    for symbol in self.elf.section_symbols(section):
                        if can_prefix_symbol(symbol):
                            symbol.name = "%s-%s" % (section_prefix,
                                                     symbol.name)
                            self.elf.get_symbol_table().link.add_string(
                                symbol.name)
        self.elf.add_segment(new_segment)

        iseg = ImageSegment(new_segment, segment_index, file_type, attrs,
                            pools)

        if attrs.protected:
            if self.protected_segment is not None:
                raise MergeError, \
                      'Only one segment can be declared protected.  ' \
                      'Found "%s" and  "%s".' % \
                      (self.protected_segment.get_attrs().abs_name(),
                      attrs.abs_name())

            self.protected_segment = iseg

        # Kernel segments need to be at the start of the memory pools
        # to place them in a different list to keep track of them.
        if file_type == Image.KERNEL:
            self.kernel_segments.append(iseg)
        else:
            self.segments.append(iseg)

        return iseg

    def add_memsection(self, attrs, machine, pools, section_prefix=None):
        """
        Create a memsection for inclusion in the image.

        If the data or file attributes of 'attr' are non-None, then a
        ELF segment will be created, otherwise the memsection will
        will be included in the address layout process, but will be
        created at runtime by Iguana server.
        """
        new_segment = None
        in_image = False

        if attrs.file is not None or attrs.data is not None:
            if attrs.file is not None:
                the_file = open(attrs.file, 'r')
                data = ByteArray(the_file.read())
                the_file.close()
            else:
                data = attrs.data

            if attrs.size is not None and len(data) < attrs.size:
                data.extend([0] * (attrs.size - len(data)))

            attrs.size = data.buffer_info()[1] * data.itemsize

            if section_prefix:
                section_name = "%s.%s" % (section_prefix, attrs.ns_node.name)
            else:
                section_name = attrs.ns_node.name
            sect = UnpreparedElfSection(self.elf,
                                        section_name,
                                        SHT_PROGBITS,
                                        attrs.virt_addr,
                                        data=data,
                                        flags=SHF_WRITE | SHF_ALLOC)
            self.elf.add_section(sect)
            new_segment = SectionedElfSegment(self.elf,
                                              PT_LOAD,
                                              attrs.virt_addr,
                                              attrs.phys_addr,
                                              PF_R | PF_W,
                                              machine.min_page_size(),
                                              sections=[sect])
            self.elf.add_segment(new_segment)
            in_image = True
# This check should be added, but currently fails with iguana.
#         elif attrs.size is None:
#             raise MergeError, \
#                   'No size attribute given for memsection \"%s\".' % attrs.abs_name()

        obj = ImageMemsection(new_segment, attrs, pools)

        # If the memsection has data that goes into the image, then
        # put it at the front of the list so that it will be near the
        # code segments.
        if in_image:
            self.memsections = [obj] + self.memsections
        else:
            self.memsections.append(obj)

        return obj

    def add_zone(self, attrs, zone):
        """Create a zone for inclusion in the image."""
        izone = ImageZone(attrs, zone)
        self.zones.append(izone)

        return izone

    def _add_group(self, distance, items, is_virtual, error_message=None):
        """Generate the group for either virtual or physical addresses."""
        group_items = [
            i.get_allocator_item(is_virtual=is_virtual) for i in items
            if i.get_allocator_item(is_virtual=is_virtual) is not None
        ]

        if group_items:
            group = ImageGroup(distance, group_items, error_message)
            self.groups.append(group)

    def add_group(self, distance, items, error_message=None):
        """
        Add a static group of items for allocation.

        A static group is a group that the developer thinks should be
        allocated together (such as a program and all of its
        memsections.

        These will later be converted into dynamic groups, which take
        into account the possibily different pools that the items will
        be allocated from.
        """
        # Generate a static group for virtual addresses.
        self._add_group(distance, items, True, error_message)

        # Generate a static group for physical addresses.
        self._add_group(distance, items, False, error_message)

    def dump(self):
        """
        Print out a virtual and physical memory map of the final
        image.
        """
        virtual_objects = {}
        physical_objects = {}

        for obj in self.objects:
            if obj.attrs.virt_addr is not None:
                vbase = obj.attrs.virt_addr
                vend = vbase + obj.attrs.size - 1
                virtual_objects[vbase, vend] = obj.attrs.abs_name()
            if obj.attrs.phys_addr is not None:
                pbase = obj.attrs.phys_addr
                pend = pbase + obj.attrs.size - 1
                if (pbase, pend) in physical_objects:
                    physical_objects[pbase, pend].append(obj.attrs.abs_name())
                else:
                    physical_objects[pbase, pend] = [obj.attrs.abs_name()]

        print "VIRTUAL:"
        for (base, end), name in sorted(virtual_objects.items()):
            print "  <%08x:%08x> %s" % (base, end, name)

        print "PHYSICAL:"
        for (base, end), names in sorted(physical_objects.items()):
            for name in names:
                print "  <%08x:%08x> %s" % (base, end, name)
示例#10
0
文件: test_core.py 项目: paromix/okl4
 def test_add_segment(self):
     ef = UnpreparedElfFile()
     seg = DataElfSegment(None, data=ByteArray("pants"))
     ef.add_segment(seg)
     self.assertEqual(ef.segments[-1], seg)