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;