/* symbols.c -symbol table-
Copyright (C) 1987 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
GAS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
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, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "obstack.h" /* For "symbols.h" */
#include "struc-symbol.h"
extern int new_broken_words
;
sy_hash
; /* symbol-name => struct symbol pointer */
/* Below are commented in "symbols.h". */
unsigned int local_bss_counter
;
symbolS
* symbol_find(); /* Keep C compiler happy. */
* Un*x idea of local labels. They are made by "n:" where n
* is any decimal digit. Refer to them with
* "nb" for previous (backward) n:
* or "nf" for next (forward) n:.
* Like Un*x AS, we have one set of local label counters for entire assembly,
* not one set per (sub)segment like in most assemblers. This implies that
* one can refer to a label in another segment, and indeed some crufty
* compilers have done just that.
* I document the symbol names here to save duplicating words elsewhere.
* The mth occurence of label n: is turned into the symbol "Ln^Am" where
* n is a digit and m is a decimal number. "L" makes it a label discarded
* unless debugging and "^A"('\1') ensures no ordinary symbol SHOULD get the
* same name as a local label symbol. The first "4:" is "L4^A1" - the m
typedef short unsigned int
static local_label_countT
static /* Returned to caller, then copied. */
char symbol_name_build
[12]; /* used for created names ("4f") */
int local_label_defined
[10];
symbol_rootP
= NULL
; /* In case we have 0 symbols (!!) */
bzero ((char *)(& abs_symbol
), sizeof(abs_symbol
));
abs_symbol
. sy_type
= N_ABS
; /* Can't initialise a union. Sigh. */
bzero ((char *)(local_label_counter
), sizeof(local_label_counter
) );
* Caller must copy returned name: we re-use the area for the next name.
char * /* Return local label name. */
local_label_name(n
, augend
)
register int n
; /* we just saw "n:", "nf" or "nb" : n a digit */
register int augend
; /* 0 for nb, 1 for n:, nf */
char symbol_name_temporary
[10]; /* build up a number, BACKWARDS */
know( augend
== 0 || augend
== 1 );
* p
++ = n
+ '0'; /* Make into ASCII */
n
= local_label_counter
[ n
] + augend
;
/* version number of this local label */
* Next code just does sprintf( {}, "%d", n);
* It is more elegant to do the next part recursively, but a procedure
* call for each digit emitted is considered too costly.
q
= symbol_name_temporary
;
for (*q
++=0; n
; q
++) /* emits NOTHING if n starts as 0 */
know(n
>0); /* We expect n > 0 always */
while ( * p
++ = * -- q
)
/* The label, as a '\0' ended string, starts at symbol_name_build. */
return (symbol_name_build
);
int n
; /* just saw "n:" */
local_label_counter
[n
] ++;
local_label_defined
[n
]=1;
colon (local_label_name (n
, 0));
* Return a pointer to a new symbol.
* Die if we can't make a new symbol.
* Fill in the symbol's values.
* Add symbol to end of symbol chain.
* Please always call this to create a new symbol.
* Changes since 1985: Symbol names may not contain '\0'. Sigh.
symbol_new (name
, type
, other
, desc
, value
, frag
)
char * name
; /* We copy this: OK to alter your copy. */
unsigned char type
; /* As in <a.out.h>. */
char other
; /* As in <a.out.h>. */
short int desc
; /* As in <a.out.h>. */
valueT value
; /* As in <a.out.h>, often an address. */
/* Often used as offset from frag address. */
struct frag
* frag
; /* For sy_frag. */
register symbolS
* symbolP
;
register char * preserved_copy_of_name
;
register unsigned int name_length
;
name_length
= strlen(name
) + 1;
obstack_grow(¬es
,name
,name_length
);
p
=obstack_finish(¬es
);
/* obstack_1done( ¬es, name, name_length, &p ); */
preserved_copy_of_name
= p
;
p
=obstack_alloc(¬es
,sizeof(struct symbol
));
/* obstack_1blank( ¬es, sizeof(struct symbol), &p ); */
symbolP
-> sy_name
= preserved_copy_of_name
;
symbolP
-> sy_type
= type
;
symbolP
-> sy_other
= other
;
symbolP
-> sy_desc
= desc
;
symbolP
-> sy_value
= value
;
symbolP
-> sy_frag
= frag
;
symbolP
-> sy_next
= NULL
; /* End of chain. */
symbolP
-> sy_forward
= NULL
; /* JF */
symbolP
-> sy_name_offset
= ~ 0; /* Impossible offset catches errors. */
symbolP
-> sy_number
= ~ 0; /* Ditto. */
* Link to end of symbol chain.
symbol_lastP
-> sy_next
= symbolP
;
* We have just seen "<name>:".
* Creates a struct symbol unless it already exists.
* Gripes if we are redefining a symbol incompatibly (and ignores it).
colon (sym_name
) /* just seen "x:" - rattle symbols & frags */
register char * sym_name
; /* symbol name, as a cannonical string */
/* We copy this string: OK to alter later. */
register struct symbol
* symbolP
; /* symbol we are working with */
/* Sun local labes go out of scope whenever a non-local symbol is
bzero((void *)local_label_defined
,sizeof(local_label_defined
));
extern md_short_jump_size
;
extern md_long_jump_size
;
possible_bytes
=md_short_jump_size
+new_broken_words
*md_long_jump_size
;
frag_opcode
=frag_var(rs_broken_word
,possible_bytes
,possible_bytes
,(relax_substateT
)0,(symbolS
*)broken_words
,(long int)0,(char *)0);
/* We want to store the pointer to where to insert the jump table in the
fr_opcode of the rs_broken_word frag. This requires a little hackery */
while(frag_tmp
&& (frag_tmp
->fr_type
!=rs_broken_word
|| frag_tmp
->fr_opcode
))
frag_tmp
=frag_tmp
->fr_next
;
frag_tmp
->fr_opcode
=frag_opcode
;
for(a
=broken_words
;a
&& a
->dispfrag
==0;a
=a
->next_broken_word
)
if (symbolP
= symbol_table_lookup( sym_name
))
* If the new symbol is .comm AND it has a size of zero,
* we ignore it (i.e. the old symbol overrides it)
if ((seg_N_TYPE
[(int) now_seg
] == (N_UNDF
| N_EXT
)) &&
((obstack_next_free(& frags
) - frag_now
-> fr_literal
) == 0))
* If the old symbol is .comm and it has a size of zero,
* we override it with the new symbol value.
if ((symbolP
-> sy_type
== (N_UNDF
| N_EXT
)) &&
(symbolP
->sy_value
== 0)) {
symbolP
-> sy_frag
= frag_now
;
symbolP
-> sy_other
= const_flag
;
symbolP
-> sy_value
= obstack_next_free(& frags
) - frag_now
-> fr_literal
;
symbolP
-> sy_type
|= seg_N_TYPE
[(int) now_seg
]; /* keep N_EXT bit */
* Now check for undefined symbols
if ((symbolP
-> sy_type
& N_TYPE
) == N_UNDF
)
if( symbolP
-> sy_other
== 0
&& symbolP
-> sy_desc
== 0
&& symbolP
-> sy_value
== 0)
symbolP
-> sy_frag
= frag_now
;
symbolP
-> sy_other
= const_flag
;
symbolP
-> sy_value
= obstack_next_free(& frags
) - frag_now
-> fr_literal
;
symbolP
-> sy_type
|= seg_N_TYPE
[(int) now_seg
]; /* keep N_EXT bit */
* There are still several cases to check:
* A .comm/.lcomm symbol being redefined as
* A .comm/.lcomm symbol being redefined with
* a larger size is also OK
char New_Type
= seg_N_TYPE
[(int) now_seg
];
if (((symbolP
->sy_type
== (N_UNDF
| N_EXT
)) ||
(symbolP
->sy_type
== N_BSS
)) &&
(((New_Type
& ~N_EXT
) == N_DATA
) ||
(New_Type
== symbolP
->sy_type
))) {
* Select which of the 2 cases this is
if (New_Type
== symbolP
->sy_type
) {
* If the new size is larger we just
* change its value. If the new size
* is smaller, we ignore this symbol
(obstack_next_free(& frags
) -
frag_now
-> fr_literal
)) {
obstack_next_free(& frags
) -
* It is a .comm/.lcomm being converted
symbolP
-> sy_frag
= frag_now
;
symbolP
-> sy_other
= const_flag
;
symbolP
-> sy_value
= obstack_next_free(& frags
) - frag_now
-> fr_literal
;
symbolP
-> sy_type
|= seg_N_TYPE
[(int) now_seg
]; /* keep N_EXT bit */
as_fatal( "Symbol \"%s\" is already defined as \"%s\"/%d.%d.%d.",
seg_name
[(int) N_TYPE_seg
[symbolP
-> sy_type
& N_TYPE
]],
symbolP
-> sy_other
, symbolP
-> sy_desc
,
as_fatal("Symbol %s already defined.",sym_name
);
symbolP
= symbol_new (sym_name
,
(unsigned char)(seg_N_TYPE
[(int) now_seg
]),
(valueT
)(obstack_next_free(&frags
)-frag_now
->fr_literal
),
symbol_table_insert (symbolP
);
* Die if we can't insert the symbol.
symbol_table_insert (symbolP
)
register char * error_string
;
know( symbolP
-> sy_name
);
if ( * (error_string
= hash_jam (sy_hash
, symbolP
-> sy_name
, (char *)symbolP
)))
as_fatal( "Inserting \"%s\" into symbol table failed: %s",
symbolP
-> sy_name
, error_string
);
* If a symbol name does not exist, create it as undefined, and insert
* it into the symbol table. Return a pointer to it.
symbol_find_or_make (name
)
register symbolS
* symbolP
;
symbolP
= symbol_table_lookup (name
);
symbolP
= symbol_new (name
, N_UNDF
, 0, 0, 0, & zero_address_frag
);
symbol_table_insert (symbolP
);
* Implement symbol table lookup.
* In: A symbol's name as a string: '\0' can't be part of a symbol name.
* Out: NULL if the name was not in the symbol table, else the address
* of a struct symbol associated with that name.
return ( (symbolS
*) hash_find( sy_hash
, name
));