From: Peter Johnson Date: Sun, 11 Jun 2006 06:57:03 +0000 (-0000) Subject: Implement first phase of align and org. X-Git-Tag: v0.6.0~172^2~24 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=114cee8b06a237248fe9f7e7afcd2675f81cf70e;p=yasm Implement first phase of align and org. svn path=/branches/new-optimizer/; revision=1567 --- diff --git a/libyasm/bc-align.c b/libyasm/bc-align.c index 152b9625..7e74cd3f 100644 --- a/libyasm/bc-align.c +++ b/libyasm/bc-align.c @@ -71,7 +71,7 @@ static const yasm_bytecode_callback bc_align_callback = { bc_align_calc_len, bc_align_expand, bc_align_tobytes, - 0 + YASM_BC_SPECIAL_OFFSET }; @@ -121,40 +121,45 @@ static int 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")); -#if 0 + long neg_thres = 0; + long pos_thres = 0; + + if (bc_align_expand(bc, 0, 0, (long)bc->offset, &neg_thres, + &pos_thres) < 0) + return -1; + + return 0; +} + +static int +bc_align_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ bytecode_align *align = (bytecode_align *)bc->contents; unsigned long end; unsigned long boundary = - yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, NULL)); + yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, 0)); if (boundary == 0) { bc->len = 0; - return YASM_BC_RESOLVE_MIN_LEN; + *pos_thres = 0; + return 0; } - end = bc->offset; - if (bc->offset & (boundary-1)) - end = (bc->offset & ~(boundary-1)) + boundary; + end = new_val; + if (new_val & (boundary-1)) + end = (new_val & ~(boundary-1)) + boundary; - bc->len = end - bc->offset; + *pos_thres = end; + bc->len = end - new_val; if (align->maxskip) { unsigned long maxskip = - yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, NULL)); - if ((end - bc->offset) > maxskip) + yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, 0)); + if ((end - new_val) > maxskip) bc->len = 0; } -#endif - return 0; -} - -static int -bc_align_expand(yasm_bytecode *bc, int span, long old_val, long new_val, - /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) -{ - yasm_internal_error(N_("align not yet implemented")); - return 0; + return 1; } static int diff --git a/libyasm/bc-int.h b/libyasm/bc-int.h index a25eeb3b..198ca2d9 100644 --- a/libyasm/bc-int.h +++ b/libyasm/bc-int.h @@ -38,7 +38,11 @@ typedef struct yasm_bytecode_callback { int (*tobytes) (yasm_bytecode *bc, unsigned char **bufp, void *d, yasm_output_value_func output_value, /*@null@*/ yasm_output_reloc_func output_reloc); - int reserve; /* Reserve space instead of outputting data */ + enum { + YASM_BC_SPECIAL_NONE = 0, + YASM_BC_SPECIAL_RESERVE,/* Reserves space instead of outputting data */ + YASM_BC_SPECIAL_OFFSET /* Adjusts offset instead of calculating len */ + } special; } yasm_bytecode_callback; struct yasm_bytecode { diff --git a/libyasm/bc-org.c b/libyasm/bc-org.c index 27760192..646d43cc 100644 --- a/libyasm/bc-org.c +++ b/libyasm/bc-org.c @@ -64,7 +64,7 @@ static const yasm_bytecode_callback bc_org_callback = { bc_org_calc_len, bc_org_expand, bc_org_tobytes, - 0 + YASM_BC_SPECIAL_OFFSET }; @@ -91,20 +91,13 @@ static int 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 bytecode_org *org = (bytecode_org *)bc->contents; + long neg_thres = 0; + long pos_thres = org->start; - /* Check for overrun */ - if (bc->offset > org->start) { - yasm_error_set(YASM_ERROR_GENERAL, - N_("ORG overlap with already existing data")); - return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN; - } + if (bc_org_expand(bc, 0, 0, (long)bc->offset, &neg_thres, &pos_thres) < 0) + return -1; - /* Generate space to start offset */ - bc->len = org->start - bc->offset; -#endif return 0; } @@ -112,8 +105,18 @@ static int bc_org_expand(yasm_bytecode *bc, int span, long old_val, long new_val, /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) { - yasm_internal_error(N_("org not yet implemented")); - return 0; + bytecode_org *org = (bytecode_org *)bc->contents; + + /* Check for overrun */ + if ((unsigned long)new_val > org->start) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("ORG overlap with already existing data")); + return -1; + } + + /* Generate space to start offset */ + bc->len = org->start - new_val; + return 1; } static int diff --git a/libyasm/bc-reserve.c b/libyasm/bc-reserve.c index 2be15122..cc0ef845 100644 --- a/libyasm/bc-reserve.c +++ b/libyasm/bc-reserve.c @@ -63,7 +63,7 @@ static const yasm_bytecode_callback bc_reserve_callback = { bc_reserve_calc_len, yasm_bc_expand_common, bc_reserve_tobytes, - 1 + YASM_BC_SPECIAL_RESERVE }; diff --git a/libyasm/bytecode.c b/libyasm/bytecode.c index b49b2d98..1320d3e6 100644 --- a/libyasm/bytecode.c +++ b/libyasm/bytecode.c @@ -83,20 +83,13 @@ yasm_bc_create_common(const yasm_bytecode_callback *callback, void *contents, yasm_bytecode *bc = yasm_xmalloc(sizeof(yasm_bytecode)); bc->callback = callback; - bc->section = NULL; - bc->multiple = (yasm_expr *)NULL; bc->len = 0; - bc->line = line; - bc->offset = ~0UL; /* obviously incorrect / uninitialized value */ - bc->opt_flags = 0; - bc->symrecs = NULL; - bc->contents = contents; return bc; @@ -206,29 +199,31 @@ yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, bc->len = 0; if (!bc->callback) - yasm_internal_error(N_("got empty bytecode in bc_resolve")); + yasm_internal_error(N_("got empty bytecode in yasm_bc_calc_len")); else 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; - num = yasm_expr_get_intnum(&bc->multiple, NULL); - if (!num) { + num = yasm_expr_get_intnum(&bc->multiple, 0); + if (num) + bc->len *= yasm_intnum_get_uint(num); + else { if (yasm_expr__contains(bc->multiple, YASM_EXPR_FLOAT)) { yasm_error_set(YASM_ERROR_VALUE, N_("expression must not contain floating point value")); retval = -1; } else { /* FIXME: Non-constant currently not allowed. */ - yasm__error(bc->line, - N_("attempt to use non-constant multiple")); + yasm_error_set(YASM_ERROR_VALUE, + N_("attempt to use non-constant multiple")); retval = -1; } } } -#endif + /* If we got an error somewhere along the line, clear out any calc len */ if (retval < 0) bc->len = 0; @@ -241,7 +236,7 @@ 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) { - yasm_internal_error(N_("got empty bytecode in bc_set_long")); + yasm_internal_error(N_("got empty bytecode in yasm_bc_expand")); /*@unreached@*/ return 0; } else @@ -267,7 +262,7 @@ yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize, } /* special case for reserve bytecodes */ - if (bc->callback->reserve) { + if (bc->callback->special == YASM_BC_SPECIAL_RESERVE) { *bufsize = bc->len; *gap = 1; return NULL; /* we didn't allocate a buffer */ diff --git a/libyasm/bytecode.h b/libyasm/bytecode.h index 7bd740d6..299bd4d6 100644 --- a/libyasm/bytecode.h +++ b/libyasm/bytecode.h @@ -317,7 +317,7 @@ void yasm_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); * \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, yasm_value *value, + (void *add_span_data, yasm_bytecode *bc, int id, const yasm_value *value, long neg_thres, long pos_thres); /** Resolve EQUs in a bytecode and calculate its minimum size. diff --git a/libyasm/section.c b/libyasm/section.c index e0402c1d..1f7d62e3 100644 --- a/libyasm/section.c +++ b/libyasm/section.c @@ -648,20 +648,19 @@ yasm_section_print(const yasm_section *sect, FILE *f, int indent_level, * Some portions are critical values that must not depend on any bytecode * offset (either relative or absolute). * - * 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. + * ALIGN/ORG/other offset-based bytecodes: Length set to bump offset to + * alignment. Span from 0 to bytecode, update on any change. Can + * update to new offset for things like align, which gets propagated + * to update dependent spans. Alignment/ORG value is critical value. + * Cannot be combined with TIMES. * * 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). If the resultant - * next bytecode offset would be less than the old next bytecode offset, - * error. Otherwise increase offset and update dependent spans. + * trivial (just multiplied in at any bytecode size increase). Span + * 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. @@ -673,9 +672,8 @@ yasm_section_print(const yasm_section *sect, FILE *f, int indent_level, * of all bytecodes assuming minimum length, building a list of all * dependent spans as we go. * "minimum" here means absolute minimum: - * - align 0 length, but bumps offset + * - align/org (offset-based) bumps offset as normal * - times values (with span-dependent values) assumed to be 0 - * - org 0 length, but 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 @@ -707,13 +705,12 @@ typedef struct yasm_span { /*@dependent@*/ yasm_bytecode *bc; - yasm_value *depval; + yasm_value depval; /* Special handling: see descriptions above */ enum { NOT_SPECIAL = 0, - SPECIAL_ALIGN, - SPECIAL_ORG, + SPECIAL_BC_OFFSET, SPECIAL_TIMES } special; @@ -734,13 +731,13 @@ typedef struct optimize_data { static void optimize_add_span(void *add_span_data, yasm_bytecode *bc, int id, - yasm_value *value, long neg_thres, long pos_thres) + const yasm_value *value, 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->depval = value; + yasm_value_init_copy(&span->depval, value); span->special = NOT_SPECIAL; span->cur_val = 0; span->new_val = 0; @@ -752,29 +749,42 @@ optimize_add_span(void *add_span_data, yasm_bytecode *bc, int id, STAILQ_INSERT_TAIL(&optd->spans, span, link); } -static void -update_all_bc_offsets(yasm_object *object) +static int +update_all_bc_offsets(yasm_object *object, yasm_errwarns *errwarns) { yasm_section *sect; + int saw_error = 0; STAILQ_FOREACH(sect, &object->sections, link) { unsigned long offset = 0; - yasm_bytecode *cur = STAILQ_FIRST(§->bcs); - yasm_bytecode *prev; + yasm_bytecode *bc = STAILQ_FIRST(§->bcs); + yasm_bytecode *prevbc; /* Skip our locally created empty bytecode first. */ - prev = cur; - cur = STAILQ_NEXT(cur, link); + prevbc = bc; + bc = STAILQ_NEXT(bc, link); /* Iterate through the remainder, if any. */ - while (cur) { - cur->offset = offset; - offset += cur->len; - prev = cur; - cur = STAILQ_NEXT(cur, link); + while (bc) { + if (bc->callback->special == YASM_BC_SPECIAL_OFFSET) { + /* Recalculate/adjust len of offset-based bytecodes here */ + long neg_thres = 0; + long pos_thres = bc->offset+bc->len; + int retval = yasm_bc_expand(bc, 0, 0, + (long)(prevbc->offset+prevbc->len), + &neg_thres, &pos_thres); + yasm_errwarn_propagate(errwarns, bc->line); + if (retval < 0) + saw_error = 1; + } + bc->offset = offset; + offset += bc->len; + prevbc = bc; + bc = STAILQ_NEXT(bc, link); } } + return saw_error; } void @@ -797,31 +807,55 @@ yasm_object_optimize(yasm_object *object, yasm_arch *arch, STAILQ_FOREACH(sect, &object->sections, link) { unsigned long offset = 0; - yasm_bytecode *cur = STAILQ_FIRST(§->bcs); - yasm_bytecode *prev; + yasm_bytecode *bc = STAILQ_FIRST(§->bcs); + yasm_bytecode *prevbc; - cur->bc_index = bc_index++; + bc->bc_index = bc_index++; /* Skip our locally created empty bytecode first. */ - prev = cur; - cur = STAILQ_NEXT(cur, link); + prevbc = bc; + bc = STAILQ_NEXT(bc, link); /* Iterate through the remainder, if any. */ - while (cur) { - cur->bc_index = bc_index++; + while (bc) { + bc->bc_index = bc_index++; + bc->offset = offset; - if (yasm_bc_calc_len(cur, optimize_add_span, &optd)) + retval = yasm_bc_calc_len(bc, optimize_add_span, &optd); + yasm_errwarn_propagate(errwarns, bc->line); + if (retval) saw_error = 1; - yasm_errwarn_propagate(errwarns, cur->line); - - /* TODO: times */ - if (cur->multiple) - yasm_internal_error("multiple not yet supported"); + else { + if (bc->callback->special == YASM_BC_SPECIAL_OFFSET) { + span = yasm_xmalloc(sizeof(yasm_span)); + + span->bc = bc; + yasm_value_initialize(&span->depval, NULL, 0); + span->special = SPECIAL_BC_OFFSET; + span->cur_val = (long)(prevbc->offset+prevbc->len); + span->new_val = 0; + span->neg_thres = 0; + span->pos_thres = (long)(bc->offset+bc->len); + span->id = 0; + span->active = 1; + + STAILQ_INSERT_TAIL(&optd.spans, span, link); + if (bc->multiple) { + yasm_error_set(YASM_ERROR_VALUE, + N_("cannot combine multiples and setting assembly position")); + yasm_errwarn_propagate(errwarns, span->bc->line); + saw_error = 1; + } + } + /* TODO: times */ + if (bc->len != 0 && bc->multiple) { + yasm_internal_error("multiple not yet supported"); + } + offset += bc->len; + } - cur->offset = offset; - offset += cur->len; - prev = cur; - cur = STAILQ_NEXT(cur, link); + prevbc = bc; + bc = STAILQ_NEXT(bc, link); } } @@ -832,47 +866,61 @@ yasm_object_optimize(yasm_object *object, yasm_arch *arch, STAILQ_FOREACH(span, &optd.spans, link) { if (!span->active) continue; - yasm_value_init_copy(&val, span->depval); - num = yasm_value_get_intnum(&val, span->bc, 1); - if (num) { - span->new_val = yasm_intnum_get_int(num); - yasm_intnum_destroy(num); - } else { - /* external or too complex; force to longer form */ - span->new_val = LONG_MAX; - span->active = 0; - } - yasm_value_delete(&val); - - if ((span->id == 0 && span->new_val != span->cur_val) || - (span->new_val < span->neg_thres - || span->new_val > span->pos_thres)) { - retval = yasm_bc_expand(span->bc, span->id, span->cur_val, - span->new_val, &neg_thres, &pos_thres); - yasm_errwarn_propagate(errwarns, span->bc->line); - if (retval < 0) - saw_error = 1; - else if (retval > 0) { - if (!span->active) { - yasm_error_set(YASM_ERROR_VALUE, - N_("secondary expansion of an external/complex value")); - yasm_errwarn_propagate(errwarns, span->bc->line); - saw_error = 1; + switch (span->special) { + case NOT_SPECIAL: + yasm_value_init_copy(&val, &span->depval); + num = yasm_value_get_intnum(&val, span->bc, 1); + if (num) { + span->new_val = yasm_intnum_get_int(num); + yasm_intnum_destroy(num); } else { - span->neg_thres = neg_thres; - span->pos_thres = pos_thres; + /* external or too complex; force to longest form */ + span->new_val = LONG_MAX; + span->active = 0; } - } else - span->active = 0; + yasm_value_delete(&val); + + if ((span->id == 0 && span->new_val != span->cur_val) || + (span->new_val < span->neg_thres + || span->new_val > span->pos_thres)) { + retval = yasm_bc_expand(span->bc, span->id, span->cur_val, + span->new_val, &neg_thres, + &pos_thres); + yasm_errwarn_propagate(errwarns, span->bc->line); + if (retval < 0) + saw_error = 1; + else if (retval > 0) { + if (!span->active) { + yasm_error_set(YASM_ERROR_VALUE, + N_("secondary expansion of an external/complex value")); + yasm_errwarn_propagate(errwarns, span->bc->line); + saw_error = 1; + } else { + span->neg_thres = neg_thres; + span->pos_thres = pos_thres; + } + } else + span->active = 0; + } + span->cur_val = span->new_val; + if (span->active) { + /* Add to interval tree */ + } + break; + case SPECIAL_BC_OFFSET: + /* Add to interval tree; nothing else to do here */ + break; + case SPECIAL_TIMES: + break; } - span->cur_val = span->new_val; } if (saw_error) return; /* Step 1c */ - update_all_bc_offsets(object); + if (update_all_bc_offsets(object, errwarns)) + return; /* Step 1d */ STAILQ_FOREACH(span, &optd.spans, link) { @@ -883,5 +931,5 @@ yasm_object_optimize(yasm_object *object, yasm_arch *arch, /* Step 2 */ /* Step 3 */ - update_all_bc_offsets(object); + update_all_bc_offsets(object, errwarns); } diff --git a/libyasm/value.c b/libyasm/value.c index 94726d13..067684e2 100644 --- a/libyasm/value.c +++ b/libyasm/value.c @@ -494,31 +494,33 @@ yasm_value_get_intnum(yasm_value *value, yasm_bytecode *bc, int calc_bc_dist) } if (value->rel) { - /* If relative portion is not in bc section, return NULL. - * Otherwise get the relative portion's offset. - */ + /* Get the relative portion's offset. */ /*@dependent@*/ yasm_bytecode *rel_prevbc; unsigned long dist; - if (!bc) - return NULL; /* Can't calculate relative value */ + if (!calc_bc_dist) + return NULL; /* Don't calculate BC distance */ sym_local = yasm_symrec_get_label(value->rel, &rel_prevbc); if (value->wrt || value->seg_of || value->section_rel || !sym_local) return NULL; /* we can't handle SEG, WRT, or external symbols */ - if (rel_prevbc->section != bc->section) - return NULL; /* not in this section */ - if (!value->curpos_rel) - return NULL; /* not PC-relative */ - /* Calculate value relative to current assembly position */ + /* Calculate relative value as integer */ dist = rel_prevbc->offset + rel_prevbc->len; - if (dist < bc->offset) { - outval = yasm_intnum_create_uint(bc->offset - dist); - yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL); - } else { - dist -= bc->offset; - outval = yasm_intnum_create_uint(dist); + if (value->curpos_rel) { + /* PC-relative */ + if (!bc) + return NULL; /* Can't calculate PC-relative value */ + if (rel_prevbc->section != bc->section) + return NULL; /* not in this section */ + + if (dist < bc->offset) { + outval = yasm_intnum_create_uint(bc->offset - dist); + yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL); + } else { + dist -= bc->offset; + outval = yasm_intnum_create_uint(dist); + } } if (value->rshift > 0) { diff --git a/libyasm/value.h b/libyasm/value.h index 89a93aa8..0517f189 100644 --- a/libyasm/value.h +++ b/libyasm/value.h @@ -100,15 +100,15 @@ int yasm_value_finalize_expr(/*@out@*/ yasm_value *value, /*@null@*/ /*@kept@*/ yasm_expr *e, unsigned int size); -/** Get value if absolute or PC-relative section-local relative. Returns NULL - * otherwise. +/** Get value if absolute, pure relative, or PC-relative section-local + * relative. Returns NULL otherwise. * \param value value * \param bc current bytecode (for PC-relative calculation); if * NULL, NULL is returned for PC-relative values. * \param calc_bc_dist if nonzero, calculates bytecode distances in absolute * portion of value * \note Adds in value.rel (correctly) if PC-relative and in the same section - * as bc (and there is no WRT or SEG). + * as bc (and there is no WRT or SEG), or if value is pure-relative. * \return Intnum if can be resolved to integer value, otherwise NULL. */ /*@null@*/ /*@only@*/ yasm_intnum *yasm_value_get_intnum diff --git a/tools/python-yasm/bytecode.pxi b/tools/python-yasm/bytecode.pxi index b5528e88..6cb47042 100644 --- a/tools/python-yasm/bytecode.pxi +++ b/tools/python-yasm/bytecode.pxi @@ -47,12 +47,6 @@ cdef extern from "libyasm/bytecode.h": cdef struct yasm_dataval cdef struct yasm_datavalhead - cdef enum yasm_bc_resolve_flags: - YASM_BC_RESOLVE_NONE - YASM_BC_RESOLVE_ERROR - YASM_BC_RESOLVE_MIN_LEN - YASM_BC_RESOLVE_UNKNOWN_LEN - cdef yasm_immval* yasm_imm_create_expr(yasm_expr *e) cdef yasm_expr* yasm_ea_get_disp(yasm_effaddr *ea) cdef void yasm_ea_set_len(yasm_effaddr *ea, unsigned int len) @@ -118,6 +112,11 @@ cdef extern from "libyasm/bytecode.h": int indent_level) cdef extern from "libyasm/bc-int.h": + cdef enum yasm_bc_special: + YASM_BC_SPECIAL_NONE + YASM_BC_SPECIAL_RESERVE + YASM_BC_SPECIAL_OFFSET + cdef struct yasm_bytecode_callback: void (*destroy) (void *contents) void (*c_print "print") (void *contents, FILE *f, int indent_level) @@ -129,7 +128,7 @@ cdef extern from "libyasm/bc-int.h": int (*tobytes) (yasm_bytecode *bc, unsigned char **bufp, void *d, yasm_output_value_func output_value, yasm_output_reloc_func output_reloc) - int reserve + yasm_bc_special special cdef struct yasm_bytecode: yasm_bytecode_callback *callback