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;
};
}
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;
}
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
}
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);
/* 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);
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");
}
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 */
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
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;
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) {
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;
}
/*@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;
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;
}
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:
* 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
/*@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)
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,
X86_BYTECODE_TYPE_MAX,
x86_bc_delete,
x86_bc_print,
- x86_bc_calc_len,
+ x86_bc_resolve,
x86_bc_tobytes
}
};
}
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;
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 */
* (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);
}
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;
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
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 */
}
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;
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;
}
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);
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) */
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 */
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;
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;
}
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
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.
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, §, &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;
* 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;
}
}
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);
}
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);
}
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;
};
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,
X86_BYTECODE_TYPE_MAX,
x86_bc_delete,
x86_bc_print,
- x86_bc_calc_len,
+ x86_bc_resolve,
x86_bc_tobytes
}
};
}
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;
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 */
* (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);
}
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;
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
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 */
}
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;
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;
}
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);
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) */
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 */
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;
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;
}
}
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;
}
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
}
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);
/* 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);
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");
}
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 */
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
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;
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) {
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;
}
/*@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;
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;
}
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:
* 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
/*@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)
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
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.
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, §, &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;
* 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;
}
}
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);
}
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);
}