Fix regular expression at doc/rdsrc.pl
[platform/upstream/nasm.git] / labels.c
index d907b35..98408b4 100644 (file)
--- a/labels.c
+++ b/labels.c
@@ -1,9 +1,38 @@
-/* labels.c  label handling for the Netwide Assembler
+/* ----------------------------------------------------------------------- *
  *
- * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
- * Julian Hall. All rights reserved. The software is
- * redistributable under the licence given in the file "Licence"
- * distributed in the NASM archive.
+ *   Copyright 1996-2009 The NASM Authors - All Rights Reserved
+ *   See the file AUTHORS included with the NASM distribution for
+ *   the specific copyright holders.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following
+ *   conditions are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * labels.c  label handling for the Netwide Assembler
  */
 
 #include "compiler.h"
  * @@, so @@local is a TASM compatible local label. Note that we only
  * check for the first @ symbol, although TASM requires both.
  */
-#define islocal(l)                                              \
-       (tasm_compatible_mode ?                                 \
-       (((l)[0] == '.' || (l)[0] == '@') && (l)[1] != '.') :   \
-       ((l)[0] == '.' && (l)[1] != '.'))
-#define islocalchar(c)                                         \
-       (tasm_compatible_mode ?                                  \
-       ((c) == '.' || (c) == '@') :                            \
-       ((c) == '.'))
-
-#define LABEL_BLOCK  128       /* no. of labels/block */
-#define LBLK_SIZE    (LABEL_BLOCK*sizeof(union label))
-
-#define END_LIST -3             /* don't clash with NO_SEG! */
-#define END_BLOCK -2
-#define BOGUS_VALUE -4
-
-#define PERMTS_SIZE  4096       /* size of text blocks */
-#if (PERMTS_SIZE > IDLEN_MAX)
-#error "IPERMTS_SIZE must be less than or equal to IDLEN_MAX"
+#define islocal(l)                                                      \
+        (tasm_compatible_mode ?                                         \
+                (((l)[0] == '.' || (l)[0] == '@') && (l)[1] != '.') :   \
+                ((l)[0] == '.' && (l)[1] != '.'))
+#define islocalchar(c)                                                  \
+        (tasm_compatible_mode ?                                         \
+                ((c) == '.' || (c) == '@') :                            \
+                ((c) == '.'))
+
+#define LABEL_BLOCK     128     /* no. of labels/block */
+#define LBLK_SIZE       (LABEL_BLOCK * sizeof(union label))
+
+#define END_LIST        -3      /* don't clash with NO_SEG! */
+#define END_BLOCK       -2
+#define BOGUS_VALUE     -4
+
+#define PERMTS_SIZE     16384   /* size of text blocks */
+#if (PERMTS_SIZE < IDLEN_MAX)
+ #error "IPERMTS_SIZE must be greater than or equal to IDLEN_MAX"
 #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
-#define LOCAL_SYMBOL (DEFINED_BIT)
-#define GLOBAL_PLACEHOLDER (GLOBAL_BIT)
-#define GLOBAL_SYMBOL (DEFINED_BIT|GLOBAL_BIT)
+#define NOT_DEFINED_YET         0
+#define TYPE_MASK               3
+#define LOCAL_SYMBOL            (DEFINED_BIT)
+#define GLOBAL_PLACEHOLDER      (GLOBAL_BIT)
+#define GLOBAL_SYMBOL           (DEFINED_BIT | GLOBAL_BIT)
 
 union label {                   /* actual label structures */
     struct {
-        int32_t segment, offset;
+        int32_t segment;
+        int64_t offset;
         char *label, *special;
         int is_global, is_norm;
     } defn;
     struct {
-        int32_t movingon, dummy;
+        int32_t movingon;
+        int64_t dummy;
         union label *next;
     } admin;
 };
@@ -75,11 +107,11 @@ struct permts {                 /* permanent text storage */
     char data[PERMTS_SIZE];     /* ... the data block itself */
 };
 
-extern bool global_offset_changed;       /* defined in nasm.c */
+extern int64_t global_offset_changed;   /* defined in nasm.c */
 
-static struct hash_table *ltab;                /* labels hash table */
-static union label *ldata;             /* all label data blocks */
-static union label *lfree;             /* labels free block */
+static struct hash_table ltab;          /* labels hash table */
+static union label *ldata;              /* all label data blocks */
+static union label *lfree;              /* labels free block */
 static struct permts *perm_head;        /* start of perm. text storage */
 static struct permts *perm_tail;        /* end of perm. text storage */
 
@@ -108,45 +140,47 @@ static union label *find_label(char *label, int create)
 
     if (islocal(label)) {
         prev = prevlabel;
-       prevlen = strlen(prev);
-       len = strlen(label);
-       if (prevlen+len >= IDLEN_MAX)
-           return NULL;        /* Error... */
-       memcpy(label_str, prev, prevlen);
-       memcpy(label_str+prevlen, label, len+1);
-       label = label_str;
+        prevlen = strlen(prev);
+        len = strlen(label);
+        if (prevlen + len >= IDLEN_MAX) {
+            nasm_error(ERR_NONFATAL, "identifier length exceed %i bytes",
+                       IDLEN_MAX);
+            return NULL;
+        }
+        memcpy(label_str, prev, prevlen);
+        memcpy(label_str+prevlen, label, len+1);
+        label = label_str;
     } else {
         prev = "";
-       prevlen = 0;
+        prevlen = 0;
     }
 
-    lpp = (union label **) hash_find(ltab, label, &ip);
+    lpp = (union label **) hash_find(&ltab, label, &ip);
     lptr = lpp ? *lpp : NULL;
 
     if (lptr || !create)
-       return lptr;
+        return lptr;
 
     /* Create a new label... */
     if (lfree->admin.movingon == END_BLOCK) {
-       /*
-        * must allocate a new block
-        */
-       lfree->admin.next =
-           (union label *)nasm_malloc(LBLK_SIZE);
-       lfree = lfree->admin.next;
-       init_block(lfree);
+        /*
+         * must allocate a new block
+         */
+        lfree->admin.next = (union label *)nasm_malloc(LBLK_SIZE);
+        lfree = lfree->admin.next;
+        init_block(lfree);
     }
-    
+
     lfree->admin.movingon = BOGUS_VALUE;
     lfree->defn.label = perm_copy(label);
     lfree->defn.special = NULL;
     lfree->defn.is_global = NOT_DEFINED_YET;
-    
+
     hash_add(&ip, lfree->defn.label, lfree);
     return lfree++;
 }
 
-bool lookup_label(char *label, int32_t *segment, int32_t *offset)
+bool lookup_label(char *label, int32_t *segment, int64_t *offset)
 {
     union label *lptr;
 
@@ -158,8 +192,9 @@ bool lookup_label(char *label, int32_t *segment, int32_t *offset)
         *segment = lptr->defn.segment;
         *offset = lptr->defn.offset;
         return true;
-    } else
-        return false;
+    }
+
+    return false;
 }
 
 bool is_extern(char *label)
@@ -173,9 +208,8 @@ bool is_extern(char *label)
     return (lptr && (lptr->defn.is_global & EXTERN_BIT));
 }
 
-void redefine_label(char *label, int32_t segment, int32_t offset, char *special,
-                    bool is_norm, bool isextrn, struct ofmt *ofmt,
-                    efunc error)
+void redefine_label(char *label, int32_t segment, int64_t offset, char *special,
+                    bool is_norm, bool isextrn)
 {
     union label *lptr;
     int exi;
@@ -185,31 +219,32 @@ void redefine_label(char *label, int32_t segment, int32_t offset, char *special,
      * are even possible, nor whether they are checked somewhere else
      */
 
-    (void)segment;              /* Don't warn that this parameter is unused */
     (void)special;              /* Don't warn that this parameter is unused */
     (void)is_norm;              /* Don't warn that this parameter is unused */
     (void)isextrn;              /* Don't warn that this parameter is unused */
-    (void)ofmt;                 /* Don't warn that this parameter is unused */
 
 #ifdef DEBUG
-#if DEBUG<3
+#if DEBUG < 3
     if (!strncmp(label, "debugdump", 9))
 #endif
-        error(ERR_DEBUG, "redefine_label (%s, %ld, %08lx, %s, %d, %d)",
+        nasm_error(ERR_DEBUG, "redefine_label (%s, %"PRIx32", %"PRIx64", %s, %d, %d)",
               label, segment, offset, special, is_norm, isextrn);
 #endif
 
     lptr = find_label(label, 1);
     if (!lptr)
-        error(ERR_PANIC, "can't find label `%s' on pass two", label);
+        nasm_error(ERR_PANIC, "can't find label `%s' on pass two", label);
 
     if (!islocal(label)) {
         if (!islocalchar(*label) && lptr->defn.is_norm)
             prevlabel = lptr->defn.label;
     }
 
-    global_offset_changed |= (lptr->defn.offset != offset);
+    if (lptr->defn.offset != offset)
+        global_offset_changed++;
+
     lptr->defn.offset = offset;
+    lptr->defn.segment = segment;
 
     if (pass0 == 1) {
         exi = !!(lptr->defn.is_global & GLOBAL_BIT);
@@ -226,28 +261,22 @@ void redefine_label(char *label, int32_t segment, int32_t offset, char *special,
 
             ofmt->symdef(xsymbol, segment, offset, exi,
                          special ? special : lptr->defn.special);
-            ofmt->current_dfmt->debug_deflabel(xsymbol, segment, offset,
-                                               exi,
-                                               special ? special : lptr->
-                                               defn.special);
+            ofmt->current_dfmt->debug_deflabel(xsymbol, segment, offset, exi,
+                                               special ? special : lptr->defn.special);
 /**    nasm_free(xsymbol);  ! outobj.c stores the pointer; ouch!!! **/
         } else {
-            if ((lptr->defn.is_global & (GLOBAL_BIT | EXTERN_BIT)) !=
-                EXTERN_BIT) {
+            if ((lptr->defn.is_global & (GLOBAL_BIT | EXTERN_BIT)) != EXTERN_BIT) {
                 ofmt->symdef(lptr->defn.label, segment, offset, exi,
                              special ? special : lptr->defn.special);
-                ofmt->current_dfmt->debug_deflabel(label, segment, offset,
-                                                   exi,
-                                                   special ? special :
-                                                   lptr->defn.special);
+                ofmt->current_dfmt->debug_deflabel(label, segment, offset, exi,
+                                                   special ? special : lptr->defn.special);
             }
         }
-    }
-    /* if (pass0 == 1) */
+    }   /* if (pass0 == 1) */
 }
 
-void define_label(char *label, int32_t segment, int32_t offset, char *special,
-                  bool is_norm, bool isextrn, struct ofmt *ofmt, efunc error)
+void define_label(char *label, int32_t segment, int64_t offset, char *special,
+                  bool is_norm, bool isextrn)
 {
     union label *lptr;
     int exi;
@@ -256,22 +285,25 @@ void define_label(char *label, int32_t segment, int32_t offset, char *special,
 #if DEBUG<3
     if (!strncmp(label, "debugdump", 9))
 #endif
-        error(ERR_DEBUG, "define_label (%s, %ld, %08lx, %s, %d, %d)",
+        nasm_error(ERR_DEBUG, "define_label (%s, %"PRIx32", %"PRIx64", %s, %d, %d)",
               label, segment, offset, special, is_norm, isextrn);
 #endif
     lptr = find_label(label, 1);
+    if (!lptr)
+        return;
     if (lptr->defn.is_global & DEFINED_BIT) {
-        error(ERR_NONFATAL, "symbol `%s' redefined", label);
+        nasm_error(ERR_NONFATAL, "symbol `%s' redefined", label);
         return;
     }
     lptr->defn.is_global |= DEFINED_BIT;
     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) {
-        error(ERR_NONFATAL, "attempt to define a local label before any"
+    else if (islocal(label) && !*prevlabel) {
+        nasm_error(ERR_NONFATAL, "attempt to define a local label before any"
               " non-local labels");
     }
 
@@ -279,7 +311,7 @@ void define_label(char *label, int32_t segment, int32_t offset, char *special,
     lptr->defn.offset = offset;
     lptr->defn.is_norm = (!islocalchar(label[0]) && is_norm);
 
-    if (pass0 == 1 || (!is_norm && !isextrn && (segment & 1))) {
+    if (pass0 == 1 || (!is_norm && !isextrn && (segment > 0) && (segment & 1))) {
         exi = !!(lptr->defn.is_global & GLOBAL_BIT);
         if (exi) {
             char *xsymbol;
@@ -294,63 +326,66 @@ void define_label(char *label, int32_t segment, int32_t offset, char *special,
 
             ofmt->symdef(xsymbol, segment, offset, exi,
                          special ? special : lptr->defn.special);
-            ofmt->current_dfmt->debug_deflabel(xsymbol, segment, offset,
-                                               exi,
-                                               special ? special : lptr->
-                                               defn.special);
+            ofmt->current_dfmt->debug_deflabel(xsymbol, segment, offset, exi,
+                                               special ? special : lptr->defn.special);
 /**    nasm_free(xsymbol);  ! outobj.c stores the pointer; ouch!!! **/
         } else {
-            if ((lptr->defn.is_global & (GLOBAL_BIT | EXTERN_BIT)) !=
-                EXTERN_BIT) {
+            if ((lptr->defn.is_global & (GLOBAL_BIT | EXTERN_BIT)) != EXTERN_BIT) {
                 ofmt->symdef(lptr->defn.label, segment, offset, exi,
                              special ? special : lptr->defn.special);
-                ofmt->current_dfmt->debug_deflabel(label, segment, offset,
-                                                   exi,
-                                                   special ? special :
-                                                   lptr->defn.special);
+                ofmt->current_dfmt->debug_deflabel(label, segment, offset, exi,
+                                                   special ? special : lptr->defn.special);
             }
         }
-    }                           /* if (pass0 == 1) */
+    }   /* if (pass0 == 1) */
 }
 
-void define_common(char *label, int32_t segment, int32_t size, char *special,
-                   struct ofmt *ofmt, efunc error)
+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);
+    if (!lptr)
         return;
+    if ((lptr->defn.is_global & DEFINED_BIT) &&
+        (passn == 1 || !(lptr->defn.is_global & COMMON_BIT))) {
+            nasm_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
-        error(ERR_NONFATAL, "attempt to define a local label as a "
+    } else {
+        nasm_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);
     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)
+void declare_as_global(char *label, char *special)
 {
     union label *lptr;
 
     if (islocal(label)) {
-        error(ERR_NONFATAL, "attempt to declare local symbol `%s' as"
+        nasm_error(ERR_NONFATAL, "attempt to declare local symbol `%s' as"
               " global", label);
         return;
     }
     lptr = find_label(label, 1);
+    if (!lptr)
+        return;
     switch (lptr->defn.is_global & TYPE_MASK) {
     case NOT_DEFINED_YET:
         lptr->defn.is_global = GLOBAL_PLACEHOLDER;
@@ -360,22 +395,24 @@ void declare_as_global(char *label, char *special, efunc error)
     case GLOBAL_SYMBOL:
         break;
     case LOCAL_SYMBOL:
-        if (!lptr->defn.is_global & EXTERN_BIT)
-            error(ERR_NONFATAL, "symbol `%s': GLOBAL directive must"
-                  " appear before symbol definition", label);
+        if (!(lptr->defn.is_global & EXTERN_BIT)) {
+            nasm_error(ERR_WARNING, "symbol `%s': GLOBAL directive "
+                  "after symbol definition is an experimental feature", label);
+            lptr->defn.is_global = GLOBAL_SYMBOL;
+        }
         break;
     }
 }
 
 int init_labels(void)
 {
-    ltab = hash_init();
+    hash_init(&ltab, HASH_LARGE);
 
     ldata = lfree = (union label *)nasm_malloc(LBLK_SIZE);
     init_block(lfree);
 
-    perm_head =
-        perm_tail = (struct permts *)nasm_malloc(sizeof(struct permts));
+    perm_head = perm_tail =
+        (struct permts *)nasm_malloc(sizeof(struct permts));
 
     perm_head->next = NULL;
     perm_head->size = PERMTS_SIZE;
@@ -394,14 +431,14 @@ void cleanup_labels(void)
 
     initialized = false;
 
-    hash_free(ltab);
+    hash_free(&ltab);
 
     lptr = lhold = ldata;
     while (lptr) {
-       lptr = &lptr[LABEL_BLOCK-1];
-       lptr = lptr->admin.next;
-       nasm_free(lhold);
-       lhold = lptr;
+        lptr = &lptr[LABEL_BLOCK-1];
+        lptr = lptr->admin.next;
+        nasm_free(lhold);
+        lhold = lptr;
     }
 
     while (perm_head) {
@@ -426,6 +463,8 @@ static char *perm_copy(const char *string)
     char *p;
     int len = strlen(string)+1;
 
+    nasm_assert(len <= PERMTS_SIZE);
+
     if (perm_tail->size - perm_tail->usage < len) {
         perm_tail->next =
             (struct permts *)nasm_malloc(sizeof(struct permts));
@@ -441,6 +480,11 @@ static char *perm_copy(const char *string)
     return p;
 }
 
+char *local_scope(char *label)
+{
+   return islocal(label) ? prevlabel : "";
+}
+
 /*
  * Notes regarding bug involving redefinition of external segments.
  *