diff options
Diffstat (limited to 'libyasm/intnum.c')
-rw-r--r-- | libyasm/intnum.c | 378 |
1 files changed, 315 insertions, 63 deletions
diff --git a/libyasm/intnum.c b/libyasm/intnum.c index b8e0a5ac..94b8e733 100644 --- a/libyasm/intnum.c +++ b/libyasm/intnum.c @@ -83,7 +83,7 @@ yasm_intnum_cleanup(void) } yasm_intnum * -yasm_intnum_create_dec(char *str, unsigned long line) +yasm_intnum_create_dec(char *str) { yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); @@ -91,7 +91,7 @@ yasm_intnum_create_dec(char *str, unsigned long line) if (BitVector_from_Dec_static(from_dec_data, conv_bv, (unsigned char *)str) == ErrCode_Ovfl) - yasm__warning(YASM_WARN_GENERAL, line, + yasm_warn_set(YASM_WARN_GENERAL, N_("Numeric constant too large for internal format")); if (Set_Max(conv_bv) < 32) { intn->type = INTNUM_UL; @@ -105,14 +105,14 @@ yasm_intnum_create_dec(char *str, unsigned long line) } yasm_intnum * -yasm_intnum_create_bin(char *str, unsigned long line) +yasm_intnum_create_bin(char *str) { yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); intn->origsize = (unsigned char)strlen(str); if(intn->origsize > BITVECT_NATIVE_SIZE) - yasm__warning(YASM_WARN_GENERAL, line, + yasm_warn_set(YASM_WARN_GENERAL, N_("Numeric constant too large for internal format")); BitVector_from_Bin(conv_bv, (unsigned char *)str); @@ -128,14 +128,14 @@ yasm_intnum_create_bin(char *str, unsigned long line) } yasm_intnum * -yasm_intnum_create_oct(char *str, unsigned long line) +yasm_intnum_create_oct(char *str) { yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); intn->origsize = strlen(str)*3; if(intn->origsize > BITVECT_NATIVE_SIZE) - yasm__warning(YASM_WARN_GENERAL, line, + yasm_warn_set(YASM_WARN_GENERAL, N_("Numeric constant too large for internal format")); BitVector_from_Oct(conv_bv, (unsigned char *)str); @@ -151,14 +151,14 @@ yasm_intnum_create_oct(char *str, unsigned long line) } yasm_intnum * -yasm_intnum_create_hex(char *str, unsigned long line) +yasm_intnum_create_hex(char *str) { yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); intn->origsize = strlen(str)*4; if(intn->origsize > BITVECT_NATIVE_SIZE) - yasm__warning(YASM_WARN_GENERAL, line, + yasm_warn_set(YASM_WARN_GENERAL, N_("Numeric constant too large for internal format")); BitVector_from_Hex(conv_bv, (unsigned char *)str); @@ -175,7 +175,7 @@ yasm_intnum_create_hex(char *str, unsigned long line) /*@-usedef -compdef -uniondef@*/ yasm_intnum * -yasm_intnum_create_charconst_nasm(const char *str, unsigned long line) +yasm_intnum_create_charconst_nasm(const char *str) { yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); size_t len = strlen(str); @@ -183,7 +183,7 @@ yasm_intnum_create_charconst_nasm(const char *str, unsigned long line) intn->origsize = len*8; if(intn->origsize > BITVECT_NATIVE_SIZE) - yasm__warning(YASM_WARN_GENERAL, line, + yasm_warn_set(YASM_WARN_GENERAL, N_("Character constant too large for internal format")); if (len > 4) { @@ -259,6 +259,82 @@ yasm_intnum_create_int(long i) } yasm_intnum * +yasm_intnum_create_leb128(const unsigned char *ptr, int sign, + unsigned long *size) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + const unsigned char *ptr_orig = ptr; + unsigned long i = 0; + + intn->origsize = 0; + + BitVector_Empty(conv_bv); + for (;;) { + BitVector_Chunk_Store(conv_bv, 7, i, *ptr); + i += 7; + if ((*ptr & 0x80) != 0x80) + break; + ptr++; + } + + *size = (ptr-ptr_orig)+1; + + if(i > BITVECT_NATIVE_SIZE) + yasm_warn_set(YASM_WARN_GENERAL, + N_("Numeric constant too large for internal format")); + else if (sign && (*ptr & 0x40) == 0x40) + BitVector_Interval_Fill(conv_bv, i, BITVECT_NATIVE_SIZE-1); + + if (Set_Max(conv_bv) < 32) { + intn->type = INTNUM_UL; + intn->val.ul = BitVector_Chunk_Read(conv_bv, 32, 0); + } else { + intn->type = INTNUM_BV; + intn->val.bv = BitVector_Clone(conv_bv); + } + + return intn; +} + +yasm_intnum * +yasm_intnum_create_sized(unsigned char *ptr, int sign, size_t srcsize, + int bigendian) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + unsigned long i = 0; + + intn->origsize = 0; + + if (srcsize*8 > BITVECT_NATIVE_SIZE) + yasm_warn_set(YASM_WARN_GENERAL, + N_("Numeric constant too large for internal format")); + + /* Read the buffer into a bitvect */ + BitVector_Empty(conv_bv); + if (bigendian) { + /* TODO */ + yasm_internal_error(N_("big endian not implemented")); + } else { + for (i = 0; i < srcsize; i++) + BitVector_Chunk_Store(conv_bv, 8, i*8, ptr[i]); + } + + /* Sign extend if needed */ + if (srcsize*8 < BITVECT_NATIVE_SIZE && sign && (ptr[i] & 0x80) == 0x80) + BitVector_Interval_Fill(conv_bv, i*8, BITVECT_NATIVE_SIZE-1); + + if (Set_Max(conv_bv) < 32) { + intn->type = INTNUM_UL; + intn->val.ul = BitVector_Chunk_Read(conv_bv, 32, 0); + } else { + intn->type = INTNUM_BV; + intn->val.bv = BitVector_Clone(conv_bv); + } + + return intn; +} + +yasm_intnum * yasm_intnum_copy(const yasm_intnum *intn) { yasm_intnum *n = yasm_xmalloc(sizeof(yasm_intnum)); @@ -286,12 +362,12 @@ yasm_intnum_destroy(yasm_intnum *intn) } /*@-nullderef -nullpass -branchstate@*/ -void -yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand, - unsigned long line) +int +yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand) { boolean carry = 0; wordptr op1, op2 = NULL; + N_int count; /* Always do computations with in full bit vector. * Bit vector results must be calculated through intermediate storage. @@ -315,8 +391,12 @@ yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand, } if (!operand && op != YASM_EXPR_NEG && op != YASM_EXPR_NOT && - op != YASM_EXPR_LNOT) - yasm_internal_error(N_("Operation needs an operand")); + op != YASM_EXPR_LNOT) { + yasm_error_set(YASM_ERROR_ARITHMETIC, + N_("operation needs an operand")); + BitVector_Empty(result); + return 1; + } /* A operation does a bitvector computation if result is allocated. */ switch (op) { @@ -331,17 +411,37 @@ yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand, break; case YASM_EXPR_DIV: /* TODO: make sure op1 and op2 are unsigned */ - BitVector_Divide(result, op1, op2, spare); + if (BitVector_is_empty(op2)) { + yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero")); + BitVector_Empty(result); + return 1; + } else + BitVector_Divide(result, op1, op2, spare); break; case YASM_EXPR_SIGNDIV: - BitVector_Divide(result, op1, op2, spare); + if (BitVector_is_empty(op2)) { + yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero")); + BitVector_Empty(result); + return 1; + } else + BitVector_Divide(result, op1, op2, spare); break; case YASM_EXPR_MOD: /* TODO: make sure op1 and op2 are unsigned */ - BitVector_Divide(spare, op1, op2, result); + if (BitVector_is_empty(op2)) { + yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero")); + BitVector_Empty(result); + return 1; + } else + BitVector_Divide(spare, op1, op2, result); break; case YASM_EXPR_SIGNMOD: - BitVector_Divide(spare, op1, op2, result); + if (BitVector_is_empty(op2)) { + yasm_error_set(YASM_ERROR_ZERO_DIVISION, N_("divide by zero")); + BitVector_Empty(result); + return 1; + } else + BitVector_Divide(spare, op1, op2, result); break; case YASM_EXPR_NEG: BitVector_Negate(result, op1); @@ -358,6 +458,10 @@ yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand, case YASM_EXPR_XOR: Set_ExclusiveOr(result, op1, op2); break; + case YASM_EXPR_XNOR: + Set_ExclusiveOr(result, op1, op2); + Set_Complement(result, result); + break; case YASM_EXPR_NOR: Set_Union(result, op1, op2); Set_Complement(result, result); @@ -372,7 +476,10 @@ yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand, case YASM_EXPR_SHR: if (operand->type == INTNUM_UL) { BitVector_Copy(result, op1); - BitVector_Move_Right(result, (N_int)operand->val.ul); + carry = BitVector_msb_(op1); + count = (N_int)operand->val.ul; + while (count-- > 0) + BitVector_shift_right(result, carry); } else /* don't even bother, just zero result */ BitVector_Empty(result); break; @@ -390,45 +497,66 @@ yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand, BitVector_Empty(result); BitVector_LSB(result, BitVector_is_empty(op1)); break; + case YASM_EXPR_LXOR: + BitVector_Empty(result); + BitVector_LSB(result, !BitVector_is_empty(op1) ^ + !BitVector_is_empty(op2)); + break; + case YASM_EXPR_LXNOR: + BitVector_Empty(result); + BitVector_LSB(result, !(!BitVector_is_empty(op1) ^ + !BitVector_is_empty(op2))); + break; + case YASM_EXPR_LNOR: + BitVector_Empty(result); + BitVector_LSB(result, !(!BitVector_is_empty(op1) || + !BitVector_is_empty(op2))); + break; case YASM_EXPR_EQ: BitVector_Empty(result); BitVector_LSB(result, BitVector_equal(op1, op2)); break; case YASM_EXPR_LT: BitVector_Empty(result); - BitVector_LSB(result, BitVector_Lexicompare(op1, op2) < 0); + BitVector_LSB(result, BitVector_Compare(op1, op2) < 0); break; case YASM_EXPR_GT: BitVector_Empty(result); - BitVector_LSB(result, BitVector_Lexicompare(op1, op2) > 0); + BitVector_LSB(result, BitVector_Compare(op1, op2) > 0); break; case YASM_EXPR_LE: BitVector_Empty(result); - BitVector_LSB(result, BitVector_Lexicompare(op1, op2) <= 0); + BitVector_LSB(result, BitVector_Compare(op1, op2) <= 0); break; case YASM_EXPR_GE: BitVector_Empty(result); - BitVector_LSB(result, BitVector_Lexicompare(op1, op2) >= 0); + BitVector_LSB(result, BitVector_Compare(op1, op2) >= 0); break; case YASM_EXPR_NE: BitVector_Empty(result); BitVector_LSB(result, !BitVector_equal(op1, op2)); break; case YASM_EXPR_SEG: - yasm__error(line, N_("invalid use of '%s'"), "SEG"); + yasm_error_set(YASM_ERROR_ARITHMETIC, N_("invalid use of '%s'"), + "SEG"); break; case YASM_EXPR_WRT: - yasm__error(line, N_("invalid use of '%s'"), "WRT"); + yasm_error_set(YASM_ERROR_ARITHMETIC, N_("invalid use of '%s'"), + "WRT"); break; case YASM_EXPR_SEGOFF: - yasm__error(line, N_("invalid use of '%s'"), ":"); + yasm_error_set(YASM_ERROR_ARITHMETIC, N_("invalid use of '%s'"), + ":"); break; case YASM_EXPR_IDENT: if (result) BitVector_Copy(result, op1); break; default: - yasm_internal_error(N_("invalid operation in intnum calculation")); + yasm_error_set(YASM_ERROR_ARITHMETIC, + N_("invalid operation in intnum calculation")); + BitVector_Empty(result); + return 1; } /* Try to fit the result into 32 bits if possible */ @@ -446,17 +574,24 @@ yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand, acc->val.bv = BitVector_Clone(result); } } + return 0; } /*@=nullderef =nullpass =branchstate@*/ void yasm_intnum_zero(yasm_intnum *intn) { + yasm_intnum_set_uint(intn, 0); +} + +void +yasm_intnum_set_uint(yasm_intnum *intn, unsigned long val) +{ if (intn->type == INTNUM_BV) { BitVector_Destroy(intn->val.bv); intn->type = INTNUM_UL; } - intn->val.ul = 0; + intn->val.ul = val; } int @@ -540,7 +675,7 @@ yasm_intnum_get_int(const yasm_intnum *intn) void yasm_intnum_get_sized(const yasm_intnum *intn, unsigned char *ptr, size_t destsize, size_t valsize, int shift, - int bigendian, int warn, unsigned long line) + int bigendian, int warn) { wordptr op1 = op1static, op2; unsigned char *buf; @@ -553,8 +688,12 @@ yasm_intnum_get_sized(const yasm_intnum *intn, unsigned char *ptr, yasm_internal_error(N_("destination too large")); /* General size warnings */ - if (warn && !yasm_intnum_check_size(intn, valsize, rshift, 2)) - yasm__warning(YASM_WARN_GENERAL, line, + if (warn<0 && !yasm_intnum_check_size(intn, valsize, rshift, 1)) + yasm_warn_set(YASM_WARN_GENERAL, + N_("value does not fit in signed %d bit field"), + valsize); + if (warn>0 && !yasm_intnum_check_size(intn, valsize, rshift, 2)) + yasm_warn_set(YASM_WARN_GENERAL, N_("value does not fit in %d bit field"), valsize); /* Read the original data into a bitvect */ @@ -578,7 +717,7 @@ yasm_intnum_get_sized(const yasm_intnum *intn, unsigned char *ptr, BitVector_Copy(conv_bv, op2); BitVector_Move_Left(conv_bv, BITVECT_NATIVE_SIZE-rshift); if (!BitVector_is_empty(conv_bv)) - yasm__warning(YASM_WARN_GENERAL, line, + yasm_warn_set(YASM_WARN_GENERAL, N_("misaligned value, truncating to boundary")); } @@ -687,27 +826,12 @@ yasm_intnum_in_range(const yasm_intnum *intn, long low, long high) && BitVector_Compare(val, hval) <= 0); } -unsigned long -yasm_intnum_get_leb128(const yasm_intnum *intn, unsigned char *ptr, int sign) +static unsigned long +get_leb128(wordptr val, unsigned char *ptr, int sign) { - wordptr val = op1static; unsigned long i, size; unsigned char *ptr_orig = ptr; - /* Shortcut 0 */ - if (intn->type == INTNUM_UL && intn->val.ul == 0) { - *ptr = 0; - return 1; - } - - /* If not already a bitvect, convert value to be written to a bitvect */ - if (intn->type == INTNUM_BV) - val = intn->val.bv; - else { - BitVector_Empty(val); - BitVector_Chunk_Store(val, 32, 0, intn->val.ul); - } - if (sign) { /* Signed mode */ if (BitVector_msb_(val)) { @@ -733,6 +857,47 @@ yasm_intnum_get_leb128(const yasm_intnum *intn, unsigned char *ptr, int sign) return (unsigned long)(ptr-ptr_orig); } +static unsigned long +size_leb128(wordptr val, int sign) +{ + if (sign) { + /* Signed mode */ + if (BitVector_msb_(val)) { + /* Negative */ + BitVector_Negate(conv_bv, val); + return (Set_Max(conv_bv)+8)/7; + } else { + /* Positive */ + return (Set_Max(val)+8)/7; + } + } else { + /* Unsigned mode */ + return (Set_Max(val)+7)/7; + } +} + +unsigned long +yasm_intnum_get_leb128(const yasm_intnum *intn, unsigned char *ptr, int sign) +{ + wordptr val = op1static; + + /* Shortcut 0 */ + if (intn->type == INTNUM_UL && intn->val.ul == 0) { + *ptr = 0; + return 1; + } + + /* If not already a bitvect, convert value to be written to a bitvect */ + if (intn->type == INTNUM_BV) + val = intn->val.bv; + else { + BitVector_Empty(val); + BitVector_Chunk_Store(val, 32, 0, intn->val.ul); + } + + return get_leb128(val, ptr, sign); +} + unsigned long yasm_intnum_size_leb128(const yasm_intnum *intn, int sign) { @@ -751,20 +916,107 @@ yasm_intnum_size_leb128(const yasm_intnum *intn, int sign) BitVector_Chunk_Store(val, 32, 0, intn->val.ul); } - if (sign) { - /* Signed mode */ - if (BitVector_msb_(val)) { - /* Negative */ - BitVector_Negate(conv_bv, val); - return (Set_Max(conv_bv)+8)/7; - } else { - /* Positive */ - return (Set_Max(val)+8)/7; - } - } else { - /* Unsigned mode */ - return (Set_Max(val)+7)/7; + return size_leb128(val, sign); +} + +unsigned long +yasm_get_sleb128(long v, unsigned char *ptr) +{ + wordptr val = op1static; + + /* Shortcut 0 */ + if (v == 0) { + *ptr = 0; + return 1; + } + + BitVector_Empty(val); + if (v >= 0) + BitVector_Chunk_Store(val, 32, 0, (unsigned long)v); + else { + BitVector_Chunk_Store(val, 32, 0, (unsigned long)(-v)); + BitVector_Negate(val, val); + } + return get_leb128(val, ptr, 1); +} + +unsigned long +yasm_size_sleb128(long v) +{ + wordptr val = op1static; + + if (v == 0) + return 1; + + BitVector_Empty(val); + if (v >= 0) + BitVector_Chunk_Store(val, 32, 0, (unsigned long)v); + else { + BitVector_Chunk_Store(val, 32, 0, (unsigned long)(-v)); + BitVector_Negate(val, val); + } + return size_leb128(val, 1); +} + +unsigned long +yasm_get_uleb128(unsigned long v, unsigned char *ptr) +{ + wordptr val = op1static; + + /* Shortcut 0 */ + if (v == 0) { + *ptr = 0; + return 1; + } + + BitVector_Empty(val); + BitVector_Chunk_Store(val, 32, 0, v); + return get_leb128(val, ptr, 0); +} + +unsigned long +yasm_size_uleb128(unsigned long v) +{ + wordptr val = op1static; + + if (v == 0) + return 1; + + BitVector_Empty(val); + BitVector_Chunk_Store(val, 32, 0, v); + return size_leb128(val, 0); +} + +char * +yasm_intnum_get_str(const yasm_intnum *intn) +{ + char *s, *s2; + + switch (intn->type) { + case INTNUM_UL: + s = yasm_xmalloc(20); + sprintf(s, "0x%lx", intn->val.ul); + return s; + case INTNUM_BV: + if (BitVector_msb_(intn->val.bv)) { + /* it's negative: negate the bitvector to get positive */ + BitVector_Negate(conv_bv, intn->val.bv); + s2 = (char *)BitVector_to_Hex(conv_bv); + s = yasm_xmalloc(strlen(s2)+4); + strcpy(s, "-0x"); + strcat(s, s2); + yasm_xfree(s2); + } else { + s2 = (char *)BitVector_to_Hex(intn->val.bv); + s = yasm_xmalloc(strlen(s2)+3); + strcpy(s, "0x"); + strcat(s, s2); + yasm_xfree(s2); + } + return s; } + /*@notreached@*/ + return NULL; } void |