Exemplo n.º 1
0
static
do_call(stream, node, need_lval) {
    auto args = node[1] - 1, i = args;
    while ( i ) {
        expr_code( stream, node[ 3 + i-- ], 0 );
        asm_push( stream );
    }

    /* If we're calling an identifier that's not local and isn't an lval,
     * it must either be an extern function or an extern array.  The latter
     * would be a syntax error but for the present lack of a type system
     * So we assume it's a function and do a direct call if possible. */
    if ( node[3][0] == 'id' ) {
        auto off, is_lval = lookup_sym( &node[3][3], &off );
        if (!off && !is_lval)
            return asm_call( stream, &node[3][3], args*4 );
    }

    /* And fall back to an indirect call with CALL *%eax. */
    expr_code( stream, node[3], 0 );
    call_ptr( stream, args*4 );
}
Exemplo n.º 2
0
int hook_create_stub(uint8_t *tramp, const uint8_t *addr, int len)
{
    const uint8_t *base_addr = addr;

    while (len > 0) {
        int length = lde(addr);
        if(length == 0) return -1;

        // How many bytes left?
        len -= length;

        // Unconditional jump with 32-bit relative offset.
        if(*addr == 0xe9) {
            const uint8_t *target = addr + *(int32_t *)(addr + 1) + 5;
            tramp += asm_jump(tramp, target);
            addr += 5;
        }
        // Call with 32-bit relative offset.
        else if(*addr == 0xe8) {
            const uint8_t *target = addr + *(int32_t *)(addr + 1) + 5;
            tramp += asm_call(tramp, target);
            addr += 5;
        }
        // Conditional jump with 32bit relative offset.
        else if(*addr == 0x0f && addr[1] >= 0x80 && addr[1] < 0x90) {

#if __x86_64__
            pipe("CRITICAL:Conditional jump and calls in 64-bit are "
                 "considered unstable!");
#endif

            // TODO This can be stabilized by creating a 8-bit conditional
            // jump with 32/64-bit jumps at each target. However, this is
            // only required for 64-bit support and then only when this
            // instruction occurs at all in the original function - which is
            // currently not the case.

            // Conditional jumps consist of two bytes.
            *tramp++ = addr[0];
            *tramp++ = addr[1];

            // When a jmp/call is performed, then the relative offset +
            // the instruction pointer + the size of the instruction is the
            // resulting address, so that's our target address.
            // As we have already written the first one or two bytes of the
            // instruction we only have the relative address left - four bytes
            // in total.
            const uint8_t *target = addr + *(int32_t *)(addr + 2) + 6;

            // We have already copied the instruction opcode(s) itself so we
            // just have to calculate the relative address now.
            *(uint32_t *) tramp = target - tramp - 4;
            tramp += 4;

            addr += 6;
        }
        // Unconditional jump with 8bit relative offset.
        else if(*addr == 0xeb) {
            const uint8_t *target = addr + *(int8_t *)(addr + 1) + 2;
            tramp += asm_jump(tramp, target);
            addr += 2;

            // TODO Check the remaining length. Also keep in mind that any
            // following nop's behind this short jump can be included in the
            // remaining available space.
        }
        // Conditional jump with 8bit relative offset.
        else if(*addr >= 0x70 && *addr < 0x80) {

#if __x86_64__
            pipe("CRITICAL:Conditional jumps in 64-bit are "
                 "considered unstable!");
#endif

            // TODO The same as for the 32-bit conditional jumps.

            // Same rules apply as with the 32bit relative offsets, except
            // for the fact that both conditional and unconditional 8bit
            // relative jumps take only one byte for the opcode.

            // Hex representation of the two types of 32bit jumps;
            // 8bit relative conditional jumps:     70..80
            // 32bit relative conditional jumps: 0f 80..90
            // Thus we have to add 0x10 to the opcode of 8bit relative
            // offset jump to obtain the 32bit relative offset jump
            // opcode.
            *tramp++ = 0x0f;
            *tramp++ = addr[0] + 0x10;

            // 8bit relative offset - we have to sign-extend it, by casting it
            // as signed char, in order to calculate the correct address.
            const uint8_t *target = addr + *(int8_t *)(addr + 1) + 2;

            // Calculate the relative address.
            *(uint32_t *) tramp = (uint32_t)(target - tramp - 4);
            tramp += 4;

            addr += 2;
        }
#if __x86_64__
        // In 64-bit mode we have RIP-relative mov and lea instructions. These
        // have to be relocated properly. Handles "mov reg64, qword [offset]"
        // and "lea reg64, qword [offset]".
        else if((*addr == 0x48 || *addr == 0x4c) &&
                (addr[1] == 0x8b || addr[1] == 0x8d) &&
                (addr[2] & 0xc7) == 0x05) {
            // Register index and full address.
            uint32_t reg = ((addr[2] >> 3) & 7) + (*addr == 0x4c ? 8 : 0);
            const uint8_t *target = addr + *(int32_t *)(addr + 3) + 7;

            // mov reg64, address
            tramp[0] = 0x48 + (reg >= 8);
            tramp[1] = 0xb8 + (reg & 7);
            *(const uint8_t **)(tramp + 2) = target;
            tramp += 10;

            // If it was a mov instruction then also emit the pointer
            // dereference part.
            if(addr[1] == 0x8b) {
                // mov reg64, qword [reg64]
                tramp[0] = reg < 8 ? 0x48 : 0x4d;
                tramp[1] = 0x8b;
                tramp[2] = (reg & 7) | ((reg & 7) << 3);
                tramp += 3;
            }
            addr += 7;
        }
#endif
        // Return instruction indicates the end of basic block as well so we
        // have to check if we already have enough space for our hook..
        else if((*addr == 0xc3 || *addr == 0xc2) && len > 0) {
Exemplo n.º 3
0
// stack should look like this:
// val
// type
static void push_expression(ClmExpNode *node) {
  if (node == NULL)
    return;

  ClmType expression_type = clm_type_of_exp(node, data.scope);
  switch (node->type) {
  case EXP_TYPE_INT:
    asm_push_const_i(node->ival);
    asm_push_const_i((int)expression_type);
    break;
  case EXP_TYPE_FLOAT:
    asm_push_const_f(node->fval);
    asm_push_const_i((int)expression_type);
    break;
  case EXP_TYPE_STRING:
    // TODO push a string onto the stack
    break;
  case EXP_TYPE_ARITH: {
    ClmType right_type = clm_type_of_exp(node->arithExp.right, data.scope);
    ClmType left_type = clm_type_of_exp(node->arithExp.left, data.scope);
    if (left_type == CLM_TYPE_MATRIX && clm_type_is_number(right_type)) {
      // here the only ops are mul & div... we are scaling matrix
      // gen left and then right here... if we don't then we have
      // int val
      // int type
      // matrix
      // cols
      // rows
      // matrix type
      // and we have to pop the int after we generate the value... which is hard
      // and since we are multiplying the matrix in place, it would be easiest
      // to
      // gen the matrix first and then the int, so we just have to pop two
      // values
      // in total
      push_expression(node->arithExp.left);
      asm_mov(EDX, ESP);
      push_expression(node->arithExp.right);
      gen_arith(node);
    } else {
      push_expression(node->arithExp.right);
      asm_mov(EDX, ESP);
      push_expression(node->arithExp.left);
      gen_arith(node);
    }
    break;
  }
  case EXP_TYPE_BOOL:
    push_expression(node->boolExp.right);
    asm_mov(EDX, ESP);
    push_expression(node->boolExp.left);
    gen_bool(node);
    break;
  case EXP_TYPE_CALL: {
    // first push everything thats not a matrix... and for matrices push a pointer
    int tempStartID = data.temporaryID;
    int i;
    ClmExpNode *param;
    char temporary[256];

    // first for any matrices that are parameters that will be pushed through
    // the stack, push them on the stack and save their location into a temporary
    // global
    for (i = node->callExp.params->length - 1; i >= 0; i--) {
      param = node->callExp.params->data[i];
      if(param->type == CLM_TYPE_MATRIX){
        ClmLocation location = clm_location_of_exp(param, data.scope);
        switch(location){
            case LOCATION_STACK:
              push_expression(param);
              next_temporary(temporary);
              asm_mov(temporary, ESP);
              break;
            default:
              break;
        }
      }
    }

    // then push every expression.. when we get to a matrix, push the pointer
    // to its location
    int tempOffset = 1;
    char index_str[256];
    for (i = node->callExp.params->length - 1; i >= 0; i--) {
      param = node->callExp.params->data[i];
      if(param->type == CLM_TYPE_MATRIX){
        ClmLocation location = clm_location_of_exp(param, data.scope);
        switch(location){
            case LOCATION_STACK:
              sprintf(temporary, "dword [temporary%d]", tempStartID + tempOffset);
              asm_push(temporary);
              tempOffset++;
              break;
            default:
            {
              // the only way its a matrix and not on the stack is if its an
              // ind exp with no indices
              ClmSymbol *symbol = clm_scope_find(data.scope, param->indExp.id);
              load_var_location(symbol, index_str, 0, NULL);
              asm_push(index_str);
              break;
            }
        }
        asm_push_const_i((int) CLM_TYPE_MATRIX);
      }else{
        push_expression(param);
      }
    }

    asm_call(node->callExp.name);

    // TODO pop off arguments from the stack
    break;
  }
  case EXP_TYPE_INDEX:
    push_index(node);
    break;
  case EXP_TYPE_MAT_DEC: {
    int i;
    if (node->matDecExp.arr != NULL) {
      for (i = node->matDecExp.length - 1; i >= 0; i--) {
        // TODO... push f or push i?
        asm_push_const_i((int)node->matDecExp.arr[i]);
      }
      asm_push_const_i(node->matDecExp.size.cols);
      asm_push_const_i(node->matDecExp.size.rows);
      asm_push_const_i((int)CLM_TYPE_MATRIX);
    } else {
      // push a matrix onto the stack with all 0s
      char cmp_label[LABEL_SIZE];
      char end_label[LABEL_SIZE];
      next_label(cmp_label);
      next_label(end_label);

      gen_exp_size(node);
      asm_pop(EAX); // # rows
      asm_pop(EBX); // # cols

      asm_mov(ECX, EAX);
      asm_imul(ECX, EBX);
      asm_dec(ECX);
      asm_label(cmp_label);
      asm_cmp(ECX, "0");
      asm_jmp_l(end_label);
      asm_push_const_i(0);
      asm_dec(ECX);
      asm_jmp(cmp_label);
      asm_label(end_label);
      asm_push(EBX);
      asm_push(EAX);
      asm_push_const_i((int)CLM_TYPE_MATRIX);
    }
    break;
  }
  case EXP_TYPE_PARAM:
    break;
  case EXP_TYPE_UNARY:
    push_expression(node->unaryExp.node);
    gen_unary(node);
    break;
  }
}