/* * Integer number functions. * * Copyright (C) 2001-2007 Peter Johnson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "util.h" #include #include #include "coretype.h" #include "bitvect.h" #include "file.h" #include "errwarn.h" #include "intnum.h" /* "Native" "word" size for intnum calculations. */ #define BITVECT_NATIVE_SIZE 256 struct yasm_intnum { union val { long l; /* integer value (for integers <32 bits) */ wordptr bv; /* bit vector (for integers >=32 bits) */ } val; enum { INTNUM_L, INTNUM_BV } type; }; /* static bitvect used for conversions */ static /*@only@*/ wordptr conv_bv; /* static bitvects used for computation */ static /*@only@*/ wordptr result, spare, op1static, op2static; static /*@only@*/ BitVector_from_Dec_static_data *from_dec_data; void yasm_intnum_initialize(void) { conv_bv = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE); result = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE); spare = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE); op1static = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE); op2static = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE); from_dec_data = BitVector_from_Dec_static_Boot(BITVECT_NATIVE_SIZE); } void yasm_intnum_cleanup(void) { BitVector_from_Dec_static_Shutdown(from_dec_data); BitVector_Destroy(op2static); BitVector_Destroy(op1static); BitVector_Destroy(spare); BitVector_Destroy(result); BitVector_Destroy(conv_bv); } /* Compress a bitvector into intnum storage. * If saved as a bitvector, clones the passed bitvector. * Can modify the passed bitvector. */ static void intnum_frombv(/*@out@*/ yasm_intnum *intn, wordptr bv) { if (Set_Max(bv) < 31) { intn->type = INTNUM_L; intn->val.l = (long)BitVector_Chunk_Read(bv, 31, 0); } else if (BitVector_msb_(bv)) { /* Negative, negate and see if we'll fit into a long. */ unsigned long ul; BitVector_Negate(bv, bv); if (Set_Max(bv) >= 32 || ((ul = BitVector_Chunk_Read(bv, 32, 0)) & 0x80000000)) { /* too negative */ BitVector_Negate(bv, bv); intn->type = INTNUM_BV; intn->val.bv = BitVector_Clone(bv); } else { intn->type = INTNUM_L; intn->val.l = -((long)ul); } } else { intn->type = INTNUM_BV; intn->val.bv = BitVector_Clone(bv); } } /* If intnum is a BV, returns its bitvector directly. * If not, converts into passed bv and returns that instead. */ static wordptr intnum_tobv(/*@returned@*/ wordptr bv, const yasm_intnum *intn) { if (intn->type == INTNUM_BV) return intn->val.bv; BitVector_Empty(bv); if (intn->val.l >= 0) BitVector_Chunk_Store(bv, 32, 0, (unsigned long)intn->val.l); else { BitVector_Chunk_Store(bv, 32, 0, (unsigned long)-intn->val.l); BitVector_Negate(bv, bv); } return bv; } yasm_intnum * yasm_intnum_create_dec(char *str) { yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); switch (BitVector_from_Dec_static(from_dec_data, conv_bv, (unsigned char *)str)) { case ErrCode_Pars: yasm_error_set(YASM_ERROR_VALUE, N_("invalid decimal literal")); break; case ErrCode_Ovfl: yasm_error_set(YASM_ERROR_OVERFLOW, N_("Numeric constant too large for internal format")); break; default: break; } intnum_frombv(intn, conv_bv); return intn; } yasm_intnum * yasm_intnum_create_bin(char *str) { yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); switch (BitVector_from_Bin(conv_bv, (unsigned char *)str)) { case ErrCode_Pars: yasm_error_set(YASM_ERROR_VALUE, N_("invalid binary literal")); break; case ErrCode_Ovfl: yasm_error_set(YASM_ERROR_OVERFLOW, N_("Numeric constant too large for internal format")); break; default: break; } intnum_frombv(intn, conv_bv); return intn; } yasm_intnum * yasm_intnum_create_oct(char *str) { yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); switch (BitVector_from_Oct(conv_bv, (unsigned char *)str)) { case ErrCode_Pars: yasm_error_set(YASM_ERROR_VALUE, N_("invalid octal literal")); break; case ErrCode_Ovfl: yasm_error_set(YASM_ERROR_OVERFLOW, N_("Numeric constant too large for internal format")); break; default: break; } intnum_frombv(intn, conv_bv); return intn; } yasm_intnum * yasm_intnum_create_hex(char *str) { yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); switch (BitVector_from_Hex(conv_bv, (unsigned char *)str)) { case ErrCode_Pars: yasm_error_set(YASM_ERROR_VALUE, N_("invalid hex literal")); break; case ErrCode_Ovfl: yasm_error_set(YASM_ERROR_OVERFLOW, N_("Numeric constant too large for internal format")); break; default: break; } intnum_frombv(intn, conv_bv); return intn; } /*@-usedef -compdef -uniondef@*/ yasm_intnum * yasm_intnum_create_charconst_nasm(const char *str) { yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); size_t len = strlen(str); if(len*8 > BITVECT_NATIVE_SIZE) yasm_error_set(YASM_ERROR_OVERFLOW, N_("Character constant too large for internal format")); /* be conservative in choosing bitvect in case MSB is set */ if (len > 3) { BitVector_Empty(conv_bv); intn->type = INTNUM_BV; } else { intn->val.l = 0; intn->type = INTNUM_L; } switch (len) { case 3: intn->val.l |= ((unsigned long)str[2]) & 0xff; intn->val.l <<= 8; /*@fallthrough@*/ case 2: intn->val.l |= ((unsigned long)str[1]) & 0xff; intn->val.l <<= 8; /*@fallthrough@*/ case 1: intn->val.l |= ((unsigned long)str[0]) & 0xff; case 0: break; default: /* >=32 bit conversion */ while (len) { BitVector_Move_Left(conv_bv, 8); BitVector_Chunk_Store(conv_bv, 8, 0, ((unsigned long)str[--len]) & 0xff); } intn->val.bv = BitVector_Clone(conv_bv); } return intn; } yasm_intnum * yasm_intnum_create_charconst_tasm(const char *str) { yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); size_t len = strlen(str); size_t i; if(len*8 > BITVECT_NATIVE_SIZE) yasm_error_set(YASM_ERROR_OVERFLOW, N_("Character constant too large for internal format")); /* be conservative in choosing bitvect in case MSB is set */ if (len > 3) { BitVector_Empty(conv_bv); intn->type = INTNUM_BV; } else { intn->val.l = 0; intn->type = INTNUM_L; } /* tasm uses big endian notation */ i = 0; switch (len) { case 3: intn->val.l |= ((unsigned long)str[i++]) & 0xff; intn->val.l <<= 8; /*@fallthrough@*/ case 2: intn->val.l |= ((unsigned long)str[i++]) & 0xff; intn->val.l <<= 8; /*@fallthrough@*/ case 1: intn->val.l |= ((unsigned long)str[i++]) & 0xff; case 0: break; default: /* >=32 bit conversion */ while (i < len) { BitVector_Chunk_Store(conv_bv, 8, (len-i-1)*8, ((unsigned long)str[i]) & 0xff); i++; } intn->val.bv = BitVector_Clone(conv_bv); } return intn; } /*@=usedef =compdef =uniondef@*/ yasm_intnum * yasm_intnum_create_uint(unsigned long i) { yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); if (i > LONG_MAX) { /* Too big, store as bitvector */ intn->val.bv = BitVector_Create(BITVECT_NATIVE_SIZE, TRUE); intn->type = INTNUM_BV; BitVector_Chunk_Store(intn->val.bv, 32, 0, i); } else { intn->val.l = (long)i; intn->type = INTNUM_L; } return intn; } yasm_intnum * yasm_intnum_create_int(long i) { yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); intn->val.l = i; intn->type = INTNUM_L; return intn; } 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; BitVector_Empty(conv_bv); for (;;) { BitVector_Chunk_Store(conv_bv, 7, i, *ptr); i += 7; if ((*ptr & 0x80) != 0x80) break; ptr++; } *size = (unsigned long)(ptr-ptr_orig)+1; if(i > BITVECT_NATIVE_SIZE) yasm_error_set(YASM_ERROR_OVERFLOW, N_("Numeric constant too large for internal format")); else if (sign && (*ptr & 0x40) == 0x40) BitVector_Interval_Fill(conv_bv, i, BITVECT_NATIVE_SIZE-1); intnum_frombv(intn, 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; if (srcsize*8 > BITVECT_NATIVE_SIZE) yasm_error_set(YASM_ERROR_OVERFLOW, 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-1] & 0x80) == 0x80) BitVector_Interval_Fill(conv_bv, i*8, BITVECT_NATIVE_SIZE-1); intnum_frombv(intn, conv_bv); return intn; } yasm_intnum * yasm_intnum_copy(const yasm_intnum *intn) { yasm_intnum *n = yasm_xmalloc(sizeof(yasm_intnum)); switch (intn->type) { case INTNUM_L: n->val.l = intn->val.l; break; case INTNUM_BV: n->val.bv = BitVector_Clone(intn->val.bv); break; } n->type = intn->type; return n; } void yasm_intnum_destroy(yasm_intnum *intn) { if (intn->type == INTNUM_BV) BitVector_Destroy(intn->val.bv); yasm_xfree(intn); } /*@-nullderef -nullpass -branchstate@*/ 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. */ op1 = intnum_tobv(op1static, acc); if (operand) op2 = intnum_tobv(op2static, operand); if (!operand && op != YASM_EXPR_NEG && op != YASM_EXPR_NOT && 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) { case YASM_EXPR_ADD: BitVector_add(result, op1, op2, &carry); break; case YASM_EXPR_SUB: BitVector_sub(result, op1, op2, &carry); break; case YASM_EXPR_MUL: BitVector_Multiply(result, op1, op2); break; case YASM_EXPR_DIV: /* TODO: make sure op1 and op2 are unsigned */ 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: 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 */ 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: 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); break; case YASM_EXPR_NOT: Set_Complement(result, op1); break; case YASM_EXPR_OR: Set_Union(result, op1, op2); break; case YASM_EXPR_AND: Set_Intersection(result, op1, op2); break; 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); break; case YASM_EXPR_SHL: if (operand->type == INTNUM_L && operand->val.l >= 0) { BitVector_Copy(result, op1); BitVector_Move_Left(result, (N_int)operand->val.l); } else /* don't even bother, just zero result */ BitVector_Empty(result); break; case YASM_EXPR_SHR: if (operand->type == INTNUM_L && operand->val.l >= 0) { BitVector_Copy(result, op1); carry = BitVector_msb_(op1); count = (N_int)operand->val.l; while (count-- > 0) BitVector_shift_right(result, carry); } else /* don't even bother, just zero result */ BitVector_Empty(result); break; case YASM_EXPR_LOR: BitVector_Empty(result); BitVector_LSB(result, !BitVector_is_empty(op1) || !BitVector_is_empty(op2)); break; case YASM_EXPR_LAND: BitVector_Empty(result); BitVector_LSB(result, !BitVector_is_empty(op1) && !BitVector_is_empty(op2)); break; case YASM_EXPR_LNOT: 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_Compare(op1, op2) < 0); break; case YASM_EXPR_GT: BitVector_Empty(result); BitVector_LSB(result, BitVector_Compare(op1, op2) > 0); break; case YASM_EXPR_LE: BitVector_Empty(result); BitVector_LSB(result, BitVector_Compare(op1, op2) <= 0); break; case YASM_EXPR_GE: BitVector_Empty(result); 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_set(YASM_ERROR_ARITHMETIC, N_("invalid use of '%s'"), "SEG"); break; case YASM_EXPR_WRT: yasm_error_set(YASM_ERROR_ARITHMETIC, N_("invalid use of '%s'"), "WRT"); break; case YASM_EXPR_SEGOFF: 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_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 */ if (acc->type == INTNUM_BV) BitVector_Destroy(acc->val.bv); intnum_frombv(acc, result); return 0; } /*@=nullderef =nullpass =branchstate@*/ int yasm_intnum_compare(const yasm_intnum *intn1, const yasm_intnum *intn2) { wordptr op1, op2; if (intn1->type == INTNUM_L && intn2->type == INTNUM_L) { if (intn1->val.l < intn2->val.l) return -1; if (intn1->val.l > intn2->val.l) return 1; return 0; } op1 = intnum_tobv(op1static, intn1); op2 = intnum_tobv(op2static, intn2); return BitVector_Compare(op1, op2); } void yasm_intnum_zero(yasm_intnum *intn) { yasm_intnum_set_int(intn, 0); } void yasm_intnum_set(yasm_intnum *intn, const yasm_intnum *val) { if (intn->type == val->type) { switch (val->type) { case INTNUM_L: intn->val.l = val->val.l; break; case INTNUM_BV: BitVector_Copy(intn->val.bv, val->val.bv); break; } } else { switch (val->type) { case INTNUM_L: BitVector_Destroy(intn->val.bv); intn->val.l = val->val.l; break; case INTNUM_BV: intn->val.bv = BitVector_Clone(val->val.bv); break; } intn->type = val->type; } } void yasm_intnum_set_uint(yasm_intnum *intn, unsigned long val) { if (val > LONG_MAX) { if (intn->type != INTNUM_BV) { intn->val.bv = BitVector_Create(BITVECT_NATIVE_SIZE, TRUE); intn->type = INTNUM_BV; } BitVector_Chunk_Store(intn->val.bv, 32, 0, val); } else { if (intn->type == INTNUM_BV) { BitVector_Destroy(intn->val.bv); intn->type = INTNUM_L; } intn->val.l = (long)val; } } void yasm_intnum_set_int(yasm_intnum *intn, long val) { if (intn->type == INTNUM_BV) BitVector_Destroy(intn->val.bv); intn->type = INTNUM_L; intn->val.l = val; } int yasm_intnum_is_zero(const yasm_intnum *intn) { return (intn->type == INTNUM_L && intn->val.l == 0); } int yasm_intnum_is_pos1(const yasm_intnum *intn) { return (intn->type == INTNUM_L && intn->val.l == 1); } int yasm_intnum_is_neg1(const yasm_intnum *intn) { return (intn->type == INTNUM_L && intn->val.l == -1); } int yasm_intnum_sign(const yasm_intnum *intn) { if (intn->type == INTNUM_L) { if (intn->val.l == 0) return 0; else if (intn->val.l < 0) return -1; else return 1; } else return BitVector_Sign(intn->val.bv); } unsigned long yasm_intnum_get_uint(const yasm_intnum *intn) { switch (intn->type) { case INTNUM_L: if (intn->val.l < 0) return 0; return (unsigned long)intn->val.l; case INTNUM_BV: if (BitVector_msb_(intn->val.bv)) return 0; if (Set_Max(intn->val.bv) > 32) return ULONG_MAX; return BitVector_Chunk_Read(intn->val.bv, 32, 0); default: yasm_internal_error(N_("unknown intnum type")); /*@notreached@*/ return 0; } } long yasm_intnum_get_int(const yasm_intnum *intn) { switch (intn->type) { case INTNUM_L: return intn->val.l; case INTNUM_BV: if (BitVector_msb_(intn->val.bv)) { /* it's negative: negate the bitvector to get a positive * number, then negate the positive number. */ unsigned long ul; BitVector_Negate(conv_bv, intn->val.bv); if (Set_Max(conv_bv) >= 32) { /* too negative */ return LONG_MIN; } ul = BitVector_Chunk_Read(conv_bv, 32, 0); /* check for too negative */ return (ul & 0x80000000) ? LONG_MIN : -((long)ul); } /* it's positive, and since it's a BV, it must be >0x7FFFFFFF */ return LONG_MAX; default: yasm_internal_error(N_("unknown intnum type")); /*@notreached@*/ return 0; } } void yasm_intnum_get_sized(const yasm_intnum *intn, unsigned char *ptr, size_t destsize, size_t valsize, int shift, int bigendian, int warn) { wordptr op1 = op1static, op2; unsigned char *buf; unsigned int len; size_t rshift = shift < 0 ? (size_t)(-shift) : 0; int carry_in; /* Currently don't support destinations larger than our native size */ if (destsize*8 > BITVECT_NATIVE_SIZE) yasm_internal_error(N_("destination too large")); /* General size warnings */ 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 */ if (bigendian) { /* TODO */ yasm_internal_error(N_("big endian not implemented")); } else BitVector_Block_Store(op1, ptr, (N_int)destsize); /* If not already a bitvect, convert value to be written to a bitvect */ op2 = intnum_tobv(op2static, intn); /* Check low bits if right shifting and warnings enabled */ if (warn && rshift > 0) { BitVector_Copy(conv_bv, op2); BitVector_Move_Left(conv_bv, (N_int)(BITVECT_NATIVE_SIZE-rshift)); if (!BitVector_is_empty(conv_bv)) yasm_warn_set(YASM_WARN_GENERAL, N_("misaligned value, truncating to boundary")); } /* Shift right if needed */ if (rshift > 0) { carry_in = BitVector_msb_(op2); while (rshift-- > 0) BitVector_shift_right(op2, carry_in); shift = 0; } /* Write the new value into the destination bitvect */ BitVector_Interval_Copy(op1, op2, (unsigned int)shift, 0, (N_int)valsize); /* Write out the new data */ buf = BitVector_Block_Read(op1, &len); if (bigendian) { /* TODO */ yasm_internal_error(N_("big endian not implemented")); } else memcpy(ptr, buf, destsize); yasm_xfree(buf); } /* Return 1 if okay size, 0 if not */ int yasm_intnum_check_size(const yasm_intnum *intn, size_t size, size_t rshift, int rangetype) { wordptr val; /* If not already a bitvect, convert value to a bitvect */ if (intn->type == INTNUM_BV) { if (rshift > 0) { val = conv_bv; BitVector_Copy(val, intn->val.bv); } else val = intn->val.bv; } else val = intnum_tobv(conv_bv, intn); if (size >= BITVECT_NATIVE_SIZE) return 1; if (rshift > 0) { int carry_in = BitVector_msb_(val); while (rshift-- > 0) BitVector_shift_right(val, carry_in); } if (rangetype > 0) { if (BitVector_msb_(val)) { /* it's negative */ int retval; BitVector_Negate(conv_bv, val); BitVector_dec(conv_bv, conv_bv); retval = Set_Max(conv_bv) < (long)size-1; return retval; } if (rangetype == 1) size--; } return (Set_Max(val) < (long)size); } int yasm_intnum_in_range(const yasm_intnum *intn, long low, long high) { wordptr val = intnum_tobv(result, intn); wordptr lval = op1static; wordptr hval = op2static; /* Convert high and low to bitvects */ BitVector_Empty(lval); if (low >= 0) BitVector_Chunk_Store(lval, 32, 0, (unsigned long)low); else { BitVector_Chunk_Store(lval, 32, 0, (unsigned long)(-low)); BitVector_Negate(lval, lval); } BitVector_Empty(hval); if (high >= 0) BitVector_Chunk_Store(hval, 32, 0, (unsigned long)high); else { BitVector_Chunk_Store(hval, 32, 0, (unsigned long)(-high)); BitVector_Negate(hval, hval); } /* Compare! */ return (BitVector_Compare(val, lval) >= 0 && BitVector_Compare(val, hval) <= 0); } static unsigned long get_leb128(wordptr val, unsigned char *ptr, int sign) { unsigned long i, size; unsigned char *ptr_orig = ptr; if (sign) { /* Signed mode */ if (BitVector_msb_(val)) { /* Negative */ BitVector_Negate(conv_bv, val); size = Set_Max(conv_bv)+2; } else { /* Positive */ size = Set_Max(val)+2; } } else { /* Unsigned mode */ size = Set_Max(val)+1; } /* Positive/Unsigned write */ for (i=0; itype == INTNUM_L && intn->val.l == 0) { *ptr = 0; return 1; } /* If not already a bitvect, convert value to be written to a bitvect */ val = intnum_tobv(op1static, intn); return get_leb128(val, ptr, sign); } unsigned long yasm_intnum_size_leb128(const yasm_intnum *intn, int sign) { wordptr val; /* Shortcut 0 */ if (intn->type == INTNUM_L && intn->val.l == 0) { return 1; } /* If not already a bitvect, convert value to a bitvect */ val = intnum_tobv(op1static, intn); 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) { unsigned char *s; switch (intn->type) { case INTNUM_L: s = yasm_xmalloc(16); sprintf((char *)s, "%ld", intn->val.l); return (char *)s; break; case INTNUM_BV: return (char *)BitVector_to_Dec(intn->val.bv); break; } /*@notreached@*/ return NULL; } void yasm_intnum_print(const yasm_intnum *intn, FILE *f) { unsigned char *s; switch (intn->type) { case INTNUM_L: fprintf(f, "0x%lx", intn->val.l); break; case INTNUM_BV: s = BitVector_to_Hex(intn->val.bv); fprintf(f, "0x%s", (char *)s); yasm_xfree(s); break; } }