c0e157e3b2
One must build yasm (included in the yasm directory) before building GMP, if building on an x86_64 machine. Note: make test and make tune do not currently build.
1050 lines
30 KiB
C
1050 lines
30 KiB
C
/*
|
|
* 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"
|
|
/*@unused@*/ RCSID("$Id: intnum.c 2051 2008-04-11 09:29:58Z peter $");
|
|
|
|
#include <ctype.h>
|
|
#include <limits.h>
|
|
|
|
#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]);
|
|
}
|
|
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] & 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; i<size; i += 7) {
|
|
*ptr = (unsigned char)BitVector_Chunk_Read(val, 7, i);
|
|
*ptr |= 0x80;
|
|
ptr++;
|
|
}
|
|
*(ptr-1) &= 0x7F; /* Clear MSB of last byte */
|
|
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;
|
|
|
|
/* Shortcut 0 */
|
|
if (intn->type == 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;
|
|
}
|
|
}
|