/* symbols.c -symbol table-
- Copyright (C) 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996
+ Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 1997
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with GAS; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ along with GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
/* #define DEBUG_SYMS / * to debug symbol list maintenance */
#ifdef DEBUG_SYMS
#define debug_verify_symchain verify_symbol_chain
#else
-#define debug_verify_symchain (void)
+#define debug_verify_symchain(root, last) ((void) 0)
#endif
struct obstack notes;
static void fb_label_init PARAMS ((void));
+static long dollar_label_instance PARAMS ((long));
+static long fb_label_instance PARAMS ((long));
/* symbol_new()
}
#endif
symbol_append (symbolP, symbol_lastP, &symbol_rootP, &symbol_lastP);
- debug_verify_symchain (symbol_rootP, symbol_lastP);
return symbolP;
}
/* Sun local labels go out of scope whenever a non-local symbol is
defined. */
- if (LOCAL_LABELS_DOLLAR && *sym_name != 'L')
- dollar_label_clear ();
+ if (LOCAL_LABELS_DOLLAR)
+ {
+ int local;
+
+#ifdef BFD_ASSEMBLER
+ local = bfd_is_local_label_name (stdoutput, sym_name);
+#else
+ local = LOCAL_LABEL (sym_name);
+#endif
+
+ if (! local)
+ dollar_label_clear ();
+ }
#ifndef WORKING_DOT_WORD
if (new_broken_words)
possible_bytes,
(relax_substateT) 0,
(symbolS *) broken_words,
- 0L,
+ (offsetT) 0,
NULL);
/* We want to store the pointer to where to insert the jump table in the
{
symbolP->sy_frag = frag_now;
#ifdef OBJ_VMS
- S_GET_OTHER(symbolP) = const_flag;
+ S_SET_OTHER(symbolP, const_flag);
#endif
S_SET_VALUE (symbolP, (valueT) frag_now_fix ());
S_SET_SEGMENT (symbolP, now_seg);
data. */
symbolP->sy_frag = frag_now;
#ifdef OBJ_VMS
- S_GET_OTHER(symbolP) = const_flag;
-#endif /* OBJ_VMS */
+ S_SET_OTHER(symbolP, const_flag);
+#endif
S_SET_VALUE (symbolP, (valueT) frag_now_fix ());
S_SET_SEGMENT (symbolP, now_seg); /* keep N_EXT bit */
}
{
know (*rootPP == NULL);
know (*lastPP == NULL);
+ addme->sy_next = NULL;
+#ifdef SYMBOLS_NEED_BACKPOINTERS
+ addme->sy_previous = NULL;
+#endif
*rootPP = addme;
*lastPP = addme;
return;
#ifdef SYMBOLS_NEED_BACKPOINTERS
addme->sy_previous = target;
#endif /* SYMBOLS_NEED_BACKPOINTERS */
+
+ debug_verify_symchain (symbol_rootP, symbol_lastP);
}
/* Set the chain pointers of SYMBOL to null. */
for (; symbol_next (symbolP) != NULL; symbolP = symbol_next (symbolP))
{
#ifdef SYMBOLS_NEED_BACKPOINTERS
- know (symbolP->sy_next->sy_previous == symbolP);
+ assert (symbolP->sy_next->sy_previous == symbolP);
#else
/* Walk the list anyways, to make sure pointers are still good. */
;
symp->sy_resolving = 1;
- reduce:
+ /* Simplify addition or subtraction of a constant by folding the
+ constant into X_add_number. */
+ if (symp->sy_value.X_op == O_add
+ || symp->sy_value.X_op == O_subtract)
+ {
+ resolve_symbol_value (symp->sy_value.X_add_symbol);
+ resolve_symbol_value (symp->sy_value.X_op_symbol);
+ if (S_GET_SEGMENT (symp->sy_value.X_op_symbol) == absolute_section)
+ {
+ right = S_GET_VALUE (symp->sy_value.X_op_symbol);
+ if (symp->sy_value.X_op == O_add)
+ symp->sy_value.X_add_number += right;
+ else
+ symp->sy_value.X_add_number -= right;
+ symp->sy_value.X_op = O_symbol;
+ symp->sy_value.X_op_symbol = NULL;
+ }
+ else if ((S_GET_SEGMENT (symp->sy_value.X_add_symbol)
+ == absolute_section)
+ && symp->sy_value.X_op == O_add)
+ {
+ left = S_GET_VALUE (symp->sy_value.X_add_symbol);
+ symp->sy_value.X_add_symbol = symp->sy_value.X_op_symbol;
+ symp->sy_value.X_add_number += left;
+ symp->sy_value.X_op = O_symbol;
+ symp->sy_value.X_op_symbol = NULL;
+ }
+ }
+
switch (symp->sy_value.X_op)
{
case O_absent:
if (symp->sy_value.X_add_number == 0)
copy_symbol_attributes (symp, symp->sy_value.X_add_symbol);
- S_SET_VALUE (symp,
- (symp->sy_value.X_add_number
- + symp->sy_frag->fr_address
- + S_GET_VALUE (symp->sy_value.X_add_symbol)));
- if (S_GET_SEGMENT (symp) == expr_section
- || S_GET_SEGMENT (symp) == undefined_section)
- S_SET_SEGMENT (symp,
- S_GET_SEGMENT (symp->sy_value.X_add_symbol));
-
/* If we have equated this symbol to an undefined symbol, we
- keep X_op set to O_symbol. This permits the routine
- which writes out relocation to detect this case, and
- convert the relocation to be against the symbol to which
- this symbol is equated. */
- if (! S_IS_DEFINED (symp) || S_IS_COMMON (symp))
- symp->sy_value.X_op = O_symbol;
+ keep X_op set to O_symbol, and we don't change
+ X_add_number. This permits the routine which writes out
+ relocation to detect this case, and convert the
+ relocation to be against the symbol to which this symbol
+ is equated. */
+ if (! S_IS_DEFINED (symp->sy_value.X_add_symbol)
+ || S_IS_COMMON (symp->sy_value.X_add_symbol))
+ {
+ symp->sy_value.X_op = O_symbol;
+ S_SET_SEGMENT (symp,
+ S_GET_SEGMENT (symp->sy_value.X_add_symbol));
+ }
+ else
+ {
+ S_SET_VALUE (symp,
+ (symp->sy_value.X_add_number
+ + symp->sy_frag->fr_address
+ + S_GET_VALUE (symp->sy_value.X_add_symbol)));
+ if (S_GET_SEGMENT (symp) == expr_section
+ || S_GET_SEGMENT (symp) == undefined_section)
+ S_SET_SEGMENT (symp,
+ S_GET_SEGMENT (symp->sy_value.X_add_symbol));
+ }
resolved = symp->sy_value.X_add_symbol->sy_resolved;
break;
resolved = symp->sy_value.X_add_symbol->sy_resolved;
break;
- case O_add:
- resolve_symbol_value (symp->sy_value.X_add_symbol);
- resolve_symbol_value (symp->sy_value.X_op_symbol);
- seg_left = S_GET_SEGMENT (symp->sy_value.X_add_symbol);
- seg_right = S_GET_SEGMENT (symp->sy_value.X_op_symbol);
- /* This case comes up with PIC support. */
- {
- symbolS *s_left = symp->sy_value.X_add_symbol;
- symbolS *s_right = symp->sy_value.X_op_symbol;
-
- if (seg_left == absolute_section)
- {
- symbolS *t;
- segT ts;
- t = s_left;
- s_left = s_right;
- s_right = t;
- ts = seg_left;
- seg_left = seg_right;
- seg_right = ts;
- }
- if (seg_right == absolute_section
- && s_right->sy_resolved)
- {
- symp->sy_value.X_add_number += S_GET_VALUE (s_right);
- symp->sy_value.X_op_symbol = 0;
- symp->sy_value.X_add_symbol = s_left;
- symp->sy_value.X_op = O_symbol;
- goto reduce;
- }
- }
- /* fall through */
-
case O_multiply:
case O_divide:
case O_modulus:
case O_bit_or_not:
case O_bit_exclusive_or:
case O_bit_and:
+ case O_add:
case O_subtract:
case O_eq:
case O_ne:
resolve_symbol_value (symp->sy_value.X_op_symbol);
seg_left = S_GET_SEGMENT (symp->sy_value.X_add_symbol);
seg_right = S_GET_SEGMENT (symp->sy_value.X_op_symbol);
- if (seg_left != seg_right
- && seg_left != undefined_section
- && seg_right != undefined_section)
- as_bad ("%s is operation on symbols in different sections",
- S_GET_NAME (symp));
- if ((S_GET_SEGMENT (symp->sy_value.X_add_symbol)
- != absolute_section)
- && symp->sy_value.X_op != O_subtract)
- as_bad ("%s is illegal operation on non-absolute symbols",
- S_GET_NAME (symp));
left = S_GET_VALUE (symp->sy_value.X_add_symbol);
right = S_GET_VALUE (symp->sy_value.X_op_symbol);
+
+ /* Subtraction is permitted if both operands are in the same
+ section. Otherwise, both operands must be absolute. We
+ already handled the case of addition or subtraction of a
+ constant above. This will probably need to be changed
+ for an object file format which supports arbitrary
+ expressions, such as IEEE-695. */
+ if ((seg_left != absolute_section
+ || seg_right != absolute_section)
+ && (symp->sy_value.X_op != O_subtract
+ || seg_left != seg_right))
+ {
+ char *file;
+ unsigned int line;
+
+ if (expr_symbol_where (symp, &file, &line))
+ {
+ if (seg_left == undefined_section)
+ as_bad_where (file, line,
+ "undefined symbol %s in operation",
+ S_GET_NAME (symp->sy_value.X_add_symbol));
+ if (seg_right == undefined_section)
+ as_bad_where (file, line,
+ "undefined symbol %s in operation",
+ S_GET_NAME (symp->sy_value.X_op_symbol));
+ if (seg_left != undefined_section
+ && seg_right != undefined_section)
+ as_bad_where (file, line, "invalid section for operation");
+ }
+ else
+ {
+ if (seg_left == undefined_section)
+ as_bad ("undefined symbol %s in operation setting %s",
+ S_GET_NAME (symp->sy_value.X_add_symbol),
+ S_GET_NAME (symp));
+ if (seg_right == undefined_section)
+ as_bad ("undefined symbol %s in operation setting %s",
+ S_GET_NAME (symp->sy_value.X_op_symbol),
+ S_GET_NAME (symp));
+ if (seg_left != undefined_section
+ && seg_right != undefined_section)
+ as_bad ("invalid section for operation setting %s",
+ S_GET_NAME (symp));
+ }
+ }
+
switch (symp->sy_value.X_op)
{
case O_multiply: val = left * right; break;
return 0;
} /* dollar_label_defined() */
-static int
+static long
dollar_label_instance (label)
long label;
{
&& (strchr (name, '\001')
|| strchr (name, '\002')
|| (! flag_keep_locals
- && (LOCAL_LABEL (name)
+ && (bfd_is_local_label (stdoutput, s->bsym)
|| (flag_mri
&& name[0] == '?'
&& name[1] == '?')))));
symbolS *s;
{
if ((s->bsym->flags & BSF_WEAK) != 0)
- as_warn ("%s already declared as weak", S_GET_NAME (s));
+ {
+ /* Let .weak override .global. */
+ return;
+ }
s->bsym->flags |= BSF_GLOBAL;
s->bsym->flags &= ~(BSF_LOCAL|BSF_WEAK);
}
symbolS *s;
{
if ((s->bsym->flags & BSF_WEAK) != 0)
- as_warn ("%s already declared as weak", S_GET_NAME (s));
+ {
+ /* Let .weak override. */
+ return;
+ }
s->bsym->flags |= BSF_LOCAL;
s->bsym->flags &= ~(BSF_GLOBAL|BSF_WEAK);
}
S_SET_WEAK (s)
symbolS *s;
{
- if ((s->bsym->flags & BSF_GLOBAL) != 0)
- as_warn ("%s already declared as global", S_GET_NAME (s));
s->bsym->flags |= BSF_WEAK;
s->bsym->flags &= ~(BSF_GLOBAL|BSF_LOCAL);
}
#endif
-void print_expr_1 PARAMS ((FILE *, expressionS *));
-void print_symbol_value_1 PARAMS ((FILE *, symbolS *));
-
void
print_symbol_value_1 (file, sym)
FILE *file;