BR 2781900: handle common labels while optimizing
authorH. Peter Anvin <hpa@zytor.com>
Sat, 27 Jun 2009 23:30:00 +0000 (16:30 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Sat, 27 Jun 2009 23:30:00 +0000 (16:30 -0700)
When optimizing, we have to keep track of common labels, since a
common symbol cannot be optimized -- only the linker will know where
it will end up.  In that sense it is similar to an EXTERN symbol.

Thus, allow them to be entered in the symbol table but make sure we
don't holler too hard on redefinition.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
labels.c
nasm.c

index 9a7fc61..49792d2 100644 (file)
--- a/labels.c
+++ b/labels.c
 #endif
 
 /* values for label.defn.is_global */
-#define DEFINED_BIT 1
-#define GLOBAL_BIT 2
-#define EXTERN_BIT 4
+#define DEFINED_BIT    1
+#define GLOBAL_BIT     2
+#define EXTERN_BIT     4
+#define COMMON_BIT     8
 
 #define NOT_DEFINED_YET 0
 #define TYPE_MASK 3
@@ -209,7 +210,9 @@ void redefine_label(char *label, int32_t segment, int64_t offset, char *special,
             prevlabel = lptr->defn.label;
     }
 
-    if (lptr->defn.offset != offset) global_offset_changed++;
+    if (lptr->defn.offset != offset)
+       global_offset_changed++;
+
     lptr->defn.offset = offset;
     lptr->defn.segment = segment;
 
@@ -270,9 +273,10 @@ void define_label(char *label, int32_t segment, int64_t offset, char *special,
     if (isextrn)
         lptr->defn.is_global |= EXTERN_BIT;
 
-    if (!islocalchar(label[0]) && is_norm)      /* not local, but not special either */
+    if (!islocalchar(label[0]) && is_norm) {
+       /* not local, but not special either */
         prevlabel = lptr->defn.label;
-    else if (islocal(label) && !*prevlabel) {
+    else if (islocal(label) && !*prevlabel) {
         error(ERR_NONFATAL, "attempt to define a local label before any"
               " non-local labels");
     }
@@ -321,26 +325,32 @@ void define_common(char *label, int32_t segment, int32_t size, char *special,
     union label *lptr;
 
     lptr = find_label(label, 1);
-    if (lptr->defn.is_global & DEFINED_BIT) {
-        error(ERR_NONFATAL, "symbol `%s' redefined", label);
-        return;
+    if ((lptr->defn.is_global & DEFINED_BIT) &&
+       (passn == 1 || !(lptr->defn.is_global & COMMON_BIT))) {
+           error(ERR_NONFATAL, "symbol `%s' redefined", label);
+           return;
     }
-    lptr->defn.is_global |= DEFINED_BIT;
+    lptr->defn.is_global |= DEFINED_BIT|COMMON_BIT;
 
-    if (!islocalchar(label[0])) /* not local, but not special either */
+    if (!islocalchar(label[0])) {
         prevlabel = lptr->defn.label;
-    else
+    } else {
         error(ERR_NONFATAL, "attempt to define a local label as a "
               "common variable");
+       return;
+    }
 
     lptr->defn.segment = segment;
     lptr->defn.offset = 0;
 
+    if (pass0 == 0)
+       return;
+
     ofmt->symdef(lptr->defn.label, segment, size, 2,
-                 special ? special : lptr->defn.special);
+                special ? special : lptr->defn.special);
     ofmt->current_dfmt->debug_deflabel(lptr->defn.label, segment, size, 2,
-                                       special ? special : lptr->defn.
-                                       special);
+                                      special ? special : lptr->defn.
+                                      special);
 }
 
 void declare_as_global(char *label, char *special, efunc error)
diff --git a/nasm.c b/nasm.c
index 5535215..9d3776a 100644 (file)
--- a/nasm.c
+++ b/nasm.c
@@ -1189,8 +1189,10 @@ static void assemble_file(char *fname, StrList **depend_ptr)
            enum directives d;
             globallineno++;
 
-            /* here we parse our directives; this is not handled by the 'real'
-             * parser. */
+            /*
+            * Here we parse our directives; this is not handled by the
+            * 'real' parser.  This really should be a separate function.
+            */
             directive = line;
            d = getkw(&directive, &value);
             if (d) {
@@ -1289,61 +1291,59 @@ static void assemble_file(char *fname, StrList **depend_ptr)
                     }           /* pass == 1 */
                     break;
                 case D_COMMON:         /* [COMMON symbol size:special] */
+               {
+                   int64_t size;
+
                     if (*value == '$')
                         value++;        /* skip initial $ if present */
-                    if (pass0 == 1) {
-                        p = value;
-                        validid = true;
-                        if (!isidstart(*p))
-                            validid = false;
-                        while (*p && !nasm_isspace(*p)) {
-                            if (!isidchar(*p))
-                                validid = false;
-                            p++;
-                        }
-                        if (!validid) {
-                            report_error(ERR_NONFATAL,
-                                         "identifier expected after COMMON");
-                            break;
-                        }
-                        if (*p) {
-                            int64_t size;
-
-                            while (*p && nasm_isspace(*p))
-                                *p++ = '\0';
-                            q = p;
-                            while (*q && *q != ':')
-                                q++;
-                            if (*q == ':') {
-                                *q++ = '\0';
-                                special = q;
-                            } else
-                                special = NULL;
-                            size = readnum(p, &rn_error);
-                            if (rn_error)
-                                report_error(ERR_NONFATAL,
-                                             "invalid size specified"
-                                             " in COMMON declaration");
-                            else
-                                define_common(value, seg_alloc(), size,
-                                              special, ofmt, report_error);
-                        } else
-                            report_error(ERR_NONFATAL,
-                                         "no size specified in"
-                                         " COMMON declaration");
-                    } else if (pass0 == 2) {    /* pass == 2 */
-                        q = value;
-                        while (*q && *q != ':') {
-                            if (nasm_isspace(*q))
-                                *q = '\0';
-                            q++;
-                        }
-                        if (*q == ':') {
-                            *q++ = '\0';
-                            ofmt->symdef(value, 0L, 0L, 3, q);
-                        }
+                   p = value;
+                   validid = true;
+                   if (!isidstart(*p))
+                       validid = false;
+                   while (*p && !nasm_isspace(*p)) {
+                       if (!isidchar(*p))
+                           validid = false;
+                       p++;
+                   }
+                   if (!validid) {
+                       report_error(ERR_NONFATAL,
+                                    "identifier expected after COMMON");
+                       break;
+                   }
+                   if (*p) {
+                       while (*p && nasm_isspace(*p))
+                           *p++ = '\0';
+                       q = p;
+                       while (*q && *q != ':')
+                           q++;
+                       if (*q == ':') {
+                           *q++ = '\0';
+                           special = q;
+                       } else {
+                           special = NULL;
+                       }
+                       size = readnum(p, &rn_error);
+                       if (rn_error) {
+                           report_error(ERR_NONFATAL,
+                                        "invalid size specified"
+                                        " in COMMON declaration");
+                           break;
+                       }
+                   } else {
+                       report_error(ERR_NONFATAL,
+                                    "no size specified in"
+                                    " COMMON declaration");
+                       break;
+                   }
+
+                    if (pass0 < 2) {
+                       define_common(value, seg_alloc(), size,
+                                     special, ofmt, report_error);
+                    } else if (pass0 == 2) {
+                       ofmt->symdef(value, 0L, 0L, 3, special);
                     }
                     break;
+               }
                 case D_ABSOLUTE:               /* [ABSOLUTE address] */
                     stdscan_reset();
                     stdscan_bufptr = value;
@@ -1690,9 +1690,10 @@ static void assemble_file(char *fname, StrList **depend_ptr)
             nasm_free(line);
             location.offset = offs = GET_CURR_OFFS;
         }                       /* end while (line = preproc->getline... */
-        if (pass1 == 2 && global_offset_changed)
+
+        if (pass0 && global_offset_changed)
             report_error(ERR_NONFATAL,
-                         "phase error detected at end of assembly.");
+                        "phase error detected at end of assembly.");
 
         if (pass1 == 1)
             preproc->cleanup(1);