Restructure bc_calc_len() family into bc_resolve() family. Many many many

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
0.3
Peter Johnson 23 years ago
parent 53002496e4
commit fe8c2a009f
  1. 9
      libyasm/arch.h
  2. 163
      libyasm/bytecode.c
  3. 31
      libyasm/bytecode.h
  4. 7
      modules/arch/x86/x86-int.h
  5. 2
      modules/arch/x86/x86arch.c
  6. 320
      modules/arch/x86/x86bc.c
  7. 6
      modules/objfmts/bin/bin-objfmt.c
  8. 68
      modules/optimizers/basic/basic-optimizer.c
  9. 9
      src/arch.h
  10. 7
      src/arch/x86/x86-int.h
  11. 2
      src/arch/x86/x86arch.c
  12. 320
      src/arch/x86/x86bc.c
  13. 163
      src/bytecode.c
  14. 31
      src/bytecode.h
  15. 6
      src/objfmts/bin/bin-objfmt.c
  16. 68
      src/optimizers/basic/basic-optimizer.c

@ -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;
};

@ -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;
}

@ -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)

@ -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,

@ -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
}
};

@ -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;
}

@ -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.

@ -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);
}

@ -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;
};

@ -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,

@ -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
}
};

@ -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;
}

@ -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;
}

@ -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)

@ -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.

@ -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);
}

Loading…
Cancel
Save