]> granicus.if.org Git - yasm/commitdiff
More gracefully handle absolute section refernce expansion, and allow for
authorPeter Johnson <peter@tortall.net>
Tue, 14 Mar 2006 08:52:41 +0000 (08:52 -0000)
committerPeter Johnson <peter@tortall.net>
Tue, 14 Mar 2006 08:52:41 +0000 (08:52 -0000)
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

libyasm/expr-int.h
libyasm/expr.c
libyasm/section.c
libyasm/section.h
libyasm/tests/Makefile.inc
libyasm/tests/absloop-err.asm [new file with mode: 0644]
libyasm/tests/absloop-err.errwarn [new file with mode: 0644]
modules/objfmts/bin/bin-objfmt.c

index a93b828229ba368a2d58cdc4e2f8a501c47409f9..456da9cabbed9206ca6e3dc1b7de9fd8cd93dcde 100644 (file)
@@ -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 {
index 7480c7420a88d8cec47da0aa9248dc09955534d4..f207b1fe03e7f102905c754a5a7403b88deb0637 100644 (file)
@@ -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; i<e->numterms; 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; j<e->numterms; 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; i<e->numterms; 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; i<e->numterms; 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:
index 12b63bd959655496fe3d75560e33e52d266e41c0..b50e571fd0514a46143db2f7d674c33bec9aa19e 100644 (file)
@@ -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)
index 531a5195ad94cfd57c06b50dc69c06a79f09e9dc..61327511b991dc99d92b6d5b8dc2d0c6ef1fbc26 100644 (file)
@@ -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
index d7ef00537d422b0a9a2efb9cc6c87eacf3e9d5ac..f14ec4d7336333d6ad07972d45a2e8ac9cb36aaa 100644 (file)
@@ -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 (file)
index 0000000..27e88a0
--- /dev/null
@@ -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 (file)
index 0000000..df8172d
--- /dev/null
@@ -0,0 +1 @@
+-:1: circular reference detected.
index 9dfca3fda110ceffe01b3ee7e4f71f2d23ff4221..0932ebb767890ce19ec6249e8af4aeb88b80b254 100644 (file)
@@ -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),