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, '<')
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, "<")
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)
def test_remove_section(self): seg = SectionedElfSegment() section = UnpreparedElfSection() self.assertRaises(InvalidArgument, seg.remove_section, section) seg.add_section(section) self.assertEqual(section in seg.sections, True) seg.remove_section(section) self.assertEqual(section in seg.sections, False) self.assertRaises(InvalidArgument, seg.remove_section, section) seg = DataElfSegment() data = ByteArray("foo") seg.set_data(data) self.assertRaises(InvalidArgument, seg.remove_section, None) seg = HeaderElfSegment() self.assertRaises(InvalidArgument, seg.remove_section, None)
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)
def _initialise_segments(self, hdr, file_, prepare): """Initialise instance from program headers.""" # Now load all the program headers # # "The time has come," the developer said, "to talk of many # things: Of section to segment mapping and scatter load, of # cabbages and kings, and why the RVCT linker is on drugs and # whether pigs have wings." # # There are two ways of determining which sections belong in a # segment: # # 1) In most cases a section is in a segment if its virtual # address range falls in the virtual address range of the # segment. These segments tend to contain multiple # PROGBITS sections and may end with a NOBITS section. # # 2) In the case of segments build with RVCT's scatter load # support the virtual address of the included sections can # be anywhere in memory. In this case a section is in the # segment if its data file offset falls in the offset range # of the segment. These segments can contain multiple # PROGBITS and NOBITS sections in any order. The file size # of the segment is the filesize of all of the PROGBITS # sections. The memory size of the segment is the sum of # the size of all of the sections, not the difference # between the lowest and highest virtual addresses. # # Some other things about ELF files that you need to know: # # a) Segments can overlap, and sections can appear in multiple # segments. # # b) Some sections do not appear in any segments. These tend # to be the symbol table and other debugging data. # # c) The offsets of NOBITS sections tend to be the same as the # offset for the next PROGBITS section, even if it is in # the next segment. However, sometimes NOBITS sections # appear at the beginning of a segment. # # d) The address offset from the start of a segment and the # file offset from the start of the segment are not # necessarily the same. # # Therefore, to map sections to segments involves two passes: # # 1) Find all of the sections that fall in the segment virtual # address range. # # 2) Find all of the remaining sections that fall in the file # offset range. If any are found then mark the segment as # a scatter-load segment. # # The file size and memory size of a segment depends on # whether or not it is a scatter load segment. For scatter # load files, the section that has the latest offset from the # beginning of the section is used, while for non-scatter-load # segments, the section with the largest virtual address is # used. # # File offsets cannot be used for both types of segments # because broken linkers can produce sections with # inconsistant virtual address to file offset mappings and # this will make elfweaver produce segments with incorrect # file sizes or memory sizes. # # "O Readers," said the developer, "You've had a pleasant run! # Shall we start the code again?" But answer came there none-- # And this was scarcely odd, because no-one would read this far # for fun. self._ph_offset = hdr.e_phoff self.segments = [] # Short circuit the return. if hdr.e_phoff == 0: return ph_list = self._get_headers(hdr, file_, ELF_PH_CLASSES, hdr.e_phoff, hdr.e_phentsize, hdr.e_phnum) # Map segments to sections, pass 1. for ph in ph_list: if ph.p_type != PT_PHDR: low = ph.p_vaddr high = low + ph.p_memsz sects = [] for section in self.sections: # See if the section's virtual address range falls within # the virtual address range of the segment. addr = section.address if low <= addr < high and addr + section.get_size() <= high: sects.append(section) if sects: seg = SectionedElfSegment(self, prog_header=ph, sections=sects) else: data = file_.get_data(ph.p_offset, ph.p_filesz) seg = DataElfSegment(self, prog_header=ph, data=data, memsz=ph.p_memsz) else: seg = HeaderElfSegment(self, prog_header=ph) self.segments.append(seg) # Map segments to sections, pass 2 sheaders = self._get_section_headers(hdr, file_) sect_offsets = [header.sh_offset for header in sheaders] for ph, seg in zip(ph_list, self.segments): if seg.has_sections(): low = ph.p_offset high = low + ph.p_filesz for (section, offset) in zip(self.sections, sect_offsets): # Scatter-load sections do not appear in multiple segments, # so skip sections that are already in some segment. if section.in_segment: continue # See if the section's file offset range falls within the # file offset range of the segment. Remember that the # trailing BSS section can have the offset of the next # section if low <= offset <= high and \ ((section.type == SHT_NOBITS and offset != low) or \ (section.type != SHT_NOBITS and section.get_size() > 0 and \ offset + section.get_size() <= high)): seg.add_section(section) seg.set_scatter_load() # If we're a scatter-load segment we need to work out in segment # offsets for our sections if seg.is_scatter_load(): for section in seg.sections: idx = self.sections.index(section) offset = sect_offsets[idx] section.set_in_segment_offset(offset - ph.p_offset) # If need be, we now prepare the segments if prepare: for ph, seg in zip(ph_list, self.segments): if ph.p_type == PT_PHDR: prog_header_size = hdr.e_phentsize * hdr.e_phnum else: prog_header_size = None seg.prepare(ph.p_offset, prog_header_size)