def test_assemble_without_ctrl(): # Create the assembly code string asm = \ """ ori r1, r0, 0x2000 # address of src0 ori r2, r0, 0x2004 # address of src1 ori r3, r0, 0x2008 # address of dest lw r4, 0(r1) # load src0 lw r5, 0(r2) # load src1 addu r6, r4, r5 # add two elements together sw r6, 0(r3) # store dest .data .word 13 # src0 .word 15 # src1 .word 0 # dest """ # Assemble code into a memory image mem_image = pisa_encoding.assemble(asm) # Create a reference text section by using binutils text_section = mk_section( ".text", 0x0400, [ 0x34012000, # li at, 0x2000 0x34022004, # li v0, 0x2004 0x34032008, # li v1, 0x2008 0x8c240000, # lw a0, 0(at) 0x8c450000, # lw a1, 0(v0) 0x00853021, # addu a2, a0, a1 0xac660000, # sw a2, 0(v1) ]) # Create a reference data section manually data_section = mk_section( ".data", 0x2000, [ 0x0000000d, # .word 13 0x0000000f, # .word 13 0x00000000, # .word 0 ]) # Build a sparse memory image mem_image_ref = SparseMemoryImage() mem_image_ref.add_section(text_section) mem_image_ref.add_section(data_section) # Check that both sparse memory image are equal assert mem_image == mem_image_ref
def test_assemble_without_ctrl(): # Create the assembly code string asm = \ """ ori r1, r0, 0x2000 # address of src0 ori r2, r0, 0x2004 # address of src1 ori r3, r0, 0x2008 # address of dest lw r4, 0(r1) # load src0 lw r5, 0(r2) # load src1 addu r6, r4, r5 # add two elements together sw r6, 0(r3) # store dest .data .word 13 # src0 .word 15 # src1 .word 0 # dest """ # Assemble code into a memory image mem_image = pisa_encoding.assemble( asm ) # Create a reference text section by using binutils text_section = mk_section( ".text", 0x0400, [ 0x34012000, # li at, 0x2000 0x34022004, # li v0, 0x2004 0x34032008, # li v1, 0x2008 0x8c240000, # lw a0, 0(at) 0x8c450000, # lw a1, 0(v0) 0x00853021, # addu a2, a0, a1 0xac660000, # sw a2, 0(v1) ]) # Create a reference data section manually data_section = mk_section( ".data", 0x2000, [ 0x0000000d, # .word 13 0x0000000f, # .word 13 0x00000000, # .word 0 ]) # Build a sparse memory image mem_image_ref = SparseMemoryImage() mem_image_ref.add_section( text_section ) mem_image_ref.add_section( data_section ) # Check that both sparse memory image are equal assert mem_image == mem_image_ref
def test_equality(): # The sparse memory image we will be testing mem_image = SparseMemoryImage() # Create first bytearray with some data data_ints_a = [ random.randint(0,1000) for r in xrange(10) ] data_bytes_a = bytearray() for data_int in data_ints_a: data_bytes_a.extend(struct.pack("<I",data_int)) # Create a second section section and add it to the sparse memory image section_a = SparseMemoryImage.Section( ".text", 0x1000, data_bytes_a ) mem_image.add_section( section_a ) # Create a second bytearray with some data data_ints_b = [ random.randint(0,1000) for r in xrange(10) ] data_bytes_b = bytearray() for data_ints in data_ints_b: data_bytes_b.extend(struct.pack("<I",data_int)) # Create a second section section and add it to the sparse memory image section_b = SparseMemoryImage.Section( ".data", 0x2000, data_bytes_b ) mem_image.add_section( section_b ) # Create a copy mem_image_copy = copy.deepcopy( mem_image ) # Check two images are equal assert mem_image == mem_image_copy # Add another section to the copy section_c = SparseMemoryImage.Section( ".test", 0x3000, bytearray("\x01\x02") ) mem_image_copy.add_section( section_c ) # Check two images are no longer equal assert mem_image != mem_image_copy
def test_equality(): # The sparse memory image we will be testing mem_image = SparseMemoryImage() # Create first bytearray with some data data_ints_a = [random.randint(0, 1000) for r in xrange(10)] data_bytes_a = bytearray() for data_int in data_ints_a: data_bytes_a.extend(struct.pack("<I", data_int)) # Create a second section section and add it to the sparse memory image section_a = SparseMemoryImage.Section(".text", 0x1000, data_bytes_a) mem_image.add_section(section_a) # Create a second bytearray with some data data_ints_b = [random.randint(0, 1000) for r in xrange(10)] data_bytes_b = bytearray() for data_ints in data_ints_b: data_bytes_b.extend(struct.pack("<I", data_int)) # Create a second section section and add it to the sparse memory image section_b = SparseMemoryImage.Section(".data", 0x2000, data_bytes_b) mem_image.add_section(section_b) # Create a copy mem_image_copy = copy.deepcopy(mem_image) # Check two images are equal assert mem_image == mem_image_copy # Add another section to the copy section_c = SparseMemoryImage.Section(".test", 0x3000, bytearray("\x01\x02")) mem_image_copy.add_section(section_c) # Check two images are no longer equal assert mem_image != mem_image_copy
def test_smi_str_labels_list(dump_asm, dump_bin): asm_file = None bin_file = None if dump_asm: asm_file = "simple-addiu.s" if dump_bin: bin_file = "simple-addiu" # obtained by manual conversion labels_list = [ [1024, [1, 0, 67, 36]], [1028, [1, 0, 29, 36]], [ 1032, [ 1, 0, 2, 36, 0, 168, 157, 64, 255, 255, 2, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ] ] mem_img_from_labels_list = SparseMemoryImage(labels_list=labels_list) asm_str = asm_start + "addiu $3, $2, 1" + asm_end mem_img_from_str = SparseMemoryImage(asm_str=asm_str, dump_asm=asm_file, dump_bin=bin_file) assert mem_img_from_str == mem_img_from_labels_list
def test_basic( tmpdir ): # Create a sparse memory image mem_image = SparseMemoryImage() section_names = [ ".text", ".data" ] for i in xrange(4): section = SparseMemoryImage.Section() section.name = section_names[ random.randint(0,1) ] section.addr = i * 0x00001000 data_ints = [ random.randint(0,1000) for r in xrange(10) ] data_bytes = bytearray() for data_int in data_ints: data_bytes.extend(struct.pack("<I",data_int)) section.data = data_bytes mem_image.add_section( section ) # Write the sparse memory image to an ELF file with tmpdir.join("elf-test").open('wb') as file_obj: elf.elf_writer( mem_image, file_obj ) # Read the ELF file back into a new sparse memory image mem_image_test = None with tmpdir.join("elf-test").open('rb') as file_obj: mem_image_test = elf.elf_reader( file_obj ) # Check that the original and new sparse memory images are equal assert mem_image == mem_image_test
def test_basic(tmpdir): # Create a sparse memory image mem_image = SparseMemoryImage() section_names = [".text", ".data"] for i in range(4): section = SparseMemoryImage.Section() section.name = section_names[random.randint(0, 1)] section.addr = i * 0x00000200 data_ints = [random.randint(0, 1000) for r in range(10)] data_bytes = bytearray() for data_int in data_ints: data_bytes.extend(struct.pack("<I", data_int)) section.data = data_bytes mem_image.add_section(section) # Write the sparse memory image to an ELF file with tmpdir.join("elf-test").open('wb') as file_obj: elf.elf_writer(mem_image, file_obj) # Read the ELF file back into a new sparse memory image mem_image_test = None with tmpdir.join("elf-test").open('rb') as file_obj: mem_image_test = elf.elf_reader(file_obj) # Check that the original and new sparse memory images are equal assert mem_image == mem_image_test
def test_symbols(): # The sparse memory image we will be testing mem_image = SparseMemoryImage() # Add some symbols mem_image.add_symbol("func_a", 0x0002000) mem_image.add_symbol("func_b", 0x0003000) mem_image.add_symbol("var_a", 0x0011000) mem_image.add_symbol("var_b", 0x0011000) # Check symbols assert mem_image.get_symbol("func_a") == 0x0002000 assert mem_image.get_symbol("func_b") == 0x0003000 assert mem_image.get_symbol("var_a") == 0x0011000 assert mem_image.get_symbol("var_b") == 0x0011000
def test_sections(): # The sparse memory image we will be testing mem_image = SparseMemoryImage() # Create first bytearray with some data data_ints_a = [ random.randint(0,1000) for r in xrange(10) ] data_bytes_a = bytearray() for data_int in data_ints_a: data_bytes_a.extend(struct.pack("<I",data_int)) # Create a second section section and add it to the sparse memory image section_a = SparseMemoryImage.Section( ".text", 0x1000, data_bytes_a ) mem_image.add_section( section_a ) # Create a second bytearray with some data data_ints_b = [ random.randint(0,1000) for r in xrange(10) ] data_bytes_b = bytearray() for data_ints in data_ints_b: data_bytes_b.extend(struct.pack("<I",data_int)) # Create a second section section and add it to the sparse memory # image. Use the alternative syntax for adding a section. section_b = SparseMemoryImage.Section( ".data", 0x2000, data_bytes_b ) mem_image.add_section( ".data", 0x2000, data_bytes_b ) # Retrieve and check both sections section_a_test = mem_image.get_section( ".text" ) assert section_a_test == section_a section_b_test = mem_image.get_section( ".data" ) assert section_b_test == section_b # Retrieve sections as a list sections_test = mem_image.get_sections() assert sections_test == [ section_a_test, section_b_test ]
def test_symbols(): # The sparse memory image we will be testing mem_image = SparseMemoryImage() # Add some symbols mem_image.add_symbol( "func_a", 0x0002000 ) mem_image.add_symbol( "func_b", 0x0003000 ) mem_image.add_symbol( "var_a", 0x0011000 ) mem_image.add_symbol( "var_b", 0x0011000 ) # Check symbols assert mem_image.get_symbol( "func_a" ) == 0x0002000 assert mem_image.get_symbol( "func_b" ) == 0x0003000 assert mem_image.get_symbol( "var_a" ) == 0x0011000 assert mem_image.get_symbol( "var_b" ) == 0x0011000
def assemble(asm_code): # If asm_code is a single string, then put it in a list to simplify the # rest of the logic. asm_code_list = asm_code if isinstance(asm_code, str): asm_code_list = [asm_code] # Create a single list of lines asm_list = [] for asm_seq in asm_code_list: asm_list.extend(asm_seq.splitlines()) # First pass to create symbol table. This is obviously very simplistic. # We can maybe make it more robust in the future. addr = 0x00000400 sym = {} for line in asm_list: line = line.partition("#")[0] line = line.strip() if line == "": continue if line.startswith(".offset"): (cmd, sep, addr_str) = line.partition(" ") addr = int(addr_str, 0) elif line.startswith(".data"): pass else: (label, sep, rest) = line.partition(":") if sep != "": sym[label.strip()] = addr else: addr += 4 # Second pass to assemble text section asm_list_idx = 0 addr = 0x00000400 text_bytes = bytearray() mngr2proc_bytes = bytearray() proc2mngr_bytes = bytearray() for line in asm_list: asm_list_idx += 1 line = line.partition("#")[0] line = line.strip() if line == "": continue if line.startswith(".offset"): (cmd, sep, addr_str) = line.partition(" ") addr = int(addr_str, 0) elif line.startswith(".data"): break else: if ":" not in line: inst_str = line # First see if we have either a < or a > if "<" in line: (temp, sep, value) = line.partition("<") bits = Bits(32, int(value, 0)) mngr2proc_bytes.extend(struct.pack("<I", bits)) inst_str = temp elif ">" in line: (temp, sep, value) = line.partition(">") bits = Bits(32, int(value, 0)) proc2mngr_bytes.extend(struct.pack("<I", bits)) inst_str = temp bits = assemble_inst(sym, addr, inst_str) text_bytes.extend(struct.pack("<I", bits.uint())) addr += 4 # Assemble data section data_bytes = bytearray() for line in asm_list[asm_list_idx:]: line = line.partition("#")[0] line = line.strip() if line == "": continue if line.startswith(".offset"): (cmd, sep, addr_str) = line.partition(" ") addr = int(addr_str, 0) elif line.startswith(".word"): (cmd, sep, value) = line.partition(" ") data_bytes.extend(struct.pack("<I", int(value, 0))) addr += 4 elif line.startswith(".hword"): (cmd, sep, value) = line.partition(" ") data_bytes.extend(struct.pack("<H", int(value, 0))) addr += 2 elif line.startswith(".byte"): (cmd, sep, value) = line.partition(" ") data_bytes.extend(struct.pack("<B", int(value, 0))) addr += 1 # Construct the corresponding section objects text_section = SparseMemoryImage.Section(".text", 0x0400, text_bytes) data_section = SparseMemoryImage.Section(".data", 0x2000, data_bytes) mngr2proc_section = SparseMemoryImage.Section(".mngr2proc", 0x3000, mngr2proc_bytes) proc2mngr_section = SparseMemoryImage.Section(".proc2mngr", 0x4000, proc2mngr_bytes) # Build a sparse memory image mem_image = SparseMemoryImage() mem_image.add_section(text_section) if len(data_section.data) > 0: mem_image.add_section(data_section) if len(mngr2proc_section.data) > 0: mem_image.add_section(mngr2proc_section) if len(proc2mngr_section.data) > 0: mem_image.add_section(proc2mngr_section) return mem_image
def assemble(asm_code): # If asm_code is a single string, then put it in a list to simplify the # rest of the logic. asm_code_list = asm_code if isinstance(asm_code, str): asm_code_list = [asm_code] # Create a single list of lines asm_list = [] for asm_seq in asm_code_list: asm_list.extend(asm_seq.splitlines()) # First pass to create symbol table. This is obviously very simplistic. # We can maybe make it more robust in the future. addr = 0x00000400 sym = {} for line in asm_list: line = line.partition('#')[0] line = line.strip() if line == "": continue if line.startswith(".offset"): (cmd, sep, addr_str) = line.partition(' ') addr = int(addr_str, 0) elif line.startswith(".data"): pass else: (label, sep, rest) = line.partition(':') if sep != "": sym[label.strip()] = addr else: addr += 4 # Second pass to assemble text section asm_list_idx = 0 addr = 0x00000400 text_bytes = bytearray() mngr2proc_bytes = bytearray() proc2mngr_bytes = bytearray() for line in asm_list: asm_list_idx += 1 line = line.partition('#')[0] line = line.strip() if line == "": continue if line.startswith(".offset"): (cmd, sep, addr_str) = line.partition(' ') addr = int(addr_str, 0) elif line.startswith(".data"): break else: if ':' not in line: inst_str = line # First see if we have either a < or a > if '<' in line: (temp, sep, value) = line.partition('<') bits = Bits(32, int(value, 0)) mngr2proc_bytes.extend(struct.pack("<I", bits)) inst_str = temp elif '>' in line: (temp, sep, value) = line.partition('>') bits = Bits(32, int(value, 0)) proc2mngr_bytes.extend(struct.pack("<I", bits)) inst_str = temp bits = assemble_inst(sym, addr, inst_str) text_bytes.extend(struct.pack("<I", bits.uint())) addr += 4 # Assemble data section data_bytes = bytearray() for line in asm_list[asm_list_idx:]: line = line.partition('#')[0] line = line.strip() if line == "": continue if line.startswith(".offset"): (cmd, sep, addr_str) = line.partition(' ') addr = int(addr_str, 0) elif line.startswith(".word"): (cmd, sep, value) = line.partition(' ') data_bytes.extend(struct.pack("<I", int(value, 0))) addr += 4 elif line.startswith(".hword"): (cmd, sep, value) = line.partition(' ') data_bytes.extend(struct.pack("<H", int(value, 0))) addr += 2 elif line.startswith(".byte"): (cmd, sep, value) = line.partition(' ') data_bytes.extend(struct.pack("<B", int(value, 0))) addr += 1 # Construct the corresponding section objects text_section = \ SparseMemoryImage.Section( ".text", 0x0400, text_bytes ) data_section = SparseMemoryImage.Section(".data", 0x2000, data_bytes) mngr2proc_section = \ SparseMemoryImage.Section( ".mngr2proc", 0x3000, mngr2proc_bytes ) proc2mngr_section = \ SparseMemoryImage.Section( ".proc2mngr", 0x4000, proc2mngr_bytes ) # Build a sparse memory image mem_image = SparseMemoryImage() mem_image.add_section(text_section) if len(data_section.data) > 0: mem_image.add_section(data_section) if len(mngr2proc_section.data) > 0: mem_image.add_section(mngr2proc_section) if len(proc2mngr_section.data) > 0: mem_image.add_section(proc2mngr_section) return mem_image
def test_assemble_with_ctrl(): # Create the assembly code string asm = \ """ addiu r1, r0, 4 # array size ori r2, r0, 0x2000 # src0 base pointer ori r3, r0, 0x2010 # src1 base pointer ori r4, r0, 0x2020 # dest base pointer addiu r5, r0, 0 # induction variable loop: lw r6, 0(r2) # load src0 lw r7, 0(r3) # load src1 addu r8, r6, r7 # addition sw r8, 0(r4) # store dest addiu r2, r2, 4 # pointer bump for src0 addiu r3, r3, 4 # pointer bump for src1 addiu r4, r4, 4 # pointer bump for dest addiu r5, r5, 1 # increment induction variable bne r5, r1, loop # loop branch .data # addr = 0x2000 # src0 array .word 89320 .word 30239 .word 1329 .word 89021 # src1 array .word 30411 .word 64198 .word 4210 .word 20199 # dest array .word 0 .word 0 .word 0 .word 0 """ # Assemble code into a memory image mem_image = pisa_encoding.assemble(asm) # Create a reference text section by using binutils text_section = mk_section( ".text", 0x0400, [ 0x24010004, # li at, 4 0x34022000, # li v0, 0x2000 0x34032010, # li v1, 0x2010 0x34042020, # li a0, 0x2020 0x24050000, # li a1, 0 0x8c460000, # lw a2, 0(v0) 0x8c670000, # lw a3, 0(v1) 0x00c74021, # addu a4, a2, a3 0xac880000, # sw a4, 0(a0) 0x24420004, # addiu v0, v0, 4 0x24630004, # addiu v1, v1, 4 0x24840004, # addiu a0, a0, 4 0x24a50001, # addiu a1, a1, 1 0x14a1fff7, # bne a1, at, 1154 <loop> ]) # Create a reference data section manually data_section = mk_section( ".data", 0x2000, [ 0x00015ce8, # .word 89320 0x0000761f, # .word 30239 0x00000531, # .word 1329 0x00015bbd, # .word 89021 0x000076cb, # .word 30411 0x0000fac6, # .word 64198 0x00001072, # .word 4210 0x00004ee7, # .word 20199 0x00000000, # .word 0 0x00000000, # .word 0 0x00000000, # .word 0 0x00000000, # .word 0 ]) # Build a sparse memory image mem_image_ref = SparseMemoryImage() mem_image_ref.add_section(text_section) mem_image_ref.add_section(data_section) # Check that both sparse memory image are equal assert mem_image == mem_image_ref
def test_assemble_with_prog_mngr(): # Create the assembly code string asm = \ """ mfc0 r1, mngr2proc < 0x13 mfc0 r2, mngr2proc < 0x57 addu r3, r1, r2 # add two elements together mtc0 r3, proc2mngr > 0x6a nop mfc0 r1, mngr2proc < 0x65 mfc0 r2, mngr2proc < 0x42 addu r3, r1, r2 # add two elements together mtc0 r3, proc2mngr > 0xa7 """ # Assemble code into a memory image mem_image = pisa_encoding.assemble(asm) # Create a reference text section by using binutils text_section = mk_section( ".text", 0x0400, [ 0x40010800, # mfc0 at, mngr2proc 0x40020800, # mfc0 v0, mngr2proc 0x00221821, # addu v1, at,v0 0x40831000, # mtc0 v1, proc2mngr 0x00000000, # nop 0x40010800, # mfc0 at, mngr2proc 0x40020800, # mfc0 v0, mngr2proc 0x00221821, # addu v1, at,v0 0x40831000, # mtc0 v1, proc2mngr ]) # Create a reference mngr2proc section manually mngr2proc_section = mk_section(".mngr2proc", 0x3000, [ 0x00000013, 0x00000057, 0x00000065, 0x00000042, ]) # Create a reference proc2mngr section manually proc2mngr_section = mk_section(".proc2mngr", 0x4000, [ 0x0000006a, 0x000000a7, ]) # Build a sparse memory image mem_image_ref = SparseMemoryImage() mem_image_ref.add_section(text_section) mem_image_ref.add_section(mngr2proc_section) mem_image_ref.add_section(proc2mngr_section) # Check that both sparse memory image are equal assert mem_image == mem_image_ref
def elf_reader(file_obj): # Read the data for the ELF header ehdr_data = file_obj.read(ElfHeader.NBYTES) # Construct an ELF header object ehdr = ElfHeader(ehdr_data) # Verify if its a known format and realy an ELF file if ehdr.ident[0:4] != '\x7fELF': raise ValueError("Not a valid ELF file") # We need to find the section string table so we can figure out the # name of each section. We know that the section header for the section # string table is entry shstrndx, so we first get the data for this # section header. file_obj.seek(ehdr.shoff + ehdr.shstrndx * ehdr.shentsize) shdr_data = file_obj.read(ehdr.shentsize) # Construct a section header object for the section string table shdr = ElfSectionHeader(shdr_data) # Read the data for the section header table file_obj.seek(shdr.offset) shstrtab_data = file_obj.read(shdr.size) # Load sections symtab_data = None strtab_data = None mem_image = SparseMemoryImage() for section_idx in range(ehdr.shnum): # Read the data for the section header file_obj.seek(ehdr.shoff + section_idx * ehdr.shentsize) shdr_data = file_obj.read(ehdr.shentsize) # Pad the returned string in case the section header is not long # enough (otherwise the unpack function would not work) shdr_data = shdr_data.ljust(ElfSectionHeader.NBYTES, '\0') # Construct a section header object shdr = ElfSectionHeader(shdr_data) # Find the section name start = shstrtab_data[shdr.name:] section_name = start.partition('\0')[0] # Only sections marked as alloc should be written to memory if not (shdr.flags & ElfSectionHeader.FLAGS_ALLOC): continue # Read the section data if it exists if section_name not in ['.sbss', '.bss']: file_obj.seek(shdr.offset) data = file_obj.read(shdr.size) # NOTE: the .bss and .sbss sections don't actually contain any # data in the ELF. These sections should be initialized to zero. # For more information see: # # - http://stackoverflow.com/questions/610682/bss-section-in-elf-file else: data = '\0' * shdr.size # Save the data holding the symbol string table if shdr.type == ElfSectionHeader.TYPE_STRTAB: strtab_data = data # Save the data holding the symbol table elif shdr.type == ElfSectionHeader.TYPE_SYMTAB: symtab_data = data # Otherwise create section and append it to our list of sections else: section = SparseMemoryImage.Section(section_name, shdr.addr, data) mem_image.add_section(section) # Load symbols. We skip the first symbol since it both "designates the # first entry in the table and serves as the undefined symbol index". # For now, I have commented this out, since we are not really using it. # num_symbols = len(symtab_data) / ElfSymTabEntry.NBYTES # for sym_idx in xrange(1,num_symbols): # # # Read the data for a symbol table entry # # start = sym_idx * ElfSymTabEntry.NBYTES # sym_data = symtab_data[start:start+ElfSymTabEntry.NBYTES] # # # Construct a symbol table entry # # sym = ElfSymTabEntry( sym_data ) # # # Get the symbol type # # sym_type = sym.info & 0xf # # # Check to see if symbol is one of the three types we want to load # # valid_sym_types = \ # [ # ElfSymTabEntry.TYPE_NOTYPE, # ElfSymTabEntry.TYPE_OBJECT, # ElfSymTabEntry.TYPE_FUNC, # ] # # # Check to see if symbol is one of the three types we want to load # # if sym_type not in valid_sym_types: # continue # # # Get the symbol name from the string table # # start = strtab_data[sym.name:] # name = start.partition('\0')[0] # # # Add symbol to the sparse memory image # # mem_image.add_symbol( name, sym.value ) return mem_image
def test_sections(): # The sparse memory image we will be testing mem_image = SparseMemoryImage() # Create first bytearray with some data data_ints_a = [random.randint(0, 1000) for r in xrange(10)] data_bytes_a = bytearray() for data_int in data_ints_a: data_bytes_a.extend(struct.pack("<I", data_int)) # Create a second section section and add it to the sparse memory image section_a = SparseMemoryImage.Section(".text", 0x1000, data_bytes_a) mem_image.add_section(section_a) # Create a second bytearray with some data data_ints_b = [random.randint(0, 1000) for r in xrange(10)] data_bytes_b = bytearray() for data_ints in data_ints_b: data_bytes_b.extend(struct.pack("<I", data_int)) # Create a second section section and add it to the sparse memory # image. Use the alternative syntax for adding a section. section_b = SparseMemoryImage.Section(".data", 0x2000, data_bytes_b) mem_image.add_section(".data", 0x2000, data_bytes_b) # Retrieve and check both sections section_a_test = mem_image.get_section(".text") assert section_a_test == section_a section_b_test = mem_image.get_section(".data") assert section_b_test == section_b # Retrieve sections as a list sections_test = mem_image.get_sections() assert sections_test == [section_a_test, section_b_test]
def test_assemble_with_ctrl(): # Create the assembly code string asm = \ """ addiu r1, r0, 4 # array size ori r2, r0, 0x2000 # src0 base pointer ori r3, r0, 0x2010 # src1 base pointer ori r4, r0, 0x2020 # dest base pointer addiu r5, r0, 0 # induction variable loop: lw r6, 0(r2) # load src0 lw r7, 0(r3) # load src1 addu r8, r6, r7 # addition sw r8, 0(r4) # store dest addiu r2, r2, 4 # pointer bump for src0 addiu r3, r3, 4 # pointer bump for src1 addiu r4, r4, 4 # pointer bump for dest addiu r5, r5, 1 # increment induction variable bne r5, r1, loop # loop branch .data # addr = 0x2000 # src0 array .word 89320 .word 30239 .word 1329 .word 89021 # src1 array .word 30411 .word 64198 .word 4210 .word 20199 # dest array .word 0 .word 0 .word 0 .word 0 """ # Assemble code into a memory image mem_image = pisa_encoding.assemble( asm ) # Create a reference text section by using binutils text_section = mk_section( ".text", 0x0400, [ 0x24010004, # li at, 4 0x34022000, # li v0, 0x2000 0x34032010, # li v1, 0x2010 0x34042020, # li a0, 0x2020 0x24050000, # li a1, 0 0x8c460000, # lw a2, 0(v0) 0x8c670000, # lw a3, 0(v1) 0x00c74021, # addu a4, a2, a3 0xac880000, # sw a4, 0(a0) 0x24420004, # addiu v0, v0, 4 0x24630004, # addiu v1, v1, 4 0x24840004, # addiu a0, a0, 4 0x24a50001, # addiu a1, a1, 1 0x14a1fff7, # bne a1, at, 1154 <loop> ]) # Create a reference data section manually data_section = mk_section( ".data", 0x2000, [ 0x00015ce8, # .word 89320 0x0000761f, # .word 30239 0x00000531, # .word 1329 0x00015bbd, # .word 89021 0x000076cb, # .word 30411 0x0000fac6, # .word 64198 0x00001072, # .word 4210 0x00004ee7, # .word 20199 0x00000000, # .word 0 0x00000000, # .word 0 0x00000000, # .word 0 0x00000000, # .word 0 ]) # Build a sparse memory image mem_image_ref = SparseMemoryImage() mem_image_ref.add_section( text_section ) mem_image_ref.add_section( data_section ) # Check that both sparse memory image are equal assert mem_image == mem_image_ref
def test_assemble_with_prog_mngr(): # Create the assembly code string asm = \ """ mfc0 r1, mngr2proc < 0x13 mfc0 r2, mngr2proc < 0x57 addu r3, r1, r2 # add two elements together mtc0 r3, proc2mngr > 0x6a nop mfc0 r1, mngr2proc < 0x65 mfc0 r2, mngr2proc < 0x42 addu r3, r1, r2 # add two elements together mtc0 r3, proc2mngr > 0xa7 """ # Assemble code into a memory image mem_image = pisa_encoding.assemble( asm ) # Create a reference text section by using binutils text_section = mk_section( ".text", 0x0400, [ 0x40010800, # mfc0 at, mngr2proc 0x40020800, # mfc0 v0, mngr2proc 0x00221821, # addu v1, at,v0 0x40831000, # mtc0 v1, proc2mngr 0x00000000, # nop 0x40010800, # mfc0 at, mngr2proc 0x40020800, # mfc0 v0, mngr2proc 0x00221821, # addu v1, at,v0 0x40831000, # mtc0 v1, proc2mngr ]) # Create a reference mngr2proc section manually mngr2proc_section = mk_section( ".mngr2proc", 0x3000, [ 0x00000013, 0x00000057, 0x00000065, 0x00000042, ]) # Create a reference proc2mngr section manually proc2mngr_section = mk_section( ".proc2mngr", 0x4000, [ 0x0000006a, 0x000000a7, ]) # Build a sparse memory image mem_image_ref = SparseMemoryImage() mem_image_ref.add_section( text_section ) mem_image_ref.add_section( mngr2proc_section ) mem_image_ref.add_section( proc2mngr_section ) # Check that both sparse memory image are equal assert mem_image == mem_image_ref
def elf_reader(file_obj): # Read the data for the ELF header ehdr_data = file_obj.read(ElfHeader.NBYTES) # Construct an ELF header object ehdr = ElfHeader(ehdr_data) # Verify if its a known format and realy an ELF file if ehdr.ident[0:4] != '\x7fELF': raise ValueError("Not a valid ELF file") # We need to find the section string table so we can figure out the # name of each section. We know that the section header for the section # string table is entry shstrndx, so we first get the data for this # section header. file_obj.seek(ehdr.shoff + ehdr.shstrndx * ehdr.shentsize) shdr_data = file_obj.read(ehdr.shentsize) # Construct a section header object for the section string table shdr = ElfSectionHeader(shdr_data) # Read the data for the section header table file_obj.seek(shdr.offset) shstrtab_data = file_obj.read(shdr.size) # Load sections symtab_data = None strtab_data = None mem_image = SparseMemoryImage() for section_idx in range(ehdr.shnum): # Read the data for the section header file_obj.seek(ehdr.shoff + section_idx * ehdr.shentsize) shdr_data = file_obj.read(ehdr.shentsize) # Pad the returned string in case the section header is not long # enough (otherwise the unpack function would not work) shdr_data = shdr_data.ljust(ElfSectionHeader.NBYTES, '\0') # Construct a section header object shdr = ElfSectionHeader(shdr_data) # Find the section name start = shstrtab_data[shdr.name:] section_name = start.partition('\0')[0] # This is the list of sections that we currently want to load. valid_section_names = \ [ ".text", ".data", ".sdata", ".xcpthandler", ".init", ".fini", ".ctors", ".dtors", ".eh_frame", ".jcr", ".sbss", ".bss", ".rodata", ".strtab", ".symtab", ] # Check to see if section is one of ones we want to load if section_name not in valid_section_names: continue # Read the section data file_obj.seek(shdr.offset) data = file_obj.read(shdr.size) # Save the data holding the symbol string table if shdr.type == ElfSectionHeader.TYPE_STRTAB: strtab_data = data # Save the data holding the symbol table elif shdr.type == ElfSectionHeader.TYPE_SYMTAB: symtab_data = data # Otherwise create section and append it to our list of sections else: section = SparseMemoryImage.Section(section_name, shdr.addr, data) mem_image.add_section(section) # Load symbols. We skip the first symbol since it both "designates the # first entry in the table and serves as the undefined symbol index". # For now, I have commented this out, since we are not really using it. # num_symbols = len(symtab_data) / ElfSymTabEntry.NBYTES # for sym_idx in xrange(1,num_symbols): # # # Read the data for a symbol table entry # # start = sym_idx * ElfSymTabEntry.NBYTES # sym_data = symtab_data[start:start+ElfSymTabEntry.NBYTES] # # # Construct a symbol table entry # # sym = ElfSymTabEntry( sym_data ) # # # Get the symbol type # # sym_type = sym.info & 0xf # # # Check to see if symbol is one of the three types we want to load # # valid_sym_types = \ # [ # ElfSymTabEntry.TYPE_NOTYPE, # ElfSymTabEntry.TYPE_OBJECT, # ElfSymTabEntry.TYPE_FUNC, # ] # # # Check to see if symbol is one of the three types we want to load # # if sym_type not in valid_sym_types: # continue # # # Get the symbol name from the string table # # start = strtab_data[sym.name:] # name = start.partition('\0')[0] # # # Add symbol to the sparse memory image # # mem_image.add_symbol( name, sym.value ) return mem_image
def assemble(asm_code): # If asm_code is a single string, then put it in a list to simplify the # rest of the logic. asm_code_list = asm_code if isinstance(asm_code, str): asm_code_list = [asm_code] # Create a single list of lines asm_list = [] for asm_seq in asm_code_list: asm_list.extend(asm_seq.splitlines()) # First pass to create symbol table. This is obviously very simplistic. # We can maybe make it more robust in the future. addr = 0x00000200 sym = {} for line in asm_list: line = line.partition('#')[0] line = line.strip() if line == "": continue if line.startswith(".offset"): (cmd, sep, addr_str) = line.partition(' ') addr = int(addr_str, 0) elif line.startswith(".data"): pass else: (label, sep, rest) = line.partition(':') if sep != "": sym[label.strip()] = addr else: addr += 4 # Second pass to assemble text section asm_list_idx = 0 addr = 0x00000200 text_bytes = bytearray() mngr2proc_bytes = bytearray() proc2mngr_bytes = bytearray() # Shunning: the way I handle multiple manager is as follows. # # At the beginning the single_core sign is true and all "> 1" "< 2" # values are dumped into the above mngr2proc_bytes and mngr2proc_bytes. # So, for single core testing the assembler works as usual. # # For multicore testing, I assume that all lists wrapped by curly braces # have the same width, and I will use the first ever length as the number # of cores. For example, when I see "> {1,2,3,4}", it means there are 4 # cores. It will then set single_core=False and num_cores=4. # Later if I see "> {1,2,3}" I will throw out assertion error. # # Also, Upon the first occurence of the mentioned curly braces, I will # just duplicate mngr2proc_bytes for #core times, and put the duplicates # into mngrs2procs. Later, when I see a "> 1", I will check the # single_core flag. If it's False, it will dump the check message into # all the duplicated bytearrays. # # The problem of co-existence if we keep mngr2proc and mngrs2procs, is # that unless we record the exact order we receive the csr instructions, # we cannot arbitrarily interleave the values in mngr2proc and mngrs2procs. mngrs2procs_bytes = [] procs2mngrs_bytes = [] single_core = True num_cores = 1 def duplicate(): # duplicate the bytes and no more mngr2proc/proc2mngr for i in xrange(num_cores): mngrs2procs_bytes.append(bytearray()) mngrs2procs_bytes[i][:] = mngr2proc_bytes procs2mngrs_bytes.append(bytearray()) procs2mngrs_bytes[i][:] = proc2mngr_bytes for line in asm_list: asm_list_idx += 1 line = line.partition('#')[0] line = line.strip() if line == "": continue if line.startswith(".offset"): (cmd, sep, addr_str) = line.partition(' ') addr = int(addr_str, 0) elif line.startswith(".data"): break else: if ':' not in line: inst_str = line # First see if we have either a < or a > if '<' in line: (temp, sep, value) = line.partition('<') value = value.lstrip(' ') if value.startswith('{'): values = map(lambda x: int(x, 0), value[1:-1].split(',')) if not single_core and len(values) != num_cores: raise Exception( "Previous curly brace pair has {} elements in between, but this one \"{}\" has {}." .format(num_cores, line, len(values))) if single_core: single_core = False num_cores = len(values) duplicate() for i in xrange(num_cores): mngrs2procs_bytes[i].extend( struct.pack("<I", Bits(32, values[i]))) else: bits = Bits(32, int(value, 0)) if single_core: mngr2proc_bytes.extend(struct.pack("<I", bits)) else: for x in mngrs2procs_bytes: x.extend(struct.pack("<I", bits)) inst_str = temp elif '>' in line: (temp, sep, value) = line.partition('>') value = value.lstrip(' ') if value.startswith('{'): values = map(lambda x: int(x, 0), value[1:-1].split(',')) if not single_core and len(values) != num_cores: raise Exception( "Previous curly brace pair has {} elements in between, but this one \"{}\" has {}." .format(num_cores, line, len(values))) if single_core: single_core = False num_cores = len(values) duplicate() for i in xrange(num_cores): procs2mngrs_bytes[i].extend( struct.pack("<I", Bits(32, values[i]))) else: bits = Bits(32, int(value, 0)) if single_core: proc2mngr_bytes.extend(struct.pack("<I", bits)) else: for x in procs2mngrs_bytes: x.extend(struct.pack("<I", bits)) inst_str = temp bits = assemble_inst(sym, addr, inst_str) text_bytes.extend(struct.pack("<I", bits.uint())) addr += 4 # Assemble data section data_bytes = bytearray() for line in asm_list[asm_list_idx:]: line = line.partition('#')[0] line = line.strip() if line == "": continue if line.startswith(".offset"): (cmd, sep, addr_str) = line.partition(' ') addr = int(addr_str, 0) elif line.startswith(".word"): (cmd, sep, value) = line.partition(' ') data_bytes.extend(struct.pack("<I", int(value, 0))) addr += 4 elif line.startswith(".hword"): (cmd, sep, value) = line.partition(' ') data_bytes.extend(struct.pack("<H", int(value, 0))) addr += 2 elif line.startswith(".byte"): (cmd, sep, value) = line.partition(' ') data_bytes.extend(struct.pack("<B", int(value, 0))) addr += 1 # Construct the corresponding section objects text_section = \ SparseMemoryImage.Section( ".text", 0x0200, text_bytes ) data_section = SparseMemoryImage.Section(".data", 0x2000, data_bytes) # Build a sparse memory image mem_image = SparseMemoryImage() mem_image.add_section(text_section) if len(data_section.data) > 0: mem_image.add_section(data_section) if single_core: mngr2proc_section = \ SparseMemoryImage.Section( ".mngr2proc", 0x13000, mngr2proc_bytes ) if len(mngr2proc_section.data) > 0: mem_image.add_section(mngr2proc_section) proc2mngr_section = \ SparseMemoryImage.Section( ".proc2mngr", 0x14000, proc2mngr_bytes ) if len(proc2mngr_section.data) > 0: mem_image.add_section(proc2mngr_section) else: for i in xrange(len(mngrs2procs_bytes)): img = SparseMemoryImage.Section(".mngr{}_2proc".format(i), 0x15000 + 0x1000 * i, mngrs2procs_bytes[i]) if len(img.data) > 0: mem_image.add_section(img) for i in xrange(len(procs2mngrs_bytes)): img = SparseMemoryImage.Section(".proc{}_2mngr".format(i), 0x16000 + 0x2000 * i, procs2mngrs_bytes[i]) if len(img.data) > 0: mem_image.add_section(img) return mem_image
def elf_reader( file_obj ): # Read the data for the ELF header ehdr_data = file_obj.read( ElfHeader.NBYTES ) # Construct an ELF header object ehdr = ElfHeader( ehdr_data ) # Verify if its a known format and realy an ELF file if ehdr.ident[0:4] != '\x7fELF': raise ValueError( "Not a valid ELF file" ) # We need to find the section string table so we can figure out the # name of each section. We know that the section header for the section # string table is entry shstrndx, so we first get the data for this # section header. file_obj.seek( ehdr.shoff + ehdr.shstrndx * ehdr.shentsize ) shdr_data = file_obj.read(ehdr.shentsize) # Construct a section header object for the section string table shdr = ElfSectionHeader( shdr_data ) # Read the data for the section header table file_obj.seek( shdr.offset ) shstrtab_data = file_obj.read( shdr.size ) # Load sections symtab_data = None strtab_data = None mem_image = SparseMemoryImage() for section_idx in range(ehdr.shnum): # Read the data for the section header file_obj.seek( ehdr.shoff + section_idx * ehdr.shentsize ) shdr_data = file_obj.read(ehdr.shentsize) # Pad the returned string in case the section header is not long # enough (otherwise the unpack function would not work) #shdr_data = shdr_data.ljust( ElfSectionHeader.NBYTES, '\0' ) fill = '\0'*( ElfSectionHeader.NBYTES - len(shdr_data) ) shdr_data = shdr_data + fill # Construct a section header object shdr = ElfSectionHeader( shdr_data ) # Find the section name #start = shstrtab_data[shdr.name:] idx = shdr.name assert idx >= 0 start = shstrtab_data[idx:] #section_name = start.partition('\0')[0] section_name = start.split('\0', 1)[0] # only sections marked as lloc should be written to memory if not (shdr.flags & ElfSectionHeader.FLAGS_ALLOC): continue # Read the section data if it exists if section_name not in ['.sbss', '.bss']: file_obj.seek( shdr.offset ) data = file_obj.read( shdr.size ) # NOTE: the .bss and .sbss sections don't actually contain any # data in the ELF. These sections should be initialized to zero. # For more information see: # # - http://stackoverflow.com/questions/610682/bss-section-in-elf-file else: data = '\0' * shdr.size # Save the data holding the symbol string table if shdr.type == ElfSectionHeader.TYPE_STRTAB: strtab_data = data # Save the data holding the symbol table elif shdr.type == ElfSectionHeader.TYPE_SYMTAB: symtab_data = data # Otherwise create section and append it to our list of sections else: section = SparseMemoryImage.Section( section_name, shdr.addr, data ) mem_image.add_section( section ) # Load symbols. We skip the first symbol since it both "designates the # first entry in the table and serves as the undefined symbol index". # For now, I have commented this out, since we are not really using it. # num_symbols = len(symtab_data) / ElfSymTabEntry.NBYTES # for sym_idx in xrange(1,num_symbols): # # # Read the data for a symbol table entry # # start = sym_idx * ElfSymTabEntry.NBYTES # sym_data = symtab_data[start:start+ElfSymTabEntry.NBYTES] # # # Construct a symbol table entry # # sym = ElfSymTabEntry( sym_data ) # # # Get the symbol type # # sym_type = sym.info & 0xf # # # Check to see if symbol is one of the three types we want to load # # valid_sym_types = \ # [ # ElfSymTabEntry.TYPE_NOTYPE, # ElfSymTabEntry.TYPE_OBJECT, # ElfSymTabEntry.TYPE_FUNC, # ] # # # Check to see if symbol is one of the three types we want to load # # if sym_type not in valid_sym_types: # continue # # # Get the symbol name from the string table # # start = strtab_data[sym.name:] # name = start.partition('\0')[0] # # # Add symbol to the sparse memory image # # mem_image.add_symbol( name, sym.value ) return mem_image
def mk_section(name, addr, words): data = bytearray() for word in words: data.extend(struct.pack("<I", word)) return SparseMemoryImage.Section(name, addr, data)