Change calc_len to call back to add_span function so that multiple spans can

be added by a single calc_len.

svn path=/branches/new-optimizer/; revision=1544
0.6.0
Peter Johnson 19 years ago
parent 309ee78ee4
commit 26e2ac882f
  1. 20
      libyasm/bc-int.h
  2. 131
      libyasm/bytecode.c
  3. 58
      libyasm/bytecode.h
  4. 37
      libyasm/intnum.c
  5. 8
      libyasm/intnum.h
  6. 229
      libyasm/section.c
  7. 191
      modules/arch/x86/x86bc.c

@ -59,10 +59,10 @@ typedef struct yasm_bytecode_callback {
void (*destroy) (/*@only@*/ void *contents);
void (*print) (const void *contents, FILE *f, int indent_level);
void (*finalize) (yasm_bytecode *bc, yasm_bytecode *prev_bc);
int (*calc_len) (yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical,
/*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
void (*set_long) (yasm_bytecode *bc);
int (*calc_len) (yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data);
int (*expand) (yasm_bytecode *bc, int span, long old_val, long new_val,
/*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
int (*tobytes) (yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
@ -79,8 +79,8 @@ struct yasm_bytecode {
/* number of times bytecode is repeated, NULL=1. */
/*@only@*/ /*@null@*/ yasm_expr *multiple;
unsigned long len; /* total length of entire bytecode (including
multiple copies), 0 if unknown */
unsigned long len; /* total length of entire bytecode
(not including multiple copies) */
/* where it came from */
unsigned long line;
@ -125,11 +125,13 @@ void yasm_bc_transform(yasm_bytecode *bc,
*/
void yasm_bc_finalize_common(yasm_bytecode *bc, yasm_bytecode *prev_bc);
/** Common bytecode callback set_long function, for where the bytecode is
* always short (calc_len always returns 0, never 1). Causes an internal
/** Common bytecode callback expand function, for where the bytecode is
* always short (calc_len never calls add_span). Causes an internal
* error if called.
*/
void yasm_bc_set_long_common(yasm_bytecode *bc);
int yasm_bc_expand_common
(yasm_bytecode *bc, int span, long old_val, long new_val,
/*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
#define yasm_bc__next(x) STAILQ_NEXT(x, link)

@ -134,10 +134,8 @@ typedef struct bytecode_insn {
static void bc_data_destroy(void *contents);
static void bc_data_print(const void *contents, FILE *f, int indent_level);
static int bc_data_calc_len
(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
/*@out@*/ long *pos_thres);
static int bc_data_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data);
static int bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
@ -145,30 +143,27 @@ static int bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
static void bc_leb128_destroy(void *contents);
static void bc_leb128_print(const void *contents, FILE *f, int indent_level);
static void bc_leb128_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
static int bc_leb128_calc_len
(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
/*@out@*/ long *pos_thres);
static int bc_leb128_calc_len(yasm_bytecode *bc,
yasm_bc_add_span_func add_span,
void *add_span_data);
static int bc_leb128_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void bc_reserve_destroy(void *contents);
static void bc_reserve_print(const void *contents, FILE *f, int indent_level);
static int bc_reserve_calc_len
(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
/*@out@*/ long *pos_thres);
static int bc_reserve_calc_len(yasm_bytecode *bc,
yasm_bc_add_span_func add_span,
void *add_span_data);
static int bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void bc_incbin_destroy(void *contents);
static void bc_incbin_print(const void *contents, FILE *f, int indent_level);
static int bc_incbin_calc_len
(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
/*@out@*/ long *pos_thres);
static int bc_incbin_calc_len(yasm_bytecode *bc,
yasm_bc_add_span_func add_span,
void *add_span_data);
static int bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
@ -176,20 +171,16 @@ static int bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
static void bc_align_destroy(void *contents);
static void bc_align_print(const void *contents, FILE *f, int indent_level);
static void bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
static int bc_align_calc_len
(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
/*@out@*/ long *pos_thres);
static int bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data);
static int bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void bc_org_destroy(void *contents);
static void bc_org_print(const void *contents, FILE *f, int indent_level);
static int bc_org_calc_len
(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
/*@out@*/ long *pos_thres);
static int bc_org_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data);
static int bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
@ -197,10 +188,8 @@ static int bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
static void bc_insn_destroy(void *contents);
static void bc_insn_print(const void *contents, FILE *f, int indent_level);
static void bc_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
static int bc_insn_calc_len
(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
/*@out@*/ long *pos_thres);
static int bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data);
static int bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
@ -212,7 +201,7 @@ static const yasm_bytecode_callback bc_data_callback = {
bc_data_print,
yasm_bc_finalize_common,
bc_data_calc_len,
yasm_bc_set_long_common,
yasm_bc_expand_common,
bc_data_tobytes
};
@ -221,7 +210,7 @@ static const yasm_bytecode_callback bc_leb128_callback = {
bc_leb128_print,
bc_leb128_finalize,
bc_leb128_calc_len,
yasm_bc_set_long_common,
yasm_bc_expand_common,
bc_leb128_tobytes
};
@ -230,7 +219,7 @@ static const yasm_bytecode_callback bc_reserve_callback = {
bc_reserve_print,
yasm_bc_finalize_common,
bc_reserve_calc_len,
yasm_bc_set_long_common,
yasm_bc_expand_common,
bc_reserve_tobytes
};
@ -239,7 +228,7 @@ static const yasm_bytecode_callback bc_incbin_callback = {
bc_incbin_print,
yasm_bc_finalize_common,
bc_incbin_calc_len,
yasm_bc_set_long_common,
yasm_bc_expand_common,
bc_incbin_tobytes
};
@ -248,7 +237,7 @@ static const yasm_bytecode_callback bc_align_callback = {
bc_align_print,
bc_align_finalize,
bc_align_calc_len,
yasm_bc_set_long_common,
yasm_bc_expand_common,
bc_align_tobytes
};
@ -257,7 +246,7 @@ static const yasm_bytecode_callback bc_org_callback = {
bc_org_print,
yasm_bc_finalize_common,
bc_org_calc_len,
yasm_bc_set_long_common,
yasm_bc_expand_common,
bc_org_tobytes
};
@ -266,7 +255,7 @@ static const yasm_bytecode_callback bc_insn_callback = {
bc_insn_print,
bc_insn_finalize,
bc_insn_calc_len,
yasm_bc_set_long_common,
yasm_bc_expand_common,
bc_insn_tobytes
};
@ -382,10 +371,13 @@ yasm_bc_finalize_common(yasm_bytecode *bc, yasm_bytecode *prev_bc)
{
}
void
yasm_bc_set_long_common(yasm_bytecode *bc)
int
yasm_bc_expand_common(yasm_bytecode *bc, int span, long old_val, long new_val,
/*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
{
yasm_internal_error(N_("bytecode does not have a long format"));
yasm_internal_error(N_("bytecode does not have any dependent spans"));
/*@unreached@*/
return 0;
}
void
@ -444,8 +436,8 @@ bc_data_print(const void *contents, FILE *f, int indent_level)
}
static int
bc_data_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
bc_data_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data)
{
bytecode_data *bc_data = (bytecode_data *)bc->contents;
yasm_dataval *dv;
@ -588,8 +580,8 @@ bc_leb128_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
}
static int
bc_leb128_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
bc_leb128_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data)
{
bytecode_leb128 *bc_leb128 = (bytecode_leb128 *)bc->contents;
bc->len += bc_leb128->len;
@ -654,8 +646,8 @@ bc_reserve_print(const void *contents, FILE *f, int indent_level)
}
static int
bc_reserve_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
bc_reserve_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data)
{
bytecode_reserve *reserve = (bytecode_reserve *)bc->contents;
/*@dependent@*/ /*@null@*/ const yasm_intnum *num;
@ -734,8 +726,8 @@ bc_incbin_print(const void *contents, FILE *f, int indent_level)
}
static int
bc_incbin_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
bc_incbin_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data)
{
bytecode_incbin *incbin = (bytecode_incbin *)bc->contents;
FILE *f;
@ -902,8 +894,8 @@ bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
}
static int
bc_align_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data)
{
yasm_internal_error(N_("align not yet implemented"));
/*
@ -1028,8 +1020,8 @@ bc_org_print(const void *contents, FILE *f, int indent_level)
}
static int
bc_org_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
bc_org_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data)
{
yasm_internal_error(N_("org not yet implemented"));
#if 0
@ -1136,8 +1128,8 @@ bc_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
}
static int
bc_insn_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data)
{
yasm_internal_error(N_("bc_insn_calc_len() is not implemented"));
/*@notreached@*/
@ -1324,24 +1316,18 @@ yasm_common_calc_bc_dist(/*@null@*/ yasm_bytecode *precbc1,
}
int
yasm_bc_calc_len(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical,
/*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data)
{
int retval = 0;
bc->len = 0;
*critical = NULL;
*neg_thres = 0;
*pos_thres = 0;
*long_len = 0;
if (!bc->callback)
yasm_internal_error(N_("got empty bytecode in bc_resolve"));
else
retval = bc->callback->calc_len(bc, long_len, critical, neg_thres,
pos_thres);
retval = bc->callback->calc_len(bc, add_span, add_span_data);
#if 0
/* Check for multiples */
if (bc->multiple) {
/*@dependent@*/ /*@null@*/ const yasm_intnum *num;
@ -1360,24 +1346,25 @@ yasm_bc_calc_len(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
}
}
}
#endif
/* If we got an error somewhere along the line, clear out any calc len */
if (retval < 0) {
if (retval < 0)
bc->len = 0;
*long_len = 0;
}
return retval;
}
void
yasm_bc_set_long(yasm_bytecode *bc, unsigned long long_len)
int
yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
/*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
{
if (!bc->callback)
if (!bc->callback) {
yasm_internal_error(N_("got empty bytecode in bc_set_long"));
else
bc->callback->set_long(bc);
bc->len = long_len;
/*@unreached@*/
return 0;
} else
return bc->callback->expand(bc, span, old_val, new_val, neg_thres,
pos_thres);
}
/*@null@*/ /*@only@*/ unsigned char *

@ -273,40 +273,44 @@ void yasm_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
/*@null@*/ yasm_intnum *yasm_common_calc_bc_dist
(/*@null@*/ yasm_bytecode *precbc1, /*@null@*/ yasm_bytecode *precbc2);
/** Resolve EQUs in a bytecode and calculate its possible lengths.
* Tries to minimize the length as much as possible for short_len.
* The short length is set in the bytecode, and the long length is returned
* in long_len (if applicable). Any bytecode multiple is NOT included in
* the length or critical expression calculations.
/**
* \param critical dependent expression for bytecode expansion
* \param neg_thres negative threshold for long/short decision
* \param pos_thres positive threshold for long/short decision
*/
typedef void (*yasm_bc_add_span_func)
(void *add_span_data, yasm_bytecode *bc, int id,
/*@only@*/ yasm_expr *dependent, long neg_thres, long pos_thres);
/** Resolve EQUs in a bytecode and calculate its minimum size.
* Returns dependent bytecode spans for cases where, if the length spanned
* increases, it could cause the bytecode size to increase.
* Any bytecode multiple is NOT included in the length or spans generation;
* this must be handled at a higher level.
* \param bc bytecode
* \param long_len longer length (returned). 0 returned if no longer
* length is available (must be short).
* \param critical critical expression if bytecode could be longer
* (returned). NULL returned if no critical expression.
* \param neg_thres negative threshold for long/short decision (returned)
* \param pos_thres positive threshold for long/short decision (returned)
* \return 0 if length is minimum (no way it can ever increase), negative if
* there was an error recognized (and output) during execution, and
* positive if the length may increase based on the critical expr.
* \return 0 if no error occurred, nonzero if there was an error recognized
* (and output) during execution.
* \note May store to bytecode updated expressions and the short length.
*/
int yasm_bc_calc_len(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical,
/*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
int yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data);
/** Mark a bytecode as long. Has no effect if the bytecode does not have
* a long form. May return back a new longer threshold that can be reached.
/** Recalculate a bytecode's length based on an expanded span length.
* \param bc bytecode
* \param long_len long length (as given by yasm_bc_calc_len)
* \param longer_len next stage of lengthening (returned)
* \param span span ID (as given to yasm_bc_add_span_func in
* yasm_bc_calc_len)
* \param old_val previous span value
* \param new_val new span value
* \param neg_thres negative threshold for long/short decision (returned)
* \param pos_thres postivie threshold for long/short decision (returned)
* \return 0 if no longer threshold, positive if length may increase further
* based on the new negative and positive thresholds.
*/
int yasm_bc_set_long(yasm_bytecode *bc, unsigned long long_len,
/*@out@*/ unsigned long *longer_len,
/*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
* \return 0 if bc no longer dependent on this span's length, negative if
* there was an error recognized (and output) during execution, and
* positive if bc size may increase for this span further based on the
* new negative and positive thresholds returned.
* \note May store to bytecode updated expressions and the updated length.
*/
int yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
/*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
/** Convert a bytecode into its byte representation.
* \param bc bytecode

@ -650,6 +650,43 @@ yasm_intnum_check_size(const yasm_intnum *intn, size_t size, size_t rshift,
return (Set_Max(val) < (long)size);
}
int
yasm_intnum_in_range(const yasm_intnum *intn, long low, long high)
{
wordptr val = result;
wordptr lval = op1static;
wordptr hval = op2static;
/* If not already a bitvect, convert value to be written to a bitvect */
if (intn->type == INTNUM_BV)
val = intn->val.bv;
else {
BitVector_Empty(val);
BitVector_Chunk_Store(val, 32, 0, intn->val.ul);
}
/* Convert high and low to bitvects */
BitVector_Empty(lval);
if (low >= 0)
BitVector_Chunk_Store(lval, 32, 0, (unsigned long)low);
else {
BitVector_Chunk_Store(lval, 32, 0, (unsigned long)(-low));
BitVector_Negate(lval, lval);
}
BitVector_Empty(hval);
if (high >= 0)
BitVector_Chunk_Store(hval, 32, 0, (unsigned long)high);
else {
BitVector_Chunk_Store(hval, 32, 0, (unsigned long)(-high));
BitVector_Negate(hval, hval);
}
/* Compare! */
return (BitVector_Compare(val, lval) >= 0
&& BitVector_Compare(val, hval) <= 0);
}
unsigned long
yasm_intnum_get_leb128(const yasm_intnum *intn, unsigned char *ptr, int sign)
{

@ -192,6 +192,14 @@ void yasm_intnum_get_sized(const yasm_intnum *intn, unsigned char *ptr,
int yasm_intnum_check_size(const yasm_intnum *intn, size_t size,
size_t rshift, int rangetype);
/** Check to see if intnum will fit into a particular numeric range.
* \param intn intnum
* \param low low end of range (inclusive)
* \param high high end of range (inclusive)
* \return Nonzero if intnum is within range.
*/
int yasm_intnum_in_range(const yasm_intnum *intn, long low, long high);
/** Output #yasm_intnum to buffer in LEB128-encoded form.
* \param intn intnum
* \param ptr pointer to storage for output bytes

@ -28,6 +28,8 @@
#include "util.h"
/*@unused@*/ RCSID("$Id$");
#include <limits.h>
#include "coretype.h"
#include "valparam.h"
#include "assocdat.h"
@ -296,22 +298,18 @@ void
yasm_object_finalize(yasm_object *object)
{
yasm_section *sect;
unsigned long bc_index = 0;
/* Iterate through sections */
STAILQ_FOREACH(sect, &object->sections, link) {
yasm_bytecode *cur = STAILQ_FIRST(&sect->bcs);
yasm_bytecode *prev;
cur->bc_index = bc_index++;
/* Skip our locally created empty bytecode first. */
prev = cur;
cur = STAILQ_NEXT(cur, link);
/* Iterate through the remainder, if any. */
while (cur) {
cur->bc_index = bc_index++;
/* Finalize */
yasm_bc_finalize(cur, prev);
prev = cur;
@ -541,7 +539,7 @@ yasm_section_print(const yasm_section *sect, FILE *f, int indent_level,
/*
* Robertson (1977) optimizer
* Based on the algorithm given in:
* Based (somewhat loosely) on the algorithm given in:
* MRC Technical Summary Report # 1779
* CODE GENERATION FOR SHORT/LONG ADDRESS MACHINES
* Edward L. Robertson
@ -567,67 +565,129 @@ yasm_section_print(const yasm_section *sect, FILE *f, int indent_level,
*
* Each span keeps track of:
* - Associated bytecode (bytecode that depends on the span length)
* - Active/inactive state (starts out active)
* - Sign (negative/positive; negative being "backwards" in address)
* - Current length in bytes
* - New length in bytes
* - Negative/Positive thresholds
* - Span ID (unique within each bytecode)
* = 0 -- need to update bytecode length on any span length change
* > 0 -- only need to update bytecode length if exceeds thresholds
* Span ID 0 is reserved for times, org, and align; other IDs can be
* arbitrarily chosen by the bytecode.
*
* How org, align, and times are handled:
* How org and align are handled:
* Some portions are critical values that must not depend on any bytecode
* offset (either relative or absolute).
*
* ALIGN: Start with 0 length. Span from 0 to align bytecode, update
* on any change (span ID 0). Alignment is critical value.
* ORG: 0 length (always). Bump offset to org value. Span from 0 to
* org bytecode, update on any change (span ID 0). If span's length
* exceeds org value, error. ORG value is critical value.
* ALIGN: 0 length (always). Bump offset to alignment. Span from 0 to
* align bytecode, update on any change. If span length
* increases past alignment, increase offset by alignment and update
* dependent spans. Alignment is critical value.
* ORG: Same as align, but if span's length exceeds org value, error.
* ORG value is critical value.
*
* How times is handled:
*
* TIMES: Handled separately from bytecode "raw" size. If not span-dependent,
* trivial (just multiplied in at any bytecode size increase). Span
* dependent times update on any change (span ID 0).
* dependent times update on any change (span ID 0). If the resultant
* next bytecode offset would be less than the old next bytecode offset,
* error. Otherwise increase offset and update dependent spans.
*
* To reduce interval tree size, a first expansion pass is performed
* before the spans are added to the tree.
*
* Basic algorithm outline:
*
* 1. Initialization:
* a. Number bytecodes sequentially (via bc_index) and calculate offsets
* of all bytecodes assuming minimum length (done in object_finalize).
* of all bytecodes assuming minimum length, building a list of all
* dependent spans as we go.
* "minimum" here means absolute minimum:
* - align and org bytecodes will be 0 length
* - align 0 length
* - times values (with span-dependent values) assumed to be 0
* b. Second pass through bytecodes continues to assume absolute minimum
* bytecode length but builds spans if necessary. To reduce interval
* tree size, this step avoids building spans for things that are
* considered "certainly long" such as inter-section references or if
* the distance calculated based on minimum length is already greater
* than the long threshold. If already certainly long, bytecode is
* updated with new length and subsequent bytecode offsets are updated
* with a running delta.
* c. Iterate over spans. Update span's length based on new bytecode offsets
* determined in 1b. If span's length exceeds long threshold, add that
* - org bumps offset
* b. Iterate over spans. Set span length based on bytecode offsets
* determined in 1a. If span is "certainly" long because the span
* is an absolute reference to another section (or external) or the
* distance calculated based on the minimum length is greater than the
* span's threshold, expand the span's bytecode, and if no further
* expansion can result, delete the span. Otherwise (or if the
* expansion results in another threshold of expansion), add span to
* interval tree.
* c. Iterate over bytecodes to update all bytecode offsets based on new
* (expanded) lengths calculated in 1b.
* d. Iterate over spans. Update span's length based on new bytecode offsets
* determined in 1c. If span's length exceeds long threshold, add that
* span to Q.
* 2. Main loop:
* While Q not empty:
* Expand BC dependent on span at head of Q (and remove span from Q).
* For each span that contains BC:
* Update span:
* If BC no longer dependent on span, mark span as inactive.
* If BC has new thresholds for span, update span.
* If BC increased in size, for each active span that contains BC:
* Increase span length by difference between short and long BC length.
* If span exceeds long threshold (or is flagged to recalculate on any
* change), add it to tail of Q.
* 3. Final pass over bytecodes to generate final offsets.
*/
void
yasm_object_optimize(yasm_object *object, yasm_arch *arch)
typedef struct yasm_span {
/*@reldef@*/ STAILQ_ENTRY(yasm_span) link;
/*@dependent@*/ yasm_bytecode *bc;
/*@owned@*/ yasm_expr *dependent;
/* Special handling: see descriptions above */
enum {
NOT_SPECIAL = 0,
SPECIAL_ALIGN,
SPECIAL_ORG,
SPECIAL_TIMES
} special;
long cur_val;
long new_val;
long neg_thres;
long pos_thres;
int id;
int active;
} yasm_span;
typedef struct optimize_data {
/*@reldef@*/ STAILQ_HEAD(yasm_spanhead, yasm_span) spans;
} optimize_data;
static void
optimize_add_span(void *add_span_data, yasm_bytecode *bc, int id,
/*@only@*/ yasm_expr *dependent, long neg_thres,
long pos_thres)
{
optimize_data *optd = (optimize_data *)add_span_data;
yasm_span *span = yasm_xmalloc(sizeof(yasm_span));
span->bc = bc;
span->dependent = dependent;
span->special = NOT_SPECIAL;
span->cur_val = 0;
span->new_val = 0;
span->neg_thres = neg_thres;
span->pos_thres = pos_thres;
span->id = id;
span->active = 1;
STAILQ_INSERT_TAIL(&optd->spans, span, link);
}
static void
update_all_bc_offsets(yasm_object *object)
{
yasm_section *sect;
int saw_error = 0;
/* Step 1b */
STAILQ_FOREACH(sect, &object->sections, link) {
unsigned long i;
unsigned long offset = 0;
yasm_bytecode *cur = STAILQ_FIRST(&sect->bcs);
yasm_bytecode *prev;
@ -638,54 +698,103 @@ yasm_object_optimize(yasm_object *object, yasm_arch *arch)
/* Iterate through the remainder, if any. */
while (cur) {
unsigned long long_len;
/*@only@*/ /*@null@*/ yasm_expr *critical;
long neg_thres;
long pos_thres;
int retval;
switch (yasm_bc_calc_len(cur, &long_len, &critical, &neg_thres,
&pos_thres)) {
case -1:
saw_error = 1;
break;
case 0:
/* No special action required */
break;
case 1:
/* Need to build a span */
yasm_bc_set_long(cur, long_len);
yasm_expr_destroy(critical);
break;
default:
yasm_internal_error(N_("bad return value from bc_calc_len"));
}
cur->offset = offset;
offset += cur->len;
prev = cur;
cur = STAILQ_NEXT(cur, link);
}
}
}
if (saw_error)
return;
void
yasm_object_optimize(yasm_object *object, yasm_arch *arch)
{
yasm_section *sect;
unsigned long bc_index = 0;
int saw_error = 0;
optimize_data optd;
yasm_span *span;
long neg_thres, pos_thres;
/* Step 3 */
STAILQ_INIT(&optd.spans);
/* Step 1a */
STAILQ_FOREACH(sect, &object->sections, link) {
unsigned long offset = 0;
yasm_bytecode *cur = STAILQ_FIRST(&sect->bcs);
yasm_bytecode *prev;
cur->bc_index = bc_index++;
/* Skip our locally created empty bytecode first. */
prev = cur;
cur = STAILQ_NEXT(cur, link);
/* Iterate through the remainder, if any. */
while (cur) {
cur->bc_index = bc_index++;
if (yasm_bc_calc_len(cur, optimize_add_span, &optd))
saw_error = 1;
/* TODO: times */
if (cur->multiple)
yasm_internal_error("multiple not yet supported");
cur->offset = offset;
offset += cur->len;
prev = cur;
cur = STAILQ_NEXT(cur, link);
}
}
if (saw_error)
return;
/* Step 1b */
STAILQ_FOREACH(span, &optd.spans, link) {
yasm_expr *depcopy = yasm_expr_copy(span->dependent);
yasm_intnum *intn =
yasm_expr_get_intnum(&depcopy, yasm_common_calc_bc_dist);
if (intn)
span->new_val = yasm_intnum_get_int(intn);
else {
/* absolute, external, or too complex; force to longer form */
span->new_val = LONG_MAX;
span->active = 0;
}
if (span->new_val < span->neg_thres
|| span->new_val > span->pos_thres) {
int retval = yasm_bc_expand(span->bc, span->id, span->cur_val,
span->new_val, &neg_thres, &pos_thres);
if (retval < 0)
saw_error = 1;
else if (retval > 0) {
span->neg_thres = neg_thres;
span->pos_thres = pos_thres;
} else
span->active = 0;
}
span->cur_val = span->new_val;
yasm_expr_destroy(depcopy);
}
if (saw_error)
return;
/* Step 1c */
update_all_bc_offsets(object);
/* Step 1d */
STAILQ_FOREACH(span, &optd.spans, link) {
if (!span->active)
continue;
}
/* Step 2 */
/* Step 3 */
update_all_bc_offsets(object);
}

@ -69,20 +69,24 @@ static void x86_ea_print(const yasm_effaddr *ea, FILE *f, int indent_level);
static void x86_bc_insn_destroy(void *contents);
static void x86_bc_insn_print(const void *contents, FILE *f,
int indent_level);
static int x86_bc_insn_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres,
long *pos_thres);
static void x86_bc_insn_set_long(yasm_bytecode *bc);
static int x86_bc_insn_calc_len(yasm_bytecode *bc,
yasm_bc_add_span_func add_span,
void *add_span_data);
static int x86_bc_insn_expand(yasm_bytecode *bc, int span, long old_val,
long new_val, /*@out@*/ long *neg_thres,
/*@out@*/ long *pos_thres);
static int x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp,
void *d, yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void x86_bc_jmp_destroy(void *contents);
static void x86_bc_jmp_print(const void *contents, FILE *f, int indent_level);
static int x86_bc_jmp_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres,
long *pos_thres);
static void x86_bc_jmp_set_long(yasm_bytecode *bc);
static int x86_bc_jmp_calc_len(yasm_bytecode *bc,
yasm_bc_add_span_func add_span,
void *add_span_data);
static int x86_bc_jmp_expand(yasm_bytecode *bc, int span, long old_val,
long new_val, /*@out@*/ long *neg_thres,
/*@out@*/ long *pos_thres);
static int x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp,
void *d, yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
@ -90,9 +94,9 @@ static int x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp,
static void x86_bc_jmpfar_destroy(void *contents);
static void x86_bc_jmpfar_print(const void *contents, FILE *f,
int indent_level);
static int x86_bc_jmpfar_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres,
long *pos_thres);
static int x86_bc_jmpfar_calc_len(yasm_bytecode *bc,
yasm_bc_add_span_func add_span,
void *add_span_data);
static int x86_bc_jmpfar_tobytes
(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
@ -112,7 +116,7 @@ static const yasm_bytecode_callback x86_bc_callback_insn = {
x86_bc_insn_print,
yasm_bc_finalize_common,
x86_bc_insn_calc_len,
x86_bc_insn_set_long,
x86_bc_insn_expand,
x86_bc_insn_tobytes
};
@ -121,7 +125,7 @@ static const yasm_bytecode_callback x86_bc_callback_jmp = {
x86_bc_jmp_print,
yasm_bc_finalize_common,
x86_bc_jmp_calc_len,
x86_bc_jmp_set_long,
x86_bc_jmp_expand,
x86_bc_jmp_tobytes
};
@ -130,7 +134,7 @@ static const yasm_bytecode_callback x86_bc_callback_jmpfar = {
x86_bc_jmpfar_print,
yasm_bc_finalize_common,
x86_bc_jmpfar_calc_len,
yasm_bc_set_long_common,
yasm_bc_expand_common,
x86_bc_jmpfar_tobytes
};
@ -534,16 +538,14 @@ x86_common_calc_len(const x86_common *common)
}
static int
x86_bc_insn_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
x86_bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data)
{
x86_insn *insn = (x86_insn *)bc->contents;
/*@null@*/ yasm_expr *temp;
x86_effaddr *x86_ea = (x86_effaddr *)insn->ea;
yasm_effaddr *ea = &x86_ea->ea;
yasm_immval *imm = insn->imm;
int retval = 0;
int common_len = 0;
if (ea) {
if (ea->disp) {
@ -579,18 +581,15 @@ x86_bc_insn_calc_len(yasm_bytecode *bc, unsigned long *long_len,
* critical expression.
*/
bc->len += 1;
long_len += (insn->common.addrsize == 16) ? 2U : 4U;
*critical = yasm_expr_copy(ea->disp);
*neg_thres = -128;
*pos_thres = 127;
retval = 1;
add_span(add_span_data, bc, 1, yasm_expr_copy(ea->disp), -128,
127);
} else
bc->len += ea->len;
}
/* Compute length of ea and add to total */
common_len += x86_ea->need_modrm + (x86_ea->need_sib ? 1:0);
common_len += (x86_ea->ea.segreg != 0) ? 1 : 0;
bc->len += x86_ea->need_modrm + (x86_ea->need_sib ? 1:0);
bc->len += (x86_ea->ea.segreg != 0) ? 1 : 0;
}
if (imm) {
@ -609,6 +608,7 @@ x86_bc_insn_calc_len(yasm_bytecode *bc, unsigned long *long_len,
/* We can use the sign-extended byte form: shorten
* the immediate length to 1.
*/
imm->len = 1;
immlen = 1;
} else {
/* We can't use the ,1. */
@ -620,11 +620,8 @@ x86_bc_insn_calc_len(yasm_bytecode *bc, unsigned long *long_len,
* expression.
*/
immlen = 1;
long_len += imm->len;
*critical = yasm_expr_copy(imm->val);
*neg_thres = -128;
*pos_thres = 127;
retval = 1;
add_span(add_span_data, bc, 2, yasm_expr_copy(imm->val),
-128, 127);
}
}
@ -645,40 +642,32 @@ x86_bc_insn_calc_len(yasm_bytecode *bc, unsigned long *long_len,
}
insn->postop = X86_POSTOP_NONE;
} else {
/* Unknown; default to ,1 form and set as critical
* expression.
/* Just assume we can't use the ,1 form: allowing this
* is more work than it's worth.
*/
immlen = 0;
long_len += imm->len;
*critical = yasm_expr_copy(imm->val);
*neg_thres = 1;
*pos_thres = 1;
retval = 1;
insn->opcode.opcode[0] = insn->opcode.opcode[1];
insn->postop = X86_POSTOP_NONE;
}
}
}
common_len += immlen;
bc->len += immlen;
}
common_len += insn->opcode.len;
common_len += x86_common_calc_len(&insn->common);
common_len += (insn->special_prefix != 0) ? 1:0;
bc->len += insn->opcode.len;
bc->len += x86_common_calc_len(&insn->common);
bc->len += (insn->special_prefix != 0) ? 1:0;
if (insn->rex != 0xff &&
(insn->rex != 0 ||
(insn->common.mode_bits == 64 && insn->common.opersize == 64 &&
insn->def_opersize_64 != 64)))
common_len++;
bc->len += common_len;
if (retval > 0)
*long_len += common_len;
return retval;
bc->len++;
return 0;
}
static void
x86_bc_insn_set_long(yasm_bytecode *bc)
static int
x86_bc_insn_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
/*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
{
x86_insn *insn = (x86_insn *)bc->contents;
/*@null@*/ yasm_expr *temp;
@ -692,93 +681,99 @@ x86_bc_insn_set_long(yasm_bytecode *bc)
ea->len = (insn->common.addrsize == 16) ? 2U : 4U;
x86_ea->modrm &= ~0300;
x86_ea->modrm |= 0200;
bc->len--;
bc->len += ea->len;
}
}
if (imm && imm->val) {
/* Handle shift postop special-casing */
if (insn->postop == X86_POSTOP_SHIFT) {
/* We can't use the ,1 form. */
insn->opcode.opcode[0] = insn->opcode.opcode[1];
if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) {
bc->len--;
bc->len += imm->len;
insn->postop = X86_POSTOP_NONE;
}
}
return 0;
}
static int
x86_bc_jmp_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
x86_bc_jmp_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data)
{
x86_jmp *jmp = (x86_jmp *)bc->contents;
int retval = 0;
unsigned int common_len;
unsigned char opersize;
/* As opersize may be 0, figure out its "real" value. */
opersize = (jmp->common.opersize == 0) ?
jmp->common.mode_bits : jmp->common.opersize;
if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) {
if (jmp->shortop.len == 0) {
yasm__error(bc->line, N_("short jump does not exist"));
return -1;
}
bc->len += x86_common_calc_len(&jmp->common);
/* We want to be sure to error if we exceed short length, so still
* put it in as a critical expression, but leave the return value as
* 0.
*/
bc->len += jmp->shortop.len + 1;
*critical = yasm_expr_create(YASM_EXPR_SUB,
yasm_expr_expr(yasm_expr_copy(jmp->target)),
yasm_expr_sym(jmp->origin), bc->line);
*neg_thres = -128;
*pos_thres = 127;
} else if (jmp->op_sel == JMP_NEAR_FORCED || jmp->shortop.len == 0) {
if (jmp->op_sel == JMP_NEAR_FORCED || jmp->shortop.len == 0) {
if (jmp->nearop.len == 0) {
yasm__error(bc->line, N_("near jump does not exist"));
return -1;
}
/* Near jump, no spans needed */
bc->len += jmp->nearop.len;
bc->len += (opersize == 16) ? 2 : 4;
} else {
/* short length goes into bytecode */
retval = 1;
bc->len += jmp->shortop.len + 1;
*long_len += jmp->nearop.len;
*long_len += (opersize == 16) ? 2 : 4;
*critical = yasm_expr_create(YASM_EXPR_SUB,
yasm_expr_expr(yasm_expr_copy(jmp->target)),
yasm_expr_sym(jmp->origin), bc->line);
*neg_thres = -128;
*pos_thres = 127;
return 0;
}
common_len = x86_common_calc_len(&jmp->common);
bc->len += common_len;
if (retval > 0)
*long_len += common_len;
if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) {
if (jmp->shortop.len == 0) {
yasm__error(bc->line, N_("short jump does not exist"));
return -1;
}
/* We want to be sure to error if we exceed short length, so
* put it in as a dependent expression (falling through).
*/
}
return retval;
/* Short jump, generate span */
bc->len += jmp->shortop.len + 1;
add_span(add_span_data, bc, 1,
yasm_expr_create(YASM_EXPR_SUB,
yasm_expr_expr(yasm_expr_copy(jmp->target)),
yasm_expr_sym(jmp->origin), bc->line),
-128, 127);
return 0;
}
static void
x86_bc_jmp_set_long(yasm_bytecode *bc)
static int
x86_bc_jmp_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
/*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
{
x86_jmp *jmp = (x86_jmp *)bc->contents;
unsigned char opersize;
if (span != 1)
yasm_internal_error(N_("unrecognized span id"));
/* As opersize may be 0, figure out its "real" value. */
opersize = (jmp->common.opersize == 0) ?
jmp->common.mode_bits : jmp->common.opersize;
if (jmp->nearop.len == 0) {
yasm__error(bc->line,
N_("short jump out of range"));
return;
yasm__error(bc->line, N_("short jump out of range"));
return -1;
}
/* Upgrade to a near jump */
jmp->op_sel = JMP_NEAR;
bc->len -= jmp->shortop.len + 1;
bc->len += jmp->nearop.len;
bc->len += (opersize == 16) ? 2 : 4;
return 0;
}
static int
x86_bc_jmpfar_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
x86_bc_jmpfar_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data)
{
x86_jmpfar *jmpfar = (x86_jmpfar *)bc->contents;
unsigned char opersize;

Loading…
Cancel
Save