From: Peter Johnson Date: Tue, 14 Mar 2006 08:52:41 +0000 (-0000) Subject: More gracefully handle absolute section refernce expansion, and allow for X-Git-Tag: v0.5.0rc2~5^2~25 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=135d4727ddf0eb2bdccfaa73500ce6f15ee11c6a;p=yasm More gracefully handle absolute section refernce expansion, and allow for correct detection of absolute section reference loops (fixing a crash case). This is also needed for an ongoing rewrite of reloc/value handling. * expr.c (expr_xform_bc_dist): Remove transformation of absolute section references; move in changed form into... (yasm_expr__level_tree): Here. The new code doesn't immediately calculate the distance from the start of the absolute section to the referenced symbol; rather it generates an expression for this quantity. As this actually adds new absolute section refs to the tree, we can't expand with YASM_EXPR_SYMs, otherwise we would expand multiple times. Thus we need a new YASM_EXPR_SYMEXP type that thus does not get expanded. Unfortunately this ripples changes a bit because everywhere *else* we look for YASM_EXPR_SYM, we now need to look for YASM_EXPR_SYMEXP as well... (expr_xform_bc_dist): Here. (yasm_expr__copy_except): Here. (yasm_expr_extract_symrec): Here. (yasm_expr_get_symrec): Here. (yasm_expr_print): Here. * bin-objfmt.c (bin_objfmt_expr_xform): And here. * expr-int.h (yasm_expr__type): Define new YASM_EXPR_SYMEXP. * section.h (yasm_section_abs_get_sym): To implement above, we need to get a symbol referencing the first bytecode in the absolute section. To avoid creating redundant symrecs, one is generated for us now. This function lets us get it in yasm_expr__level_tree(). * section.c (yasm_section_abs_get_sym): Implement. (yasm_section): Add necessary SECTION_ABSOLUTE data. (yasm_section_create_absolute): Create the symrec here. * absloop-err.asm: New test for absolute section reference loops. svn path=/trunk/yasm/; revision=1417 --- diff --git a/libyasm/expr-int.h b/libyasm/expr-int.h index a93b8282..456da9ca 100644 --- a/libyasm/expr-int.h +++ b/libyasm/expr-int.h @@ -34,7 +34,8 @@ typedef enum { YASM_EXPR_INT = 1<<1, YASM_EXPR_FLOAT = 1<<2, YASM_EXPR_SYM = 1<<3, - YASM_EXPR_EXPR = 1<<4 + YASM_EXPR_SYMEXP = 1<<4, /* post-expanded sym (due to absolute expansion) */ + YASM_EXPR_EXPR = 1<<5 } yasm_expr__type; struct yasm_expr__item { diff --git a/libyasm/expr.c b/libyasm/expr.c index 7480c742..f207b1fe 100644 --- a/libyasm/expr.c +++ b/libyasm/expr.c @@ -155,8 +155,7 @@ yasm_expr_reg(unsigned long reg) } /* Transforms instances of symrec-symrec [symrec+(-1*symrec)] into integers if - * possible. Also transforms single symrec's that reference absolute sections. - * Uses a simple n^2 algorithm because n is usually quite small. + * possible. Uses a simple n^2 algorithm because n is usually quite small. */ static /*@only@*/ yasm_expr * expr_xform_bc_dist(/*@returned@*/ /*@only@*/ yasm_expr *e, @@ -168,24 +167,6 @@ expr_xform_bc_dist(/*@returned@*/ /*@only@*/ yasm_expr *e, /*@null@*/ yasm_intnum *dist; int numterms; - for (i=0; inumterms; i++) { - /* Transform symrecs that reference absolute sections into - * absolute start expr + intnum(dist). - */ - if (e->terms[i].type == YASM_EXPR_SYM && - yasm_symrec_get_label(e->terms[i].data.sym, &precbc) && - (sect = yasm_bc_get_section(precbc)) && - yasm_section_is_absolute(sect) && - (dist = calc_bc_dist(yasm_section_bcs_first(sect), precbc))) { - const yasm_expr *start = yasm_section_get_start(sect); - e->terms[i].type = YASM_EXPR_EXPR; - e->terms[i].data.expn = - yasm_expr_create(YASM_EXPR_ADD, - yasm_expr_expr(yasm_expr_copy(start)), - yasm_expr_int(dist), e->line); - } - } - /* Handle symrec-symrec in ADD exprs by looking for (-1*symrec) and * symrec term pairs (where both symrecs are in the same segment). */ @@ -208,10 +189,12 @@ expr_xform_bc_dist(/*@returned@*/ /*@only@*/ yasm_expr *e, continue; if (sube->terms[0].type == YASM_EXPR_INT && - sube->terms[1].type == YASM_EXPR_SYM) { + (sube->terms[1].type == YASM_EXPR_SYM || + sube->terms[1].type == YASM_EXPR_SYMEXP)) { intn = sube->terms[0].data.intn; sym = sube->terms[1].data.sym; - } else if (sube->terms[0].type == YASM_EXPR_SYM && + } else if ((sube->terms[0].type == YASM_EXPR_SYM || + sube->terms[0].type == YASM_EXPR_SYMEXP) && sube->terms[1].type == YASM_EXPR_INT) { sym = sube->terms[0].data.sym; intn = sube->terms[1].data.intn; @@ -227,7 +210,8 @@ expr_xform_bc_dist(/*@returned@*/ /*@only@*/ yasm_expr *e, /* Now look for a symrec term in the same segment */ for (j=0; jnumterms; j++) { - if (e->terms[j].type == YASM_EXPR_SYM && + if ((e->terms[j].type == YASM_EXPR_SYM || + e->terms[j].type == YASM_EXPR_SYMEXP) && yasm_symrec_get_label(e->terms[j].data.sym, &precbc2) && (sect = yasm_bc_get_section(precbc2)) && sect == sect2 && @@ -717,13 +701,18 @@ yasm_expr__level_tree(yasm_expr *e, int fold_const, int simplify_ident, /* traverse terms */ for (i=0; inumterms; i++) { - /* First expand equ's */ + /* Expansion stage first: expand equ's, and expand symrecs that + * reference absolute sections into + * absolute start expr + (symrec - first bc in abs section). + */ if (e->terms[i].type == YASM_EXPR_SYM) { + yasm__exprentry *np; const yasm_expr *equ_expr = yasm_symrec_get_equ(e->terms[i].data.sym); - if (equ_expr) { - yasm__exprentry *np; + /*@dependent@*/ yasm_section *sect; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; + if (equ_expr) { /* Check for circular reference */ SLIST_FOREACH(np, eh, next) { if (np->e == equ_expr) { @@ -738,6 +727,45 @@ yasm_expr__level_tree(yasm_expr *e, int fold_const, int simplify_ident, ee.e = equ_expr; SLIST_INSERT_HEAD(eh, &ee, next); + } else if (yasm_symrec_get_label(e->terms[i].data.sym, &precbc) && + (sect = yasm_bc_get_section(precbc)) && + yasm_section_is_absolute(sect)) { + const yasm_expr *start = yasm_section_get_start(sect); + yasm_expr *sube, *sube2; + + /* Check for circular reference */ + SLIST_FOREACH(np, eh, next) { + if (np->e == start) { + yasm__error(e->line, + N_("circular reference detected.")); + return e; + } + } + + sube = yasm_xmalloc(sizeof(yasm_expr)); + sube->op = YASM_EXPR_SUB; + sube->line = e->line; + sube->numterms = 2; + sube->terms[0].type = YASM_EXPR_SYMEXP; + sube->terms[0].data.sym = e->terms[i].data.sym; + sube->terms[1].type = YASM_EXPR_SYMEXP; + sube->terms[1].data.sym = yasm_section_abs_get_sym(sect); + assert(sube->terms[1].data.sym != NULL); + + sube2 = yasm_xmalloc(sizeof(yasm_expr)); + sube2->op = YASM_EXPR_ADD; + sube2->line = e->line; + sube2->numterms = 2; + sube2->terms[0].type = YASM_EXPR_EXPR; + sube2->terms[0].data.expn = yasm_expr_copy(start); + sube2->terms[1].type = YASM_EXPR_EXPR; + sube2->terms[1].data.expn = sube; + + e->terms[i].type = YASM_EXPR_EXPR; + e->terms[i].data.expn = sube2; + + ee.e = start; + SLIST_INSERT_HEAD(eh, &ee, next); } } @@ -831,6 +859,7 @@ yasm_expr__copy_except(const yasm_expr *e, int except) dest->type = src->type; switch (src->type) { case YASM_EXPR_SYM: + case YASM_EXPR_SYMEXP: /* Symbols don't need to be copied */ dest->data.sym = src->data.sym; break; @@ -1004,7 +1033,8 @@ yasm_expr_extract_symrec(yasm_expr **ep, return yasm_expr_extract_symrec(&((*ep)->terms[0].data.expn), relocate_action, calc_bc_dist); /* Replace sym with 0 value, return sym */ - if ((*ep)->terms[0].type == YASM_EXPR_SYM) { + if ((*ep)->terms[0].type == YASM_EXPR_SYM || + (*ep)->terms[0].type == YASM_EXPR_SYMEXP) { sym = (*ep)->terms[0].data.sym; symterm = 0; } @@ -1012,7 +1042,8 @@ yasm_expr_extract_symrec(yasm_expr **ep, case YASM_EXPR_ADD: /* Search for sym, if found, delete it from expr and return it */ for (i=0; i<(*ep)->numterms; i++) { - if ((*ep)->terms[i].type == YASM_EXPR_SYM) { + if ((*ep)->terms[i].type == YASM_EXPR_SYM || + (*ep)->terms[i].type == YASM_EXPR_SYMEXP) { sym = (*ep)->terms[i].data.sym; symterm = i; break; @@ -1176,7 +1207,9 @@ yasm_expr_get_symrec(yasm_expr **ep, int simplify) if (simplify) *ep = yasm_expr_simplify(*ep, NULL); - if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_SYM) + if ((*ep)->op == YASM_EXPR_IDENT && + ((*ep)->terms[0].type == YASM_EXPR_SYM || + (*ep)->terms[0].type == YASM_EXPR_SYMEXP)) return (*ep)->terms[0].data.sym; else return (yasm_symrec *)NULL; @@ -1303,6 +1336,7 @@ yasm_expr_print(const yasm_expr *e, FILE *f) for (i=0; inumterms; i++) { switch (e->terms[i].type) { case YASM_EXPR_SYM: + case YASM_EXPR_SYMEXP: fprintf(f, "%s", yasm_symrec_get_name(e->terms[i].data.sym)); break; case YASM_EXPR_EXPR: diff --git a/libyasm/section.c b/libyasm/section.c index 12b63bd9..b50e571f 100644 --- a/libyasm/section.c +++ b/libyasm/section.c @@ -64,9 +64,16 @@ struct yasm_section { union { /* SECTION_GENERAL data */ - struct general { + struct { /*@owned@*/ char *name; /* strdup()'ed name (given by user) */ } general; + /* SECTION_ABSOLUTE data */ + struct { + /* Internally created first symrec in section. Used by + * yasm_expr__level_tree during absolute reference expansion. + */ + /*@dependent@*/ yasm_symrec *first; + } absolute; } data; /* associated data; NULL if none */ @@ -201,6 +208,9 @@ yasm_object_create_absolute(yasm_object *object, yasm_expr *start, STAILQ_INIT(&s->relocs); s->destroy_reloc = NULL; + s->data.absolute.first = + yasm_symtab_define_label(object->symtab, ".absstart", bc, 0, 0); + s->code = 0; s->res_only = 1; s->def = 0; @@ -476,6 +486,14 @@ yasm_section_get_name(const yasm_section *sect) return NULL; } +yasm_symrec * +yasm_section_abs_get_sym(const yasm_section *sect) +{ + if (sect->type == SECTION_ABSOLUTE) + return sect->data.absolute.first; + return NULL; +} + void yasm_section_set_start(yasm_section *sect, yasm_expr *start, unsigned long line) diff --git a/libyasm/section.h b/libyasm/section.h index 531a5195..61327511 100644 --- a/libyasm/section.h +++ b/libyasm/section.h @@ -298,6 +298,13 @@ int yasm_section_bcs_traverse /*@observer@*/ /*@null@*/ const char *yasm_section_get_name (const yasm_section *sect); +/** Get starting symbol of an absolute section. + * \param sect section + * \return Starting symrec, or NULL if section is not absolute. + */ +/*@dependent@*/ /*@null@*/ yasm_symrec *yasm_section_abs_get_sym + (const yasm_section *sect); + /** Change starting address of a section. * \param sect section * \param start starting address diff --git a/libyasm/tests/Makefile.inc b/libyasm/tests/Makefile.inc index d7ef0053..f14ec4d7 100644 --- a/libyasm/tests/Makefile.inc +++ b/libyasm/tests/Makefile.inc @@ -7,6 +7,8 @@ TESTS += splitpath_test TESTS += libyasm/tests/libyasm_test.sh EXTRA_DIST += libyasm/tests/libyasm_test.sh +EXTRA_DIST += libyasm/tests/absloop-err.asm +EXTRA_DIST += libyasm/tests/absloop-err.errwarn EXTRA_DIST += libyasm/tests/charconst64.asm EXTRA_DIST += libyasm/tests/charconst64.errwarn EXTRA_DIST += libyasm/tests/charconst64.hex diff --git a/libyasm/tests/absloop-err.asm b/libyasm/tests/absloop-err.asm new file mode 100644 index 00000000..27e88a0f --- /dev/null +++ b/libyasm/tests/absloop-err.asm @@ -0,0 +1,6 @@ +[absolute x] +label1: +[absolute label1] +x: +[section .text] +mov ax, [x] diff --git a/libyasm/tests/absloop-err.errwarn b/libyasm/tests/absloop-err.errwarn new file mode 100644 index 00000000..df8172d3 --- /dev/null +++ b/libyasm/tests/absloop-err.errwarn @@ -0,0 +1 @@ +-:1: circular reference detected. diff --git a/modules/objfmts/bin/bin-objfmt.c b/modules/objfmts/bin/bin-objfmt.c index 9dfca3fd..0932ebb7 100644 --- a/modules/objfmts/bin/bin-objfmt.c +++ b/modules/objfmts/bin/bin-objfmt.c @@ -116,7 +116,8 @@ bin_objfmt_expr_xform(/*@returned@*/ /*@only@*/ yasm_expr *e, /* Transform symrecs that reference sections into * start expr + intnum(dist). */ - if (e->terms[i].type == YASM_EXPR_SYM && + if ((e->terms[i].type == YASM_EXPR_SYM || + e->terms[i].type == YASM_EXPR_SYMEXP) && yasm_symrec_get_label(e->terms[i].data.sym, &precbc) && (sect = yasm_bc_get_section(precbc)) && (dist = yasm_common_calc_bc_dist(yasm_section_bcs_first(sect),