]> granicus.if.org Git - yasm/commitdiff
Restructure bc_calc_len() family into bc_resolve() family. Many many many
authorPeter Johnson <peter@tortall.net>
Mon, 18 Mar 2002 07:16:52 +0000 (07:16 -0000)
committerPeter Johnson <peter@tortall.net>
Mon, 18 Mar 2002 07:16:52 +0000 (07:16 -0000)
bugfixes to the bc_tobytes() family and other functions.  Binary object output
is now close to complete: just a few more bugs to kill!

svn path=/trunk/yasm/; revision=528

16 files changed:
libyasm/arch.h
libyasm/bytecode.c
libyasm/bytecode.h
modules/arch/x86/x86-int.h
modules/arch/x86/x86arch.c
modules/arch/x86/x86bc.c
modules/objfmts/bin/bin-objfmt.c
modules/optimizers/basic/basic-optimizer.c
src/arch.h
src/arch/x86/x86-int.h
src/arch/x86/x86arch.c
src/arch/x86/x86bc.c
src/bytecode.c
src/bytecode.h
src/objfmts/bin/bin-objfmt.c
src/optimizers/basic/basic-optimizer.c

index 4fb5aa58fab815a0c3f2a65d7e88cfeceeb022f5..86779b04804e9e381bf2a2ee15bd140d925e3094 100644 (file)
@@ -39,14 +39,13 @@ struct arch {
        void (*bc_delete) (bytecode *bc);
        void (*bc_print) (FILE *f, const bytecode *bc);
 
-       /* See bytecode.h comments on bc_calc_len() */
-       int (*bc_calc_len) (bytecode *bc, const section *sect,
-                           resolve_label_func resolve_label);
+       /* See bytecode.h comments on bc_resolve() */
+       int (*bc_resolve) (bytecode *bc, int save, const section *sect,
+                          resolve_label_func resolve_label);
        /* See bytecode.h comments on bc_tobytes() */
        int (*bc_tobytes) (bytecode *bc, unsigned char **bufp,
                           const section *sect, void *d,
-                          output_expr_func output_expr,
-                          resolve_label_func resolve_label);
+                          output_expr_func output_expr);
     } bc;
 };
 
index 6b78ebe538e7fa6b0d1dc8e6444b6f6fbfe50470..dc13e5102f9a3c8ec10b840f47222a28b8cb92cc 100644 (file)
@@ -293,7 +293,7 @@ bc_print(FILE *f, const bytecode *bc)
 }
 
 static int
-bc_calc_len_data(bytecode_data *bc_data, unsigned long *len)
+bc_resolve_data(bytecode_data *bc_data, unsigned long *len)
 {
     dataval *dv;
     size_t slen;
@@ -319,17 +319,24 @@ bc_calc_len_data(bytecode_data *bc_data, unsigned long *len)
 }
 
 static int
-bc_calc_len_reserve(bytecode_reserve *reserve, unsigned long *len,
-                   const section *sect, resolve_label_func resolve_label)
+bc_resolve_reserve(bytecode_reserve *reserve, unsigned long *len, int save,
+                  const section *sect, resolve_label_func resolve_label)
 {
     int retval = 1;
     /*@null@*/ expr *temp;
+    expr **tempp;
     /*@dependent@*/ /*@null@*/ const intnum *num;
 
-    temp = expr_copy(reserve->numitems);
-    assert(temp != NULL);
-    expr_expand_labelequ(temp, sect, 1, resolve_label);
-    num = expr_get_intnum(&temp);
+    if (save) {
+       temp = NULL;
+       tempp = &reserve->numitems;
+    } else {
+       temp = expr_copy(reserve->numitems);
+       assert(temp != NULL);
+       tempp = &temp;
+    }
+    expr_expand_labelequ(*tempp, sect, 1, resolve_label);
+    num = expr_get_intnum(tempp);
     if (!num)
        retval = -1;
     else
@@ -339,21 +346,28 @@ bc_calc_len_reserve(bytecode_reserve *reserve, unsigned long *len,
 }
 
 static int
-bc_calc_len_incbin(bytecode_incbin *incbin, unsigned long *len,
-                  unsigned long line, const section *sect,
-                  resolve_label_func resolve_label)
+bc_resolve_incbin(bytecode_incbin *incbin, unsigned long *len, int save,
+                 unsigned long line, const section *sect,
+                 resolve_label_func resolve_label)
 {
     FILE *f;
     /*@null@*/ expr *temp;
+    expr **tempp;
     /*@dependent@*/ /*@null@*/ const intnum *num;
     unsigned long start = 0, maxlen = 0xFFFFFFFFUL, flen;
 
     /* Try to convert start to integer value */
     if (incbin->start) {
-       temp = expr_copy(incbin->start);
-       assert(temp != NULL);
-       expr_expand_labelequ(temp, sect, 1, resolve_label);
-       num = expr_get_intnum(&temp);
+       if (save) {
+           temp = NULL;
+           tempp = &incbin->start;
+       } else {
+           temp = expr_copy(incbin->start);
+           assert(temp != NULL);
+           tempp = &temp;
+       }
+       expr_expand_labelequ(*tempp, sect, 1, resolve_label);
+       num = expr_get_intnum(tempp);
        if (num)
            start = intnum_get_uint(num);
        expr_delete(temp);
@@ -363,10 +377,16 @@ bc_calc_len_incbin(bytecode_incbin *incbin, unsigned long *len,
 
     /* Try to convert maxlen to integer value */
     if (incbin->maxlen) {
-       temp = expr_copy(incbin->maxlen);
-       assert(temp != NULL);
-       expr_expand_labelequ(temp, sect, 1, resolve_label);
-       num = expr_get_intnum(&temp);
+       if (save) {
+           temp = NULL;
+           tempp = &incbin->maxlen;
+       } else {
+           temp = expr_copy(incbin->maxlen);
+           assert(temp != NULL);
+           tempp = &temp;
+       }
+       expr_expand_labelequ(*tempp, sect, 1, resolve_label);
+       num = expr_get_intnum(tempp);
        if (num)
            maxlen = intnum_get_uint(num);
        expr_delete(temp);
@@ -374,7 +394,9 @@ bc_calc_len_incbin(bytecode_incbin *incbin, unsigned long *len,
            return -1;
     }
 
-    /* FIXME: Search include path for filename */
+    /* FIXME: Search include path for filename.  Save full path back into
+     * filename if save is true.
+     */
 
     /* Open file and determine its length */
     f = fopen(incbin->filename, "rb");
@@ -406,14 +428,15 @@ bc_calc_len_incbin(bytecode_incbin *incbin, unsigned long *len,
 }
 
 int
-bc_calc_len(bytecode *bc, const section *sect,
-           resolve_label_func resolve_label)
+bc_resolve(bytecode *bc, int save, const section *sect,
+          resolve_label_func resolve_label)
 {
     int retval = 1;
     bytecode_data *bc_data;
     bytecode_reserve *reserve;
     bytecode_incbin *incbin;
     /*@null@*/ expr *temp;
+    expr **tempp;
     /*@dependent@*/ /*@null@*/ const intnum *num;
 
     bc->len = 0;       /* start at 0 */
@@ -423,31 +446,38 @@ bc_calc_len(bytecode *bc, const section *sect,
            InternalError(_("got empty bytecode in bc_calc_len"));
        case BC_DATA:
            bc_data = bc_get_data(bc);
-           retval = bc_calc_len_data(bc_data, &bc->len);
+           retval = bc_resolve_data(bc_data, &bc->len);
            break;
        case BC_RESERVE:
            reserve = bc_get_data(bc);
-           retval = bc_calc_len_reserve(reserve, &bc->len, sect,
-                                        resolve_label);
+           retval = bc_resolve_reserve(reserve, &bc->len, save, sect,
+                                       resolve_label);
            break;
        case BC_INCBIN:
            incbin = bc_get_data(bc);
-           retval = bc_calc_len_incbin(incbin, &bc->len, bc->line, sect,
-                                       resolve_label);
+           retval = bc_resolve_incbin(incbin, &bc->len, save, bc->line, sect,
+                                      resolve_label);
            break;
        default:
            if (bc->type < cur_arch->bc.type_max)
-               retval = cur_arch->bc.bc_calc_len(bc, sect, resolve_label);
+               retval = cur_arch->bc.bc_resolve(bc, save, sect,
+                                                resolve_label);
            else
                InternalError(_("Unknown bytecode type"));
     }
 
     /* Multiply len by number of multiples */
     if (bc->multiple) {
-       temp = expr_copy(bc->multiple);
-       assert(temp != NULL);
-       expr_expand_labelequ(temp, sect, 1, resolve_label);
-       num = expr_get_intnum(&temp);
+       if (save) {
+           temp = NULL;
+           tempp = &bc->multiple;
+       } else {
+           temp = expr_copy(bc->multiple);
+           assert(temp != NULL);
+           tempp = &temp;
+       }
+       expr_expand_labelequ(*tempp, sect, 1, resolve_label);
+       num = expr_get_intnum(tempp);
        if (!num)
            retval = -1;
        else
@@ -496,21 +526,14 @@ bc_tobytes_data(bytecode_data *bc_data, unsigned char **bufp,
 
 static int
 bc_tobytes_reserve(bytecode_reserve *reserve, unsigned char **bufp,
-                  const section *sect, resolve_label_func resolve_label)
+                  unsigned long len)
 {
-    /*@dependent@*/ /*@null@*/ const intnum *num;
-    unsigned long numitems, i;
-
-    expr_expand_labelequ(reserve->numitems, sect, 1, resolve_label);
-    num = expr_get_intnum(&reserve->numitems);
-    if (!num)
-       InternalError(_("could not determine number of items in bc_tobytes_reserve"));
-    numitems = intnum_get_uint(num)*reserve->itemsize;
+    unsigned long i;
 
     /* Go ahead and zero the bytes.  Probably most objfmts will want it
      * zero'd if they're actually going to output it.
      */
-    for (i=0; i<numitems; i++)
+    for (i=0; i<len; i++)
        WRITE_BYTE(*bufp, 0);
 
     return 0;
@@ -518,24 +541,20 @@ bc_tobytes_reserve(bytecode_reserve *reserve, unsigned char **bufp,
 
 static int
 bc_tobytes_incbin(bytecode_incbin *incbin, unsigned char **bufp,
-                 unsigned long buflen, unsigned long line,
-                 const section *sect, resolve_label_func resolve_label)
+                 unsigned long len, unsigned long line)
 {
     FILE *f;
     /*@dependent@*/ /*@null@*/ const intnum *num;
     unsigned long start = 0;
 
-    /* Try to convert start to integer value */
+    /* Convert start to integer value */
     if (incbin->start) {
-       expr_expand_labelequ(incbin->start, sect, 1, resolve_label);
        num = expr_get_intnum(&incbin->start);
        if (!num)
            InternalError(_("could not determine start in bc_tobytes_incbin"));
        start = intnum_get_uint(num);
     }
 
-    /* FIXME: Search include path for filename */
-
     /* Open file */
     f = fopen(incbin->filename, "rb");
     if (!f) {
@@ -552,15 +571,15 @@ bc_tobytes_incbin(bytecode_incbin *incbin, unsigned char **bufp,
        return 1;
     }
 
-    /* Read buflen bytes */
-    if (fread(*bufp, buflen, 1, f) < buflen) {
+    /* Read len bytes */
+    if (fread(*bufp, len, 1, f) < len) {
        ErrorAt(line, _("`incbin': unable to read %lu bytes from file `%s'"),
-               buflen, incbin->filename);
+               len, incbin->filename);
        fclose(f);
        return 1;
     }
 
-    *bufp += buflen;
+    *bufp += len;
     fclose(f);
     return 0;
 }
@@ -568,22 +587,36 @@ bc_tobytes_incbin(bytecode_incbin *incbin, unsigned char **bufp,
 /*@null@*/ /*@only@*/ unsigned char *
 bc_tobytes(bytecode *bc, unsigned char *buf, unsigned long *bufsize,
           /*@out@*/ unsigned long *multiple, /*@out@*/ int *gap,
-          const section *sect, void *d, output_expr_func output_expr,
-          resolve_label_func resolve_label)
+          const section *sect, void *d, output_expr_func output_expr)
 {
     /*@only@*/ /*@null@*/ unsigned char *mybuf = NULL;
-    unsigned char *destbuf;
+    unsigned char *origbuf, *destbuf;
     /*@dependent@*/ /*@null@*/ const intnum *num;
     bytecode_data *bc_data;
     bytecode_reserve *reserve;
     bytecode_incbin *incbin;
+    unsigned long datasize;
     int error = 0;
 
-    if (*bufsize < bc->len) {
+    if (bc->multiple) {
+       num = expr_get_intnum(&bc->multiple);
+       if (!num)
+           InternalError(_("could not determine multiple in bc_tobytes"));
+       *multiple = intnum_get_uint(num);
+    } else
+       *multiple = 1;
+
+    datasize = bc->len / (*multiple);
+
+    if (*bufsize < datasize) {
        mybuf = xmalloc(sizeof(bc->len));
+       origbuf = mybuf;
        destbuf = mybuf;
-    } else
+    } else {
+       origbuf = buf;
        destbuf = buf;
+    }
+    *bufsize = datasize;
 
     *gap = 0;
 
@@ -597,33 +630,23 @@ bc_tobytes(bytecode *bc, unsigned char *buf, unsigned long *bufsize,
            break;
        case BC_RESERVE:
            reserve = bc_get_data(bc);
-           error = bc_tobytes_reserve(reserve, &destbuf, sect, resolve_label);
+           error = bc_tobytes_reserve(reserve, &destbuf, bc->len);
            *gap = 1;
            break;
        case BC_INCBIN:
            incbin = bc_get_data(bc);
-           error = bc_tobytes_incbin(incbin, &destbuf, bc->len, bc->line,
-                                     sect, resolve_label);
+           error = bc_tobytes_incbin(incbin, &destbuf, bc->len, bc->line);
            break;
        default:
            if (bc->type < cur_arch->bc.type_max)
                error = cur_arch->bc.bc_tobytes(bc, &destbuf, sect, d,
-                                               output_expr, resolve_label);
+                                               output_expr);
            else
                InternalError(_("Unknown bytecode type"));
     }
 
-    if (bc->multiple) {
-       expr_expand_labelequ(bc->multiple, sect, 1, resolve_label);
-       num = expr_get_intnum(&bc->multiple);
-       if (!num)
-           InternalError(_("could not determine multiple in bc_tobytes"));
-       *multiple = intnum_get_uint(num);
-    } else
-       *multiple = 1;
-    if (!error && ((destbuf - buf) != bc->len))
+    if (!error && ((destbuf - origbuf) != datasize))
        InternalError(_("written length does not match optimized length"));
-    *bufsize = bc->len;
     return mybuf;
 }
 
index f011b6ecf12955cecfaf9c4ab7c1be443449f49b..0dbf5c4d1ee22c5a7690edc9af1d829adda84073 100644 (file)
@@ -58,18 +58,22 @@ void bc_delete(/*@only@*/ /*@null@*/ bytecode *bc);
 
 void bc_print(FILE *f, const bytecode *bc);
 
-/* Calculates length of bytecode, saving in bc structure.
+/* Resolves labels in bytecode, and calculates its length.
+ * Tries to minimize the length as much as possible.
  * Returns whether the length is the minimum possible (1=yes, 0=no).
  * Returns -1 if the length was indeterminate.
+ * Note: sometimes it's impossible to determine if a length is the minimum
+ *       possible.  In this case, this function returns that the length is NOT
+ *       the minimum.
  * resolve_label is the function used to determine the value (offset) of a
  *  in-file label (eg, not an EXTERN variable, which is indeterminate).
- * This function does *not* modify bc other than the length/size values (eg
- *  it doesn't keep the values returned by resolve_label except temporarily to
- *  try to minimize the length).
- * sect is passed along to resolve_label.
+ * When save is zero, this function does *not* modify bc other than the
+ * length/size values (i.e. it doesn't keep the values returned by
+ * resolve_label except temporarily to try to minimize the length).
+ * When save is nonzero, all fields in bc may be modified by this function.
  */
-int bc_calc_len(bytecode *bc, const section *sect,
-               resolve_label_func resolve_label);
+int bc_resolve(bytecode *bc, int save, const section *sect,
+              resolve_label_func resolve_label);
 
 /* Converts the bytecode bc into its byte representation.
  * Inputs:
@@ -78,17 +82,6 @@ int bc_calc_len(bytecode *bc, const section *sect,
  *  bufsize       - the size of buf
  *  d             - the data to pass to each call to output_expr()
  *  output_expr   - the function to call to convert expressions to byte rep
- *   output_expr inputs:
- *    bc      - the bytecode containing the expr that is being output
- *    ep      - a pointer to the expression to output
- *    bufp    - pointer to pointer to buffer to contain byte representation
- *    valsize - the size (in bytes) to be used for the byte rep
- *    d       - the data passed into bc_tobytes
- *   output_expr returns nonzero if an error occurred, 0 otherwise
- *  resolve_label - the function to call to determine the values of
- *                  expressions that are *not* output to the file
- *   resolve_label inputs:
- *    sym - the symbol to resolve
  * Outputs:
  *  bufsize       - the size of the generated data.
  *  multiple      - the number of times the data should be dup'ed when output
@@ -102,7 +95,7 @@ int bc_calc_len(bytecode *bc, const section *sect,
 /*@null@*/ /*@only@*/ unsigned char *bc_tobytes(bytecode *bc,
     unsigned char *buf, unsigned long *bufsize,
     /*@out@*/ unsigned long *multiple, /*@out@*/ int *gap, const section *sect,
-    void *d, output_expr_func output_expr, resolve_label_func resolve_label);
+    void *d, output_expr_func output_expr);
 
 /* void bcs_initialize(bytecodehead *headp); */
 #define        bcs_initialize(headp)   STAILQ_INIT(headp)
index ce867271334c0c959ede4a5c0d7744c9ae4a302a..f027c3a651805a5c7bdea42760508d0fb219fe7e 100644 (file)
@@ -96,11 +96,10 @@ typedef struct x86_jmprel {
 
 void x86_bc_delete(bytecode *bc);
 void x86_bc_print(FILE *f, const bytecode *bc);
-int x86_bc_calc_len(bytecode *bc, const section *sect,
-                   resolve_label_func resolve_label);
-int x86_bc_tobytes(bytecode *bc, unsigned char **bufp, const section *sect,
-                  void *d, output_expr_func output_expr,
+int x86_bc_resolve(bytecode *bc, int save, const section *sect,
                   resolve_label_func resolve_label);
+int x86_bc_tobytes(bytecode *bc, unsigned char **bufp, const section *sect,
+                  void *d, output_expr_func output_expr);
 
 int x86_expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
                     unsigned char nosplit, unsigned char *displen,
index 3d8bec49ec89392a45c9f44042e5dd57fb1e8c56..755e8bed5ea2420c950ce254c062049a31c2959a 100644 (file)
@@ -38,7 +38,7 @@ arch x86_arch = {
        X86_BYTECODE_TYPE_MAX,
        x86_bc_delete,
        x86_bc_print,
-       x86_bc_calc_len,
+       x86_bc_resolve,
        x86_bc_tobytes
     }
 };
index 939b8999606fe3720f66584f9f33929468371b11..7a0f06fdc8a3f9b59858e5f41e5e6a188cbbc8a6 100644 (file)
@@ -463,8 +463,8 @@ x86_bc_print(FILE *f, const bytecode *bc)
 }
 
 static int
-x86_bc_calc_len_insn(x86_insn *insn, unsigned long *len, const section *sect,
-                    resolve_label_func resolve_label)
+x86_bc_resolve_insn(x86_insn *insn, unsigned long *len, int save,
+                   const section *sect, resolve_label_func resolve_label)
 {
     /*@null@*/ expr *temp;
     effaddr *ea = insn->ea;
@@ -499,35 +499,25 @@ x86_bc_calc_len_insn(x86_insn *insn, unsigned long *len, const section *sect,
                return -1;   /* failed, don't bother checking rest of insn */
            }
 
-           if (!temp) {
-               /* If the expression was deleted (temp=NULL), then make the
-                * temp info permanent.
-                */
+           expr_delete(temp);
 
-               /* Delete the "real" expression */
-               expr_delete(ea->disp);
-               ea->disp = NULL;
-               *ead = ead_t;   /* structure copy */
-               ea->len = displen;
-           } else if (displen == 1) {
-               /* Fits into a byte.  We'll assume it never gets bigger, so
-                * make temp info permanent, but NOT the expr itself (as that
-                * may change).
-                */
-               expr_delete(temp);
-               *ead = ead_t;   /* structure copy */
-               ea->len = displen;
-           } else {
-               /* Fits into a word/dword, or unknown.  As this /may/ change in
-                * a future pass, so discard temp info.
-                */
-               expr_delete(temp);
+           if (displen != 1) {
+               /* Fits into a word/dword, or unknown. */
                retval = 0;         /* may not be smallest size */
 
                /* Handle unknown case, make displen word-sized */
                if (displen == 0xff)
                    displen = (insn->addrsize == 32) ? 4 : 2;
            }
+
+           if (save) {
+               *ead = ead_t;   /* structure copy */
+               ea->len = displen;
+               if (displen == 0 && ea->disp) {
+                   expr_delete(ea->disp);
+                   ea->disp = NULL;
+               }
+           }
        }
 
        /* Compute length of ea and add to total */
@@ -552,8 +542,21 @@ x86_bc_calc_len_insn(x86_insn *insn, unsigned long *len, const section *sect,
                     * (as we add it back in below).
                     */
                    *len -= imm->len;
+
+                   if (save) {
+                       /* Make the ,1 form permanent. */
+                       insn->opcode[0] = insn->opcode[1];
+                       /* Delete imm, as it's not needed. */
+                       expr_delete(imm->val);
+                       xfree(imm);
+                       insn->imm = (immval *)NULL;
+                   }
                } else
                    retval = 0;     /* we could still get ,1 */
+
+               /* Not really necessary, but saves confusion over it. */
+               if (save)
+                   insn->shift_op = 0;
            }
 
            expr_delete(temp);
@@ -571,9 +574,9 @@ x86_bc_calc_len_insn(x86_insn *insn, unsigned long *len, const section *sect,
 }
 
 static int
-x86_bc_calc_len_jmprel(x86_jmprel *jmprel, unsigned long *len,
-                      unsigned long offset, const section *sect,
-                      resolve_label_func resolve_label)
+x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save,
+                     const bytecode *bc, const section *sect,
+                     resolve_label_func resolve_label)
 {
     int retval = 1;
     /*@null@*/ expr *temp;
@@ -587,17 +590,44 @@ x86_bc_calc_len_jmprel(x86_jmprel *jmprel, unsigned long *len,
     opersize = (jmprel->opersize == 0) ? jmprel->mode_bits :
        jmprel->opersize;
 
-    /* We don't check here to see if forced forms are actually legal; we
-     * assume that they are, and only check it in x86_bc_tobytes_jmprel().
+    /* 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:
            /* 1 byte relative displacement */
            jrshort = 1;
+           if (save) {
+               if (!num) {
+                   ErrorAt(bc->line,
+                           _("short jump target external or out of segment"));
+                   return -1;
+               } else {
+                   target = intnum_get_uint(num);
+                   rel = (long)(target -
+                                (bc->offset+jmprel->shortop.opcode_len+1));
+                   /* does a short form exist? */
+                   if (jmprel->shortop.opcode_len == 0) {
+                       ErrorAt(bc->line, _("short jump does not exist"));
+                       return -1;
+                   }
+                   /* short displacement must fit in -128 <= rel <= +127 */
+                   if (rel < -128 || rel > 127) {
+                       ErrorAt(bc->line, _("short jump out of range"));
+                       return -1;
+                   }
+               }
+           }
            break;
        case JR_NEAR_FORCED:
            /* 2/4 byte relative displacement (depending on operand size) */
            jrshort = 0;
+           if (save) {
+               if (jmprel->nearop.opcode_len == 0) {
+                   ErrorAt(bc->line, _("near jump does not exist"));
+                   return -1;
+               }
+           }
            break;
        default:
            /* Try to find shortest displacement based on difference between
@@ -611,42 +641,63 @@ x86_bc_calc_len_jmprel(x86_jmprel *jmprel, unsigned long *len,
            num = expr_get_intnum(&temp);
            if (num) {
                target = intnum_get_uint(num);
-               rel = (long)(target-(offset+jmprel->shortop.opcode_len+1));
+               rel = (long)(target-(bc->offset+jmprel->shortop.opcode_len+1));
                /* short displacement must fit within -128 <= rel <= +127 */
                if (jmprel->shortop.opcode_len != 0 && rel >= -128 &&
                    rel <= 127) {
                    /* It fits into a short displacement. */
                    jrshort = 1;
-               } else {
+               } else if (jmprel->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)
                        retval = 0;
+               } else {
+                   /* Doesn't fit into short, and there's no near opcode.
+                    * Error out if saving, otherwise just make it a short
+                    * (in the hopes that a short might make it possible for
+                    * it to actually be within short range).
+                    */
+                   if (save) {
+                       ErrorAt(bc->line, _("short jump out of range"));
+                       return -1;
+                   }
+                   jrshort = 1;
                }
            } else {
-               /* It's unknown (e.g. out of this segment or external).
-                * Thus, assume near displacement.  If a near opcode is not
-                * available, use a short opcode instead.
+               /* 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)
                        retval = 0;
                    jrshort = 0;
-               } else
+               } else {
+                   if (save) {
+                       ErrorAt(bc->line,
+                               _("short jump target or out of segment"));
+                       return -1;
+                   }
                    jrshort = 1;
+               }
            }
            expr_delete(temp);
            break;
     }
 
     if (jrshort) {
+       if (save)
+           jmprel->op_sel = JR_SHORT;
        if (jmprel->shortop.opcode_len == 0)
            return -1;      /* uh-oh, that size not available */
 
        *len += jmprel->shortop.opcode_len + 1;
     } else {
+       if (save)
+           jmprel->op_sel = JR_NEAR;
        if (jmprel->nearop.opcode_len == 0)
            return -1;      /* uh-oh, that size not available */
 
@@ -663,8 +714,8 @@ x86_bc_calc_len_jmprel(x86_jmprel *jmprel, unsigned long *len,
 }
 
 int
-x86_bc_calc_len(bytecode *bc, const section *sect,
-               resolve_label_func resolve_label)
+x86_bc_resolve(bytecode *bc, int save, const section *sect,
+              resolve_label_func resolve_label)
 {
     x86_insn *insn;
     x86_jmprel *jmprel;
@@ -672,11 +723,12 @@ x86_bc_calc_len(bytecode *bc, const section *sect,
     switch ((x86_bytecode_type)bc->type) {
        case X86_BC_INSN:
            insn = bc_get_data(bc);
-           return x86_bc_calc_len_insn(insn, &bc->len, sect, resolve_label);
+           return x86_bc_resolve_insn(insn, &bc->len, save, sect,
+                                      resolve_label);
        case X86_BC_JMPREL:
            jmprel = bc_get_data(bc);
-           return x86_bc_calc_len_jmprel(jmprel, &bc->len, bc->offset, sect,
-                                         resolve_label);
+           return x86_bc_resolve_jmprel(jmprel, &bc->len, save, bc, sect,
+                                        resolve_label);
        default:
            break;
     }
@@ -685,57 +737,13 @@ x86_bc_calc_len(bytecode *bc, const section *sect,
 
 static int
 x86_bc_tobytes_insn(x86_insn *insn, unsigned char **bufp, const section *sect,
-                   const bytecode *bc, void *d, output_expr_func output_expr,
-                   resolve_label_func resolve_label)
+                   const bytecode *bc, void *d, output_expr_func output_expr)
 {
     /*@null@*/ effaddr *ea = insn->ea;
     x86_effaddr_data *ead = ea_get_data(ea);
     immval *imm = insn->imm;
     unsigned int i;
 
-    /* We need to figure out the EA first to determine the addrsize.
-     * Of course, the ModR/M, SIB, and displacement are not output until later.
-     */
-    if (ea) {
-       if ((ea->disp) && ((!ead->valid_sib && ead->need_sib) ||
-                          (!ead->valid_modrm && ead->need_modrm))) {
-           /* Expand equ's and labels */
-           expr_expand_labelequ(ea->disp, sect, 1, resolve_label);
-
-           /* Check validity of effective address and calc R/M bits of
-            * Mod/RM byte and SIB byte.  We won't know the Mod field
-            * of the Mod/RM byte until we know more about the
-            * displacement.
-            */
-           if (!x86_expr_checkea(&ea->disp, &insn->addrsize, insn->mode_bits,
-                                 ea->nosplit, &ea->len, &ead->modrm,
-                                 &ead->valid_modrm, &ead->need_modrm,
-                                 &ead->sib, &ead->valid_sib,
-                                 &ead->need_sib))
-               InternalError(_("expr_checkea failed from x86 tobytes_insn"));
-       }
-    }
-
-    /* Also check for shift_op special-casing (affects imm). */
-    if (insn->shift_op && imm && imm->val) {
-       /*@dependent@*/ /*@null@*/ const intnum *num;
-
-       expr_expand_labelequ(imm->val, sect, 1, resolve_label);
-
-       num = expr_get_intnum(&imm->val);
-       if (num) {
-           if (intnum_get_uint(num) == 1) {
-               /* Use ,1 form: first copy ,1 opcode. */
-               insn->opcode[0] = insn->opcode[1];
-               /* Delete imm, as it's not needed. */
-               expr_delete(imm->val);
-               xfree(imm);
-               insn->imm = (immval *)NULL;
-           }
-           insn->shift_op = 0;
-       }
-    }
-
     /* Prefixes */
     if (insn->lockrep_pre != 0)
        WRITE_BYTE(*bufp, insn->lockrep_pre);
@@ -766,9 +774,35 @@ x86_bc_tobytes_insn(x86_insn *insn, unsigned char **bufp, const section *sect,
            WRITE_BYTE(*bufp, ead->sib);
        }
 
-       if (ea->disp)
-           if (output_expr(&ea->disp, bufp, ea->len, sect, bc, 0, d))
-               return 1;
+       if (ea->disp) {
+           x86_effaddr_data ead_t = *ead;  /* structure copy */
+           unsigned char displen = ea->len;
+           unsigned char addrsize = insn->addrsize;
+
+           ead_t.valid_modrm = 0;  /* force checkea to actually run */
+
+           /* Call checkea() to simplify the registers out of the
+            * displacement.  Throw away all of the return values except for
+            * the modified expr.
+            */
+           if (!x86_expr_checkea(&ea->disp, &addrsize, insn->mode_bits,
+                                 ea->nosplit, &displen, &ead_t.modrm,
+                                 &ead_t.valid_modrm, &ead_t.need_modrm,
+                                 &ead_t.sib, &ead_t.valid_sib,
+                                 &ead_t.need_sib))
+               InternalError(_("checkea failed"));
+
+           if (ea->disp) {
+               if (output_expr(&ea->disp, bufp, ea->len, sect, bc, 0, d))
+                   return 1;
+           } else {
+               /* 0 displacement, but we didn't know it before, so we have to
+                * write out 0 value.
+                */
+               for (i=0; i<ea->len; i++)
+                   WRITE_BYTE(*bufp, 0);
+           }
+       }
     }
 
     /* Immediate (if required) */
@@ -784,14 +818,9 @@ x86_bc_tobytes_insn(x86_insn *insn, unsigned char **bufp, const section *sect,
 static int
 x86_bc_tobytes_jmprel(x86_jmprel *jmprel, unsigned char **bufp,
                      const section *sect, const bytecode *bc, void *d,
-                     output_expr_func output_expr,
-                     resolve_label_func resolve_label)
+                     output_expr_func output_expr)
 {
-    /*@dependent@*/ /*@null@*/ const intnum *num;
-    unsigned long target;
-    long rel;
     unsigned char opersize;
-    int jrshort = 0;
     unsigned int i;
 
     /* Prefixes */
@@ -807,100 +836,48 @@ x86_bc_tobytes_jmprel(x86_jmprel *jmprel, unsigned char **bufp,
     opersize = (jmprel->opersize == 0) ? jmprel->mode_bits :
        jmprel->opersize;
 
-    /* Get displacement value here so that forced forms can be checked. */
-    expr_expand_labelequ(jmprel->target, sect, 0, resolve_label);
-    num = expr_get_intnum(&jmprel->target);
-
     /* Check here to see if forced forms are actually legal. */
     switch (jmprel->op_sel) {
        case JR_SHORT_FORCED:
+       case JR_SHORT:
            /* 1 byte relative displacement */
-           jrshort = 1;
-           if (!num) {
-               ErrorAt(bc->line,
-                       _("short jump target external or out of segment"));
+           if (jmprel->shortop.opcode_len == 0)
+               InternalError(_("short jump does not exist"));
+
+           /* Opcode */
+           for (i=0; i<jmprel->shortop.opcode_len; i++)
+               WRITE_BYTE(*bufp, jmprel->shortop.opcode[i]);
+
+           /* Relative displacement */
+           if (output_expr(&jmprel->target, bufp, 1, sect, bc, 1, d))
                return 1;
-           } else {
-               target = intnum_get_uint(num);
-               rel = (long)(target-(bc->offset+jmprel->shortop.opcode_len+1));
-               /* does a short form exist? */
-               if (jmprel->shortop.opcode_len == 0) {
-                   ErrorAt(bc->line, _("short jump does not exist"));
-                   return 1;
-               }
-               /* short displacement must fit within -128 <= rel <= +127 */
-               if (rel < -128 || rel > 127) {
-                   ErrorAt(bc->line, _("short jump out of range"));
-                   return 1;
-               }
-           }
            break;
        case JR_NEAR_FORCED:
+       case JR_NEAR:
            /* 2/4 byte relative displacement (depending on operand size) */
-           jrshort = 0;
            if (jmprel->nearop.opcode_len == 0) {
                ErrorAt(bc->line, _("near jump does not exist"));
                return 1;
            }
-           break;
-       default:
-           /* Try to find shortest displacement based on difference between
-            * target expr value and our (this bytecode's) offset.
-            */
-           if (num) {
-               target = intnum_get_uint(num);
-               rel = (long)(target-(bc->offset+jmprel->shortop.opcode_len+1));
-               /* short displacement must fit within -128 <= rel <= +127 */
-               if (jmprel->shortop.opcode_len != 0 && rel >= -128 &&
-                   rel <= 127) {
-                   /* It fits into a short displacement. */
-                   jrshort = 1;
-               } else {
-                   /* It's near. */
-                   jrshort = 0;
-                   if (jmprel->nearop.opcode_len == 0) {
-                       InternalError(_("near jump does not exist"));
-                       return 1;
-                   }
-               }
-           } else {
-               /* It's unknown (e.g. out of this segment or external).
-                * Thus, assume near displacement.  If a near opcode is not
-                * available, error out.
-                */
-               jrshort = 0;
-               if (jmprel->nearop.opcode_len == 0) {
-                   ErrorAt(bc->line,
-                           _("short jump target or out of segment"));
-                   return 1;
-               }
-           }
-           break;
-    }
 
-    if (jrshort) {
-       /* Opcode */
-       for (i=0; i<jmprel->shortop.opcode_len; i++)
-           WRITE_BYTE(*bufp, jmprel->shortop.opcode[i]);
+           /* Opcode */
+           for (i=0; i<jmprel->nearop.opcode_len; i++)
+               WRITE_BYTE(*bufp, jmprel->nearop.opcode[i]);
 
-       /* Relative displacement */
-       output_expr(&jmprel->target, bufp, 1, sect, bc, 1, d);
-    } else {
-       /* Opcode */
-       for (i=0; i<jmprel->nearop.opcode_len; i++)
-           WRITE_BYTE(*bufp, jmprel->nearop.opcode[i]);
-
-       /* Relative displacement */
-       output_expr(&jmprel->target, bufp, (opersize == 32) ? 4 : 2, sect, bc,
-                   1, d);
+           /* Relative displacement */
+           if (output_expr(&jmprel->target, bufp, (opersize == 32) ? 4 : 2,
+                           sect, bc, 1, d))
+               return 1;
+           break;
+       default:
+           InternalError(_("unrecognized relative jump op_sel"));
     }
     return 0;
 }
 
 int
 x86_bc_tobytes(bytecode *bc, unsigned char **bufp, const section *sect,
-              void *d, output_expr_func output_expr,
-              resolve_label_func resolve_label)
+              void *d, output_expr_func output_expr)
 {
     x86_insn *insn;
     x86_jmprel *jmprel;
@@ -908,16 +885,15 @@ x86_bc_tobytes(bytecode *bc, unsigned char **bufp, const section *sect,
     switch ((x86_bytecode_type)bc->type) {
        case X86_BC_INSN:
            insn = bc_get_data(bc);
-           return x86_bc_tobytes_insn(insn, bufp, sect, bc, d, output_expr,
-                                      resolve_label);
+           return x86_bc_tobytes_insn(insn, bufp, sect, bc, d, output_expr);
            break;
        case X86_BC_JMPREL:
            jmprel = bc_get_data(bc);
            return x86_bc_tobytes_jmprel(jmprel, bufp, sect, bc, d,
-                                        output_expr, resolve_label);
+                                        output_expr);
        default:
            break;
     }
-    return 1;
+    return 0;
 }
 
index 5af6dc492b56b6837b838b30874e080d05f39755..1e8a06cd5355803661c05743c07569d6e41224f7 100644 (file)
@@ -127,9 +127,6 @@ bin_objfmt_resolve_label2(symrec *sym, /*@null@*/ const section *cursect,
        startval -= cursectstart;
     }
 
-    /* If a section is done, the following will always succeed.  If it's in-
-     * progress, this will fail if the bytecode comes AFTER the current one.
-     */
     if (precbc)
        return intnum_new_int(startval + precbc->offset + precbc->len);
     else
@@ -249,8 +246,7 @@ bin_objfmt_output_bytecode(bytecode *bc, /*@null@*/ void *d)
     int gap;
 
     bigbuf = bc_tobytes(bc, info->buf, &size, &multiple, &gap, info->sect,
-                       info, bin_objfmt_output_expr,
-                       bin_objfmt_resolve_label);
+                       info, bin_objfmt_output_expr);
 
     /* Warn that gaps are converted to 0.  The 0 bytes are generated by
      * bc_tobytes() so no special handling is needed.
index a12ad29295524fd7c92cb78e0451018cc0bdb9ca..381d44a492ac614e06204240378e6c5e1469cb47 100644 (file)
@@ -94,6 +94,48 @@ basic_optimize_resolve_label(symrec *sym, int withstart)
     return NULL;
 }
 
+static /*@only@*/ /*@null@*/ intnum *
+basic_optimize_resolve_label_2(symrec *sym, int withstart)
+{
+    /*@dependent@*/ section *sect;
+    /*@dependent@*/ /*@null@*/ bytecode *precbc;
+    /*@null@*/ bytecode *bc;
+    /*@null@*/ expr *startexpr;
+    /*@dependent@*/ /*@null@*/ const intnum *start;
+    unsigned long startval = 0;
+
+    if (!symrec_get_label(sym, &sect, &precbc))
+       return NULL;
+
+    /* determine actual bc from preceding bc (how labels are stored) */
+    if (!precbc)
+       bc = bcs_first(section_get_bytecodes(sect));
+    else
+       bc = bcs_next(precbc);
+    assert(bc != NULL);
+
+    /* Figure out the starting offset of the entire section */
+    if (withstart || section_is_absolute(sect)) {
+       startexpr = expr_copy(section_get_start(sect));
+       assert(startexpr != NULL);
+       expr_expand_labelequ(startexpr, sect, 1,
+                            basic_optimize_resolve_label_2);
+       start = expr_get_intnum(&startexpr);
+       if (!start)
+           return NULL;
+       startval = intnum_get_uint(start);
+       expr_delete(startexpr);
+    }
+
+    /* If a section is done, the following will always succeed.  If it's in-
+     * progress, this will fail if the bytecode comes AFTER the current one.
+     */
+    if (precbc)
+       return intnum_new_int(startval + precbc->offset + precbc->len);
+    else
+       return intnum_new_int(startval + bc->offset);
+}
+
 typedef struct basic_optimize_data {
     bytecode *precbc;
     const section *sect;
@@ -122,7 +164,7 @@ basic_optimize_bytecode_1(bytecode *bc, void *d)
      * is minimum or not, and just check for indeterminate length (indicative
      * of circular reference).
      */
-    if (bc_calc_len(bc, data->sect, basic_optimize_resolve_label) < 0) {
+    if (bc_resolve(bc, 0, data->sect, basic_optimize_resolve_label) < 0) {
        ErrorAt(bc->line, _("Circular reference detected."));
        return -1;
     }
@@ -162,23 +204,41 @@ basic_optimize_section_1(section *sect, /*@unused@*/ /*@null@*/ void *d)
 }
 
 static int
-basic_optimize_bytecode_2(bytecode *bc, /*@unused@*/ /*@null@*/ void *d)
+basic_optimize_bytecode_2(bytecode *bc, /*@null@*/ void *d)
 {
+    basic_optimize_data *data = (basic_optimize_data *)d;
+
+    assert(data != NULL);
+
     if (bc->opt_flags != BCFLAG_DONE) {
        InternalError(_("Optimizer pass 1 missed a bytecode!"));
        return -1;
     }
+
+    if (!data->precbc)
+       bc->offset = 0;
+    else
+       bc->offset = data->precbc->offset + data->precbc->len;
+    data->precbc = bc;
+
+    if (bc_resolve(bc, 1, data->sect, basic_optimize_resolve_label_2) < 0)
+       return -1;
     return 0;
 }
 
 static int
 basic_optimize_section_2(section *sect, /*@unused@*/ /*@null@*/ void *d)
 {
+    basic_optimize_data data;
+
+    data.precbc = NULL;
+    data.sect = sect;
+
     if (section_get_opt_flags(sect) != SECTFLAG_DONE) {
        InternalError(_("Optimizer pass 1 missed a section!"));
        return -1;
     }
-    return bcs_traverse(section_get_bytecodes(sect), NULL,
+    return bcs_traverse(section_get_bytecodes(sect), &data,
                        basic_optimize_bytecode_2);
 }
 
@@ -200,7 +260,7 @@ basic_optimize(sectionhead *sections)
     if (sections_traverse(sections, NULL, basic_optimize_section_1) < 0)
        return;
 
-    /* FIXME: Really necessary?  Check completion of all sections */
+    /* Check completion of all sections and save bytecode changes */
     sections_traverse(sections, NULL, basic_optimize_section_2);
 }
 
index 4fb5aa58fab815a0c3f2a65d7e88cfeceeb022f5..86779b04804e9e381bf2a2ee15bd140d925e3094 100644 (file)
@@ -39,14 +39,13 @@ struct arch {
        void (*bc_delete) (bytecode *bc);
        void (*bc_print) (FILE *f, const bytecode *bc);
 
-       /* See bytecode.h comments on bc_calc_len() */
-       int (*bc_calc_len) (bytecode *bc, const section *sect,
-                           resolve_label_func resolve_label);
+       /* See bytecode.h comments on bc_resolve() */
+       int (*bc_resolve) (bytecode *bc, int save, const section *sect,
+                          resolve_label_func resolve_label);
        /* See bytecode.h comments on bc_tobytes() */
        int (*bc_tobytes) (bytecode *bc, unsigned char **bufp,
                           const section *sect, void *d,
-                          output_expr_func output_expr,
-                          resolve_label_func resolve_label);
+                          output_expr_func output_expr);
     } bc;
 };
 
index ce867271334c0c959ede4a5c0d7744c9ae4a302a..f027c3a651805a5c7bdea42760508d0fb219fe7e 100644 (file)
@@ -96,11 +96,10 @@ typedef struct x86_jmprel {
 
 void x86_bc_delete(bytecode *bc);
 void x86_bc_print(FILE *f, const bytecode *bc);
-int x86_bc_calc_len(bytecode *bc, const section *sect,
-                   resolve_label_func resolve_label);
-int x86_bc_tobytes(bytecode *bc, unsigned char **bufp, const section *sect,
-                  void *d, output_expr_func output_expr,
+int x86_bc_resolve(bytecode *bc, int save, const section *sect,
                   resolve_label_func resolve_label);
+int x86_bc_tobytes(bytecode *bc, unsigned char **bufp, const section *sect,
+                  void *d, output_expr_func output_expr);
 
 int x86_expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits,
                     unsigned char nosplit, unsigned char *displen,
index 3d8bec49ec89392a45c9f44042e5dd57fb1e8c56..755e8bed5ea2420c950ce254c062049a31c2959a 100644 (file)
@@ -38,7 +38,7 @@ arch x86_arch = {
        X86_BYTECODE_TYPE_MAX,
        x86_bc_delete,
        x86_bc_print,
-       x86_bc_calc_len,
+       x86_bc_resolve,
        x86_bc_tobytes
     }
 };
index 939b8999606fe3720f66584f9f33929468371b11..7a0f06fdc8a3f9b59858e5f41e5e6a188cbbc8a6 100644 (file)
@@ -463,8 +463,8 @@ x86_bc_print(FILE *f, const bytecode *bc)
 }
 
 static int
-x86_bc_calc_len_insn(x86_insn *insn, unsigned long *len, const section *sect,
-                    resolve_label_func resolve_label)
+x86_bc_resolve_insn(x86_insn *insn, unsigned long *len, int save,
+                   const section *sect, resolve_label_func resolve_label)
 {
     /*@null@*/ expr *temp;
     effaddr *ea = insn->ea;
@@ -499,35 +499,25 @@ x86_bc_calc_len_insn(x86_insn *insn, unsigned long *len, const section *sect,
                return -1;   /* failed, don't bother checking rest of insn */
            }
 
-           if (!temp) {
-               /* If the expression was deleted (temp=NULL), then make the
-                * temp info permanent.
-                */
+           expr_delete(temp);
 
-               /* Delete the "real" expression */
-               expr_delete(ea->disp);
-               ea->disp = NULL;
-               *ead = ead_t;   /* structure copy */
-               ea->len = displen;
-           } else if (displen == 1) {
-               /* Fits into a byte.  We'll assume it never gets bigger, so
-                * make temp info permanent, but NOT the expr itself (as that
-                * may change).
-                */
-               expr_delete(temp);
-               *ead = ead_t;   /* structure copy */
-               ea->len = displen;
-           } else {
-               /* Fits into a word/dword, or unknown.  As this /may/ change in
-                * a future pass, so discard temp info.
-                */
-               expr_delete(temp);
+           if (displen != 1) {
+               /* Fits into a word/dword, or unknown. */
                retval = 0;         /* may not be smallest size */
 
                /* Handle unknown case, make displen word-sized */
                if (displen == 0xff)
                    displen = (insn->addrsize == 32) ? 4 : 2;
            }
+
+           if (save) {
+               *ead = ead_t;   /* structure copy */
+               ea->len = displen;
+               if (displen == 0 && ea->disp) {
+                   expr_delete(ea->disp);
+                   ea->disp = NULL;
+               }
+           }
        }
 
        /* Compute length of ea and add to total */
@@ -552,8 +542,21 @@ x86_bc_calc_len_insn(x86_insn *insn, unsigned long *len, const section *sect,
                     * (as we add it back in below).
                     */
                    *len -= imm->len;
+
+                   if (save) {
+                       /* Make the ,1 form permanent. */
+                       insn->opcode[0] = insn->opcode[1];
+                       /* Delete imm, as it's not needed. */
+                       expr_delete(imm->val);
+                       xfree(imm);
+                       insn->imm = (immval *)NULL;
+                   }
                } else
                    retval = 0;     /* we could still get ,1 */
+
+               /* Not really necessary, but saves confusion over it. */
+               if (save)
+                   insn->shift_op = 0;
            }
 
            expr_delete(temp);
@@ -571,9 +574,9 @@ x86_bc_calc_len_insn(x86_insn *insn, unsigned long *len, const section *sect,
 }
 
 static int
-x86_bc_calc_len_jmprel(x86_jmprel *jmprel, unsigned long *len,
-                      unsigned long offset, const section *sect,
-                      resolve_label_func resolve_label)
+x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save,
+                     const bytecode *bc, const section *sect,
+                     resolve_label_func resolve_label)
 {
     int retval = 1;
     /*@null@*/ expr *temp;
@@ -587,17 +590,44 @@ x86_bc_calc_len_jmprel(x86_jmprel *jmprel, unsigned long *len,
     opersize = (jmprel->opersize == 0) ? jmprel->mode_bits :
        jmprel->opersize;
 
-    /* We don't check here to see if forced forms are actually legal; we
-     * assume that they are, and only check it in x86_bc_tobytes_jmprel().
+    /* 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:
            /* 1 byte relative displacement */
            jrshort = 1;
+           if (save) {
+               if (!num) {
+                   ErrorAt(bc->line,
+                           _("short jump target external or out of segment"));
+                   return -1;
+               } else {
+                   target = intnum_get_uint(num);
+                   rel = (long)(target -
+                                (bc->offset+jmprel->shortop.opcode_len+1));
+                   /* does a short form exist? */
+                   if (jmprel->shortop.opcode_len == 0) {
+                       ErrorAt(bc->line, _("short jump does not exist"));
+                       return -1;
+                   }
+                   /* short displacement must fit in -128 <= rel <= +127 */
+                   if (rel < -128 || rel > 127) {
+                       ErrorAt(bc->line, _("short jump out of range"));
+                       return -1;
+                   }
+               }
+           }
            break;
        case JR_NEAR_FORCED:
            /* 2/4 byte relative displacement (depending on operand size) */
            jrshort = 0;
+           if (save) {
+               if (jmprel->nearop.opcode_len == 0) {
+                   ErrorAt(bc->line, _("near jump does not exist"));
+                   return -1;
+               }
+           }
            break;
        default:
            /* Try to find shortest displacement based on difference between
@@ -611,42 +641,63 @@ x86_bc_calc_len_jmprel(x86_jmprel *jmprel, unsigned long *len,
            num = expr_get_intnum(&temp);
            if (num) {
                target = intnum_get_uint(num);
-               rel = (long)(target-(offset+jmprel->shortop.opcode_len+1));
+               rel = (long)(target-(bc->offset+jmprel->shortop.opcode_len+1));
                /* short displacement must fit within -128 <= rel <= +127 */
                if (jmprel->shortop.opcode_len != 0 && rel >= -128 &&
                    rel <= 127) {
                    /* It fits into a short displacement. */
                    jrshort = 1;
-               } else {
+               } else if (jmprel->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)
                        retval = 0;
+               } else {
+                   /* Doesn't fit into short, and there's no near opcode.
+                    * Error out if saving, otherwise just make it a short
+                    * (in the hopes that a short might make it possible for
+                    * it to actually be within short range).
+                    */
+                   if (save) {
+                       ErrorAt(bc->line, _("short jump out of range"));
+                       return -1;
+                   }
+                   jrshort = 1;
                }
            } else {
-               /* It's unknown (e.g. out of this segment or external).
-                * Thus, assume near displacement.  If a near opcode is not
-                * available, use a short opcode instead.
+               /* 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)
                        retval = 0;
                    jrshort = 0;
-               } else
+               } else {
+                   if (save) {
+                       ErrorAt(bc->line,
+                               _("short jump target or out of segment"));
+                       return -1;
+                   }
                    jrshort = 1;
+               }
            }
            expr_delete(temp);
            break;
     }
 
     if (jrshort) {
+       if (save)
+           jmprel->op_sel = JR_SHORT;
        if (jmprel->shortop.opcode_len == 0)
            return -1;      /* uh-oh, that size not available */
 
        *len += jmprel->shortop.opcode_len + 1;
     } else {
+       if (save)
+           jmprel->op_sel = JR_NEAR;
        if (jmprel->nearop.opcode_len == 0)
            return -1;      /* uh-oh, that size not available */
 
@@ -663,8 +714,8 @@ x86_bc_calc_len_jmprel(x86_jmprel *jmprel, unsigned long *len,
 }
 
 int
-x86_bc_calc_len(bytecode *bc, const section *sect,
-               resolve_label_func resolve_label)
+x86_bc_resolve(bytecode *bc, int save, const section *sect,
+              resolve_label_func resolve_label)
 {
     x86_insn *insn;
     x86_jmprel *jmprel;
@@ -672,11 +723,12 @@ x86_bc_calc_len(bytecode *bc, const section *sect,
     switch ((x86_bytecode_type)bc->type) {
        case X86_BC_INSN:
            insn = bc_get_data(bc);
-           return x86_bc_calc_len_insn(insn, &bc->len, sect, resolve_label);
+           return x86_bc_resolve_insn(insn, &bc->len, save, sect,
+                                      resolve_label);
        case X86_BC_JMPREL:
            jmprel = bc_get_data(bc);
-           return x86_bc_calc_len_jmprel(jmprel, &bc->len, bc->offset, sect,
-                                         resolve_label);
+           return x86_bc_resolve_jmprel(jmprel, &bc->len, save, bc, sect,
+                                        resolve_label);
        default:
            break;
     }
@@ -685,57 +737,13 @@ x86_bc_calc_len(bytecode *bc, const section *sect,
 
 static int
 x86_bc_tobytes_insn(x86_insn *insn, unsigned char **bufp, const section *sect,
-                   const bytecode *bc, void *d, output_expr_func output_expr,
-                   resolve_label_func resolve_label)
+                   const bytecode *bc, void *d, output_expr_func output_expr)
 {
     /*@null@*/ effaddr *ea = insn->ea;
     x86_effaddr_data *ead = ea_get_data(ea);
     immval *imm = insn->imm;
     unsigned int i;
 
-    /* We need to figure out the EA first to determine the addrsize.
-     * Of course, the ModR/M, SIB, and displacement are not output until later.
-     */
-    if (ea) {
-       if ((ea->disp) && ((!ead->valid_sib && ead->need_sib) ||
-                          (!ead->valid_modrm && ead->need_modrm))) {
-           /* Expand equ's and labels */
-           expr_expand_labelequ(ea->disp, sect, 1, resolve_label);
-
-           /* Check validity of effective address and calc R/M bits of
-            * Mod/RM byte and SIB byte.  We won't know the Mod field
-            * of the Mod/RM byte until we know more about the
-            * displacement.
-            */
-           if (!x86_expr_checkea(&ea->disp, &insn->addrsize, insn->mode_bits,
-                                 ea->nosplit, &ea->len, &ead->modrm,
-                                 &ead->valid_modrm, &ead->need_modrm,
-                                 &ead->sib, &ead->valid_sib,
-                                 &ead->need_sib))
-               InternalError(_("expr_checkea failed from x86 tobytes_insn"));
-       }
-    }
-
-    /* Also check for shift_op special-casing (affects imm). */
-    if (insn->shift_op && imm && imm->val) {
-       /*@dependent@*/ /*@null@*/ const intnum *num;
-
-       expr_expand_labelequ(imm->val, sect, 1, resolve_label);
-
-       num = expr_get_intnum(&imm->val);
-       if (num) {
-           if (intnum_get_uint(num) == 1) {
-               /* Use ,1 form: first copy ,1 opcode. */
-               insn->opcode[0] = insn->opcode[1];
-               /* Delete imm, as it's not needed. */
-               expr_delete(imm->val);
-               xfree(imm);
-               insn->imm = (immval *)NULL;
-           }
-           insn->shift_op = 0;
-       }
-    }
-
     /* Prefixes */
     if (insn->lockrep_pre != 0)
        WRITE_BYTE(*bufp, insn->lockrep_pre);
@@ -766,9 +774,35 @@ x86_bc_tobytes_insn(x86_insn *insn, unsigned char **bufp, const section *sect,
            WRITE_BYTE(*bufp, ead->sib);
        }
 
-       if (ea->disp)
-           if (output_expr(&ea->disp, bufp, ea->len, sect, bc, 0, d))
-               return 1;
+       if (ea->disp) {
+           x86_effaddr_data ead_t = *ead;  /* structure copy */
+           unsigned char displen = ea->len;
+           unsigned char addrsize = insn->addrsize;
+
+           ead_t.valid_modrm = 0;  /* force checkea to actually run */
+
+           /* Call checkea() to simplify the registers out of the
+            * displacement.  Throw away all of the return values except for
+            * the modified expr.
+            */
+           if (!x86_expr_checkea(&ea->disp, &addrsize, insn->mode_bits,
+                                 ea->nosplit, &displen, &ead_t.modrm,
+                                 &ead_t.valid_modrm, &ead_t.need_modrm,
+                                 &ead_t.sib, &ead_t.valid_sib,
+                                 &ead_t.need_sib))
+               InternalError(_("checkea failed"));
+
+           if (ea->disp) {
+               if (output_expr(&ea->disp, bufp, ea->len, sect, bc, 0, d))
+                   return 1;
+           } else {
+               /* 0 displacement, but we didn't know it before, so we have to
+                * write out 0 value.
+                */
+               for (i=0; i<ea->len; i++)
+                   WRITE_BYTE(*bufp, 0);
+           }
+       }
     }
 
     /* Immediate (if required) */
@@ -784,14 +818,9 @@ x86_bc_tobytes_insn(x86_insn *insn, unsigned char **bufp, const section *sect,
 static int
 x86_bc_tobytes_jmprel(x86_jmprel *jmprel, unsigned char **bufp,
                      const section *sect, const bytecode *bc, void *d,
-                     output_expr_func output_expr,
-                     resolve_label_func resolve_label)
+                     output_expr_func output_expr)
 {
-    /*@dependent@*/ /*@null@*/ const intnum *num;
-    unsigned long target;
-    long rel;
     unsigned char opersize;
-    int jrshort = 0;
     unsigned int i;
 
     /* Prefixes */
@@ -807,100 +836,48 @@ x86_bc_tobytes_jmprel(x86_jmprel *jmprel, unsigned char **bufp,
     opersize = (jmprel->opersize == 0) ? jmprel->mode_bits :
        jmprel->opersize;
 
-    /* Get displacement value here so that forced forms can be checked. */
-    expr_expand_labelequ(jmprel->target, sect, 0, resolve_label);
-    num = expr_get_intnum(&jmprel->target);
-
     /* Check here to see if forced forms are actually legal. */
     switch (jmprel->op_sel) {
        case JR_SHORT_FORCED:
+       case JR_SHORT:
            /* 1 byte relative displacement */
-           jrshort = 1;
-           if (!num) {
-               ErrorAt(bc->line,
-                       _("short jump target external or out of segment"));
+           if (jmprel->shortop.opcode_len == 0)
+               InternalError(_("short jump does not exist"));
+
+           /* Opcode */
+           for (i=0; i<jmprel->shortop.opcode_len; i++)
+               WRITE_BYTE(*bufp, jmprel->shortop.opcode[i]);
+
+           /* Relative displacement */
+           if (output_expr(&jmprel->target, bufp, 1, sect, bc, 1, d))
                return 1;
-           } else {
-               target = intnum_get_uint(num);
-               rel = (long)(target-(bc->offset+jmprel->shortop.opcode_len+1));
-               /* does a short form exist? */
-               if (jmprel->shortop.opcode_len == 0) {
-                   ErrorAt(bc->line, _("short jump does not exist"));
-                   return 1;
-               }
-               /* short displacement must fit within -128 <= rel <= +127 */
-               if (rel < -128 || rel > 127) {
-                   ErrorAt(bc->line, _("short jump out of range"));
-                   return 1;
-               }
-           }
            break;
        case JR_NEAR_FORCED:
+       case JR_NEAR:
            /* 2/4 byte relative displacement (depending on operand size) */
-           jrshort = 0;
            if (jmprel->nearop.opcode_len == 0) {
                ErrorAt(bc->line, _("near jump does not exist"));
                return 1;
            }
-           break;
-       default:
-           /* Try to find shortest displacement based on difference between
-            * target expr value and our (this bytecode's) offset.
-            */
-           if (num) {
-               target = intnum_get_uint(num);
-               rel = (long)(target-(bc->offset+jmprel->shortop.opcode_len+1));
-               /* short displacement must fit within -128 <= rel <= +127 */
-               if (jmprel->shortop.opcode_len != 0 && rel >= -128 &&
-                   rel <= 127) {
-                   /* It fits into a short displacement. */
-                   jrshort = 1;
-               } else {
-                   /* It's near. */
-                   jrshort = 0;
-                   if (jmprel->nearop.opcode_len == 0) {
-                       InternalError(_("near jump does not exist"));
-                       return 1;
-                   }
-               }
-           } else {
-               /* It's unknown (e.g. out of this segment or external).
-                * Thus, assume near displacement.  If a near opcode is not
-                * available, error out.
-                */
-               jrshort = 0;
-               if (jmprel->nearop.opcode_len == 0) {
-                   ErrorAt(bc->line,
-                           _("short jump target or out of segment"));
-                   return 1;
-               }
-           }
-           break;
-    }
 
-    if (jrshort) {
-       /* Opcode */
-       for (i=0; i<jmprel->shortop.opcode_len; i++)
-           WRITE_BYTE(*bufp, jmprel->shortop.opcode[i]);
+           /* Opcode */
+           for (i=0; i<jmprel->nearop.opcode_len; i++)
+               WRITE_BYTE(*bufp, jmprel->nearop.opcode[i]);
 
-       /* Relative displacement */
-       output_expr(&jmprel->target, bufp, 1, sect, bc, 1, d);
-    } else {
-       /* Opcode */
-       for (i=0; i<jmprel->nearop.opcode_len; i++)
-           WRITE_BYTE(*bufp, jmprel->nearop.opcode[i]);
-
-       /* Relative displacement */
-       output_expr(&jmprel->target, bufp, (opersize == 32) ? 4 : 2, sect, bc,
-                   1, d);
+           /* Relative displacement */
+           if (output_expr(&jmprel->target, bufp, (opersize == 32) ? 4 : 2,
+                           sect, bc, 1, d))
+               return 1;
+           break;
+       default:
+           InternalError(_("unrecognized relative jump op_sel"));
     }
     return 0;
 }
 
 int
 x86_bc_tobytes(bytecode *bc, unsigned char **bufp, const section *sect,
-              void *d, output_expr_func output_expr,
-              resolve_label_func resolve_label)
+              void *d, output_expr_func output_expr)
 {
     x86_insn *insn;
     x86_jmprel *jmprel;
@@ -908,16 +885,15 @@ x86_bc_tobytes(bytecode *bc, unsigned char **bufp, const section *sect,
     switch ((x86_bytecode_type)bc->type) {
        case X86_BC_INSN:
            insn = bc_get_data(bc);
-           return x86_bc_tobytes_insn(insn, bufp, sect, bc, d, output_expr,
-                                      resolve_label);
+           return x86_bc_tobytes_insn(insn, bufp, sect, bc, d, output_expr);
            break;
        case X86_BC_JMPREL:
            jmprel = bc_get_data(bc);
            return x86_bc_tobytes_jmprel(jmprel, bufp, sect, bc, d,
-                                        output_expr, resolve_label);
+                                        output_expr);
        default:
            break;
     }
-    return 1;
+    return 0;
 }
 
index 6b78ebe538e7fa6b0d1dc8e6444b6f6fbfe50470..dc13e5102f9a3c8ec10b840f47222a28b8cb92cc 100644 (file)
@@ -293,7 +293,7 @@ bc_print(FILE *f, const bytecode *bc)
 }
 
 static int
-bc_calc_len_data(bytecode_data *bc_data, unsigned long *len)
+bc_resolve_data(bytecode_data *bc_data, unsigned long *len)
 {
     dataval *dv;
     size_t slen;
@@ -319,17 +319,24 @@ bc_calc_len_data(bytecode_data *bc_data, unsigned long *len)
 }
 
 static int
-bc_calc_len_reserve(bytecode_reserve *reserve, unsigned long *len,
-                   const section *sect, resolve_label_func resolve_label)
+bc_resolve_reserve(bytecode_reserve *reserve, unsigned long *len, int save,
+                  const section *sect, resolve_label_func resolve_label)
 {
     int retval = 1;
     /*@null@*/ expr *temp;
+    expr **tempp;
     /*@dependent@*/ /*@null@*/ const intnum *num;
 
-    temp = expr_copy(reserve->numitems);
-    assert(temp != NULL);
-    expr_expand_labelequ(temp, sect, 1, resolve_label);
-    num = expr_get_intnum(&temp);
+    if (save) {
+       temp = NULL;
+       tempp = &reserve->numitems;
+    } else {
+       temp = expr_copy(reserve->numitems);
+       assert(temp != NULL);
+       tempp = &temp;
+    }
+    expr_expand_labelequ(*tempp, sect, 1, resolve_label);
+    num = expr_get_intnum(tempp);
     if (!num)
        retval = -1;
     else
@@ -339,21 +346,28 @@ bc_calc_len_reserve(bytecode_reserve *reserve, unsigned long *len,
 }
 
 static int
-bc_calc_len_incbin(bytecode_incbin *incbin, unsigned long *len,
-                  unsigned long line, const section *sect,
-                  resolve_label_func resolve_label)
+bc_resolve_incbin(bytecode_incbin *incbin, unsigned long *len, int save,
+                 unsigned long line, const section *sect,
+                 resolve_label_func resolve_label)
 {
     FILE *f;
     /*@null@*/ expr *temp;
+    expr **tempp;
     /*@dependent@*/ /*@null@*/ const intnum *num;
     unsigned long start = 0, maxlen = 0xFFFFFFFFUL, flen;
 
     /* Try to convert start to integer value */
     if (incbin->start) {
-       temp = expr_copy(incbin->start);
-       assert(temp != NULL);
-       expr_expand_labelequ(temp, sect, 1, resolve_label);
-       num = expr_get_intnum(&temp);
+       if (save) {
+           temp = NULL;
+           tempp = &incbin->start;
+       } else {
+           temp = expr_copy(incbin->start);
+           assert(temp != NULL);
+           tempp = &temp;
+       }
+       expr_expand_labelequ(*tempp, sect, 1, resolve_label);
+       num = expr_get_intnum(tempp);
        if (num)
            start = intnum_get_uint(num);
        expr_delete(temp);
@@ -363,10 +377,16 @@ bc_calc_len_incbin(bytecode_incbin *incbin, unsigned long *len,
 
     /* Try to convert maxlen to integer value */
     if (incbin->maxlen) {
-       temp = expr_copy(incbin->maxlen);
-       assert(temp != NULL);
-       expr_expand_labelequ(temp, sect, 1, resolve_label);
-       num = expr_get_intnum(&temp);
+       if (save) {
+           temp = NULL;
+           tempp = &incbin->maxlen;
+       } else {
+           temp = expr_copy(incbin->maxlen);
+           assert(temp != NULL);
+           tempp = &temp;
+       }
+       expr_expand_labelequ(*tempp, sect, 1, resolve_label);
+       num = expr_get_intnum(tempp);
        if (num)
            maxlen = intnum_get_uint(num);
        expr_delete(temp);
@@ -374,7 +394,9 @@ bc_calc_len_incbin(bytecode_incbin *incbin, unsigned long *len,
            return -1;
     }
 
-    /* FIXME: Search include path for filename */
+    /* FIXME: Search include path for filename.  Save full path back into
+     * filename if save is true.
+     */
 
     /* Open file and determine its length */
     f = fopen(incbin->filename, "rb");
@@ -406,14 +428,15 @@ bc_calc_len_incbin(bytecode_incbin *incbin, unsigned long *len,
 }
 
 int
-bc_calc_len(bytecode *bc, const section *sect,
-           resolve_label_func resolve_label)
+bc_resolve(bytecode *bc, int save, const section *sect,
+          resolve_label_func resolve_label)
 {
     int retval = 1;
     bytecode_data *bc_data;
     bytecode_reserve *reserve;
     bytecode_incbin *incbin;
     /*@null@*/ expr *temp;
+    expr **tempp;
     /*@dependent@*/ /*@null@*/ const intnum *num;
 
     bc->len = 0;       /* start at 0 */
@@ -423,31 +446,38 @@ bc_calc_len(bytecode *bc, const section *sect,
            InternalError(_("got empty bytecode in bc_calc_len"));
        case BC_DATA:
            bc_data = bc_get_data(bc);
-           retval = bc_calc_len_data(bc_data, &bc->len);
+           retval = bc_resolve_data(bc_data, &bc->len);
            break;
        case BC_RESERVE:
            reserve = bc_get_data(bc);
-           retval = bc_calc_len_reserve(reserve, &bc->len, sect,
-                                        resolve_label);
+           retval = bc_resolve_reserve(reserve, &bc->len, save, sect,
+                                       resolve_label);
            break;
        case BC_INCBIN:
            incbin = bc_get_data(bc);
-           retval = bc_calc_len_incbin(incbin, &bc->len, bc->line, sect,
-                                       resolve_label);
+           retval = bc_resolve_incbin(incbin, &bc->len, save, bc->line, sect,
+                                      resolve_label);
            break;
        default:
            if (bc->type < cur_arch->bc.type_max)
-               retval = cur_arch->bc.bc_calc_len(bc, sect, resolve_label);
+               retval = cur_arch->bc.bc_resolve(bc, save, sect,
+                                                resolve_label);
            else
                InternalError(_("Unknown bytecode type"));
     }
 
     /* Multiply len by number of multiples */
     if (bc->multiple) {
-       temp = expr_copy(bc->multiple);
-       assert(temp != NULL);
-       expr_expand_labelequ(temp, sect, 1, resolve_label);
-       num = expr_get_intnum(&temp);
+       if (save) {
+           temp = NULL;
+           tempp = &bc->multiple;
+       } else {
+           temp = expr_copy(bc->multiple);
+           assert(temp != NULL);
+           tempp = &temp;
+       }
+       expr_expand_labelequ(*tempp, sect, 1, resolve_label);
+       num = expr_get_intnum(tempp);
        if (!num)
            retval = -1;
        else
@@ -496,21 +526,14 @@ bc_tobytes_data(bytecode_data *bc_data, unsigned char **bufp,
 
 static int
 bc_tobytes_reserve(bytecode_reserve *reserve, unsigned char **bufp,
-                  const section *sect, resolve_label_func resolve_label)
+                  unsigned long len)
 {
-    /*@dependent@*/ /*@null@*/ const intnum *num;
-    unsigned long numitems, i;
-
-    expr_expand_labelequ(reserve->numitems, sect, 1, resolve_label);
-    num = expr_get_intnum(&reserve->numitems);
-    if (!num)
-       InternalError(_("could not determine number of items in bc_tobytes_reserve"));
-    numitems = intnum_get_uint(num)*reserve->itemsize;
+    unsigned long i;
 
     /* Go ahead and zero the bytes.  Probably most objfmts will want it
      * zero'd if they're actually going to output it.
      */
-    for (i=0; i<numitems; i++)
+    for (i=0; i<len; i++)
        WRITE_BYTE(*bufp, 0);
 
     return 0;
@@ -518,24 +541,20 @@ bc_tobytes_reserve(bytecode_reserve *reserve, unsigned char **bufp,
 
 static int
 bc_tobytes_incbin(bytecode_incbin *incbin, unsigned char **bufp,
-                 unsigned long buflen, unsigned long line,
-                 const section *sect, resolve_label_func resolve_label)
+                 unsigned long len, unsigned long line)
 {
     FILE *f;
     /*@dependent@*/ /*@null@*/ const intnum *num;
     unsigned long start = 0;
 
-    /* Try to convert start to integer value */
+    /* Convert start to integer value */
     if (incbin->start) {
-       expr_expand_labelequ(incbin->start, sect, 1, resolve_label);
        num = expr_get_intnum(&incbin->start);
        if (!num)
            InternalError(_("could not determine start in bc_tobytes_incbin"));
        start = intnum_get_uint(num);
     }
 
-    /* FIXME: Search include path for filename */
-
     /* Open file */
     f = fopen(incbin->filename, "rb");
     if (!f) {
@@ -552,15 +571,15 @@ bc_tobytes_incbin(bytecode_incbin *incbin, unsigned char **bufp,
        return 1;
     }
 
-    /* Read buflen bytes */
-    if (fread(*bufp, buflen, 1, f) < buflen) {
+    /* Read len bytes */
+    if (fread(*bufp, len, 1, f) < len) {
        ErrorAt(line, _("`incbin': unable to read %lu bytes from file `%s'"),
-               buflen, incbin->filename);
+               len, incbin->filename);
        fclose(f);
        return 1;
     }
 
-    *bufp += buflen;
+    *bufp += len;
     fclose(f);
     return 0;
 }
@@ -568,22 +587,36 @@ bc_tobytes_incbin(bytecode_incbin *incbin, unsigned char **bufp,
 /*@null@*/ /*@only@*/ unsigned char *
 bc_tobytes(bytecode *bc, unsigned char *buf, unsigned long *bufsize,
           /*@out@*/ unsigned long *multiple, /*@out@*/ int *gap,
-          const section *sect, void *d, output_expr_func output_expr,
-          resolve_label_func resolve_label)
+          const section *sect, void *d, output_expr_func output_expr)
 {
     /*@only@*/ /*@null@*/ unsigned char *mybuf = NULL;
-    unsigned char *destbuf;
+    unsigned char *origbuf, *destbuf;
     /*@dependent@*/ /*@null@*/ const intnum *num;
     bytecode_data *bc_data;
     bytecode_reserve *reserve;
     bytecode_incbin *incbin;
+    unsigned long datasize;
     int error = 0;
 
-    if (*bufsize < bc->len) {
+    if (bc->multiple) {
+       num = expr_get_intnum(&bc->multiple);
+       if (!num)
+           InternalError(_("could not determine multiple in bc_tobytes"));
+       *multiple = intnum_get_uint(num);
+    } else
+       *multiple = 1;
+
+    datasize = bc->len / (*multiple);
+
+    if (*bufsize < datasize) {
        mybuf = xmalloc(sizeof(bc->len));
+       origbuf = mybuf;
        destbuf = mybuf;
-    } else
+    } else {
+       origbuf = buf;
        destbuf = buf;
+    }
+    *bufsize = datasize;
 
     *gap = 0;
 
@@ -597,33 +630,23 @@ bc_tobytes(bytecode *bc, unsigned char *buf, unsigned long *bufsize,
            break;
        case BC_RESERVE:
            reserve = bc_get_data(bc);
-           error = bc_tobytes_reserve(reserve, &destbuf, sect, resolve_label);
+           error = bc_tobytes_reserve(reserve, &destbuf, bc->len);
            *gap = 1;
            break;
        case BC_INCBIN:
            incbin = bc_get_data(bc);
-           error = bc_tobytes_incbin(incbin, &destbuf, bc->len, bc->line,
-                                     sect, resolve_label);
+           error = bc_tobytes_incbin(incbin, &destbuf, bc->len, bc->line);
            break;
        default:
            if (bc->type < cur_arch->bc.type_max)
                error = cur_arch->bc.bc_tobytes(bc, &destbuf, sect, d,
-                                               output_expr, resolve_label);
+                                               output_expr);
            else
                InternalError(_("Unknown bytecode type"));
     }
 
-    if (bc->multiple) {
-       expr_expand_labelequ(bc->multiple, sect, 1, resolve_label);
-       num = expr_get_intnum(&bc->multiple);
-       if (!num)
-           InternalError(_("could not determine multiple in bc_tobytes"));
-       *multiple = intnum_get_uint(num);
-    } else
-       *multiple = 1;
-    if (!error && ((destbuf - buf) != bc->len))
+    if (!error && ((destbuf - origbuf) != datasize))
        InternalError(_("written length does not match optimized length"));
-    *bufsize = bc->len;
     return mybuf;
 }
 
index f011b6ecf12955cecfaf9c4ab7c1be443449f49b..0dbf5c4d1ee22c5a7690edc9af1d829adda84073 100644 (file)
@@ -58,18 +58,22 @@ void bc_delete(/*@only@*/ /*@null@*/ bytecode *bc);
 
 void bc_print(FILE *f, const bytecode *bc);
 
-/* Calculates length of bytecode, saving in bc structure.
+/* Resolves labels in bytecode, and calculates its length.
+ * Tries to minimize the length as much as possible.
  * Returns whether the length is the minimum possible (1=yes, 0=no).
  * Returns -1 if the length was indeterminate.
+ * Note: sometimes it's impossible to determine if a length is the minimum
+ *       possible.  In this case, this function returns that the length is NOT
+ *       the minimum.
  * resolve_label is the function used to determine the value (offset) of a
  *  in-file label (eg, not an EXTERN variable, which is indeterminate).
- * This function does *not* modify bc other than the length/size values (eg
- *  it doesn't keep the values returned by resolve_label except temporarily to
- *  try to minimize the length).
- * sect is passed along to resolve_label.
+ * When save is zero, this function does *not* modify bc other than the
+ * length/size values (i.e. it doesn't keep the values returned by
+ * resolve_label except temporarily to try to minimize the length).
+ * When save is nonzero, all fields in bc may be modified by this function.
  */
-int bc_calc_len(bytecode *bc, const section *sect,
-               resolve_label_func resolve_label);
+int bc_resolve(bytecode *bc, int save, const section *sect,
+              resolve_label_func resolve_label);
 
 /* Converts the bytecode bc into its byte representation.
  * Inputs:
@@ -78,17 +82,6 @@ int bc_calc_len(bytecode *bc, const section *sect,
  *  bufsize       - the size of buf
  *  d             - the data to pass to each call to output_expr()
  *  output_expr   - the function to call to convert expressions to byte rep
- *   output_expr inputs:
- *    bc      - the bytecode containing the expr that is being output
- *    ep      - a pointer to the expression to output
- *    bufp    - pointer to pointer to buffer to contain byte representation
- *    valsize - the size (in bytes) to be used for the byte rep
- *    d       - the data passed into bc_tobytes
- *   output_expr returns nonzero if an error occurred, 0 otherwise
- *  resolve_label - the function to call to determine the values of
- *                  expressions that are *not* output to the file
- *   resolve_label inputs:
- *    sym - the symbol to resolve
  * Outputs:
  *  bufsize       - the size of the generated data.
  *  multiple      - the number of times the data should be dup'ed when output
@@ -102,7 +95,7 @@ int bc_calc_len(bytecode *bc, const section *sect,
 /*@null@*/ /*@only@*/ unsigned char *bc_tobytes(bytecode *bc,
     unsigned char *buf, unsigned long *bufsize,
     /*@out@*/ unsigned long *multiple, /*@out@*/ int *gap, const section *sect,
-    void *d, output_expr_func output_expr, resolve_label_func resolve_label);
+    void *d, output_expr_func output_expr);
 
 /* void bcs_initialize(bytecodehead *headp); */
 #define        bcs_initialize(headp)   STAILQ_INIT(headp)
index 5af6dc492b56b6837b838b30874e080d05f39755..1e8a06cd5355803661c05743c07569d6e41224f7 100644 (file)
@@ -127,9 +127,6 @@ bin_objfmt_resolve_label2(symrec *sym, /*@null@*/ const section *cursect,
        startval -= cursectstart;
     }
 
-    /* If a section is done, the following will always succeed.  If it's in-
-     * progress, this will fail if the bytecode comes AFTER the current one.
-     */
     if (precbc)
        return intnum_new_int(startval + precbc->offset + precbc->len);
     else
@@ -249,8 +246,7 @@ bin_objfmt_output_bytecode(bytecode *bc, /*@null@*/ void *d)
     int gap;
 
     bigbuf = bc_tobytes(bc, info->buf, &size, &multiple, &gap, info->sect,
-                       info, bin_objfmt_output_expr,
-                       bin_objfmt_resolve_label);
+                       info, bin_objfmt_output_expr);
 
     /* Warn that gaps are converted to 0.  The 0 bytes are generated by
      * bc_tobytes() so no special handling is needed.
index a12ad29295524fd7c92cb78e0451018cc0bdb9ca..381d44a492ac614e06204240378e6c5e1469cb47 100644 (file)
@@ -94,6 +94,48 @@ basic_optimize_resolve_label(symrec *sym, int withstart)
     return NULL;
 }
 
+static /*@only@*/ /*@null@*/ intnum *
+basic_optimize_resolve_label_2(symrec *sym, int withstart)
+{
+    /*@dependent@*/ section *sect;
+    /*@dependent@*/ /*@null@*/ bytecode *precbc;
+    /*@null@*/ bytecode *bc;
+    /*@null@*/ expr *startexpr;
+    /*@dependent@*/ /*@null@*/ const intnum *start;
+    unsigned long startval = 0;
+
+    if (!symrec_get_label(sym, &sect, &precbc))
+       return NULL;
+
+    /* determine actual bc from preceding bc (how labels are stored) */
+    if (!precbc)
+       bc = bcs_first(section_get_bytecodes(sect));
+    else
+       bc = bcs_next(precbc);
+    assert(bc != NULL);
+
+    /* Figure out the starting offset of the entire section */
+    if (withstart || section_is_absolute(sect)) {
+       startexpr = expr_copy(section_get_start(sect));
+       assert(startexpr != NULL);
+       expr_expand_labelequ(startexpr, sect, 1,
+                            basic_optimize_resolve_label_2);
+       start = expr_get_intnum(&startexpr);
+       if (!start)
+           return NULL;
+       startval = intnum_get_uint(start);
+       expr_delete(startexpr);
+    }
+
+    /* If a section is done, the following will always succeed.  If it's in-
+     * progress, this will fail if the bytecode comes AFTER the current one.
+     */
+    if (precbc)
+       return intnum_new_int(startval + precbc->offset + precbc->len);
+    else
+       return intnum_new_int(startval + bc->offset);
+}
+
 typedef struct basic_optimize_data {
     bytecode *precbc;
     const section *sect;
@@ -122,7 +164,7 @@ basic_optimize_bytecode_1(bytecode *bc, void *d)
      * is minimum or not, and just check for indeterminate length (indicative
      * of circular reference).
      */
-    if (bc_calc_len(bc, data->sect, basic_optimize_resolve_label) < 0) {
+    if (bc_resolve(bc, 0, data->sect, basic_optimize_resolve_label) < 0) {
        ErrorAt(bc->line, _("Circular reference detected."));
        return -1;
     }
@@ -162,23 +204,41 @@ basic_optimize_section_1(section *sect, /*@unused@*/ /*@null@*/ void *d)
 }
 
 static int
-basic_optimize_bytecode_2(bytecode *bc, /*@unused@*/ /*@null@*/ void *d)
+basic_optimize_bytecode_2(bytecode *bc, /*@null@*/ void *d)
 {
+    basic_optimize_data *data = (basic_optimize_data *)d;
+
+    assert(data != NULL);
+
     if (bc->opt_flags != BCFLAG_DONE) {
        InternalError(_("Optimizer pass 1 missed a bytecode!"));
        return -1;
     }
+
+    if (!data->precbc)
+       bc->offset = 0;
+    else
+       bc->offset = data->precbc->offset + data->precbc->len;
+    data->precbc = bc;
+
+    if (bc_resolve(bc, 1, data->sect, basic_optimize_resolve_label_2) < 0)
+       return -1;
     return 0;
 }
 
 static int
 basic_optimize_section_2(section *sect, /*@unused@*/ /*@null@*/ void *d)
 {
+    basic_optimize_data data;
+
+    data.precbc = NULL;
+    data.sect = sect;
+
     if (section_get_opt_flags(sect) != SECTFLAG_DONE) {
        InternalError(_("Optimizer pass 1 missed a section!"));
        return -1;
     }
-    return bcs_traverse(section_get_bytecodes(sect), NULL,
+    return bcs_traverse(section_get_bytecodes(sect), &data,
                        basic_optimize_bytecode_2);
 }
 
@@ -200,7 +260,7 @@ basic_optimize(sectionhead *sections)
     if (sections_traverse(sections, NULL, basic_optimize_section_1) < 0)
        return;
 
-    /* FIXME: Really necessary?  Check completion of all sections */
+    /* Check completion of all sections and save bytecode changes */
     sections_traverse(sections, NULL, basic_optimize_section_2);
 }