def test_nulltable(self): st = UnpreparedElfStringTable(None) self.assertEqual(st.get_string_idx(0), "") self.assertEqual(st.index_of(""), 0) self.assertEqual(st.index_of("anything"), None) self.assertEqual(st.offset_of(""), 0) self.assertEqual(st.offset_of("anything"), None) self.assertEqual(st.get_file_data(), array.array('B', '\x00'))
def test_fromdata(self): data = ByteArray('\0name.\0Variable\0able\0xx\0') st = UnpreparedElfStringTable(None, data = data) st = st.prepare(0, 0, 0) self.assertEqual(len(st.get_strings()), 5) self.assertEqual(st.get_string_idx(1), "name.") self.assertEqual(st.get_string_idx(2), "Variable") self.assertEqual(st.get_string_idx(3), "able") self.assertEqual(st.get_string_idx(4), "xx") self.assertEqual(st.get_string_ofs(0), "") self.assertEqual(st.get_string_ofs(1), "name.") self.assertEqual(st.get_string_ofs(7), "Variable") self.assertEqual(st.get_string_ofs(11), "able") self.assertEqual(st.get_string_ofs(16), "able") self.assertEqual(st.get_file_data(), data)
def test_copy_into(self): elf_from = UnpreparedElfFile() elf_to = UnpreparedElfFile() sect = BaseElfSection(elf_from, "test") # FIXME #self.assertRaises(NotImplementedError, sect.copy_into, elf_to) sect = UnpreparedElfSection(elf_from, "test") new_sect = sect.copy_into(elf_to) self.assertEquals(sect.name, new_sect.name) prep_sect = sect.prepare(0, 0, 0) # FIXME #self.assertRaises(NotImplementedError, prep_sect.copy_into, elf_to) sect = UnpreparedElfSection(elf_from, "test", SHT_NOBITS) new_sect = sect.copy_into(elf_to) self.assertEquals(sect.name, new_sect.name) sect = UnpreparedElfStringTable(elf_from, "string") strings = ["foo", "bar", "baz"] for string in strings: sect.add_string(string) new_sect = sect.copy_into(elf_to) for i in range(len(strings)): self.assertEquals(sect.get_string_idx(i), new_sect.get_string_idx(i))
def test_prepare_sections(self): empty_sec_seg, full_sec_seg, _, _, _, _ = self._get_segments() for seg in [empty_sec_seg, full_sec_seg]: all_sections = seg.sections sh_string_table = UnpreparedElfStringTable(None) ofs = 0x1000 seg.prepare(ofs) seg.prepare_sections(all_sections, sh_string_table)
def test_add_symbols(self): ef = UnpreparedElfFile() sect = UnpreparedElfSection(ef, "test_sect") symtab = UnpreparedElfSymbolTable(ef, ".symtab") for name in ["foo", "bar"]: symtab.add_symbol(ElfSymbol(name, sect)) ef = UnpreparedElfFile() sect = UnpreparedElfSection(ef, "test_ect") strtab = UnpreparedElfStringTable(ef, ".strtab") symtab = UnpreparedElfSymbolTable(ef, ".symtab", link=strtab) for name in ["foo", "bar"]: symtab.add_symbol(ElfSymbol(name, sect))
def add_symbols(self, symbols): """ Add a list of symbols to this files symbol table. If the symbol table doesn't exit yet, it will be created. symbols: a list of ElfSymbol objects """ symtab = self.get_symbol_table() if symtab is None: # we need to create a symbol table string_table = UnpreparedElfStringTable(self, ".strtab") symtab = UnpreparedElfSymbolTable(self, ".symtab", link=string_table) self.sections.append(string_table) self.sections.append(symtab) for sym in symbols: symtab.add_symbol(sym)
def main(args): """Main program entry point.""" # We should be able ot use 'elfadorn ld' as a drop-in replacement for 'ld' # Here we detect if this is the case, and patch the command line args appropriately. # This way we avoid maintainid two different methods of dealing with args if "--" not in args: args = [args[0] , "--"] + args[1:] parser = optparse.OptionParser("%prog [options] -- <linker> [linker_options]", add_help_option=0) parser.add_option("-H", "--help", action="help") parser.add_option("-o", "--output", dest="target", metavar="FILE", help="Linker will create FILE.") parser.add_option("-f", "--file-segment-list", dest="file_segment_list", metavar="FILE", help="File containing segment names to be added to .segment_names, \ one per line") parser.add_option("-c", "--cmd-segment-list", dest="cmd_segment_list", help="quoted list of comma separated segment names to be added to .segment_names,") parser.add_option("-s", "--create-segments", dest="create_segments", action="store_true", help="Set to enable gathering orphaned sections and placing each in a new segment") (options, args) = parser.parse_args(args) if not options.target: i = 0 for a in args: if a == "-o": options.target = args[i+1] break i = i + 1 if not options.target: print "Error: -o flag must be supplied." sys.exit(1) # we need to parse the options # we are interested in any -T, --scatter or --script= options # plus the ordinary files specified on the command line scripts = get_script_names(args) objects = remove_arguments(args) linker_name = objects[1] objects = objects[2:] linker_type = get_linker_name(args, linker_name) if linker_type == "rvct": if options.create_segments: print "Warning: creating segments from sections not applicable to RVCT. Disabling option." options.create_segments = False # next get section names (sections, additional_scripts) = get_section_names(objects) scripts = scripts + additional_scripts # then get the text of the linker script script_text = get_linker_script_text(linker_name, scripts, additional_scripts, []) if options.create_segments: # get rid of any sections named in the script_text mentioned_sections = linker_script_sections(script_text) orphaned_sections = sections for section in mentioned_sections: # Our grammar is not perfect, sometimes it gets confused and gives back * # as a section but it is actually a filename if section != "*": remove_sections_wildcard(orphaned_sections, section) # mips-ld treats .reginfo sections somewhat magically, we do not want to treat this # as an orphan and create a segment for him, else ld will drop the text data and bss # sections completely. Magic. if '.reginfo' in orphaned_sections: orphaned_sections.remove('.reginfo') # work out the new linker command line if scripts == []: default = get_linker_script_text(args[1], [], [], args[2:]) open("default.lds", "w").write(default) if len(orphaned_sections) != 0: args += ["--script=default.lds"] # write out an additional linker script file to pass to the linker if len(orphaned_sections) != 0: write_linker_script(orphaned_sections, "additional.lds") additional_scripts.append("additional.lds") args += ["--script=additional.lds"] else: # if we dont care about these, just say there are none. orphaned_sections = [] # execute the linker if os.spawnvp(os.P_WAIT, args[1], args[1:]) != 0: sys.exit(1) # load the elf file elf = UnpreparedElfFile(filename=options.target) wordsize = elf.wordsize endianess = elf.endianess seglist = get_segment_names(options, elf, scripts, linker_type, orphaned_sections) # create the string table segname_tab = UnpreparedElfStringTable(".segment_names") # add the segment names for segname in seglist: segname = segname.strip() segname_tab.add_string("%s" % segname) # add the table to the file elf.add_section(segname_tab) elf = elf.prepare(wordsize, endianess) # write the file elf.to_filename(options.target)
def test_simpletable(self): st = UnpreparedElfStringTable(None) self.assertEqual(st.add_string("name."), 1) self.assertEqual(st.add_string("Variable"), 7) self.assertEqual(st.add_string("able"), 16) # this isn't a good test. we don't know it will be at 16, it'd just be obvious. it could also be at 11 or so self.assertEqual(st.add_string("xx"), 21) self.assertEqual(len(st.get_strings()), 5) self.assertEqual(st.get_string_idx(1), "name.") self.assertEqual(st.get_string_idx(2), "Variable") self.assertEqual(st.get_string_idx(3), "able") self.assertEqual(st.get_string_idx(4), "xx") self.assertEqual(st.get_string_ofs(0), "") self.assertEqual(st.get_string_ofs(1), "name.") self.assertEqual(st.get_string_ofs(7), "Variable") self.assertEqual(st.get_string_ofs(11), "able") self.assertEqual(st.get_string_ofs(16), "able") self.assertEqual(st.get_file_data(), array.array('B', '\0name.\0Variable\0able\0xx\0'))
def test_getstringidx_out_of_bounds(self): st = UnpreparedElfStringTable(None) self.assertEqual(st.get_string_idx(1), None)
def _get_string_tables(self): empty_st = UnpreparedElfStringTable(None) added_st = UnpreparedElfStringTable(None) added_st.add_string("name.") added_st.add_string("Variable") added_st.add_string("able") added_st.add_string("xx") data = ByteArray('\0name.\0Variable\0able\0\0xx\0') data_st = UnpreparedElfStringTable(None, data = data) prep_empty_st = UnpreparedElfStringTable(None) prep_added_st = UnpreparedElfStringTable(None) prep_added_st.add_string("name.") prep_added_st.add_string("Variable") prep_added_st.add_string("able") prep_added_st.add_string("xx") data = ByteArray('\0name.\0Variable\0able\0xx\0') prep_data_st = UnpreparedElfStringTable(None, data = data) prep_empty_st = prep_empty_st.prepare(1, 2, 3) prep_added_st = prep_added_st.prepare(1, 2, 3) prep_data_st = prep_data_st.prepare(1, 2, 3) return empty_st, added_st, data_st, prep_empty_st, prep_added_st, prep_data_st
def __init__(self, elffile): UnpreparedElfStringTable.__init__(self, elffile, ".segment_names")
def main(args): """Main program entry point.""" # We should be able ot use 'elfadorn ld' as a drop-in replacement for 'ld' # Here we detect if this is the case, and patch the command line args appropriately. # This way we avoid maintainid two different methods of dealing with args if "--" not in args: args = [args[0], "--"] + args[1:] parser = optparse.OptionParser( "%prog [options] -- <linker> [linker_options]", add_help_option=0) parser.add_option("-H", "--help", action="help") parser.add_option("-o", "--output", dest="target", metavar="FILE", help="Linker will create FILE.") parser.add_option( "-f", "--file-segment-list", dest="file_segment_list", metavar="FILE", help="File containing segment names to be added to .segment_names, \ one per line") parser.add_option( "-c", "--cmd-segment-list", dest="cmd_segment_list", help= "quoted list of comma separated segment names to be added to .segment_names," ) parser.add_option( "-s", "--create-segments", dest="create_segments", action="store_true", help= "Set to enable gathering orphaned sections and placing each in a new segment" ) (options, args) = parser.parse_args(args) if not options.target: i = 0 for a in args: if a == "-o": options.target = args[i + 1] break i = i + 1 if not options.target: print "Error: -o flag must be supplied." sys.exit(1) # we need to parse the options # we are interested in any -T, --scatter or --script= options # plus the ordinary files specified on the command line scripts = get_script_names(args) objects = remove_arguments(args) linker_name = objects[1] objects = objects[2:] linker_type = get_linker_name(args, linker_name) if linker_type == "rvct": if options.create_segments: print "Warning: creating segments from sections not applicable to RVCT. Disabling option." options.create_segments = False # next get section names (sections, additional_scripts) = get_section_names(objects) scripts = scripts + additional_scripts # then get the text of the linker script script_text = get_linker_script_text(linker_name, scripts, additional_scripts, []) if options.create_segments: # get rid of any sections named in the script_text mentioned_sections = linker_script_sections(script_text) orphaned_sections = sections for section in mentioned_sections: # Our grammar is not perfect, sometimes it gets confused and gives back * # as a section but it is actually a filename if section != "*": remove_sections_wildcard(orphaned_sections, section) # mips-ld treats .reginfo sections somewhat magically, we do not want to treat this # as an orphan and create a segment for him, else ld will drop the text data and bss # sections completely. Magic. if '.reginfo' in orphaned_sections: orphaned_sections.remove('.reginfo') # work out the new linker command line if scripts == []: default = get_linker_script_text(args[1], [], [], args[2:]) open("default.lds", "w").write(default) if len(orphaned_sections) != 0: args += ["--script=default.lds"] # write out an additional linker script file to pass to the linker if len(orphaned_sections) != 0: write_linker_script(orphaned_sections, "additional.lds") additional_scripts.append("additional.lds") args += ["--script=additional.lds"] else: # if we dont care about these, just say there are none. orphaned_sections = [] # execute the linker if os.spawnvp(os.P_WAIT, args[1], args[1:]) != 0: sys.exit(1) # load the elf file elf = UnpreparedElfFile(filename=options.target) wordsize = elf.wordsize endianess = elf.endianess seglist = get_segment_names(options, elf, scripts, linker_type, orphaned_sections) # create the string table segname_tab = UnpreparedElfStringTable(".segment_names") # add the segment names for segname in seglist: segname = segname.strip() segname_tab.add_string("%s" % segname) # add the table to the file elf.add_section(segname_tab) elf = elf.prepare(wordsize, endianess) # write the file elf.to_filename(options.target)