Exemple #1
0
def element_selection(expr, symbol_table):
    instrs = symbol_table['__ expression __'](left_exp(expr), symbol_table)
    # if we are loading the structure then just remove the Load instr, calculate the elements offset and Load that elem
    if is_load(instrs):
        return element_instrs(
            c_type(left_exp(expr)), right_exp(expr), loc(expr), load_instrs=all_but_last(instrs, Loads, loc(expr))
        )

    struct_size, member_size = size(c_type(left_exp(expr))), size_arrays_as_pointers(c_type(expr))
    addr_instrs = add(  # calculate the loaded structured members address
        load_stack_pointer(loc(expr)),
        push(struct_member_offset(c_type(left_exp(expr)), right_exp(expr)), loc(expr)),
        loc(expr)
    )
    return chain(  # copy the element then move it to the base of the structure and deallocate everything else
        set_instr(
            chain(  # load the value in question if its not an array (which is just an address ...)
                (addr_instrs if isinstance(c_type(expr), ArrayType) else load(addr_instrs, member_size, loc(expr))),
                add(load_stack_pointer(loc(expr)), push((struct_size + member_size), loc(expr)), loc(expr)),
            ),
            member_size,
            loc(expr)
        ),
        allocate(-(struct_size - member_size), loc(expr))  # deallocate structure and copied member (set leaves value)
    )
Exemple #2
0
def element_selection(expr, symbol_table):
    instrs = symbol_table['__ expression __'](left_exp(expr), symbol_table)
    # if we are loading the structure then just remove the Load instr, calculate the elements offset and Load that elem
    if is_load(instrs):
        return element_instrs(c_type(left_exp(expr)),
                              right_exp(expr),
                              loc(expr),
                              load_instrs=all_but_last(instrs, Loads,
                                                       loc(expr)))

    struct_size, member_size = size(c_type(
        left_exp(expr))), size_arrays_as_pointers(c_type(expr))
    addr_instrs = add(  # calculate the loaded structured members address
        load_stack_pointer(loc(expr)),
        push(struct_member_offset(c_type(left_exp(expr)), right_exp(expr)),
             loc(expr)), loc(expr))
    return chain(  # copy the element then move it to the base of the structure and deallocate everything else
        set_instr(
            chain(  # load the value in question if its not an array (which is just an address ...)
                (addr_instrs if isinstance(c_type(expr), ArrayType) else load(
                    addr_instrs, member_size, loc(expr))),
                add(load_stack_pointer(loc(expr)),
                    push((struct_size + member_size), loc(expr)), loc(expr)),
            ),
            member_size,
            loc(expr)),
        allocate(-(struct_size - member_size), loc(
            expr))  # deallocate structure and copied member (set leaves value)
    )
Exemple #3
0
def const_string_expr(expr):  # strings are embedded ...
    data = static_binaries(expr)
    _initial_data = peek(data)  # there should be at least one char, '\0'
    _push = push(Address(_initial_data, loc(expr)), loc(expr))
    return chain(
        relative_jump(Offset(peek(_push, loc(expr)), loc(expr)), loc(expr)),
        consume_all(data, _push))
Exemple #4
0
def subtract(l_instrs, r_instrs, location, operand_types):
    exp_c_type, left_exp_c_type, right_exp_c_type = operand_types
    if all(imap(isinstance, operand_types[1:], repeat(PointerType))):  # subtracting two pointers ...
        return divide(
            subtract.rules[base_c_type(void_pointer_type)][size(void_pointer_type)](l_instrs, r_instrs, location),
            push(size_extended(c_type(c_type(left_exp_c_type))), location),
            location,
            operand_types
        )

    return pointer_arithmetic(l_instrs, r_instrs, location, operand_types)
Exemple #5
0
def calculate_pointer_offset(instrs, pointer_type, location):
    return multiply(
        instrs,
        push(size_extended(c_type(pointer_type)), location),
        location,
        (
            PointerType(c_type(pointer_type), location=location),
            pointer_type,
            LongType(LongType(location=location), location=location, unsigned=True)
        )
    )
Exemple #6
0
def push_frame(
        arguments_instrs=(),
        location=LocationNotSet,
        total_size_of_arguments=0,
        omit_pointer_for_return_value=False,
):
    return chain(
        load_base_stack_pointer(location),  # save previous base stack pointer ...
        arguments_instrs,
        # Pointer to where to store return values, if applicable (ie non-zero return size)...
        () if omit_pointer_for_return_value else
        # calculate pointer for ret value, excluding base pointer ...
        add(load_stack_pointer(location), push((total_size_of_arguments + size(void_pointer_type)), location), location)
    )
Exemple #7
0
def call_function(function_call_expr, symbol_table):
    l, expr = loc(function_call_expr), left_exp(function_call_expr)
    return chain(  # if expression is a simple identifier of function type, no need for AbsoluteJump, use RelativeJump
        set_base_stack_pointer(load_stack_pointer(l), l),
        relative_jump(Offset(symbol_table[name(expr)].get_address_obj(l).obj, l), l),
    ) if isinstance(expr, IdentifierExpression) and isinstance(c_type(expr), FunctionType) else absolute_jump(
        chain(
            symbol_table['__ expression __'](expr, symbol_table),   # load callee address
            # calculate new base stack pointer excluding the callees address ...
            # give the callee a new frame... if we where to reset the base stack ptr before evaluating the left_expr
            # we run the risk of failing to properly load function address if it was store as a local function pointer
            set_base_stack_pointer(add(load_stack_pointer(l), push(size(void_pointer_type), l), l), l)
        ),
        l
    )
Exemple #8
0
def array_subscript(expr, symbol_table):
    assert isinstance(c_type(left_exp(expr)), PointerType) and isinstance(
        c_type(right_exp(expr)), IntegralType)
    expression = symbol_table['__ expression __']
    l = loc(expr)
    addr_instrs = add(
        expression(left_exp(expr), symbol_table),
        multiply(
            cast(  # convert right expression to address type in order to properly multiply ...
                expression(right_exp(expr), symbol_table),
                c_type(right_exp(expr)), void_pointer_type, l),
            push(size(c_type(expr)), l),
            l),
        l,
    )  # Load value unless the return type is also an ArrayTyp
    return addr_instrs if isinstance(c_type(expr), ArrayType) \
        else load(addr_instrs, size_arrays_as_pointers(c_type(expr)), l)
Exemple #9
0
def push_frame(
    arguments_instrs=(),
    location=LocationNotSet,
    total_size_of_arguments=0,
    omit_pointer_for_return_value=False,
):
    return chain(
        load_base_stack_pointer(
            location),  # save previous base stack pointer ...
        arguments_instrs,
        # Pointer to where to store return values, if applicable (ie non-zero return size)...
        () if omit_pointer_for_return_value else
        # calculate pointer for ret value, excluding base pointer ...
        add(
            load_stack_pointer(location),
            push((total_size_of_arguments +
                  size(void_pointer_type)), location), location))
Exemple #10
0
def call_function(function_call_expr, symbol_table):
    l, expr = loc(function_call_expr), left_exp(function_call_expr)
    return chain(  # if expression is a simple identifier of function type, no need for AbsoluteJump, use RelativeJump
        set_base_stack_pointer(load_stack_pointer(l), l),
        relative_jump(
            Offset(symbol_table[name(expr)].get_address_obj(l).obj, l), l),
    ) if isinstance(expr, IdentifierExpression) and isinstance(
        c_type(expr), FunctionType
    ) else absolute_jump(
        chain(
            symbol_table['__ expression __'](
                expr, symbol_table),  # load callee address
            # calculate new base stack pointer excluding the callees address ...
            # give the callee a new frame... if we where to reset the base stack ptr before evaluating the left_expr
            # we run the risk of failing to properly load function address if it was store as a local function pointer
            set_base_stack_pointer(
                add(load_stack_pointer(l), push(size(void_pointer_type), l),
                    l), l)),
        l)
Exemple #11
0
def array_subscript(expr, symbol_table):
    assert isinstance(c_type(left_exp(expr)), PointerType) and isinstance(c_type(right_exp(expr)), IntegralType)
    expression = symbol_table['__ expression __']
    l = loc(expr)
    addr_instrs = add(
        expression(left_exp(expr), symbol_table),
        multiply(
            cast(  # convert right expression to address type in order to properly multiply ...
                expression(right_exp(expr), symbol_table),
                c_type(right_exp(expr)),
                void_pointer_type,
                l
            ),
            push(size(c_type(expr)), l),
            l
        ),
        l,
    )   # Load value unless the return type is also an ArrayTyp
    return addr_instrs if isinstance(c_type(expr), ArrayType) \
        else load(addr_instrs, size_arrays_as_pointers(c_type(expr)), l)
Exemple #12
0
def pop_frame(location=LocationNotSet,
              total_size_of_arguments=0,
              omit_pointer_for_return_value=False):
    # return pop_frame_instr(location)  # method 1 requires special instruction that has to manage blocks

    # method 2 (5 instructions LoadBaseStackPtr, Push, Add, SetStackPtr, SetBaseStackPtr)
    # method 2 seems to be faster even though it has an extra instruction compare to method 3,
    # not really sure why ... probably because the optimizer is removing some of them

    return set_base_stack_pointer(
        set_stack_pointer(
            add(
                # remove parameters and ret addr ...
                load_base_stack_pointer(location),
                push(  # remove parameters, ret address pointer, and ptr for ret value if it was emitted ...
                    sum((total_size_of_arguments, size(void_pointer_type),
                         (not omit_pointer_for_return_value) *
                         size(void_pointer_type))), location),
                location),
            location),
        location)
Exemple #13
0
def function_call(expr, symbol_table):
    assert not isinstance(c_type(expr), ArrayType)
    l, return_instr = loc(expr), Pass(loc(expr))
    total_size_of_arguments = sum(
        imap(size_arrays_as_pointers, imap(c_type, right_exp(expr))))
    return_size = size(c_type(expr), overrides={VoidType: 0})
    omit_pointer_for_return_value = not return_size

    # if omit_pointer_for_return_value:
    #     # if the function call is a statement or its return type has zero size.
    #     # lets do some minor optimizations, since function calls already quite expensive as it is.
    #     expr.c_type = VoidType(loc(l))  # change the return type of the expression to void.
    #     # since we are omitting the return pointer, we have to update the parameter offsets, since they are calculated
    #     # assuming that a return pointer is added ...
    #     # all sets should be decrease by size(void_pointer) for this expression but this may not be true for other
    #     # function call expressions that may actually use the return value of this as such ... :(
    # we would need to check if the functions return value is ALWAYS ignored if and only if then can we omit
    # the return pointer for know its only applicable for for functions whose return size is zero ...
    # TODO: post-compilation optimization that optimizes functions whose returned values is ALWAYS ignored.
    expression = symbol_table['__ expression __']
    return chain(
        # Allocate space for return value, save frame.
        allocate(return_size, l),
        push_frame(
            # Push arguments in reverse order (right to left) ...
            chain.from_iterable(
                imap(expression, reverse(right_exp(expr)),
                     repeat(symbol_table))),
            location=l,
            total_size_of_arguments=total_size_of_arguments,
            omit_pointer_for_return_value=omit_pointer_for_return_value),
        push(Address(return_instr, l),
             l),  # make callee aware of were to return to.
        call_function(expr, symbol_table),
        (return_instr, ),
        # Pop Frame, first stack pointer then base stack pointer
        pop_frame(location=l,
                  total_size_of_arguments=total_size_of_arguments,
                  omit_pointer_for_return_value=omit_pointer_for_return_value))
Exemple #14
0
def function_call(expr, symbol_table):
    assert not isinstance(c_type(expr), ArrayType)
    l, return_instr = loc(expr), Pass(loc(expr))
    total_size_of_arguments = sum(imap(size_arrays_as_pointers, imap(c_type, right_exp(expr))))
    return_size = size(c_type(expr), overrides={VoidType: 0})
    omit_pointer_for_return_value = not return_size

    # if omit_pointer_for_return_value:
    #     # if the function call is a statement or its return type has zero size.
    #     # lets do some minor optimizations, since function calls already quite expensive as it is.
    #     expr.c_type = VoidType(loc(l))  # change the return type of the expression to void.
    #     # since we are omitting the return pointer, we have to update the parameter offsets, since they are calculated
    #     # assuming that a return pointer is added ...
    #     # all sets should be decrease by size(void_pointer) for this expression but this may not be true for other
    #     # function call expressions that may actually use the return value of this as such ... :(
    # we would need to check if the functions return value is ALWAYS ignored if and only if then can we omit
    # the return pointer for know its only applicable for for functions whose return size is zero ...
    # TODO: post-compilation optimization that optimizes functions whose returned values is ALWAYS ignored.
    expression = symbol_table['__ expression __']
    return chain(
        # Allocate space for return value, save frame.
        allocate(return_size, l),
        push_frame(
            # Push arguments in reverse order (right to left) ...
            chain.from_iterable(imap(expression, reverse(right_exp(expr)), repeat(symbol_table))),
            location=l,
            total_size_of_arguments=total_size_of_arguments,
            omit_pointer_for_return_value=omit_pointer_for_return_value
        ),
        push(Address(return_instr, l), l),  # make callee aware of were to return to.
        call_function(expr, symbol_table),
        (return_instr,),
        # Pop Frame, first stack pointer then base stack pointer
        pop_frame(
            location=l,
            total_size_of_arguments=total_size_of_arguments,
            omit_pointer_for_return_value=omit_pointer_for_return_value
        )
    )
Exemple #15
0
def return_statement(stmnt, symbol_table):
    # TODO: check if we can omit the setting the return value if if it is immediately removed ...
    return_type = c_type(c_type(symbol_table['__ CURRENT FUNCTION __']))
    assert not isinstance(c_type(return_type), ArrayType)
    if isinstance(return_type, VoidType) or not exp(stmnt):
     # just return if void type or expr is empty or size of expression is zero.
        return return_instrs(loc(stmnt))

    return chain(
        cast(symbol_table['__ expression __'](exp(stmnt), symbol_table), c_type(exp(stmnt)), return_type, loc(stmnt)),
        set_instr(
            load(
                add(load_base_stack_pointer(loc(stmnt)), push(size(void_pointer_type), loc(stmnt)), loc(stmnt)),
                size(void_pointer_type),
                loc(stmnt)
            ),
            size(return_type),
            loc(stmnt)
        ),
        # TODO: see if we can remove the following instr, since pop_frame will reset the base and stack pointers
        # allocate(-size(return_type), loc(stmnt)),  # Set leaves the value on the stack
        return_instrs(loc(stmnt))
    )
Exemple #16
0
def pop_frame(location=LocationNotSet, total_size_of_arguments=0, omit_pointer_for_return_value=False):
    # return pop_frame_instr(location)  # method 1 requires special instruction that has to manage blocks

    # method 2 (5 instructions LoadBaseStackPtr, Push, Add, SetStackPtr, SetBaseStackPtr)
    # method 2 seems to be faster even though it has an extra instruction compare to method 3,
    # not really sure why ... probably because the optimizer is removing some of them

    return set_base_stack_pointer(
        set_stack_pointer(
            add(
                # remove parameters and ret addr ...
                load_base_stack_pointer(location),
                push(    # remove parameters, ret address pointer, and ptr for ret value if it was emitted ...
                    sum((
                        total_size_of_arguments, size(void_pointer_type),
                        (not omit_pointer_for_return_value) * size(void_pointer_type))),
                    location
                ),
                location
            ),
            location
        ),
        location
    )
Exemple #17
0
def const_string_expr(expr):  # strings are embedded ...
    data = static_binaries(expr)
    _initial_data = peek(data)  # there should be at least one char, '\0'
    _push = push(Address(_initial_data, loc(expr)), loc(expr))
    return chain(relative_jump(Offset(peek(_push, loc(expr)), loc(expr)), loc(expr)), consume_all(data, _push))
Exemple #18
0
def element_instrs(struct_obj, member_name, location, load_instrs=iter(())):
    instrs = add(load_instrs, push(struct_member_offset(struct_obj, member_name), location), location)
    return instrs if isinstance(c_type(struct_obj.members[member_name]), ArrayType) else \
        load(instrs, size_arrays_as_pointers(c_type(struct_obj.members[member_name])), location)
Exemple #19
0
 def load_address(self, location):
     return push(Address(self._initial_data, location), location)
Exemple #20
0
def element_instrs(struct_obj, member_name, location, load_instrs=iter(())):
    instrs = add(load_instrs,
                 push(struct_member_offset(struct_obj, member_name), location),
                 location)
    return instrs if isinstance(c_type(struct_obj.members[member_name]), ArrayType) else \
        load(instrs, size_arrays_as_pointers(c_type(struct_obj.members[member_name])), location)
Exemple #21
0
 def load_address(self, location):
     return add(load_base_stack_pointer(location),
                push(self.offset, location), location)
Exemple #22
0
 def load_address(self, location):
     return add(load_base_stack_pointer(location), push(self.offset, location), location)