summaryrefslogtreecommitdiff
path: root/libyasm/intnum.c
diff options
context:
space:
mode:
Diffstat (limited to 'libyasm/intnum.c')
-rw-r--r--libyasm/intnum.c378
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