const yasm_section *sect, void *d,
yasm_output_expr_func output_expr);
- /** Output #yasm_floatnum to buffer.
+ /** Output #yasm_floatnum to buffer. Puts the value into the least
+ * significant bits of the destination, or may be shifted into more
+ * significant bits by the shift parameter. The destination bits are
+ * cleared before being set.
* Architecture-specific because of endianness.
* \param flt floating point value
- * \param bufp buffer to write into
- * \param valsize length (in bytes)
- * \param e expression containing value
- * \return Nonzero on error, otherwise updates *bufp by valsize (number of
- * bytes saved to bufp).
+ * \param buf buffer to write into
+ * \param destsize destination size (in bytes)
+ * \param valsize size (in bits)
+ * \param shift left shift (in bits)
+ * \param warn enables standard overflow/underflow warnings
+ * \param lindex line index; may be 0 if warn is 0.
+ * \return Nonzero on error.
*/
- int (*floatnum_tobytes) (const yasm_floatnum *flt, unsigned char **bufp,
- unsigned long valsize, const yasm_expr *e);
-
- /** Output #yasm_intnum to buffer.
+ int (*floatnum_tobytes) (const yasm_floatnum *flt, unsigned char *buf,
+ size_t destsize, size_t valsize, size_t shift,
+ int warn, unsigned long lindex);
+
+ /** Output #yasm_intnum to buffer. Puts the value into the least
+ * significant bits of the destination, or may be shifted into more
+ * significant bits by the shift parameter. The destination bits are
+ * cleared before being set.
* \param intn integer value
- * \param bufp buffer to write into
- * \param valsize length (in bytes)
- * \param e expression containing value
+ * \param buf buffer to write into
+ * \param destsize destination size (in bytes)
+ * \param valsize size (in bits)
+ * \param shift left shift (in bits); may be negative to specify right
+ * shift (standard warnings include truncation to boundary)
* \param bc bytecode being output ("parent" of value)
* \param rel value is a relative displacement from bc
- * \return Nonzero on error, otherwise updates *bufp by valsize (number of
- * bytes saved to bufp).
+ * \param warn enables standard warnings (value doesn't fit into
+ * valsize bits)
+ * \param lindex line index; may be 0 if warn is 0
+ * \return Nonzero on error.
*/
- int (*intnum_tobytes) (const yasm_intnum *intn, unsigned char **bufp,
- unsigned long valsize, const yasm_expr *e,
- const yasm_bytecode *bc, int rel);
+ int (*intnum_tobytes) (const yasm_intnum *intn, unsigned char *buf,
+ size_t destsize, size_t valsize, int shift,
+ const yasm_bytecode *bc, int rel, int warn,
+ unsigned long lindex);
/** Get the equivalent byte size of a register.
* \param reg register
case DV_EMPTY:
break;
case DV_EXPR:
- if (output_expr(&dv->data.expn, bufp, bc_data->size,
+ if (output_expr(&dv->data.expn, *bufp, bc_data->size,
+ bc_data->size*8, 0,
(unsigned long)(*bufp-bufp_orig), sect, bc, 0,
- d))
+ 1, d))
return 1;
+ *bufp += bc_data->size;
break;
case DV_STRING:
slen = strlen(dv->data.str_val);
/** Convert yasm_expr to its byte representation. Usually implemented by
* object formats to keep track of relocations and verify legal expressions.
+ * Must put the value into the least significant bits of the destination,
+ * unless shifted into more significant bits by the shift parameter. The
+ * destination bits must be cleared before being set.
* \param ep (double) pointer to expression
- * \param bufp (double) pointer to buffer for byte representation
- * \param valsize size (in bytes) of the byte representation
+ * \param buf buffer for byte representation
+ * \param destsize destination size (in bytes)
+ * \param valsize size (in bits)
+ * \param shift left shift (in bits); may be negative to specify right
+ * shift (standard warnings include truncation to boundary)
* \param offset offset (in bytes) of the expr contents from the start
* of the bytecode (sometimes needed for conditional jumps)
* \param sect current section (usually passed into higher-level
* \param bc current bytecode (usually passed into higher-level
* calling function)
* \param rel if nonzero, expr should be treated as PC/IP-relative
+ * \param warn enables standard warnings: zero for none;
+ * nonzero for overflow/underflow floating point warnings;
+ * negative for signed integer warnings,
+ * positive for unsigned integer warnings
* \param d objfmt-specific data (passed into higher-level calling
* function)
* \return Nonzero if an error occurred, 0 otherwise.
*/
typedef int (*yasm_output_expr_func)
- (yasm_expr **ep, unsigned char **bufp, unsigned long valsize,
- unsigned long offset, /*@observer@*/ const yasm_section *sect,
- yasm_bytecode *bc, int rel, /*@null@*/ void *d)
- /*@uses *ep@*/ /*@sets **bufp@*/;
+ (yasm_expr **ep, /*@out@*/ unsigned char *buf, size_t destsize,
+ size_t valsize, int shift, unsigned long offset,
+ /*@observer@*/ const yasm_section *sect, yasm_bytecode *bc, int rel,
+ int warn, /*@null@*/ void *d) /*@uses *ep@*/;
/** Convert a yasm_objfmt-specific data bytecode into its byte representation.
* Usually implemented by object formats to output their own generated data.
{
unsigned char t[4];
- if (yasm_floatnum_get_sized(flt, t, 4)) {
+ if (yasm_floatnum_get_sized(flt, t, 4, 32, 0, 0, 0, 0)) {
*ret_val = 0xDEADBEEFUL; /* Obviously incorrect return value */
return 1;
}
*/
int
yasm_floatnum_get_sized(const yasm_floatnum *flt, unsigned char *ptr,
- size_t size)
+ size_t destsize, size_t valsize, size_t shift,
+ int bigendian, int warn, unsigned long lindex)
{
- switch (size) {
+ int retval;
+ if (destsize*8 != valsize || shift>0 || bigendian) {
+ /* TODO */
+ yasm_internal_error(N_("unsupported floatnum functionality"));
+ }
+ switch (destsize) {
case 4:
- return floatnum_get_common(flt, ptr, 4, 23, 1, 8);
+ retval = floatnum_get_common(flt, ptr, 4, 23, 1, 8);
+ break;
case 8:
- return floatnum_get_common(flt, ptr, 8, 52, 1, 11);
+ retval = floatnum_get_common(flt, ptr, 8, 52, 1, 11);
+ break;
case 10:
- return floatnum_get_common(flt, ptr, 10, 64, 0, 15);
+ retval = floatnum_get_common(flt, ptr, 10, 64, 0, 15);
+ break;
default:
yasm_internal_error(N_("Invalid float conversion size"));
/*@notreached@*/
- return 1; /* never reached, but silence GCC warning */
+ return 1;
+ }
+ if (warn) {
+ if (retval < 0)
+ yasm__warning(YASM_WARN_GENERAL, lindex,
+ N_("underflow in floating point expression"));
+ else if (retval > 0)
+ yasm__warning(YASM_WARN_GENERAL, lindex,
+ N_("overflow in floating point expression"));
}
+ return retval;
}
/* 1 if the size is valid, 0 if it isn't */
yasm_floatnum_check_size(/*@unused@*/ const yasm_floatnum *flt, size_t size)
{
switch (size) {
- case 4:
- case 8:
- case 10:
+ case 32:
+ case 64:
+ case 80:
return 1;
default:
return 0;
yasm_xfree(str);
/* 32-bit (single precision) format */
- fprintf(f, "32-bit: %d: ", yasm_floatnum_get_sized(flt, out, 4));
+ fprintf(f, "32-bit: %d: ",
+ yasm_floatnum_get_sized(flt, out, 4, 32, 0, 0, 0, 0));
for (i=0; i<4; i++)
fprintf(f, "%02x ", out[i]);
fprintf(f, "\n");
/* 64-bit (double precision) format */
- fprintf(f, "64-bit: %d: ", yasm_floatnum_get_sized(flt, out, 8));
+ fprintf(f, "64-bit: %d: ",
+ yasm_floatnum_get_sized(flt, out, 8, 64, 0, 0, 0, 0));
for (i=0; i<8; i++)
fprintf(f, "%02x ", out[i]);
fprintf(f, "\n");
/* 80-bit (extended precision) format */
- fprintf(f, "80-bit: %d: ", yasm_floatnum_get_sized(flt, out, 10));
+ fprintf(f, "80-bit: %d: ",
+ yasm_floatnum_get_sized(flt, out, 10, 80, 0, 0, 0, 0));
for (i=0; i<10; i++)
fprintf(f, "%02x ", out[i]);
fprintf(f, "\n");
int yasm_floatnum_get_int(const yasm_floatnum *flt,
/*@out@*/ unsigned long *ret_val);
-/** Convert a floatnum to Intel-format little-endian byte string.
- * [0] should be the first byte output to an Intel-format file.
- * \note Not all sizes are valid. Currently, only 4 (single-precision), 8
- * (double-precision), and 10 (extended-precision) are valid sizes.
+/** Output a #yasm_floatnum to buffer in little-endian or big-endian. Puts the
+ * value into the least significant bits of the destination, or may be shifted
+ * into more significant bits by the shift parameter. The destination bits are
+ * cleared before being set. [0] should be the first byte output to the file.
+ * \note Not all sizes are valid. Currently, only 32 (single-precision), 64
+ * (double-precision), and 80 (extended-precision) are valid sizes.
* Use yasm_floatnum_check_size() to check for supported sizes.
* \param flt floatnum
* \param ptr pointer to storage for size bytes of output
- * \param size size (in bytes) of desired output.
+ * \param destsize destination size (in bytes)
+ * \param valsize size (in bits)
+ * \param shift left shift (in bits)
+ * \param bigendian endianness (nonzero=big, zero=little)
+ * \param warn enables standard overflow/underflow warnings
+ * \param lindex line index; may be 0 if warn is 0.
* \return Nonzero if flt can't fit into the specified precision: -1 if
* underflow occurred, 1 if overflow occurred.
*/
-int yasm_floatnum_get_sized(const yasm_floatnum *flt,
- /*@out@*/ unsigned char *ptr, size_t size);
+int yasm_floatnum_get_sized(const yasm_floatnum *flt, unsigned char *ptr,
+ size_t destsize, size_t valsize, size_t shift,
+ int bigendian, int warn, unsigned long lindex);
/** Basic check to see if size is valid for flt conversion (using
* yasm_floatnum_get_sized()). Doesn't actually check for underflow/overflow
- * but rather checks for size=4,8,10
+ * but rather checks for size=32,64,80
* (at present).
* \param flt floatnum
- * \param size size (in bytes) of desired conversion output
+ * \param size number of bits of output space
* \return 1 if valid size, 0 if invalid size.
*/
int yasm_floatnum_check_size(const yasm_floatnum *flt, size_t size);
/* it's negative: negate the bitvector to get a positive
* number, then negate the positive number.
*/
- wordptr abs_bv = BitVector_Create(BITVECT_NATIVE_SIZE, FALSE);
unsigned long ul;
- BitVector_Negate(abs_bv, intn->val.bv);
- if (Set_Max(abs_bv) >= 32) {
+ BitVector_Negate(conv_bv, intn->val.bv);
+ if (Set_Max(conv_bv) >= 32) {
/* too negative */
- BitVector_Destroy(abs_bv);
return LONG_MIN;
}
- ul = BitVector_Chunk_Read(abs_bv, 32, 0);
- BitVector_Destroy(abs_bv);
+ ul = BitVector_Chunk_Read(conv_bv, 32, 0);
/* check for too negative */
return (ul & 0x80000000) ? LONG_MIN : -((long)ul);
}
}
void
-yasm_intnum_get_sized(const yasm_intnum *intn, unsigned char *ptr, size_t size)
+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 lindex)
{
- unsigned long ul;
+ wordptr op1 = op1static, op2;
unsigned char *buf;
unsigned int len;
+ size_t rshift = shift < 0 ? (size_t)(-shift) : 0;
+ int carry_in;
- switch (intn->type) {
- case INTNUM_UL:
- ul = intn->val.ul;
- while (size-- > 0) {
- YASM_WRITE_8(ptr, ul);
- if (ul != 0)
- ul >>= 8;
- }
- break;
- case INTNUM_BV:
- buf = BitVector_Block_Read(intn->val.bv, &len);
- if (len < (unsigned int)size)
- yasm_internal_error(N_("Invalid size specified (too large)"));
- memcpy(ptr, buf, size);
- yasm_xfree(buf);
- break;
+ /* 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 && !yasm_intnum_check_size(intn, valsize, rshift, 2))
+ yasm__warning(YASM_WARN_GENERAL, lindex,
+ 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, destsize);
+
+ /* If not already a bitvect, convert value to be written to a bitvect */
+ if (intn->type == INTNUM_BV)
+ op2 = intn->val.bv;
+ else {
+ op2 = op2static;
+ BitVector_Empty(op2);
+ BitVector_Chunk_Store(op2, 32, 0, intn->val.ul);
+ }
+
+ /* Check low bits if right shifting and warnings enabled */
+ if (warn && rshift > 0) {
+ 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, lindex,
+ 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, shift, 0, 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, int is_signed)
+yasm_intnum_check_size(const yasm_intnum *intn, size_t size, size_t rshift,
+ int rangetype)
{
- if (is_signed) {
- switch (intn->type) {
- case INTNUM_UL:
- if (size >= 4)
- return 1;
-
- /* INTNUM_UL is always positive */
- switch (size) {
- case 4:
- return (intn->val.ul <= 0x7FFFFFFF);
- case 3:
- return (intn->val.ul <= 0x007FFFFF);
- case 2:
- return (intn->val.ul <= 0x00007FFF);
- case 1:
- return (intn->val.ul <= 0x0000007F);
- }
- break;
- case INTNUM_BV:
- if (size >= BITVECT_NATIVE_SIZE/8)
- return 1;
- if (BitVector_msb_(intn->val.bv)) {
- /* it's negative */
- wordptr abs_bv = BitVector_Create(BITVECT_NATIVE_SIZE,
- FALSE);
- int retval;
-
- BitVector_Negate(abs_bv, intn->val.bv);
- retval = Set_Max(abs_bv) < (long)(size*8);
-
- BitVector_Destroy(abs_bv);
- return retval;
- } else
- return (Set_Max(intn->val.bv) < (long)(size*8));
- }
+ 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 {
- switch (intn->type) {
- case INTNUM_UL:
- if (size >= 4)
- return 1;
- switch (size) {
- case 3:
- return ((intn->val.ul & 0x00FFFFFF) == intn->val.ul);
- case 2:
- return ((intn->val.ul & 0x0000FFFF) == intn->val.ul);
- case 1:
- return ((intn->val.ul & 0x000000FF) == intn->val.ul);
- }
- break;
- case INTNUM_BV:
- if (size >= BITVECT_NATIVE_SIZE/8)
- return 1;
- else
- return (Set_Max(intn->val.bv) < (long)(size*8));
+ val = conv_bv;
+ BitVector_Empty(val);
+ BitVector_Chunk_Store(val, 32, 0, intn->val.ul);
+ }
+
+ 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 0;
+ return (Set_Max(val) < (long)size);
}
void
*/
long yasm_intnum_get_int(const yasm_intnum *intn);
-/** Convert an intnum to Intel-format little-endian byte string.
- * [0] should be the first byte output to an Intel-format file.
- * \note Parameter intnum is truncated to fit into specified size. Use
- * intnum_check_size() to check for overflow.
+/** Output #yasm_intnum to buffer in little-endian or big-endian. Puts the
+ * value into the least significant bits of the destination, or may be shifted
+ * into more significant bits by the shift parameter. The destination bits are
+ * cleared before being set. [0] should be the first byte output to the file.
* \param intn intnum
* \param ptr pointer to storage for size bytes of output
- * \param size size (in bytes) of desired output.
+ * \param destsize destination size (in bytes)
+ * \param valsize size (in bits)
+ * \param shift left shift (in bits); may be negative to specify right
+ * shift (standard warnings include truncation to boundary)
+ * \param bigendian endianness (nonzero=big, zero=little)
+ * \param warn enables standard warnings (value doesn't fit into valsize
+ * bits)
+ * \param lindex line index; may be 0 if warn is 0
*/
void yasm_intnum_get_sized(const yasm_intnum *intn, unsigned char *ptr,
- size_t size);
+ size_t destsize, size_t valsize, int shift,
+ int bigendian, int warn, unsigned long lindex);
-/** Check to see if intnum will fit without overflow into size bytes.
+/** Check to see if intnum will fit without overflow into size bits.
* If is_signed is 1, intnum is treated as a signed number.
* \param intn intnum
- * \param size number of bytes of output space
- * \param is_signed nonzero, intnum should be treated as signed
+ * \param size number of bits of output space
+ * \param rshift right shift
+ * \param rangetype signed/unsigned range selection:
+ * 0 => (0, unsigned max);
+ * 1 => (signed min, signed max);
+ * 2 => (signed min, unsigned max)
* \return Nonzero if intnum will fit.
*/
int yasm_intnum_check_size(const yasm_intnum *intn, size_t size,
- int is_signed);
+ size_t rshift, int rangetype);
/** Print an intnum. For debugging purposes.
* \param f file
for (i=0; i<num; i++) {
get_common_setup(vals, i);
- fail_unless(yasm_floatnum_get_sized(flt, outval, 4) == vals[i].ret32,
- ret_msg);
+ fail_unless(yasm_floatnum_get_sized(flt, outval, 4, 32, 0, 0, 0, 0) ==
+ vals[i].ret32, ret_msg);
fail_unless(get_common_check_result(4, outval, vals[i].result32) == 0,
result_msg);
}
for (i=0; i<num; i++) {
get_common_setup(vals, i);
- fail_unless(yasm_floatnum_get_sized(flt, outval, 4) == vals[i].ret32,
- ret_msg);
+ fail_unless(yasm_floatnum_get_sized(flt, outval, 4, 32, 0, 0, 0, 0) ==
+ vals[i].ret32, ret_msg);
fail_unless(get_common_check_result(4, outval, vals[i].result32) == 0,
result_msg);
}
for (i=0; i<num; i++) {
get_common_setup(vals, i);
- fail_unless(yasm_floatnum_get_sized(flt, outval, 8) == vals[i].ret64,
- ret_msg);
+ fail_unless(yasm_floatnum_get_sized(flt, outval, 8, 64, 0, 0, 0, 0) ==
+ vals[i].ret64, ret_msg);
fail_unless(get_common_check_result(8, outval, vals[i].result64) == 0,
result_msg);
}
for (i=0; i<num; i++) {
get_common_setup(vals, i);
- fail_unless(yasm_floatnum_get_sized(flt, outval, 8) == vals[i].ret64,
- ret_msg);
+ fail_unless(yasm_floatnum_get_sized(flt, outval, 8, 64, 0, 0, 0, 0) ==
+ vals[i].ret64, ret_msg);
fail_unless(get_common_check_result(8, outval, vals[i].result64) == 0,
result_msg);
}
for (i=0; i<num; i++) {
get_common_setup(vals, i);
- fail_unless(yasm_floatnum_get_sized(flt, outval, 10) == vals[i].ret80,
- ret_msg);
+ fail_unless(yasm_floatnum_get_sized(flt, outval, 10, 80, 0, 0, 0, 0) ==
+ vals[i].ret80, ret_msg);
fail_unless(get_common_check_result(10, outval, vals[i].result80) == 0,
result_msg);
}
for (i=0; i<num; i++) {
get_common_setup(vals, i);
- fail_unless(yasm_floatnum_get_sized(flt, outval, 10) == vals[i].ret80,
- ret_msg);
+ fail_unless(yasm_floatnum_get_sized(flt, outval, 10, 80, 0, 0, 0, 0) ==
+ vals[i].ret80, ret_msg);
fail_unless(get_common_check_result(10, outval, vals[i].result80) == 0,
result_msg);
}
/*@unused@*/ RCSID("$IdPath$");
#define YASM_LIB_INTERNAL
-#define YASM_EXPR_INTERNAL
#include <libyasm.h>
#include "lc3barch.h"
}
static int
-yasm_lc3b__floatnum_tobytes(const yasm_floatnum *flt, unsigned char **bufp,
- unsigned long valsize, const yasm_expr *e)
+yasm_lc3b__floatnum_tobytes(const yasm_floatnum *flt, unsigned char *buf,
+ size_t destsize, size_t valsize, size_t shift,
+ int warn, unsigned long lindex)
{
- yasm__error(e->line, N_("LC-3b does not support floating point"));
+ yasm__error(lindex, N_("LC-3b does not support floating point"));
return 1;
}
/*@null@*/ yasm_insn_operandhead *operands, yasm_section *cur_section,
/*@null@*/ yasm_bytecode *prev_bc, unsigned long lindex);
-int yasm_lc3b__intnum_tobytes(const yasm_intnum *intn, unsigned char **bufp,
- unsigned long valsize, const yasm_expr *e,
- const yasm_bytecode *bc, int rel);
+int yasm_lc3b__intnum_tobytes(const yasm_intnum *intn, unsigned char *buf,
+ size_t destsize, size_t valsize, int shift,
+ const yasm_bytecode *bc, int rel, int warn,
+ unsigned long lindex);
unsigned int yasm_lc3b__get_reg_size(unsigned long reg);
}
indent_level--;
}
- fprintf(f, "%*sOrigin=", indent_level, "");
+ fprintf(f, "\n%*sOrigin=", indent_level, "");
if (insn->origin) {
fprintf(f, "\n");
yasm_symrec_print(f, indent_level+1, insn->origin);
rel -= 2;
yasm_expr_delete(temp);
/* 9-bit signed, word-multiple displacement */
- if (rel < -512 || rel > 512) {
+ if (rel < -512 || rel > 511) {
yasm__error(bc->line, N_("target out of range"));
return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
}
yasm_output_expr_func output_expr)
{
lc3b_insn *insn;
- unsigned int opcode;
- unsigned int val;
- int rel = 0;
if ((lc3b_bytecode_type)bc->type != LC3B_BC_INSN)
return 0;
insn = (lc3b_insn *)bc;
- /* Change into PC-relative if necessary */
- if (insn->imm_type == LC3B_IMM_9_PC) {
- insn->imm = yasm_expr_new(YASM_EXPR_SUB, yasm_expr_expr(insn->imm),
- yasm_expr_sym(insn->origin), bc->line);
- rel = 1;
- }
-
- /* Get immediate value */
- if (output_expr(&insn->imm, bufp, 2, 0, sect, bc, rel, d))
- return 1;
- *bufp -= 2;
- YASM_LOAD_16_L(val, *bufp);
+ /* Output opcode */
+ YASM_SAVE_16_L(*bufp, insn->opcode);
- opcode = insn->opcode;
-
- /* Insert immediate into opcode. Warn on overflow? */
+ /* Insert immediate into opcode. */
switch (insn->imm_type) {
case LC3B_IMM_NONE:
break;
case LC3B_IMM_4:
- opcode &= ~0xF;
- opcode |= (val & 0xF);
+ if (output_expr(&insn->imm, *bufp, 2, 4, 0, 0, sect, bc, 0, 1, d))
+ return 1;
break;
case LC3B_IMM_5:
- opcode &= ~0x1F;
- opcode |= (val & 0x1F);
+ if (output_expr(&insn->imm, *bufp, 2, 5, 0, 0, sect, bc, 0, 1, d))
+ return 1;
break;
case LC3B_IMM_6_WORD:
- if (val & 1)
- yasm__warning(YASM_WARN_GENERAL, bc->line,
- N_("Misaligned access, truncating to boundary"));
- val >>= 1;
- /*@fallthrough@*/
+ if (output_expr(&insn->imm, *bufp, 2, 6, -1, 0, sect, bc, 0, 1, d))
+ return 1;
+ break;
case LC3B_IMM_6_BYTE:
- opcode &= ~0x3F;
- opcode |= (val & 0x3F);
+ if (output_expr(&insn->imm, *bufp, 2, 6, 0, 0, sect, bc, 0, 1, d))
+ return 1;
break;
case LC3B_IMM_8:
- if (val & 1)
- yasm__warning(YASM_WARN_GENERAL, bc->line,
- N_("Misaligned access, truncating to boundary"));
- opcode &= ~0xFF;
- opcode |= ((val>>1) & 0xFF);
+ if (output_expr(&insn->imm, *bufp, 2, 8, -1, 0, sect, bc, 0, 1, d))
+ return 1;
break;
case LC3B_IMM_9_PC:
- val -= 2;
- /*@fallthrough@*/
+ insn->imm = yasm_expr_new(YASM_EXPR_SUB, yasm_expr_expr(insn->imm),
+ yasm_expr_sym(insn->origin), bc->line);
+ if (output_expr(&insn->imm, *bufp, 2, 9, -1, 0, sect, bc, 1, 1, d))
+ return 1;
+ break;
case LC3B_IMM_9:
- if (val & 1)
- yasm__warning(YASM_WARN_GENERAL, bc->line,
- N_("Misaligned access, truncating to boundary"));
- opcode &= ~0x1FF;
- opcode |= ((val>>1) & 0x1FF);
+ if (output_expr(&insn->imm, *bufp, 2, 9, -1, 0, sect, bc, 0, 1, d))
+ return 1;
break;
default:
yasm_internal_error(N_("Unrecognized immediate type"));
}
- /* Output it */
- YASM_WRITE_16_L(*bufp, opcode);
-
+ *bufp += 2; /* all instructions are 2 bytes in size */
return 0;
}
int
-yasm_lc3b__intnum_tobytes(const yasm_intnum *intn, unsigned char **bufp,
- unsigned long valsize, const yasm_expr *e,
- const yasm_bytecode *bc, int rel)
+yasm_lc3b__intnum_tobytes(const yasm_intnum *intn, unsigned char *buf,
+ size_t destsize, size_t valsize, int shift,
+ const yasm_bytecode *bc, int rel, int warn,
+ unsigned long lindex)
{
- /* Write value out. */
- yasm_intnum_get_sized(intn, *bufp, (size_t)valsize);
- *bufp += valsize;
+ if (rel) {
+ yasm_intnum *relnum, *delta;
+ if (valsize != 9)
+ yasm_internal_error(
+ N_("tried to do PC-relative offset from invalid sized value"));
+ relnum = yasm_intnum_copy(intn);
+ delta = yasm_intnum_new_uint(bc->len);
+ yasm_intnum_calc(relnum, YASM_EXPR_SUB, delta, lindex);
+ yasm_intnum_delete(delta);
+ yasm_intnum_get_sized(relnum, buf, destsize, valsize, shift, 0, warn,
+ lindex);
+ yasm_intnum_delete(relnum);
+ } else {
+ /* Write value out. */
+ yasm_intnum_get_sized(intn, buf, destsize, valsize, shift, 0, warn,
+ lindex);
+ }
return 0;
}
+; Need to update for multi-segment someday.\r
+\r
;.SEGMENT CodeSegment: \r
DONTBR: LEA R0, AA \r
LEA R1, BB \r
LEA R2, CC \r
- LD R7, R0, ADATA3F \r
+ LD R7, R0, ADATA3F-AA\r
\r
- LD R6, R2, CDATA3F \r
- ST R7, R1, BDATA3D \r
- ST R7, R1, BDATA3F \r
- ST R7, R1, BDATA3C \r
+ LD R6, R2, CDATA3F-CC\r
+ ST R7, R1, BDATA3D-BB\r
+ ST R7, R1, BDATA3F-BB\r
+ ST R7, R1, BDATA3C-BB\r
\r
\r
ADD R3, R2, -3 \r
STB R7, R4, 0 \r
\r
STB R6, R3, 0 \r
- LD R5, R1, BDATA3A \r
- LD R7, R0, ADATA39 \r
- ST R7, R1, BDATA38 \r
+ LD R5, R1, BDATA3A-BB\r
+ LD R7, R0, ADATA39-AA\r
+ ST R7, R1, BDATA38-BB\r
\r
- ST R7, R1, BDATA39 \r
- ST R7, R1, BDATA3A\r
+ ST R7, R1, BDATA39-BB\r
+ ST R7, R1, BDATA3A-BB\r
ADD R3, R2, -9\r
ADD R4, R2, -10\r
\r
STB R6, R3, 0 \r
STB R7, R4, 0 \r
- ST R7, R2, CDATA3B \r
- LD R7, R2, CDATA37 \r
+ ST R7, R2, CDATA3B-CC\r
+ LD R7, R2, CDATA37-CC\r
\r
- LD R6, R1, BDATA35 \r
- ST R6, R2, CDATA37 \r
- LD R5, R2, CDATA36 \r
- LD R7, R0, ADATA36 \r
+ LD R6, R1, BDATA35-BB\r
+ ST R6, R2, CDATA37-CC\r
+ LD R5, R2, CDATA36-CC\r
+ LD R7, R0, ADATA36-AA\r
\r
- LD R7, R1, BDATA35 \r
- LD R6, R2, CDATA35 \r
- LD R7, R0, ADATA37 \r
- ST R7, R1, BDATA37 \r
+ LD R7, R1, BDATA35-BB\r
+ LD R6, R2, CDATA35-CC\r
+ LD R7, R0, ADATA37-AA\r
+ ST R7, R1, BDATA37-BB\r
\r
AND R3, R3, 0 \r
AND R4, R4, 0 \r
ADD R3, R3, 11 \r
ADD R4, R4, -1 \r
\r
-LOOP: LD R7, R0, ADATA32 \r
- LD R7, R1, BDATA32\r
- LD R7, R2, CDATA31\r
+LOOP: LD R7, R0, ADATA32-AA\r
+ LD R7, R1, BDATA32-BB\r
+ LD R7, R2, CDATA31-CC\r
ADD R3, R3, R4\r
\r
BRp LOOP \r
- LD R6, R1, BDATA0 \r
- LD R6, R1, BDATA4 \r
- LD R6, R1, BDATA10 \r
+ LD R6, R1, BDATA0-BB\r
+ LD R6, R1, BDATA4-BB\r
+ LD R6, R1, BDATA10-BB\r
\r
- ST R7, R1, BDATA4 \r
- ST R7, R1, BDATA11 \r
- ST R7, R0, ADATA8 \r
+ ST R7, R1, BDATA4-BB\r
+ ST R7, R1, BDATA11-BB\r
+ ST R7, R0, ADATA8-AA\r
STOP: BRnzp STOP \r
\r
\r
EXTRA_DIST += modules/arch/x86/tests/opersize.hex
EXTRA_DIST += modules/arch/x86/tests/opsize-err.asm
EXTRA_DIST += modules/arch/x86/tests/opsize-err.errwarn
+EXTRA_DIST += modules/arch/x86/tests/overflow.asm
+EXTRA_DIST += modules/arch/x86/tests/overflow.errwarn
+EXTRA_DIST += modules/arch/x86/tests/overflow.hex
EXTRA_DIST += modules/arch/x86/tests/ret.asm
EXTRA_DIST += modules/arch/x86/tests/ret.errwarn
EXTRA_DIST += modules/arch/x86/tests/ret.hex
--- /dev/null
+[bits 16]
+mov ax, 'abcd'
+mov ax, 0x1ffff
+mov eax, 0x111111111
+
+dd 0x123456789
+dd -1
+dw 0x12345
+dw -1
+
+jmp 0x1234:0x56789ABC
+jmp dword 0x1234:0x56789ABC
--- /dev/null
+-:2: warning: value does not fit in 16 bit field
+-:3: warning: value does not fit in 16 bit field
+-:4: warning: value does not fit in 32 bit field
+-:6: warning: value does not fit in 32 bit field
+-:8: warning: value does not fit in 16 bit field
+-:11: warning: value does not fit in 16 bit field
--- /dev/null
+b8
+61
+62
+b8
+ff
+ff
+66
+b8
+11
+11
+11
+11
+89
+67
+45
+23
+ff
+ff
+ff
+ff
+45
+23
+ff
+ff
+ea
+bc
+9a
+34
+12
+66
+ea
+bc
+9a
+78
+56
+34
+12
+-:7: warning: value does not fit in 16 bit field
void yasm_x86__parse_seg_override(yasm_effaddr *ea, unsigned long segreg,
unsigned long lindex);
-int yasm_x86__floatnum_tobytes(const yasm_floatnum *flt, unsigned char **bufp,
- unsigned long valsize, const yasm_expr *e);
-int yasm_x86__intnum_tobytes(const yasm_intnum *intn, unsigned char **bufp,
- unsigned long valsize, const yasm_expr *e,
- const yasm_bytecode *bc, int rel);
+int yasm_x86__floatnum_tobytes(const yasm_floatnum *flt, unsigned char *buf,
+ size_t destsize, size_t valsize, size_t shift,
+ int warn, unsigned long lindex);
+int yasm_x86__intnum_tobytes(const yasm_intnum *intn, unsigned char *buf,
+ size_t destsize, size_t valsize, int shift,
+ const yasm_bytecode *bc, int rel, int warn,
+ unsigned long lindex);
unsigned int yasm_x86__get_reg_size(unsigned long reg);
yasm_internal_error(N_("checkea failed"));
if (ea->disp) {
- if (output_expr(&ea->disp, bufp, ea->len,
+ if (output_expr(&ea->disp, *bufp, ea->len, ea->len*8, 0,
(unsigned long)(*bufp-bufp_orig), sect, bc, 0,
- d))
+ 1, d))
return 1;
+ *bufp += ea->len;
} else {
/* 0 displacement, but we didn't know it before, so we have to
* write out 0 value.
/* Immediate (if required) */
if (imm && imm->val) {
- /* TODO: check imm->len vs. sized len from expr? */
- if (output_expr(&imm->val, bufp, imm->len,
- (unsigned long)(*bufp-bufp_orig), sect, bc, 0, d))
+ if (output_expr(&imm->val, *bufp, imm->len, imm->len*8, 0,
+ (unsigned long)(*bufp-bufp_orig), sect, bc, 0, 1, d))
return 1;
+ *bufp += imm->len;
}
return 0;
jmp->target =
yasm_expr_new(YASM_EXPR_SUB, yasm_expr_expr(jmp->target),
yasm_expr_sym(jmp->origin), bc->line);
- if (output_expr(&jmp->target, bufp, 1,
- (unsigned long)(*bufp-bufp_orig), sect, bc, 1, d))
+ if (output_expr(&jmp->target, *bufp, 1, 8, 0,
+ (unsigned long)(*bufp-bufp_orig), sect, bc, 1, 1,
+ d))
return 1;
+ *bufp += 1;
break;
case JMP_NEAR_FORCED:
case JMP_NEAR:
jmp->target =
yasm_expr_new(YASM_EXPR_SUB, yasm_expr_expr(jmp->target),
yasm_expr_sym(jmp->origin), bc->line);
- if (output_expr(&jmp->target, bufp, (opersize == 16) ? 2UL : 4UL,
- (unsigned long)(*bufp-bufp_orig), sect, bc, 1, d))
+ i = (opersize == 16) ? 2 : 4;
+ if (output_expr(&jmp->target, *bufp, i, i*8, 0,
+ (unsigned long)(*bufp-bufp_orig), sect, bc, 1, 1,
+ d))
return 1;
+ *bufp += i;
break;
case JMP_FAR:
/* far absolute (4/6 byte depending on operand size) */
targetseg = yasm_expr_extract_segment(&jmp->target);
if (!targetseg)
yasm_internal_error(N_("could not extract segment for far jump"));
- if (output_expr(&jmp->target, bufp,
- (opersize == 16) ? 2UL : 4UL,
- (unsigned long)(*bufp-bufp_orig), sect, bc, 0, d))
+ i = (opersize == 16) ? 2 : 4;
+ if (output_expr(&jmp->target, *bufp, i, i*8, 0,
+ (unsigned long)(*bufp-bufp_orig), sect, bc, 0, 1,
+ d))
return 1;
- if (output_expr(&targetseg, bufp, 2UL,
- (unsigned long)(*bufp-bufp_orig), sect, bc, 0, d))
+ *bufp += i;
+ if (output_expr(&targetseg, *bufp, 2, 2*8, 0,
+ (unsigned long)(*bufp-bufp_orig), sect, bc, 0, 1,
+ d))
return 1;
+ *bufp += 2;
break;
default:
}
int
-yasm_x86__intnum_tobytes(const yasm_intnum *intn, unsigned char **bufp,
- unsigned long valsize, const yasm_expr *e,
- const yasm_bytecode *bc, int rel)
+yasm_x86__intnum_tobytes(const yasm_intnum *intn, unsigned char *buf,
+ size_t destsize, size_t valsize, int shift,
+ const yasm_bytecode *bc, int rel, int warn,
+ unsigned long lindex)
{
if (rel) {
- long val;
- if (valsize != 1 && valsize != 2 && valsize != 4)
+ yasm_intnum *relnum, *delta;
+ if (valsize != 8 && valsize != 16 && valsize != 32)
yasm_internal_error(
N_("tried to do PC-relative offset from invalid sized value"));
- val = yasm_intnum_get_uint(intn);
- val -= bc->len;
- switch ((unsigned int)valsize) {
- case 1:
- YASM_WRITE_8(*bufp, val);
- break;
- case 2:
- YASM_WRITE_16_L(*bufp, val);
- break;
- case 4:
- YASM_WRITE_32_L(*bufp, val);
- break;
- }
+ relnum = yasm_intnum_copy(intn);
+ delta = yasm_intnum_new_uint(bc->len);
+ yasm_intnum_calc(relnum, YASM_EXPR_SUB, delta, lindex);
+ yasm_intnum_delete(delta);
+ yasm_intnum_get_sized(relnum, buf, destsize, valsize, shift, 0, warn,
+ lindex);
+ yasm_intnum_delete(relnum);
} else {
/* Write value out. */
- yasm_intnum_get_sized(intn, *bufp, (size_t)valsize);
- *bufp += valsize;
+ yasm_intnum_get_sized(intn, buf, destsize, valsize, shift, 0, warn,
+ lindex);
}
return 0;
}
/* make sure the displacement will fit in 16/32 bits if unsigned,
* and 8 bits if signed.
*/
- if (!yasm_intnum_check_size(intn, (size_t)wordsize, 0) &&
- !yasm_intnum_check_size(intn, 1, 1)) {
+ if (!yasm_intnum_check_size(intn, (size_t)wordsize*8, 0, 0) &&
+ !yasm_intnum_check_size(intn, 8, 0, 1)) {
yasm__error(e->line, N_("invalid effective address"));
return 1;
}
}
int
-yasm_x86__floatnum_tobytes(const yasm_floatnum *flt, unsigned char **bufp,
- unsigned long valsize, const yasm_expr *e)
+yasm_x86__floatnum_tobytes(const yasm_floatnum *flt, unsigned char *buf,
+ size_t destsize, size_t valsize, size_t shift,
+ int warn, unsigned long lindex)
{
- int fltret;
-
- if (!yasm_floatnum_check_size(flt, (size_t)valsize)) {
- yasm__error(e->line, N_("invalid floating point constant size"));
+ if (!yasm_floatnum_check_size(flt, valsize)) {
+ yasm__error(lindex, N_("invalid floating point constant size"));
return 1;
}
- fltret = yasm_floatnum_get_sized(flt, *bufp, (size_t)valsize);
- if (fltret < 0) {
- yasm__error(e->line, N_("underflow in floating point expression"));
- return 1;
- }
- if (fltret > 0) {
- yasm__error(e->line, N_("overflow in floating point expression"));
- return 1;
- }
- *bufp += valsize;
+ yasm_floatnum_get_sized(flt, buf, destsize, valsize, shift, 0, warn,
+ lindex);
return 0;
}
}
static int
-bin_objfmt_output_expr(yasm_expr **ep, unsigned char **bufp,
- unsigned long valsize,
+bin_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
+ size_t valsize, int shift,
/*@unused@*/ unsigned long offset,
/*@observer@*/ const yasm_section *sect,
- yasm_bytecode *bc, int rel,
+ yasm_bytecode *bc, int rel, int warn,
/*@unused@*/ /*@null@*/ void *d)
{
/*@dependent@*/ /*@null@*/ const yasm_intnum *intn;
*/
*ep = yasm_expr__level_tree(*ep, 1, 1, NULL, bin_objfmt_expr_xform, NULL,
- NULL);
+ NULL);
/* Handle floating point expressions */
flt = yasm_expr_get_floatnum(ep);
if (flt)
- return cur_arch->floatnum_tobytes(flt, bufp, valsize, *ep);
+ return cur_arch->floatnum_tobytes(flt, buf, destsize, valsize, shift,
+ warn, bc->line);
/* Handle integer expressions */
intn = yasm_expr_get_intnum(ep, NULL);
if (intn)
- return cur_arch->intnum_tobytes(intn, bufp, valsize, *ep, bc, rel);
+ return cur_arch->intnum_tobytes(intn, buf, destsize, valsize, shift,
+ bc, rel, warn, bc->line);
/* Check for complex float expressions */
if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) {
- yasm__error((*ep)->line, N_("floating point expression too complex"));
+ yasm__error(bc->line, N_("floating point expression too complex"));
return 1;
}
/* Couldn't output, assume it contains an external reference. */
- yasm__error((*ep)->line,
+ yasm__error(bc->line,
N_("binary object format does not support external references"));
return 1;
}
-:2: invalid floating point constant size
-:3: invalid floating point constant size
--:4: overflow in floating point expression
--:5: underflow in floating point expression
+-:4: warning: overflow in floating point expression
+-:5: warning: underflow in floating point expression
-:8: invalid floating point constant size
-:9: invalid floating point constant size
--:11: overflow in floating point expression
--:12: underflow in floating point expression
+-:11: warning: overflow in floating point expression
+-:12: warning: underflow in floating point expression
+-:2: warning: value does not fit in 8 bit field
+-:3: warning: value does not fit in 16 bit field
+-:4: warning: value does not fit in 32 bit field
+-:5: warning: value does not fit in 64 bit field
+-:6: warning: value does not fit in 80 bit field
}
static int
-coff_objfmt_output_expr(yasm_expr **ep, unsigned char **bufp,
- unsigned long valsize, unsigned long offset,
+coff_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
+ size_t valsize, int shift, unsigned long offset,
/*@observer@*/ const yasm_section *sect,
- yasm_bytecode *bc, int rel, /*@null@*/ void *d)
+ yasm_bytecode *bc, int rel, int warn,
+ /*@null@*/ void *d)
{
/*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
/*@dependent@*/ /*@null@*/ const yasm_intnum *intn;
/* Handle floating point expressions */
flt = yasm_expr_get_floatnum(ep);
if (flt)
- return cur_arch->floatnum_tobytes(flt, bufp, valsize, *ep);
+ return cur_arch->floatnum_tobytes(flt, buf, destsize, valsize, shift,
+ warn, bc->line);
/* Handle integer expressions, with relocation if necessary */
sym = yasm_expr_extract_symrec(ep, yasm_common_calc_bc_dist);
coff_reloc *reloc;
yasm_sym_vis vis;
- if (valsize != 4) {
- yasm__error((*ep)->line, N_("coff: invalid relocation size"));
+ if (valsize != 32) {
+ yasm__error(bc->line, N_("coff: invalid relocation size"));
return 1;
}
}
intn = yasm_expr_get_intnum(ep, NULL);
if (intn)
- return cur_arch->intnum_tobytes(intn, bufp, valsize, *ep, bc, rel);
+ return cur_arch->intnum_tobytes(intn, buf, destsize, valsize, shift,
+ bc, rel, warn, bc->line);
/* Check for complex float expressions */
if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) {
- yasm__error((*ep)->line, N_("floating point expression too complex"));
+ yasm__error(bc->line, N_("floating point expression too complex"));
return 1;
}
- yasm__error((*ep)->line, N_("coff: relocation too complex"));
+ yasm__error(bc->line, N_("coff: relocation too complex"));
return 1;
}
/* PASS1 */
static int
-elf_objfmt_output_expr(yasm_expr **ep, unsigned char **bufp,
- unsigned long valsize, unsigned long offset,
+elf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
+ size_t valsize, int shift, unsigned long offset,
/*@observer@*/ const yasm_section *sect,
- yasm_bytecode *bc, int rel, /*@null@*/ void *d)
+ yasm_bytecode *bc, int rel, int warn,
+ /*@null@*/ void *d)
{
/*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
/*@dependent@*/ /*@null@*/ const yasm_intnum *intn;
/* Handle floating point expressions */
flt = yasm_expr_get_floatnum(ep);
if (flt)
- return cur_arch->floatnum_tobytes(flt, bufp, valsize, *ep);
+ return cur_arch->floatnum_tobytes(flt, buf, destsize, valsize, shift,
+ warn, bc->line);
/* Handle integer expressions, with relocation if necessary */
sym = yasm_expr_extract_symrec(ep, yasm_common_calc_bc_dist);
yasm_sym_vis vis;
/* XXX: this can't be platform portable */
- if (valsize != 4) {
- yasm__error((*ep)->line, N_("elf: invalid relocation size"));
+ if (valsize != 32) {
+ yasm__error(bc->line, N_("elf: invalid relocation size"));
return 1;
}
intn = yasm_expr_get_intnum(ep, NULL);
if (intn)
- return cur_arch->intnum_tobytes(intn, bufp, valsize, *ep, bc, rel);
+ return cur_arch->intnum_tobytes(intn, buf, destsize, valsize, shift,
+ bc, rel, warn, bc->line);
/* Check for complex float expressions */
if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) {
- yasm__error((*ep)->line, N_("floating point expression too complex"));
+ yasm__error(bc->line, N_("floating point expression too complex"));
return 1;
}
- yasm__error((*ep)->line, N_("elf: relocation too complex"));
+ yasm__error(bc->line, N_("elf: relocation too complex"));
return 1;
}