Source code for asm_analyser.architectures.arm.arm_util

'''Provides some utility functions that are useful for the translation of
ARM assembly to C.
'''
import re
from typing import List
from asm_analyser.blocks.code_block import CodeBlock


[docs]def get_needed_regs(blocks: List[CodeBlock]) -> str: '''Determines the global variables that need to be created as registers. Parameters ---------- blocks : list[CodeBlock] All the labeled code blocks with their instructions. Returns ------- str Variable declarations in C. ''' needed_vars = {'r0', 'r1', 'r2', 'r3', 'r4'} for block in blocks: for instr in block.instructions: for j, op in enumerate(instr[2]): if re.match('^\[?r\d{1,2}\]?$', op): needed_vars.add(instr[2][j]) result = '_arm_reg ' result += ', '.join(needed_vars) return result + ';\n'
[docs]def get_malloc_start(blocks: List[CodeBlock], stack_size: int) -> str: '''Fills the malloc_start method in the template. Constants for the C-code are defined in this section and the necessary memory is allocated. Parameters ---------- blocks : list[CodeBlock] All the labeled code blocks with their instructions. stack_size : int Size of the simulated stack in bytes Returns ------- str C-code containing the contents for the malloc_start function in the template. ''' blocks = [block for block in blocks if not block.is_code] byte_array = [] # calculate and allocate the necessary memory for block in blocks: if block.instructions[0][1] == '.ascii': byte_array.append(len(block.instructions[0][2][0])) elif block.instructions[0][1] == '.word': byte_array.append(len(block.instructions) * 4) elif block.instructions[0][1] == '.comm': byte_array.append(int(block.instructions[0][2][1])) elif block.instructions[0][1] == '.space': byte_array.append(int(block.instructions[0][2][0])) total_length = sum(byte_array) + stack_size result = f'_asm_analysis_.malloc_0 = (uint8_t*) malloc({total_length});\n' result += f'_asm_analysis_.sp.i = {stack_size-4};\n' result += f'_asm_analysis_.fp = _asm_analysis_.sp;\n' return result
[docs]def get_needed_consts(blocks: List[CodeBlock]) -> str: '''Creates the global variables needed for constants. These constants variables are used to store pointers to memory containing the constants (e.g. array, string,...) Parameters ---------- blocks : list[CodeBlock] All the labeled code blocks with their instructions. Returns ------- str Variable declarations in C. ''' contants = [block.name for block in blocks if not block.is_code] if len(contants) <= 0: return '' result = 'int32_t ' result += ', '.join(contants) return result + ';\n'
[docs]def get_constant_defs(blocks: List[CodeBlock], stack_size: int) -> str: '''Fills the constants from "get_needed_consts". This is done by allocating memory with malloc in C and then saving the values to that memory. The pointer to that memory is stored in a global variable. Parameters ---------- blocks : list[CodeBlock] All the labeled code blocks with their instructions. stack_size : int Size of the simulated stack in bytes Returns ------- str C code that defines the arm constants. ''' blocks = [block for block in blocks if not block.is_code] if len(blocks) <= 0: return '' block_order = {} block_count = 0 for block in blocks: if block.parent_name not in block_order: block_order[block.parent_name] = block_count block_count += 1 # sort the blocks in each section so that 'LCx' definitions come first blocks = sorted(blocks, key=lambda b: (block_order[b.parent_name], 'LC' not in b.name)) result = '' byte_array = [] # calculate and allocate the necessary memory for block in blocks: if block.instructions[0][1] == '.ascii': byte_array.append(len(block.instructions[0][2][0])) elif block.instructions[0][1] == '.word': byte_array.append(len(block.instructions) * 4) elif block.instructions[0][1] == '.comm': byte_array.append(int(block.instructions[0][2][1])) elif block.instructions[0][1] == '.space': byte_array.append(int(block.instructions[0][2][0])) # define the constants for i, block in enumerate(blocks): if i == 0: result += f'_asm_analysis_.{block.name} = {stack_size};\n' else: result += f'_asm_analysis_.{block.name} = {stack_size+sum(byte_array[:i])};\n' if block.instructions[0][1] == '.ascii': result += f'strcpy(_asm_analysis_.malloc_0+_asm_analysis_.{block.name}, ' result += f'{block.instructions[0][2][0]});\n\n' elif block.instructions[0][1] == '.word': arr = [instr[2][0] for instr in block.instructions] result += f'int32_t array{block.name}[] = {{{",".join(arr)}}};\n' result += f'for(int i=0; i<{len(arr)}; i++) *((uint32_t*)(_asm_analysis_.malloc_0+_asm_analysis_.{block.name}+i*4)) = array{block.name}[i];\n\n' elif block.instructions[0][1] == '.comm': pass elif block.instructions[0][1] == '.space': pass return result
[docs]def get_function_decls(blocks: List[CodeBlock]) -> str: '''Creates the functions declarations in C for every arm function. Returns ------- str C code containing the function declarations. ''' funcs = [block.name for block in blocks if block.is_function] if len(funcs) <= 0: return '' result = 'void ' result += '();\nvoid '.join(funcs) return result + '();\n'