-/* 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;
};
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 */
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(<ab, 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;
*segment = lptr->defn.segment;
*offset = lptr->defn.offset;
return true;
- } else
- return false;
+ }
+
+ return false;
}
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;
* 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);
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;
#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");
}
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;
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;
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(<ab, 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;
initialized = false;
- hash_free(ltab);
+ hash_free(<ab);
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) {
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));
return p;
}
+char *local_scope(char *label)
+{
+ return islocal(label) ? prevlabel : "";
+}
+
/*
* Notes regarding bug involving redefinition of external segments.
*