MFC: FAR jmp/call support and a some Doxygen documentation updates.
svn path=/branches/YASM_0_2/; revision=967
diff --git a/yasm/libyasm/bytecode.c b/yasm/libyasm/bytecode.c
index 0f102b5..e0649f3 100644
--- a/yasm/libyasm/bytecode.c
+++ b/yasm/libyasm/bytecode.c
@@ -443,7 +443,7 @@
if (dist < precbc1->offset + precbc1->len) {
intn = yasm_intnum_new_uint(precbc1->offset + precbc1->len
- dist);
- yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
+ yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, precbc1->line);
return intn;
}
dist -= precbc1->offset + precbc1->len;
@@ -452,7 +452,7 @@
} else {
if (precbc1) {
intn = yasm_intnum_new_uint(precbc1->offset + precbc1->len);
- yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
+ yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, precbc1->line);
return intn;
} else {
return yasm_intnum_new_uint(0);
diff --git a/yasm/libyasm/coretype.h b/yasm/libyasm/coretype.h
index 3cd2b5b..492f1af 100644
--- a/yasm/libyasm/coretype.h
+++ b/yasm/libyasm/coretype.h
@@ -1,14 +1,17 @@
-/* $IdPath$
- * YASM core (used by many modules/header files) type definitions.
+/**
+ * \file coretype.h
+ * \brief YASM core type definitions.
+ *
+ * $IdPath$
*
* Copyright (C) 2001 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
+ * - 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
+ * - 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.
*
@@ -27,94 +30,132 @@
#ifndef YASM_CORETYPE_H
#define YASM_CORETYPE_H
+/** Architecture interface. \see arch.h for details. */
typedef struct yasm_arch yasm_arch;
-
+/** Preprocessor interface. \see preproc.h for details. */
typedef struct yasm_preproc yasm_preproc;
+/** Parser interface. \see parser.h for details. */
typedef struct yasm_parser yasm_parser;
+/** Optimizer interface. \see optimizer.h for details. */
typedef struct yasm_optimizer yasm_optimizer;
+/** Object format interface. \see objfmt.h for details. */
typedef struct yasm_objfmt yasm_objfmt;
+/** Debug format interface. \see dbgfmt.h for details. */
typedef struct yasm_dbgfmt yasm_dbgfmt;
+/** Bytecode (opaque type).
+ * \see bytecode.h for related functions.
+ * Define YASM_BC_INTERNAL to get visible internals.
+ */
typedef struct yasm_bytecode yasm_bytecode;
+/** List of bytecodes (opaque type). \see bytecode.h for related functions. */
typedef struct yasm_bytecodehead yasm_bytecodehead;
+/** Section (opaque type). \see section.h for related functions. */
typedef struct yasm_section yasm_section;
+/** List of sections (opaque type). \see section.h for related functions. */
typedef struct yasm_sectionhead yasm_sectionhead;
+/** Symbol record (opaque type). \see symrec.h for related functions. */
typedef struct yasm_symrec yasm_symrec;
+/** Expression (opaque type).
+ * \see expr.h for related functions.
+ * Define YASM_EXPR_INTERNAL to get visible internals.
+ */
typedef struct yasm_expr yasm_expr;
+/** Integer value (opaque type). \see intnum.h for related functions. */
typedef struct yasm_intnum yasm_intnum;
+/** Floating point value (opaque type).
+ * \see floatnum.h for related functions.
+ */
typedef struct yasm_floatnum yasm_floatnum;
+/** Line number management interface. \see linemgr.h for more details. */
typedef struct yasm_linemgr yasm_linemgr;
+/** Value/parameter pair (opaque type).
+ * \see valparam.h for related functions.
+ */
typedef struct yasm_valparam yasm_valparam;
+/** List of value/parameters (opaque type).
+ * \see valparam.h for related functions.
+ */
typedef struct yasm_valparamhead yasm_valparamhead;
+/** Expression operators usable in #yasm_expr expressions. */
typedef enum {
- YASM_EXPR_ADD,
- YASM_EXPR_SUB,
- YASM_EXPR_MUL,
- YASM_EXPR_DIV,
- YASM_EXPR_SIGNDIV,
- YASM_EXPR_MOD,
- YASM_EXPR_SIGNMOD,
- YASM_EXPR_NEG,
- YASM_EXPR_NOT,
- YASM_EXPR_OR,
- YASM_EXPR_AND,
- YASM_EXPR_XOR,
- YASM_EXPR_SHL,
- YASM_EXPR_SHR,
- YASM_EXPR_LOR,
- YASM_EXPR_LAND,
- YASM_EXPR_LNOT,
- YASM_EXPR_LT,
- YASM_EXPR_GT,
- YASM_EXPR_EQ,
- YASM_EXPR_LE,
- YASM_EXPR_GE,
- YASM_EXPR_NE,
- YASM_EXPR_SEG,
- YASM_EXPR_WRT,
- YASM_EXPR_SEGOFF, /* The ':' in SEG:OFF */
- YASM_EXPR_IDENT /* no operation, just a value */
+ YASM_EXPR_IDENT, /**< No operation, just a value. */
+ YASM_EXPR_ADD, /**< Arithmetic addition (+). */
+ YASM_EXPR_SUB, /**< Arithmetic subtraction (-). */
+ YASM_EXPR_MUL, /**< Arithmetic multiplication (*). */
+ YASM_EXPR_DIV, /**< Arithmetic unsigned division. */
+ YASM_EXPR_SIGNDIV, /**< Arithmetic signed division. */
+ YASM_EXPR_MOD, /**< Arithmetic unsigned modulus. */
+ YASM_EXPR_SIGNMOD, /**< Arithmetic signed modulus. */
+ YASM_EXPR_NEG, /**< Arithmetic negation (-). */
+ YASM_EXPR_NOT, /**< Bitwise negation. */
+ YASM_EXPR_OR, /**< Bitwise OR. */
+ YASM_EXPR_AND, /**< Bitwise AND. */
+ YASM_EXPR_XOR, /**< Bitwise XOR. */
+ YASM_EXPR_SHL, /**< Shift left (logical). */
+ YASM_EXPR_SHR, /**< Shift right (logical). */
+ YASM_EXPR_LOR, /**< Logical OR. */
+ YASM_EXPR_LAND, /**< Logical AND. */
+ YASM_EXPR_LNOT, /**< Logical negation. */
+ YASM_EXPR_LT, /**< Less than comparison. */
+ YASM_EXPR_GT, /**< Greater than comparison. */
+ YASM_EXPR_EQ, /**< Equality comparison. */
+ YASM_EXPR_LE, /**< Less than or equal to comparison. */
+ YASM_EXPR_GE, /**< Greater than or equal to comparison. */
+ YASM_EXPR_NE, /**< Not equal comparison. */
+ YASM_EXPR_NONNUM, /**< Start of non-numeric operations (not an op). */
+ YASM_EXPR_SEG, /**< SEG operator (gets segment portion of address). */
+ YASM_EXPR_WRT, /**< WRT operator (gets offset of address relative to
+ * some other segment). */
+ YASM_EXPR_SEGOFF /**< The ':' in segment:offset. */
} yasm_expr_op;
-/* EXTERN and COMMON are mutually exclusive */
+/** Symbol record visibility.
+ * \see symrec.h for related functions.
+ * \note YASM_SYM_EXTERN and YASM_SYM_COMMON are mutually exclusive.
+ */
typedef enum {
- YASM_SYM_LOCAL = 0, /* default, local only */
- YASM_SYM_GLOBAL = 1 << 0, /* if it's declared GLOBAL */
- YASM_SYM_COMMON = 1 << 1, /* if it's declared COMMON */
- YASM_SYM_EXTERN = 1 << 2 /* if it's declared EXTERN */
+ YASM_SYM_LOCAL = 0, /**< Default, local only */
+ YASM_SYM_GLOBAL = 1 << 0, /**< If symbol is declared GLOBAL */
+ YASM_SYM_COMMON = 1 << 1, /**< If symbol is declared COMMON */
+ YASM_SYM_EXTERN = 1 << 2 /**< If symbol is declared EXTERN */
} yasm_sym_vis;
-/* Determines the distance, in bytes, between the starting offsets of two
- * bytecodes in a section.
- * Inputs: sect, the section in which the bytecodes reside.
- * precbc1, preceding bytecode to the first bytecode
- * precbc2, preceding bytecode to the second bytecode
- * Outputs: dist, the distance in bytes (bc2-bc1)
- * Returns distance in bytes (bc2-bc1), or NULL if the distance was
- * indeterminate.
+/** Determine the distance between the starting offsets of two bytecodes in a
+ * section.
+ * \param sect section containing the two bytecodes
+ * \param precbc1 preceding bytecode to the first bytecode (NULL
+ * indicates first bytecode in section)
+ * \param precbc2 preceding bytecode to the second bytecode (NULL
+ * indicates first bytecode in section)
+ * \return Distance in bytes between the two bytecodes (bc2-bc1), or NULL if
+ * the distance was indeterminate.
*/
typedef /*@null@*/ yasm_intnum * (*yasm_calc_bc_dist_func)
(yasm_section *sect, /*@null@*/ yasm_bytecode *precbc1,
/*@null@*/ yasm_bytecode *precbc2);
-/* Converts an expr to its byte representation. Usually implemented by
+/** Convert yasm_expr to its byte representation. Usually implemented by
* object formats to keep track of relocations and verify legal expressions.
- * Inputs:
- * ep - (double) pointer to the expression to output
- * bufp - (double) pointer to buffer to contain byte representation
- * valsize - the size (in bytes) to be used for the byte rep
- * offset - the offset (in bytes) of the expr contents from the bc start
- * sect - current section (usually passed into higher-level calling fct)
- * bc - current bytecode (usually passed into higher-level calling fct)
- * rel - should the expr be treated as PC/IP-relative? (nonzero=yes)
- * d - objfmt-specific data (passed into higher-level calling fct)
- * Returns nonzero if an error occurred, 0 otherwise
+ * \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 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
+ * calling function)
+ * \param bc current bytecode (usually passed into higher-level
+ * calling function)
+ * \param rel if nonzero, expr should be treated as PC/IP-relative
+ * \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,
@@ -122,15 +163,14 @@
yasm_bytecode *bc, int rel, /*@null@*/ void *d)
/*@uses *ep@*/ /*@sets **bufp@*/;
-/* Converts a objfmt data bytecode into its byte representation. Usually
- * implemented by object formats to output their own generated data.
- * Inputs:
- * type - objfmt-specific type
- * data - objfmt-specific data
- * bufp - (double) pointer to buffer to contain byte representation
- * bufp is guaranteed to have enough space to store the data into (as given
- * by the original bc_new_objfmt_data() call).
- * Returns nonzero if an error occurred, 0 otherwise.
+/** Convert a yasm_objfmt-specific data bytecode into its byte representation.
+ * Usually implemented by object formats to output their own generated data.
+ * \param type yasm_objfmt-specific type
+ * \param data data
+ * \param bufp (double) pointer to buffer for byte representation
+ * \note bufp is guaranteed to have enough space to store the data into (as
+ * given by the original yasm_bc_new_objfmt_data() call).
+ * \return Nonzero if an error occurred, 0 otherwise.
*/
typedef int (*yasm_output_bc_objfmt_data_func)
(unsigned int type, /*@observer@*/ void *data, unsigned char **bufp)
diff --git a/yasm/libyasm/expr.c b/yasm/libyasm/expr.c
index 26b1b06..f386841 100644
--- a/yasm/libyasm/expr.c
+++ b/yasm/libyasm/expr.c
@@ -518,6 +518,11 @@
yasm_xfree(e);
e = sube;
}
+
+ /* If non-numeric expression, don't fold constants. */
+ if (e->op > YASM_EXPR_NONNUM)
+ fold_const = 0;
+
level_numterms = e->numterms;
level_fold_numterms = 0;
for (i=0; i<e->numterms; i++) {
@@ -565,7 +570,7 @@
for (i=first_int_term+1, o=first_int_term+1; i<e->numterms; i++) {
if (e->terms[i].type == YASM_EXPR_INT) {
yasm_intnum_calc(e->terms[first_int_term].data.intn, e->op,
- e->terms[i].data.intn);
+ e->terms[i].data.intn, e->line);
fold_numterms--;
level_numterms--;
/* make sure to delete folded intnum */
@@ -634,7 +639,8 @@
e->terms[first_int_term] = sube->terms[j]; /* struc */
} else {
yasm_intnum_calc(e->terms[first_int_term].data.intn,
- e->op, sube->terms[j].data.intn);
+ e->op, sube->terms[j].data.intn,
+ e->line);
/* make sure to delete folded intnum */
yasm_intnum_delete(sube->terms[j].data.intn);
}
@@ -878,6 +884,12 @@
}
/*@=mustfree@*/
+int
+yasm_expr_is_op(const yasm_expr *e, yasm_expr_op op)
+{
+ return (e->op == op);
+}
+
static int
expr_contains_callback(const yasm_expr__item *ei, void *d)
{
@@ -1015,6 +1027,35 @@
return sym;
}
+yasm_expr *
+yasm_expr_extract_segment(yasm_expr **ep)
+{
+ yasm_expr *retval;
+ yasm_expr *e = *ep;
+
+ /* If not SEG:OFF, we can't do this transformation */
+ if (e->op != YASM_EXPR_SEGOFF)
+ return NULL;
+
+ /* Extract the SEG portion out to its own expression */
+ if (e->terms[0].type == YASM_EXPR_EXPR)
+ retval = e->terms[0].data.expn;
+ else {
+ /* Need to build IDENT expression to hold non-expression contents */
+ retval = yasm_xmalloc(sizeof(yasm_expr));
+ retval->op = YASM_EXPR_IDENT;
+ retval->numterms = 1;
+ retval->terms[0] = e->terms[0]; /* structure copy */
+ }
+
+ /* Delete the SEG: portion by changing the expression into an IDENT */
+ e->op = YASM_EXPR_IDENT;
+ e->numterms = 1;
+ e->terms[0] = e->terms[1]; /* structure copy */
+
+ return retval;
+}
+
/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
const yasm_intnum *
yasm_expr_get_intnum(yasm_expr **ep, yasm_calc_bc_dist_func calc_bc_dist)
@@ -1166,6 +1207,9 @@
case YASM_EXPR_IDENT:
opstr[0] = 0;
break;
+ default:
+ strcpy(opstr, " !UNK! ");
+ break;
}
for (i=0; i<e->numterms; i++) {
switch (e->terms[i].type) {
diff --git a/yasm/libyasm/expr.h b/yasm/libyasm/expr.h
index 674135d..f9a8b37 100644
--- a/yasm/libyasm/expr.h
+++ b/yasm/libyasm/expr.h
@@ -1,14 +1,17 @@
-/* $IdPath$
- * Expression handling header file
+/**
+ * \file expr.h
+ * \brief YASM expression interface
+ *
+ * $IdPath$
*
* Copyright (C) 2001 Michael Urman, 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
+ * - 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
+ * - 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.
*
@@ -27,94 +30,206 @@
#ifndef YASM_EXPR_H
#define YASM_EXPR_H
+/** Expression item (opaque type). \internal */
typedef struct yasm_expr__item yasm_expr__item;
+/** Initialize expression internal data structures.
+ * \param a architecture in use
+ */
void yasm_expr_initialize(yasm_arch *a);
-/*@only@*/ yasm_expr *yasm_expr_new(yasm_expr_op, /*@only@*/ yasm_expr__item *,
- /*@only@*/ /*@null@*/ yasm_expr__item *,
- unsigned long lindex);
+/** Create a new expression e=a op b.
+ * \param op operation
+ * \param a expression item a
+ * \param b expression item b (optional depending on op)
+ * \param lindex line index (where expression defined)
+ * \return Newly allocated expression.
+ */
+/*@only@*/ yasm_expr *yasm_expr_new
+ (yasm_expr_op op, /*@only@*/ yasm_expr__item *a,
+ /*@only@*/ /*@null@*/ yasm_expr__item *b, unsigned long lindex);
-/*@only@*/ yasm_expr__item *yasm_expr_sym(/*@keep@*/ yasm_symrec *);
-/*@only@*/ yasm_expr__item *yasm_expr_expr(/*@keep@*/ yasm_expr *);
-/*@only@*/ yasm_expr__item *yasm_expr_int(/*@keep@*/ yasm_intnum *);
-/*@only@*/ yasm_expr__item *yasm_expr_float(/*@keep@*/ yasm_floatnum *);
+/** Create a new symbol expression item.
+ * \param sym symbol
+ * \return Newly allocated expression item.
+ */
+/*@only@*/ yasm_expr__item *yasm_expr_sym(/*@keep@*/ yasm_symrec *sym);
+
+/** Create a new expression expression item.
+ * \param e expression
+ * \return Newly allocated expression item.
+ */
+/*@only@*/ yasm_expr__item *yasm_expr_expr(/*@keep@*/ yasm_expr *e);
+
+/** Create a new intnum expression item.
+ * \param intn intnum
+ * \return Newly allocated expression item.
+ */
+/*@only@*/ yasm_expr__item *yasm_expr_int(/*@keep@*/ yasm_intnum *intn);
+
+/** Create a new floatnum expression item.
+ * \param flt floatnum
+ * \return Newly allocated expression item.
+ */
+/*@only@*/ yasm_expr__item *yasm_expr_float(/*@keep@*/ yasm_floatnum *flt);
+
+/** Create a new register expression item.
+ * \param reg register
+ * \return Newly allocated expression item.
+ */
/*@only@*/ yasm_expr__item *yasm_expr_reg(unsigned long reg);
+/** Create a new expression tree e=l op r.
+ * \param l expression for left side of new expression
+ * \param o operation
+ * \param r expression for right side of new expression
+ * \param i line index
+ * \return Newly allocated expression.
+ */
#define yasm_expr_new_tree(l,o,r,i) \
yasm_expr_new ((o), yasm_expr_expr(l), yasm_expr_expr(r), i)
+
+/** Create a new expression branch e=op r.
+ * \param o operation
+ * \param r expression for right side of new expression
+ * \param i line index
+ * \return Newly allocated expression.
+ */
#define yasm_expr_new_branch(o,r,i) \
yasm_expr_new ((o), yasm_expr_expr(r), (yasm_expr__item *)NULL, i)
+
+/** Create a new expression identity e=r.
+ * \param r expression for identity within new expression
+ * \param i line index
+ * \return Newly allocated expression.
+ */
#define yasm_expr_new_ident(r,i) \
yasm_expr_new (YASM_EXPR_IDENT, (r), (yasm_expr__item *)NULL, i)
-/* allocates and makes an exact duplicate of e */
+/** Duplicate an expression.
+ * \param e expression
+ * \return Newly allocated expression identical to e.
+ */
yasm_expr *yasm_expr_copy(const yasm_expr *e);
+/** Destroy (free allocated memory for) an expression.
+ * \param e expression
+ */
void yasm_expr_delete(/*@only@*/ /*@null@*/ yasm_expr *e);
-/* "Extra" transformation function that may be inserted into an
- * expr_level_tree() invocation.
- * Inputs: e, the expression being simplified
- * d, data provided as expr_xform_extra_data to expr_level_tree()
- * Returns updated e.
+/** Determine if an expression is a specified operation (at the top level).
+ * \param e expression
+ * \param op operator
+ * \return Nonzero if the expression was the specified operation at the top
+ * level, zero otherwise.
+ */
+int yasm_expr_is_op(const yasm_expr *e, yasm_expr_op op);
+
+/** Extra transformation function for yasm_expr__level_tree().
+ * \param e expression being simplified
+ * \param d data provided as expr_xform_extra_data to
+ * yasm_expr__level_tree()
+ * \return Transformed e.
*/
typedef /*@only@*/ yasm_expr * (*yasm_expr_xform_func)
(/*@returned@*/ /*@only@*/ yasm_expr *e, /*@null@*/ void *d);
+/** Linked list of expression entries.
+ * \internal
+ * Used internally by yasm_expr__level_tree().
+ */
typedef struct yasm__exprhead yasm__exprhead;
#ifdef YASM_INTERNAL
SLIST_HEAD(yasm__exprhead, yasm__exprentry);
#endif
-/* Level an entire expn tree. Call with eh = NULL */
+/** Level an entire expression tree.
+ * \internal
+ * \param e expression
+ * \param fold_const enable constant folding if nonzero
+ * \param simplify_ident simplify identities
+ * \param calc_bc_dist bytecode distance-calculation function
+ * \param expr_xform_extra extra transformation function
+ * \param expr_xform_extra_data data to pass to expr_xform_extra
+ * \param eh call with NULL (for internal use in recursion)
+ * \return Leveled expression.
+ */
/*@only@*/ /*@null@*/ yasm_expr *yasm_expr__level_tree
(/*@returned@*/ /*@only@*/ /*@null@*/ yasm_expr *e, int fold_const,
int simplify_ident, /*@null@*/ yasm_calc_bc_dist_func calc_bc_dist,
/*@null@*/ yasm_expr_xform_func expr_xform_extra,
/*@null@*/ void *expr_xform_extra_data, /*@null@*/ yasm__exprhead *eh);
-/* Simplifies the expression e as much as possible, eliminating extraneous
- * branches and simplifying integer-only subexpressions.
+/** Simplify an expression as much as possible. Eliminates extraneous
+ * branches and simplifies integer-only subexpressions. Simplified version
+ * of yasm_expr__level_tree().
+ * \param e expression
+ * \param cbd bytecode distance-calculation function
+ * \return Simplified expression.
*/
#define yasm_expr_simplify(e, cbd) \
yasm_expr__level_tree(e, 1, 1, cbd, NULL, NULL, NULL)
-/* Extracts a single symrec out of an expression, replacing it with the
- * symrec's value (if it's a label). Returns NULL if it's unable to extract a
- * symrec (too complex of expr, none present, etc).
+/** Extract a single symbol out of an expression. Replaces it with the
+ * symbol's value (if it's a label).
+ * \param ep expression (pointer to)
+ * \param calc_bc_dist bytecode distance-calculation function
+ * \return NULL if unable to extract a symbol (too complex of expr, none
+ * present, etc); otherwise returns the extracted symbol.
*/
/*@dependent@*/ /*@null@*/ yasm_symrec *yasm_expr_extract_symrec
(yasm_expr **ep, yasm_calc_bc_dist_func calc_bc_dist);
-/* Gets the integer value of e if the expression is just an integer. If the
- * expression is more complex (contains anything other than integers, ie
- * floats, non-valued labels, registers), returns NULL.
+/** Extract the segment portion of a SEG:OFF expression, leaving the offset.
+ * \param ep expression (pointer to)
+ * \return NULL if unable to extract a segment (YASM_EXPR_SEGOFF not the
+ * top-level operator), otherwise the segment expression. The input
+ * expression is modified such that on return, it's the offset
+ * expression.
+ */
+/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_segment(yasm_expr **ep);
+
+/** Get the integer value of an expression if it's just an integer.
+ * \param ep expression (pointer to)
+ * \param calc_bc_dist bytecode distance-calculation function
+ * \return NULL if the expression is too complex (contains anything other than
+ * integers, ie floats, non-valued labels, registers); otherwise the
+ * intnum value of the expression.
*/
/*@dependent@*/ /*@null@*/ const yasm_intnum *yasm_expr_get_intnum
(yasm_expr **ep, /*@null@*/ yasm_calc_bc_dist_func calc_bc_dist);
-/* Gets the float value of e if the expression is just an float. If the
- * expression is more complex (contains anything other than floats, ie
- * integers, non-valued labels, registers), returns NULL.
+/** Get the floating point value of an expression if it's just an floatnum.
+ * \param ep expression (pointer to)
+ * \return NULL if the expression is too complex (contains anything other than
+ * floats, ie integers, non-valued labels, registers); otherwise the
+ * floatnum value of the expression.
*/
/*@dependent@*/ /*@null@*/ const yasm_floatnum *yasm_expr_get_floatnum
(yasm_expr **ep);
-/* Gets the symrec value of e if the expression is just an symbol. If the
- * expression is more complex, returns NULL. Simplifies the expr first if
- * simplify is nonzero.
+/** Get the symbol value of an expression if it's just a symbol.
+ * \param ep expression (pointer to)
+ * \param simplify if nonzero, simplify the expression first
+ * \return NULL if the expression is too complex; otherwise the symbol value of
+ * the expression.
*/
/*@dependent@*/ /*@null@*/ const yasm_symrec *yasm_expr_get_symrec
(yasm_expr **ep, int simplify);
-/* Gets the register value of e if the expression is just a register. If the
- * expression is more complex, returns NULL. Simplifies the expr first if
- * simplify is nonzero.
+/** Get the register value of an expression if it's just a register.
+ * \param ep expression (pointer to)
+ * \param simplify if nonzero, simplify the expression first
+ * \return NULL if the expression is too complex; otherwise the register value
+ * of the expression.
*/
/*@dependent@*/ /*@null@*/ const unsigned long *yasm_expr_get_reg
(yasm_expr **ep, int simplify);
-void yasm_expr_print(FILE *f, /*@null@*/ const yasm_expr *);
+/** Print an expression. For debugging purposes.
+ * \param f file
+ * \param e expression
+ */
+void yasm_expr_print(FILE *f, /*@null@*/ const yasm_expr *e);
#endif
diff --git a/yasm/libyasm/intnum.c b/yasm/libyasm/intnum.c
index 81b46d5..97f1c6c 100644
--- a/yasm/libyasm/intnum.c
+++ b/yasm/libyasm/intnum.c
@@ -241,7 +241,8 @@
/*@-nullderef -nullpass -branchstate@*/
void
-yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand)
+yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand,
+ unsigned long lindex)
{
wordptr result = (wordptr)NULL, op1 = (wordptr)NULL, op2 = (wordptr)NULL;
wordptr spare = (wordptr)NULL;
@@ -439,6 +440,15 @@
} else
acc->val.ul = acc->val.ul != operand->val.ul;
break;
+ case YASM_EXPR_SEG:
+ yasm__error(lindex, N_("invalid use of '%s'"), "SEG");
+ break;
+ case YASM_EXPR_WRT:
+ yasm__error(lindex, N_("invalid use of '%s'"), "WRT");
+ break;
+ case YASM_EXPR_SEGOFF:
+ yasm__error(lindex, N_("invalid use of '%s'"), ":");
+ break;
case YASM_EXPR_IDENT:
if (result)
BitVector_Copy(result, op1);
diff --git a/yasm/libyasm/intnum.h b/yasm/libyasm/intnum.h
index eff2dfd..55ade70 100644
--- a/yasm/libyasm/intnum.h
+++ b/yasm/libyasm/intnum.h
@@ -1,14 +1,17 @@
-/* $IdPath$
- * Integer number functions header file.
+/**
+ * \file intnum.h
+ * \brief YASM integer number interface.
+ *
+ * $IdPath$
*
* Copyright (C) 2001 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
+ * - 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
+ * - 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.
*
@@ -27,54 +30,145 @@
#ifndef YASM_INTNUM_H
#define YASM_INTNUM_H
+/** Initialize intnum internal data structures. */
void yasm_intnum_initialize(void);
-/* Clean up internal allocations */
+
+/** Clean up internal intnum allocations. */
void yasm_intnum_cleanup(void);
+/** Create a new intnum from a decimal string.
+ * \param str decimal string
+ * \param lindex line index (where the number came from)
+ * \return Newly allocated intnum.
+ */
/*@only@*/ yasm_intnum *yasm_intnum_new_dec(char *str, unsigned long lindex);
+
+/** Create a new intnum from a binary string.
+ * \param str binary string
+ * \param lindex line index (where the number came from)
+ * \return Newly allocated intnum.
+ */
/*@only@*/ yasm_intnum *yasm_intnum_new_bin(char *str, unsigned long lindex);
+
+/** Create a new intnum from an octal string.
+ * \param str octal string
+ * \param lindex line index (where the number came from)
+ * \return Newly allocated intnum.
+ */
/*@only@*/ yasm_intnum *yasm_intnum_new_oct(char *str, unsigned long lindex);
+
+/** Create a new intnum from a hexidecimal string.
+ * \param str hexidecimal string
+ * \param lindex line index (where the number came from)
+ * \return Newly allocated intnum.
+ */
/*@only@*/ yasm_intnum *yasm_intnum_new_hex(char *str, unsigned long lindex);
-/* convert character constant to integer value, using NASM rules */
+
+/** Convert character constant to integer value, using NASM rules. NASM syntax
+ * supports automatic conversion from strings such as 'abcd' to a 32-bit
+ * integer value. This function performs those conversions.
+ * \param str character constant string
+ * \param lindex line index (where the number came from)
+ * \return Newly allocated intnum.
+ */
/*@only@*/ yasm_intnum *yasm_intnum_new_charconst_nasm(const char *str,
unsigned long lindex);
+
+/** Create a new intnum from an unsigned integer value.
+ * \param i unsigned integer value
+ * \return Newly allocated intnum.
+ */
/*@only@*/ yasm_intnum *yasm_intnum_new_uint(unsigned long i);
+
+/** Create a new intnum from an signed integer value.
+ * \param i signed integer value
+ * \return Newly allocated intnum.
+ */
/*@only@*/ yasm_intnum *yasm_intnum_new_int(long i);
+
+/** Duplicate an intnum.
+ * \param intn intnum
+ * \return Newly allocated intnum with the same value as intn.
+ */
/*@only@*/ yasm_intnum *yasm_intnum_copy(const yasm_intnum *intn);
+
+/** Destroy (free allocated memory for) an intnum.
+ * \param intn intnum
+ */
void yasm_intnum_delete(/*@only@*/ yasm_intnum *intn);
-/* calculation function: acc = acc op operand */
-void yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand);
+/** Floating point calculation function: acc = acc op operand.
+ * \note Not all operations in yasm_expr_op may be supported; unsupported
+ * operations will result in an error.
+ * \param acc intnum accumulator
+ * \param op operation
+ * \param operand intnum operand
+ * \param lindex line index (of expression)
+ */
+void yasm_intnum_calc(yasm_intnum *acc, yasm_expr_op op, yasm_intnum *operand,
+ unsigned long lindex);
-/* simple value checks (for catching identities and the like) */
+/** Simple value check for 0.
+ * \param acc intnum
+ * \return Nonzero if acc==0.
+ */
int yasm_intnum_is_zero(yasm_intnum *acc);
+
+/** Simple value check for 1.
+ * \param acc intnum
+ * \return Nonzero if acc==1.
+ */
int yasm_intnum_is_pos1(yasm_intnum *acc);
+
+/** Simple value check for -1.
+ * \param acc intnum
+ * \return Nonzero if acc==-1.
+ */
int yasm_intnum_is_neg1(yasm_intnum *acc);
-/* The get functions truncate intn to the size specified; they don't check
- * for overflow. Use intnum_check_size() to check for overflow.
- */
-
-/* Return a 32-bit value in "standard" C format (eg, of unknown endian).
- * intnum_get_uint() treats intn as an unsigned integer (and returns as such).
- * intnum_get_int() treats intn as a signed integer (and returns as such).
+/** Convert an intnum to an unsigned 32-bit value. The value is in "standard"
+ * C format (eg, of unknown endian).
+ * \note Parameter intnum is truncated to fit into 32 bits. Use
+ * intnum_check_size() to check for overflow.
+ * \param intn intnum
+ * \return Unsigned 32-bit value of intn.
*/
unsigned long yasm_intnum_get_uint(const yasm_intnum *intn);
+
+/** Convert an intnum to a signed 32-bit value. The value is in "standard" C
+ * format (eg, of unknown endian).
+ * \note Parameter intnum is truncated to fit into 32 bits. Use
+ * intnum_check_size() to check for overflow.
+ * \param intn intnum
+ * \return Signed 32-bit value of intn.
+ */
long yasm_intnum_get_int(const yasm_intnum *intn);
-/* ptr will point to the Intel-format little-endian byte string after
- * call (eg, [0] should be the first byte output to the file).
+/** 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.
+ * \param intn intnum
+ * \param ptr pointer to storage for size bytes of output
+ * \param size size (in bytes) of desired output.
*/
void yasm_intnum_get_sized(const yasm_intnum *intn, unsigned char *ptr,
size_t size);
-/* Check to see if intn will fit without overflow in size bytes.
- * If is_signed is 1, intn is treated as a signed number.
- * Returns 1 if it will, 0 if not.
+/** Check to see if intnum will fit without overflow into size bytes.
+ * 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
+ * \return Nonzero if intnum will fit.
*/
int yasm_intnum_check_size(const yasm_intnum *intn, size_t size,
int is_signed);
+/** Print an intnum. For debugging purposes.
+ * \param f file
+ * \param intn intnum
+ */
void yasm_intnum_print(FILE *f, const yasm_intnum *intn);
#endif
diff --git a/yasm/modules/arch/x86/tests/Makefile.inc b/yasm/modules/arch/x86/tests/Makefile.inc
index 54d0400..7cfc3d8 100644
--- a/yasm/modules/arch/x86/tests/Makefile.inc
+++ b/yasm/modules/arch/x86/tests/Makefile.inc
@@ -20,6 +20,9 @@
modules/arch/x86/tests/effaddr.asm \
modules/arch/x86/tests/effaddr.errwarn \
modules/arch/x86/tests/effaddr.hex \
+ modules/arch/x86/tests/farbasic.asm \
+ modules/arch/x86/tests/farbasic.errwarn \
+ modules/arch/x86/tests/farbasic.hex \
modules/arch/x86/tests/genopcode.asm \
modules/arch/x86/tests/genopcode.errwarn \
modules/arch/x86/tests/genopcode.hex \
diff --git a/yasm/modules/arch/x86/x86arch.h b/yasm/modules/arch/x86/x86arch.h
index ec97469..508206d 100644
--- a/yasm/modules/arch/x86/x86arch.h
+++ b/yasm/modules/arch/x86/x86arch.h
@@ -29,9 +29,9 @@
typedef enum {
X86_BC_INSN = YASM_BYTECODE_TYPE_BASE,
- X86_BC_JMPREL
+ X86_BC_JMP
} x86_bytecode_type;
-#define X86_BYTECODE_TYPE_MAX X86_BC_JMPREL+1
+#define X86_BYTECODE_TYPE_MAX X86_BC_JMP+1
/* 0-15 (low 4 bits) used for register number, stored in same data area.
* Note 8-15 are only valid for some registers, and only in 64-bit mode.
@@ -65,12 +65,13 @@
} x86_parse_targetmod;
typedef enum {
- JR_NONE,
- JR_SHORT,
- JR_NEAR,
- JR_SHORT_FORCED,
- JR_NEAR_FORCED
-} x86_jmprel_opcode_sel;
+ JMP_NONE,
+ JMP_SHORT,
+ JMP_NEAR,
+ JMP_SHORT_FORCED,
+ JMP_NEAR_FORCED,
+ JMP_FAR /* not really relative, but fits here */
+} x86_jmp_opcode_sel;
typedef enum {
X86_REX_W = 3,
@@ -129,22 +130,25 @@
yasm_bytecode *yasm_x86__bc_new_insn(x86_new_insn_data *d);
-/* Structure with *all* inputs passed to x86_bytecode_new_jmprel().
+/* Structure with *all* inputs passed to x86_bytecode_new_jmp().
* Pass 0 for the opcode_len if that version of the opcode doesn't exist.
*/
-typedef struct x86_new_jmprel_data {
+typedef struct x86_new_jmp_data {
unsigned long lindex;
/*@keep@*/ yasm_expr *target;
- x86_jmprel_opcode_sel op_sel;
+ /*@dependent@*/ yasm_symrec *origin;
+ x86_jmp_opcode_sel op_sel;
unsigned char short_op_len;
unsigned char short_op[3];
unsigned char near_op_len;
unsigned char near_op[3];
+ unsigned char far_op_len;
+ unsigned char far_op[3];
unsigned char addrsize;
unsigned char opersize;
-} x86_new_jmprel_data;
+} x86_new_jmp_data;
-yasm_bytecode *yasm_x86__bc_new_jmprel(x86_new_jmprel_data *d);
+yasm_bytecode *yasm_x86__bc_new_jmp(x86_new_jmp_data *d);
extern unsigned char yasm_x86_LTX_mode_bits;
diff --git a/yasm/modules/arch/x86/x86bc.c b/yasm/modules/arch/x86/x86bc.c
index ff78ba0..a7e0972 100644
--- a/yasm/modules/arch/x86/x86bc.c
+++ b/yasm/modules/arch/x86/x86bc.c
@@ -92,26 +92,27 @@
unsigned char mode_bits;
} x86_insn;
-typedef struct x86_jmprel {
+typedef struct x86_jmp {
yasm_bytecode bc; /* base structure */
yasm_expr *target; /* target location */
+ /*@dependent@*/ yasm_symrec *origin; /* jump origin */
struct {
unsigned char opcode[3];
unsigned char opcode_len; /* 0 = no opc for this version */
- } shortop, nearop;
+ } shortop, nearop, farop;
/* which opcode are we using? */
/* The *FORCED forms are specified in the source as such */
- x86_jmprel_opcode_sel op_sel;
+ x86_jmp_opcode_sel op_sel;
unsigned char addrsize; /* 0 or =mode_bits => no override */
unsigned char opersize; /* 0 indicates no override */
unsigned char lockrep_pre; /* 0 indicates no prefix */
unsigned char mode_bits;
-} x86_jmprel;
+} x86_jmp;
int
@@ -181,41 +182,46 @@
/*@-compmempass -mustfree@*/
yasm_bytecode *
-yasm_x86__bc_new_jmprel(x86_new_jmprel_data *d)
+yasm_x86__bc_new_jmp(x86_new_jmp_data *d)
{
- x86_jmprel *jmprel;
+ x86_jmp *jmp;
- jmprel = (x86_jmprel *)
- yasm_bc_new_common((yasm_bytecode_type)X86_BC_JMPREL,
- sizeof(x86_jmprel), d->lindex);
+ jmp = (x86_jmp *) yasm_bc_new_common((yasm_bytecode_type)X86_BC_JMP,
+ sizeof(x86_jmp), d->lindex);
- jmprel->target = d->target;
- jmprel->op_sel = d->op_sel;
+ jmp->target = d->target;
+ jmp->origin = d->origin;
+ jmp->op_sel = d->op_sel;
- if ((d->op_sel == JR_SHORT_FORCED) && (d->near_op_len == 0))
+ if ((d->op_sel == JMP_SHORT_FORCED) && (d->near_op_len == 0))
yasm__error(d->lindex,
N_("no SHORT form of that jump instruction exists"));
- if ((d->op_sel == JR_NEAR_FORCED) && (d->short_op_len == 0))
+ if ((d->op_sel == JMP_NEAR_FORCED) && (d->short_op_len == 0))
yasm__error(d->lindex,
N_("no NEAR form of that jump instruction exists"));
- jmprel->shortop.opcode[0] = d->short_op[0];
- jmprel->shortop.opcode[1] = d->short_op[1];
- jmprel->shortop.opcode[2] = d->short_op[2];
- jmprel->shortop.opcode_len = d->short_op_len;
+ jmp->shortop.opcode[0] = d->short_op[0];
+ jmp->shortop.opcode[1] = d->short_op[1];
+ jmp->shortop.opcode[2] = d->short_op[2];
+ jmp->shortop.opcode_len = d->short_op_len;
- jmprel->nearop.opcode[0] = d->near_op[0];
- jmprel->nearop.opcode[1] = d->near_op[1];
- jmprel->nearop.opcode[2] = d->near_op[2];
- jmprel->nearop.opcode_len = d->near_op_len;
+ jmp->nearop.opcode[0] = d->near_op[0];
+ jmp->nearop.opcode[1] = d->near_op[1];
+ jmp->nearop.opcode[2] = d->near_op[2];
+ jmp->nearop.opcode_len = d->near_op_len;
- jmprel->addrsize = d->addrsize;
- jmprel->opersize = d->opersize;
- jmprel->lockrep_pre = 0;
+ jmp->farop.opcode[0] = d->far_op[0];
+ jmp->farop.opcode[1] = d->far_op[1];
+ jmp->farop.opcode[2] = d->far_op[2];
+ jmp->farop.opcode_len = d->far_op_len;
- jmprel->mode_bits = yasm_x86_LTX_mode_bits;
+ jmp->addrsize = d->addrsize;
+ jmp->opersize = d->opersize;
+ jmp->lockrep_pre = 0;
- return (yasm_bytecode *)jmprel;
+ jmp->mode_bits = yasm_x86_LTX_mode_bits;
+
+ return (yasm_bytecode *)jmp;
}
/*@=compmempass =mustfree@*/
@@ -334,7 +340,7 @@
yasm_x86__bc_insn_opersize_override(yasm_bytecode *bc, unsigned int opersize)
{
x86_insn *insn;
- x86_jmprel *jmprel;
+ x86_jmp *jmp;
if (!bc)
return;
@@ -344,9 +350,9 @@
insn = (x86_insn *)bc;
insn->opersize = (unsigned char)opersize;
break;
- case X86_BC_JMPREL:
- jmprel = (x86_jmprel *)bc;
- jmprel->opersize = (unsigned char)opersize;
+ case X86_BC_JMP:
+ jmp = (x86_jmp *)bc;
+ jmp->opersize = (unsigned char)opersize;
break;
default:
yasm_internal_error(
@@ -358,7 +364,7 @@
yasm_x86__bc_insn_addrsize_override(yasm_bytecode *bc, unsigned int addrsize)
{
x86_insn *insn;
- x86_jmprel *jmprel;
+ x86_jmp *jmp;
if (!bc)
return;
@@ -368,9 +374,9 @@
insn = (x86_insn *)bc;
insn->addrsize = (unsigned char)addrsize;
break;
- case X86_BC_JMPREL:
- jmprel = (x86_jmprel *)bc;
- jmprel->addrsize = (unsigned char)addrsize;
+ case X86_BC_JMP:
+ jmp = (x86_jmp *)bc;
+ jmp->addrsize = (unsigned char)addrsize;
break;
default:
yasm_internal_error(
@@ -383,7 +389,7 @@
unsigned long lindex)
{
x86_insn *insn;
- x86_jmprel *jmprel;
+ x86_jmp *jmp;
unsigned char *lockrep_pre = (unsigned char *)NULL;
if (!bc)
@@ -394,9 +400,9 @@
insn = (x86_insn *)bc;
lockrep_pre = &insn->lockrep_pre;
break;
- case X86_BC_JMPREL:
- jmprel = (x86_jmprel *)bc;
- lockrep_pre = &jmprel->lockrep_pre;
+ case X86_BC_JMP:
+ jmp = (x86_jmp *)bc;
+ lockrep_pre = &jmp->lockrep_pre;
break;
default:
yasm_internal_error(
@@ -414,7 +420,7 @@
yasm_x86__bc_delete(yasm_bytecode *bc)
{
x86_insn *insn;
- x86_jmprel *jmprel;
+ x86_jmp *jmp;
switch ((x86_bytecode_type)bc->type) {
case X86_BC_INSN:
@@ -426,9 +432,9 @@
yasm_xfree(insn->imm);
}
break;
- case X86_BC_JMPREL:
- jmprel = (x86_jmprel *)bc;
- yasm_expr_delete(jmprel->target);
+ case X86_BC_JMP:
+ jmp = (x86_jmp *)bc;
+ yasm_expr_delete(jmp->target);
break;
}
}
@@ -451,7 +457,7 @@
yasm_x86__bc_print(FILE *f, int indent_level, const yasm_bytecode *bc)
{
const x86_insn *insn;
- const x86_jmprel *jmprel;
+ const x86_jmp *jmp;
switch ((x86_bytecode_type)bc->type) {
case X86_BC_INSN:
@@ -495,59 +501,74 @@
(unsigned int)insn->shift_op,
(unsigned int)insn->mode_bits);
break;
- case X86_BC_JMPREL:
- jmprel = (const x86_jmprel *)bc;
- fprintf(f, "%*s_Relative Jump_\n", indent_level, "");
+ case X86_BC_JMP:
+ jmp = (const x86_jmp *)bc;
+ fprintf(f, "%*s_Jump_\n", indent_level, "");
fprintf(f, "%*sTarget=", indent_level, "");
- yasm_expr_print(f, jmprel->target);
+ yasm_expr_print(f, jmp->target);
+ fprintf(f, "%*sOrigin=\n", indent_level, "");
+ yasm_symrec_print(f, indent_level+1, jmp->origin);
fprintf(f, "\n%*sShort Form:\n", indent_level, "");
- if (jmprel->shortop.opcode_len == 0)
+ if (jmp->shortop.opcode_len == 0)
fprintf(f, "%*sNone\n", indent_level+1, "");
else
fprintf(f, "%*sOpcode: %02x %02x %02x OpLen=%u\n",
indent_level+1, "",
- (unsigned int)jmprel->shortop.opcode[0],
- (unsigned int)jmprel->shortop.opcode[1],
- (unsigned int)jmprel->shortop.opcode[2],
- (unsigned int)jmprel->shortop.opcode_len);
+ (unsigned int)jmp->shortop.opcode[0],
+ (unsigned int)jmp->shortop.opcode[1],
+ (unsigned int)jmp->shortop.opcode[2],
+ (unsigned int)jmp->shortop.opcode_len);
fprintf(f, "%*sNear Form:\n", indent_level, "");
- if (jmprel->nearop.opcode_len == 0)
+ if (jmp->nearop.opcode_len == 0)
fprintf(f, "%*sNone\n", indent_level+1, "");
else
fprintf(f, "%*sOpcode: %02x %02x %02x OpLen=%u\n",
indent_level+1, "",
- (unsigned int)jmprel->nearop.opcode[0],
- (unsigned int)jmprel->nearop.opcode[1],
- (unsigned int)jmprel->nearop.opcode[2],
- (unsigned int)jmprel->nearop.opcode_len);
+ (unsigned int)jmp->nearop.opcode[0],
+ (unsigned int)jmp->nearop.opcode[1],
+ (unsigned int)jmp->nearop.opcode[2],
+ (unsigned int)jmp->nearop.opcode_len);
+ fprintf(f, "%*sFar Form:\n", indent_level, "");
+ if (jmp->farop.opcode_len == 0)
+ fprintf(f, "%*sNone\n", indent_level+1, "");
+ else
+ fprintf(f, "%*sOpcode: %02x %02x %02x OpLen=%u\n",
+ indent_level+1, "",
+ (unsigned int)jmp->farop.opcode[0],
+ (unsigned int)jmp->farop.opcode[1],
+ (unsigned int)jmp->farop.opcode[2],
+ (unsigned int)jmp->farop.opcode_len);
fprintf(f, "%*sOpSel=", indent_level, "");
- switch (jmprel->op_sel) {
- case JR_NONE:
+ switch (jmp->op_sel) {
+ case JMP_NONE:
fprintf(f, "None");
break;
- case JR_SHORT:
+ case JMP_SHORT:
fprintf(f, "Short");
break;
- case JR_NEAR:
+ case JMP_NEAR:
fprintf(f, "Near");
break;
- case JR_SHORT_FORCED:
+ case JMP_SHORT_FORCED:
fprintf(f, "Forced Short");
break;
- case JR_NEAR_FORCED:
+ case JMP_NEAR_FORCED:
fprintf(f, "Forced Near");
break;
+ case JMP_FAR:
+ fprintf(f, "Far");
+ break;
default:
fprintf(f, "UNKNOWN!!");
break;
}
fprintf(f, "\n%*sAddrSize=%u OperSize=%u LockRepPre=%02x\n",
indent_level, "",
- (unsigned int)jmprel->addrsize,
- (unsigned int)jmprel->opersize,
- (unsigned int)jmprel->lockrep_pre);
+ (unsigned int)jmp->addrsize,
+ (unsigned int)jmp->opersize,
+ (unsigned int)jmp->lockrep_pre);
fprintf(f, "%*sBITS=%u\n", indent_level, "",
- (unsigned int)jmprel->mode_bits);
+ (unsigned int)jmp->mode_bits);
break;
}
}
@@ -666,30 +687,31 @@
}
static yasm_bc_resolve_flags
-x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save,
- const yasm_bytecode *bc, const yasm_section *sect,
- yasm_calc_bc_dist_func calc_bc_dist)
+x86_bc_resolve_jmp(x86_jmp *jmp, unsigned long *len, int save,
+ const yasm_bytecode *bc, const yasm_section *sect,
+ yasm_calc_bc_dist_func calc_bc_dist)
{
yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN;
/*@null@*/ yasm_expr *temp;
/*@dependent@*/ /*@null@*/ const yasm_intnum *num;
long rel;
unsigned char opersize;
- int jrshort = 0;
+ x86_jmp_opcode_sel jrtype = JMP_NONE;
/* As opersize may be 0, figure out its "real" value. */
- opersize = (jmprel->opersize == 0) ? jmprel->mode_bits :
- jmprel->opersize;
+ opersize = (jmp->opersize == 0) ? jmp->mode_bits : jmp->opersize;
/* We only check to see if forced forms are actually legal if we're in
* save mode. Otherwise we assume that they are legal.
*/
- switch (jmprel->op_sel) {
- case JR_SHORT_FORCED:
+ switch (jmp->op_sel) {
+ case JMP_SHORT_FORCED:
/* 1 byte relative displacement */
- jrshort = 1;
+ jrtype = JMP_SHORT;
if (save) {
- temp = yasm_expr_copy(jmprel->target);
+ temp = yasm_expr_copy(jmp->target);
+ temp = yasm_expr_new(YASM_EXPR_SUB, yasm_expr_expr(temp),
+ yasm_expr_sym(jmp->origin), bc->line);
num = yasm_expr_get_intnum(&temp, calc_bc_dist);
if (!num) {
yasm__error(bc->line,
@@ -698,10 +720,10 @@
return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
} else {
rel = yasm_intnum_get_int(num);
- rel -= jmprel->shortop.opcode_len+1;
+ rel -= jmp->shortop.opcode_len+1;
yasm_expr_delete(temp);
/* does a short form exist? */
- if (jmprel->shortop.opcode_len == 0) {
+ if (jmp->shortop.opcode_len == 0) {
yasm__error(bc->line, N_("short jump does not exist"));
return YASM_BC_RESOLVE_ERROR |
YASM_BC_RESOLVE_UNKNOWN_LEN;
@@ -715,38 +737,52 @@
}
}
break;
- case JR_NEAR_FORCED:
+ case JMP_NEAR_FORCED:
/* 2/4 byte relative displacement (depending on operand size) */
- jrshort = 0;
+ jrtype = JMP_NEAR;
if (save) {
- if (jmprel->nearop.opcode_len == 0) {
+ if (jmp->nearop.opcode_len == 0) {
yasm__error(bc->line, N_("near jump does not exist"));
return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
}
}
break;
default:
+ temp = yasm_expr_copy(jmp->target);
+ temp = yasm_expr_simplify(temp, NULL);
+
+ /* Check for far displacement (seg:off). */
+ if (yasm_expr_is_op(temp, YASM_EXPR_SEGOFF)) {
+ jrtype = JMP_FAR;
+ break; /* length handled below */
+ } else if (jmp->op_sel == JMP_FAR) {
+ yasm__error(bc->line,
+ N_("far jump does not have a far displacement"));
+ return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
+ }
+
/* Try to find shortest displacement based on difference between
* target expr value and our (this bytecode's) offset. Note this
* requires offset to be set BEFORE calling calc_len in order for
* this test to be valid.
*/
- temp = yasm_expr_copy(jmprel->target);
+ temp = yasm_expr_new(YASM_EXPR_SUB, yasm_expr_expr(temp),
+ yasm_expr_sym(jmp->origin), bc->line);
num = yasm_expr_get_intnum(&temp, calc_bc_dist);
if (num) {
rel = yasm_intnum_get_int(num);
- rel -= jmprel->shortop.opcode_len+1;
+ rel -= jmp->shortop.opcode_len+1;
/* short displacement must fit within -128 <= rel <= +127 */
- if (jmprel->shortop.opcode_len != 0 && rel >= -128 &&
+ if (jmp->shortop.opcode_len != 0 && rel >= -128 &&
rel <= 127) {
/* It fits into a short displacement. */
- jrshort = 1;
- } else if (jmprel->nearop.opcode_len != 0) {
+ jrtype = JMP_SHORT;
+ } else if (jmp->nearop.opcode_len != 0) {
/* Near for now, but could get shorter in the future if
* there's a short form available.
*/
- jrshort = 0;
- if (jmprel->shortop.opcode_len != 0)
+ jrtype = JMP_NEAR;
+ if (jmp->shortop.opcode_len != 0)
retval = YASM_BC_RESOLVE_NONE;
} else {
/* Doesn't fit into short, and there's no near opcode.
@@ -760,17 +796,17 @@
return YASM_BC_RESOLVE_ERROR |
YASM_BC_RESOLVE_UNKNOWN_LEN;
}
- jrshort = 1;
+ jrtype = JMP_SHORT;
}
} else {
/* It's unknown. Thus, assume near displacement. If a near
* opcode is not available, use a short opcode instead.
* If we're saving, error if a near opcode is not available.
*/
- if (jmprel->nearop.opcode_len != 0) {
- if (jmprel->shortop.opcode_len != 0)
+ if (jmp->nearop.opcode_len != 0) {
+ if (jmp->shortop.opcode_len != 0)
retval = YASM_BC_RESOLVE_NONE;
- jrshort = 0;
+ jrtype = JMP_NEAR;
} else {
if (save) {
yasm__error(bc->line,
@@ -778,34 +814,47 @@
return YASM_BC_RESOLVE_ERROR |
YASM_BC_RESOLVE_UNKNOWN_LEN;
}
- jrshort = 1;
+ jrtype = JMP_SHORT;
}
}
yasm_expr_delete(temp);
break;
}
- if (jrshort) {
- if (save)
- jmprel->op_sel = JR_SHORT;
- if (jmprel->shortop.opcode_len == 0)
- return YASM_BC_RESOLVE_UNKNOWN_LEN; /* that size not available */
+ switch (jrtype) {
+ case JMP_SHORT:
+ if (save)
+ jmp->op_sel = JMP_SHORT;
+ if (jmp->shortop.opcode_len == 0)
+ return YASM_BC_RESOLVE_UNKNOWN_LEN; /* size not available */
- *len += jmprel->shortop.opcode_len + 1;
- } else {
- if (save)
- jmprel->op_sel = JR_NEAR;
- if (jmprel->nearop.opcode_len == 0)
- return YASM_BC_RESOLVE_UNKNOWN_LEN; /* that size not available */
+ *len += jmp->shortop.opcode_len + 1;
+ break;
+ case JMP_NEAR:
+ if (save)
+ jmp->op_sel = JMP_NEAR;
+ if (jmp->nearop.opcode_len == 0)
+ return YASM_BC_RESOLVE_UNKNOWN_LEN; /* size not available */
- *len += jmprel->nearop.opcode_len;
- *len += (opersize == 32) ? 4 : 2;
+ *len += jmp->nearop.opcode_len;
+ *len += (opersize == 32) ? 4 : 2;
+ break;
+ case JMP_FAR:
+ if (save)
+ jmp->op_sel = JMP_FAR;
+ if (jmp->farop.opcode_len == 0)
+ return YASM_BC_RESOLVE_UNKNOWN_LEN; /* size not available */
+
+ *len += jmp->farop.opcode_len;
+ *len += 2; /* segment */
+ *len += (opersize == 32) ? 4 : 2;
+ break;
+ default:
+ yasm_internal_error(N_("unknown jump type"));
}
- *len += (jmprel->addrsize != 0 && jmprel->addrsize != jmprel->mode_bits) ?
- 1:0;
- *len += (jmprel->opersize != 0 && jmprel->opersize != jmprel->mode_bits) ?
- 1:0;
- *len += (jmprel->lockrep_pre != 0) ? 1:0;
+ *len += (jmp->addrsize != 0 && jmp->addrsize != jmp->mode_bits) ? 1:0;
+ *len += (jmp->opersize != 0 && jmp->opersize != jmp->mode_bits) ? 1:0;
+ *len += (jmp->lockrep_pre != 0) ? 1:0;
return retval;
}
@@ -818,9 +867,9 @@
case X86_BC_INSN:
return x86_bc_resolve_insn((x86_insn *)bc, &bc->len, save, sect,
calc_bc_dist);
- case X86_BC_JMPREL:
- return x86_bc_resolve_jmprel((x86_jmprel *)bc, &bc->len, save, bc,
- sect, calc_bc_dist);
+ case X86_BC_JMP:
+ return x86_bc_resolve_jmp((x86_jmp *)bc, &bc->len, save, bc, sect,
+ calc_bc_dist);
default:
break;
}
@@ -924,62 +973,92 @@
}
static int
-x86_bc_tobytes_jmprel(x86_jmprel *jmprel, unsigned char **bufp,
- const yasm_section *sect, yasm_bytecode *bc,
- void *d, yasm_output_expr_func output_expr)
+x86_bc_tobytes_jmp(x86_jmp *jmp, unsigned char **bufp,
+ const yasm_section *sect, yasm_bytecode *bc,
+ void *d, yasm_output_expr_func output_expr)
{
unsigned char opersize;
unsigned int i;
unsigned char *bufp_orig = *bufp;
+ /*@null@*/ yasm_expr *targetseg;
/* Prefixes */
- if (jmprel->lockrep_pre != 0)
- YASM_WRITE_8(*bufp, jmprel->lockrep_pre);
+ if (jmp->lockrep_pre != 0)
+ YASM_WRITE_8(*bufp, jmp->lockrep_pre);
/* FIXME: branch hints! */
- if (jmprel->opersize != 0 && jmprel->opersize != jmprel->mode_bits)
+ if (jmp->opersize != 0 && jmp->opersize != jmp->mode_bits)
YASM_WRITE_8(*bufp, 0x66);
- if (jmprel->addrsize != 0 && jmprel->addrsize != jmprel->mode_bits)
+ if (jmp->addrsize != 0 && jmp->addrsize != jmp->mode_bits)
YASM_WRITE_8(*bufp, 0x67);
/* As opersize may be 0, figure out its "real" value. */
- opersize = (jmprel->opersize == 0) ? jmprel->mode_bits :
- jmprel->opersize;
+ opersize = (jmp->opersize == 0) ? jmp->mode_bits : jmp->opersize;
/* Check here to see if forced forms are actually legal. */
- switch (jmprel->op_sel) {
- case JR_SHORT_FORCED:
- case JR_SHORT:
+ switch (jmp->op_sel) {
+ case JMP_SHORT_FORCED:
+ case JMP_SHORT:
/* 1 byte relative displacement */
- if (jmprel->shortop.opcode_len == 0)
+ if (jmp->shortop.opcode_len == 0)
yasm_internal_error(N_("short jump does not exist"));
/* Opcode */
- for (i=0; i<jmprel->shortop.opcode_len; i++)
- YASM_WRITE_8(*bufp, jmprel->shortop.opcode[i]);
+ for (i=0; i<jmp->shortop.opcode_len; i++)
+ YASM_WRITE_8(*bufp, jmp->shortop.opcode[i]);
/* Relative displacement */
- if (output_expr(&jmprel->target, bufp, 1,
+ 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))
return 1;
break;
- case JR_NEAR_FORCED:
- case JR_NEAR:
+ case JMP_NEAR_FORCED:
+ case JMP_NEAR:
/* 2/4 byte relative displacement (depending on operand size) */
- if (jmprel->nearop.opcode_len == 0) {
+ if (jmp->nearop.opcode_len == 0) {
yasm__error(bc->line, N_("near jump does not exist"));
return 1;
}
/* Opcode */
- for (i=0; i<jmprel->nearop.opcode_len; i++)
- YASM_WRITE_8(*bufp, jmprel->nearop.opcode[i]);
+ for (i=0; i<jmp->nearop.opcode_len; i++)
+ YASM_WRITE_8(*bufp, jmp->nearop.opcode[i]);
/* Relative displacement */
- if (output_expr(&jmprel->target, bufp,
- (opersize == 32) ? 4UL : 2UL,
+ 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 == 32) ? 4UL : 2UL,
(unsigned long)(*bufp-bufp_orig), sect, bc, 1, d))
return 1;
break;
+ case JMP_FAR:
+ /* far absolute (4/6 byte depending on operand size) */
+ if (jmp->farop.opcode_len == 0) {
+ yasm__error(bc->line, N_("far jump does not exist"));
+ return 1;
+ }
+
+ /* Opcode */
+ for (i=0; i<jmp->farop.opcode_len; i++)
+ YASM_WRITE_8(*bufp, jmp->farop.opcode[i]);
+
+ /* Absolute displacement: segment and offset */
+ jmp->target = yasm_expr_simplify(jmp->target, NULL);
+ 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 == 32) ? 4UL : 2UL,
+ (unsigned long)(*bufp-bufp_orig), sect, bc, 0, d))
+ return 1;
+ if (output_expr(&targetseg, bufp, 2UL,
+ (unsigned long)(*bufp-bufp_orig), sect, bc, 0, d))
+ return 1;
+
+ break;
default:
yasm_internal_error(N_("unrecognized relative jump op_sel"));
}
@@ -995,9 +1074,9 @@
case X86_BC_INSN:
return x86_bc_tobytes_insn((x86_insn *)bc, bufp, sect, bc, d,
output_expr);
- case X86_BC_JMPREL:
- return x86_bc_tobytes_jmprel((x86_jmprel *)bc, bufp, sect, bc, d,
- output_expr);
+ case X86_BC_JMP:
+ return x86_bc_tobytes_jmp((x86_jmp *)bc, bufp, sect, bc, d,
+ output_expr);
default:
break;
}
diff --git a/yasm/modules/arch/x86/x86id.re b/yasm/modules/arch/x86/x86id.re
index d7a8bc7..cc09ed1 100644
--- a/yasm/modules/arch/x86/x86id.re
+++ b/yasm/modules/arch/x86/x86id.re
@@ -82,7 +82,7 @@
#define MOD_SpAdd (1UL<<5) /* Parameter adds to "spare" value */
#define MOD_OpSizeR (1UL<<6) /* Parameter replaces opersize */
#define MOD_Imm8 (1UL<<7) /* Parameter is included as immediate byte */
-#define MOD_AdSizeR (1UL<<8) /* Parameter replaces addrsize (jmprel only) */
+#define MOD_AdSizeR (1UL<<8) /* Parameter replaces addrsize (jmp only) */
/* Modifiers that aren't actually used as modifiers. Rather, if set, bits
* 20-27 in the modifier are used as an index into an array.
@@ -153,8 +153,8 @@
* 6 = operand data is added to opcode byte 1
* 7 = operand data goes into BOTH ea and spare
* [special case for imul opcode]
- * 8 = relative jump (outputs a jmprel instead of normal insn)
- * 9 = operand size goes into address size (jmprel only)
+ * 8 = relative jump (outputs a jmp instead of normal insn)
+ * 9 = operand size goes into address size (jmp only)
* The below describes postponed actions: actions which can't be completed at
* parse-time due to things like EQU and complex expressions. For these, some
* additional data (stored in the second byte of the opcode with a one-byte
@@ -164,6 +164,7 @@
* 0 = none
* 1 = shift operation with a ,1 short form (instead of imm8).
* 2 = large imm16/32 that can become a sign-extended imm8.
+ * 3 = can be far jump
*/
#define OPT_Imm 0x0
#define OPT_Reg 0x1
@@ -224,6 +225,7 @@
#define OPAP_None (0UL<<16)
#define OPAP_ShiftOp (1UL<<16)
#define OPAP_SImm8Avail (2UL<<16)
+#define OPAP_JmpFar (3UL<<16)
#define OPAP_MASK (3UL<<16)
typedef struct x86_insn_info {
@@ -855,12 +857,12 @@
{ CPU_Any, 0, 16, 0, {0, 0, 0}, 0, 1, {OPT_Imm|OPS_16|OPA_JmpRel, 0, 0} },
{ CPU_386, 0, 32, 0, {0, 0, 0}, 0, 1, {OPT_Imm|OPS_32|OPA_JmpRel, 0, 0} },
- { CPU_Any, 0, 16, 1, {0xE8, 0, 0}, 0, 1,
- {OPT_Imm|OPS_16|OPTM_Near|OPA_JmpRel, 0, 0} },
- { CPU_386, 0, 32, 1, {0xE8, 0, 0}, 0, 1,
- {OPT_Imm|OPS_32|OPTM_Near|OPA_JmpRel, 0, 0} },
- { CPU_Any, 0, 0, 1, {0xE8, 0, 0}, 0, 1,
- {OPT_Imm|OPS_Any|OPTM_Near|OPA_JmpRel, 0, 0} },
+ { CPU_Any, 0, 16, 1, {0xE8, 0x9A, 0}, 0, 1,
+ {OPT_Imm|OPS_16|OPTM_Near|OPA_JmpRel|OPAP_JmpFar, 0, 0} },
+ { CPU_386, 0, 32, 1, {0xE8, 0x9A, 0}, 0, 1,
+ {OPT_Imm|OPS_32|OPTM_Near|OPA_JmpRel|OPAP_JmpFar, 0, 0} },
+ { CPU_Any, 0, 0, 1, {0xE8, 0x9A, 0}, 0, 1,
+ {OPT_Imm|OPS_Any|OPTM_Near|OPA_JmpRel|OPAP_JmpFar, 0, 0} },
{ CPU_Any, 0, 16, 1, {0xFF, 0, 0}, 2, 1, {OPT_RM|OPS_16|OPA_EA, 0, 0} },
{ CPU_386|CPU_Not64, 0, 32, 1, {0xFF, 0, 0}, 2, 1,
@@ -877,7 +879,12 @@
{ CPU_Any, 0, 0, 1, {0xFF, 0, 0}, 2, 1,
{OPT_Mem|OPS_Any|OPTM_Near|OPA_EA, 0, 0} },
- /* TODO: Far Imm 16:16/32 */
+ { CPU_Any, 0, 16, 1, {0x9A, 0, 0}, 3, 1,
+ {OPT_Imm|OPS_16|OPTM_Far|OPA_JmpRel, 0, 0} },
+ { CPU_386, 0, 32, 1, {0x9A, 0, 0}, 3, 1,
+ {OPT_Imm|OPS_32|OPTM_Far|OPA_JmpRel, 0, 0} },
+ { CPU_Any, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
+ {OPT_Imm|OPS_Any|OPTM_Far|OPA_JmpRel, 0, 0} },
{ CPU_Any, 0, 16, 1, {0xFF, 0, 0}, 3, 1,
{OPT_Mem|OPS_16|OPTM_Far|OPA_EA, 0, 0} },
@@ -893,12 +900,12 @@
{ CPU_Any, 0, 0, 1, {0xEB, 0, 0}, 0, 1,
{OPT_Imm|OPS_Any|OPTM_Short|OPA_JmpRel, 0, 0} },
- { CPU_Any, 0, 16, 1, {0xE9, 0, 0}, 0, 1,
- {OPT_Imm|OPS_16|OPTM_Near|OPA_JmpRel, 0, 0} },
- { CPU_386, 0, 32, 1, {0xE9, 0, 0}, 0, 1,
- {OPT_Imm|OPS_32|OPTM_Near|OPA_JmpRel, 0, 0} },
- { CPU_Any, 0, 0, 1, {0xE9, 0, 0}, 0, 1,
- {OPT_Imm|OPS_Any|OPTM_Near|OPA_JmpRel, 0, 0} },
+ { CPU_Any, 0, 16, 1, {0xE9, 0xEA, 0}, 0, 1,
+ {OPT_Imm|OPS_16|OPTM_Near|OPA_JmpRel|OPAP_JmpFar, 0, 0} },
+ { CPU_386, 0, 32, 1, {0xE9, 0xEA, 0}, 0, 1,
+ {OPT_Imm|OPS_32|OPTM_Near|OPA_JmpRel|OPAP_JmpFar, 0, 0} },
+ { CPU_Any, 0, 0, 1, {0xE9, 0xEA, 0}, 0, 1,
+ {OPT_Imm|OPS_Any|OPTM_Near|OPA_JmpRel|OPAP_JmpFar, 0, 0} },
{ CPU_Any, 0, 16, 1, {0xFF, 0, 0}, 4, 1, {OPT_RM|OPS_16|OPA_EA, 0, 0} },
{ CPU_386|CPU_Not64, 0, 32, 1, {0xFF, 0, 0}, 4, 1,
@@ -915,7 +922,12 @@
{ CPU_Any, 0, 0, 1, {0xFF, 0, 0}, 4, 1,
{OPT_Mem|OPS_Any|OPTM_Near|OPA_EA, 0, 0} },
- /* TODO: Far Imm 16:16/32 */
+ { CPU_Any, 0, 16, 1, {0xEA, 0, 0}, 3, 1,
+ {OPT_Imm|OPS_16|OPTM_Far|OPA_JmpRel, 0, 0} },
+ { CPU_386, 0, 32, 1, {0xEA, 0, 0}, 3, 1,
+ {OPT_Imm|OPS_32|OPTM_Far|OPA_JmpRel, 0, 0} },
+ { CPU_Any, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
+ {OPT_Imm|OPS_Any|OPTM_Far|OPA_JmpRel, 0, 0} },
{ CPU_Any, 0, 16, 1, {0xFF, 0, 0}, 5, 1,
{OPT_Mem|OPS_16|OPTM_Far|OPA_EA, 0, 0} },
@@ -1509,12 +1521,12 @@
static yasm_bytecode *
-x86_new_jmprel(const unsigned long data[4], int num_operands,
- yasm_insn_operandhead *operands, x86_insn_info *jrinfo,
- yasm_section *cur_section, /*@null@*/ yasm_bytecode *prev_bc,
- unsigned long lindex)
+x86_new_jmp(const unsigned long data[4], int num_operands,
+ yasm_insn_operandhead *operands, x86_insn_info *jinfo,
+ yasm_section *cur_section, /*@null@*/ yasm_bytecode *prev_bc,
+ unsigned long lindex)
{
- x86_new_jmprel_data d;
+ x86_new_jmp_data d;
int num_info = (int)(data[1]&0xFF);
x86_insn_info *info = (x86_insn_info *)data[0];
unsigned long mod_data = data[1] >> 8;
@@ -1527,35 +1539,53 @@
op = yasm_ops_first(operands);
if (op->type != YASM_INSN__OPERAND_IMM)
yasm_internal_error(N_("invalid operand conversion"));
- d.target = yasm_expr_new(YASM_EXPR_SUB, yasm_expr_expr(op->data.val),
- yasm_expr_sym(yasm_symrec_define_label("$", cur_section, prev_bc,
- 0, lindex)), lindex);
- /* See if the user explicitly specified short/near. */
- switch ((int)(jrinfo->operands[0] & OPTM_MASK)) {
+ /* Far target needs to become "seg imm:imm". */
+ if ((jinfo->operands[0] & OPTM_MASK) == OPTM_Far)
+ d.target = yasm_expr_new_tree(
+ yasm_expr_new_branch(YASM_EXPR_SEG, op->data.val, lindex),
+ YASM_EXPR_SEGOFF, yasm_expr_copy(op->data.val), lindex);
+ else
+ d.target = op->data.val;
+
+ /* Need to save jump origin for relative jumps. */
+ d.origin = yasm_symrec_define_label("$", cur_section, prev_bc, 0, lindex);
+
+ /* Initially assume no far opcode is available. */
+ d.far_op_len = 0;
+
+ /* See if the user explicitly specified short/near/far. */
+ switch ((int)(jinfo->operands[0] & OPTM_MASK)) {
case OPTM_Short:
- d.op_sel = JR_SHORT_FORCED;
+ d.op_sel = JMP_SHORT_FORCED;
break;
case OPTM_Near:
- d.op_sel = JR_NEAR_FORCED;
+ d.op_sel = JMP_NEAR_FORCED;
+ break;
+ case OPTM_Far:
+ d.op_sel = JMP_FAR;
+ d.far_op_len = info->opcode_len;
+ d.far_op[0] = info->opcode[0];
+ d.far_op[1] = info->opcode[1];
+ d.far_op[2] = info->opcode[2];
break;
default:
- d.op_sel = JR_NONE;
+ d.op_sel = JMP_NONE;
}
/* Set operand size */
- d.opersize = jrinfo->opersize;
+ d.opersize = jinfo->opersize;
/* Check for address size setting in second operand, if present */
- if (jrinfo->num_operands > 1 &&
- (jrinfo->operands[1] & OPA_MASK) == OPA_AdSizeR)
- d.addrsize = (unsigned char)size_lookup[(jrinfo->operands[1] &
+ if (jinfo->num_operands > 1 &&
+ (jinfo->operands[1] & OPA_MASK) == OPA_AdSizeR)
+ d.addrsize = (unsigned char)size_lookup[(jinfo->operands[1] &
OPS_MASK)>>OPS_SHIFT];
else
d.addrsize = 0;
/* Check for address size override */
- if (jrinfo->modifiers & MOD_AdSizeR)
+ if (jinfo->modifiers & MOD_AdSizeR)
d.addrsize = (unsigned char)(mod_data & 0xFF);
/* Scan through other infos for this insn looking for short/near versions.
@@ -1601,11 +1631,15 @@
d.near_op[2] = info->opcode[2];
if (info->modifiers & MOD_Op1Add)
d.near_op[1] += (unsigned char)(mod_data & 0xFF);
+ if ((info->operands[0] & OPAP_MASK) == OPAP_JmpFar) {
+ d.far_op_len = 1;
+ d.far_op[0] = info->opcode[info->opcode_len];
+ }
break;
}
}
- return yasm_x86__bc_new_jmprel(&d);
+ return yasm_x86__bc_new_jmp(&d);
}
yasm_bytecode *
@@ -1906,8 +1940,8 @@
/* Shortcut to JmpRel */
if (operands && (info->operands[0] & OPA_MASK) == OPA_JmpRel)
- return x86_new_jmprel(data, num_operands, operands, info, cur_section,
- prev_bc, lindex);
+ return x86_new_jmp(data, num_operands, operands, info, cur_section,
+ prev_bc, lindex);
/* Copy what we can from info */
d.lindex = lindex;
diff --git a/yasm/modules/optimizers/basic/basic-optimizer.c b/yasm/modules/optimizers/basic/basic-optimizer.c
index ff47e17..4d2e1bd 100644
--- a/yasm/modules/optimizers/basic/basic-optimizer.c
+++ b/yasm/modules/optimizers/basic/basic-optimizer.c
@@ -66,7 +66,8 @@
if (dist < precbc1->offset + precbc1->len) {
intn = yasm_intnum_new_uint(precbc1->offset +
precbc1->len - dist);
- yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
+ yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL,
+ precbc1->line);
return intn;
}
dist -= precbc1->offset + precbc1->len;
@@ -82,7 +83,7 @@
if (precbc1) {
if (precbc1->opt_flags == BCFLAG_DONE) {
intn = yasm_intnum_new_uint(precbc1->offset + precbc1->len);
- yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
+ yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, precbc1->line);
return intn;
} else {
return NULL;