386BSD 0.0 development
[unix-history] / usr / src / usr.bin / gas / symbols.c
CommitLineData
729b9b0d
WJ
1/* symbols.c -symbol table-
2 Copyright (C) 1987 Free Software Foundation, Inc.
3
4This file is part of GAS, the GNU Assembler.
5
6GAS is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GAS is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GAS; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
21#include "as.h"
22#include "hash.h"
23#include "obstack.h" /* For "symbols.h" */
24#include "struc-symbol.h"
25#include "symbols.h"
26#include "frags.h"
27
28#ifndef WORKING_DOT_WORD
29extern int new_broken_words;
30#endif
31#ifdef VMS
32extern char const_flag;
33#endif
34
35static
36struct hash_control *
37sy_hash; /* symbol-name => struct symbol pointer */
38
39 /* Below are commented in "symbols.h". */
40unsigned int local_bss_counter;
41symbolS * symbol_rootP;
42symbolS * symbol_lastP;
43symbolS abs_symbol;
44struct obstack notes;
45
46
47
48symbolS * symbol_find(); /* Keep C compiler happy. */
49
50/*
51 * Un*x idea of local labels. They are made by "n:" where n
52 * is any decimal digit. Refer to them with
53 * "nb" for previous (backward) n:
54 * or "nf" for next (forward) n:.
55 *
56 * Like Un*x AS, we have one set of local label counters for entire assembly,
57 * not one set per (sub)segment like in most assemblers. This implies that
58 * one can refer to a label in another segment, and indeed some crufty
59 * compilers have done just that.
60 *
61 * I document the symbol names here to save duplicating words elsewhere.
62 * The mth occurence of label n: is turned into the symbol "Ln^Am" where
63 * n is a digit and m is a decimal number. "L" makes it a label discarded
64 * unless debugging and "^A"('\1') ensures no ordinary symbol SHOULD get the
65 * same name as a local label symbol. The first "4:" is "L4^A1" - the m
66 * numbers begin at 1.
67 */
68
69typedef short unsigned int
70local_label_countT;
71
72static local_label_countT
73local_label_counter[10];
74
75static /* Returned to caller, then copied. */
76 char symbol_name_build[12]; /* used for created names ("4f") */
77
78#ifdef SUN_ASM_SYNTAX
79int local_label_defined[10];
80#endif
81
82\f
83void
84symbol_begin()
85{
86 symbol_lastP = NULL;
87 symbol_rootP = NULL; /* In case we have 0 symbols (!!) */
88 sy_hash = hash_new();
89 bzero ((char *)(& abs_symbol), sizeof(abs_symbol));
90 abs_symbol . sy_type = N_ABS; /* Can't initialise a union. Sigh. */
91 bzero ((char *)(local_label_counter), sizeof(local_label_counter) );
92 local_bss_counter = 0;
93}
94\f
95/*
96 * local_label_name()
97 *
98 * Caller must copy returned name: we re-use the area for the next name.
99 */
100
101char * /* Return local label name. */
102local_label_name(n, augend)
103 register int n; /* we just saw "n:", "nf" or "nb" : n a digit */
104 register int augend; /* 0 for nb, 1 for n:, nf */
105{
106 register char * p;
107 register char * q;
108 char symbol_name_temporary[10]; /* build up a number, BACKWARDS */
109
110 know( n >= 0 );
111 know( augend == 0 || augend == 1 );
112 p = symbol_name_build;
113 * p ++ = 'L';
114 * p ++ = n + '0'; /* Make into ASCII */
115 * p ++ = 1; /* ^A */
116 n = local_label_counter [ n ] + augend;
117 /* version number of this local label */
118 /*
119 * Next code just does sprintf( {}, "%d", n);
120 * It is more elegant to do the next part recursively, but a procedure
121 * call for each digit emitted is considered too costly.
122 */
123 q = symbol_name_temporary;
124 for (*q++=0; n; q++) /* emits NOTHING if n starts as 0 */
125 {
126 know(n>0); /* We expect n > 0 always */
127 *q = n % 10 + '0';
128 n /= 10;
129 }
130 while ( * p ++ = * -- q )
131 {
132 }
133 /* The label, as a '\0' ended string, starts at symbol_name_build. */
134 return (symbol_name_build);
135}
136
137
138void
139local_colon (n)
140 int n; /* just saw "n:" */
141{
142 local_label_counter [n] ++;
143#ifdef SUN_ASM_SYNTAX
144 local_label_defined[n]=1;
145#endif
146 colon (local_label_name (n, 0));
147}
148\f
149/*
150 * symbol_new()
151 *
152 * Return a pointer to a new symbol.
153 * Die if we can't make a new symbol.
154 * Fill in the symbol's values.
155 * Add symbol to end of symbol chain.
156 *
157 *
158 * Please always call this to create a new symbol.
159 *
160 * Changes since 1985: Symbol names may not contain '\0'. Sigh.
161 */
162
163symbolS *
164symbol_new (name, type, other, desc, value, frag)
165 char * name; /* We copy this: OK to alter your copy. */
166 unsigned char type; /* As in <a.out.h>. */
167 char other; /* As in <a.out.h>. */
168 short int desc; /* As in <a.out.h>. */
169 valueT value; /* As in <a.out.h>, often an address. */
170 /* Often used as offset from frag address. */
171 struct frag * frag; /* For sy_frag. */
172{
173 register symbolS * symbolP;
174 register char * preserved_copy_of_name;
175 register unsigned int name_length;
176 char * p;
177
178 name_length = strlen(name) + 1;
179 obstack_grow(&notes,name,name_length);
180 p=obstack_finish(&notes);
181 /* obstack_1done( &notes, name, name_length, &p ); */
182 preserved_copy_of_name = p;
183 p=obstack_alloc(&notes,sizeof(struct symbol));
184 /* obstack_1blank( &notes, sizeof(struct symbol), &p ); */
185 symbolP = (symbolS *) p;
186 symbolP -> sy_name = preserved_copy_of_name;
187 symbolP -> sy_type = type;
188 symbolP -> sy_other = other;
189 symbolP -> sy_desc = desc;
190 symbolP -> sy_value = value;
191 symbolP -> sy_frag = frag;
192 symbolP -> sy_next = NULL; /* End of chain. */
193 symbolP -> sy_forward = NULL; /* JF */
194#ifdef SUSPECT
195 symbolP -> sy_name_offset = ~ 0; /* Impossible offset catches errors. */
196 symbolP -> sy_number = ~ 0; /* Ditto. */
197#endif
198 /*
199 * Link to end of symbol chain.
200 */
201 if (symbol_lastP)
202 {
203 symbol_lastP -> sy_next = symbolP;
204 }
205 else
206 {
207 symbol_rootP = symbolP;
208 }
209 symbol_lastP = symbolP;
210
211 return (symbolP);
212}
213\f
214/*
215 * colon()
216 *
217 * We have just seen "<name>:".
218 * Creates a struct symbol unless it already exists.
219 *
220 * Gripes if we are redefining a symbol incompatibly (and ignores it).
221 *
222 */
223void
224colon (sym_name) /* just seen "x:" - rattle symbols & frags */
225 register char * sym_name; /* symbol name, as a cannonical string */
226 /* We copy this string: OK to alter later. */
227{
228 register struct symbol * symbolP; /* symbol we are working with */
229
230#ifdef SUN_ASM_SYNTAX
231 /* Sun local labes go out of scope whenever a non-local symbol is
232 defined. */
233
234 if(*sym_name !='L')
235 bzero((void *)local_label_defined,sizeof(local_label_defined));
236#endif
237
238#ifndef WORKING_DOT_WORD
239 if(new_broken_words) {
240 struct broken_word *a;
241 int possible_bytes;
242 fragS *frag_tmp;
243 char *frag_opcode;
244 extern md_short_jump_size;
245 extern md_long_jump_size;
246
247 possible_bytes=md_short_jump_size+new_broken_words*md_long_jump_size;
248 frag_tmp=frag_now;
249 frag_opcode=frag_var(rs_broken_word,possible_bytes,possible_bytes,(relax_substateT)0,(symbolS *)broken_words,(long int)0,(char *)0);
250
251 /* We want to store the pointer to where to insert the jump table in the
252 fr_opcode of the rs_broken_word frag. This requires a little hackery */
253 while(frag_tmp && (frag_tmp->fr_type!=rs_broken_word || frag_tmp->fr_opcode))
254 frag_tmp=frag_tmp->fr_next;
255 know(frag_tmp);
256 frag_tmp->fr_opcode=frag_opcode;
257 new_broken_words = 0;
258
259 for(a=broken_words;a && a->dispfrag==0;a=a->next_broken_word)
260 a->dispfrag=frag_tmp;
261 }
262#endif
263 if (symbolP = symbol_table_lookup( sym_name ))
264 {
265#ifdef VMS
266 /*
267 * If the new symbol is .comm AND it has a size of zero,
268 * we ignore it (i.e. the old symbol overrides it)
269 */
270 if ((seg_N_TYPE [(int) now_seg] == (N_UNDF | N_EXT)) &&
271 ((obstack_next_free(& frags) - frag_now -> fr_literal) == 0))
272 return;
273 /*
274 * If the old symbol is .comm and it has a size of zero,
275 * we override it with the new symbol value.
276 */
277 if ((symbolP -> sy_type == (N_UNDF | N_EXT)) &&
278 (symbolP->sy_value == 0)) {
279 symbolP -> sy_frag = frag_now;
280 symbolP -> sy_other = const_flag;
281 symbolP -> sy_value = obstack_next_free(& frags) - frag_now -> fr_literal;
282 symbolP -> sy_type |= seg_N_TYPE [(int) now_seg]; /* keep N_EXT bit */
283 return;
284 }
285#endif /* VMS */
286 /*
287 * Now check for undefined symbols
288 */
289 if ((symbolP -> sy_type & N_TYPE) == N_UNDF)
290 {
291 if( symbolP -> sy_other == 0
292 && symbolP -> sy_desc == 0
293 && symbolP -> sy_value == 0)
294 {
295 symbolP -> sy_frag = frag_now;
296#ifdef VMS
297 symbolP -> sy_other = const_flag;
298#endif
299 symbolP -> sy_value = obstack_next_free(& frags) - frag_now -> fr_literal;
300 know( N_UNDF == 0 );
301 symbolP -> sy_type |= seg_N_TYPE [(int) now_seg]; /* keep N_EXT bit */
302 }
303 else
304 {
305#ifdef VMS
306 /*
307 * There are still several cases to check:
308 * A .comm/.lcomm symbol being redefined as
309 * initialized data is OK
310 * A .comm/.lcomm symbol being redefined with
311 * a larger size is also OK
312 */
313 char New_Type = seg_N_TYPE [(int) now_seg];
314 if (((symbolP->sy_type == (N_UNDF | N_EXT)) ||
315 (symbolP->sy_type == N_BSS)) &&
316 (((New_Type & ~N_EXT) == N_DATA) ||
317 (New_Type == symbolP->sy_type))) {
318 /*
319 * Select which of the 2 cases this is
320 */
321 if (New_Type == symbolP->sy_type) {
322 /*
323 * If the new size is larger we just
324 * change its value. If the new size
325 * is smaller, we ignore this symbol
326 */
327 if (symbolP->sy_value <
328 (obstack_next_free(& frags) -
329 frag_now -> fr_literal)) {
330 symbolP -> sy_value =
331 obstack_next_free(& frags) -
332 frag_now -> fr_literal;
333 }
334 } else {
335 /*
336 * It is a .comm/.lcomm being converted
337 * to initialized data.
338 */
339 symbolP -> sy_frag = frag_now;
340 symbolP -> sy_other = const_flag;
341 symbolP -> sy_value = obstack_next_free(& frags) - frag_now -> fr_literal;
342 symbolP -> sy_type |= seg_N_TYPE [(int) now_seg]; /* keep N_EXT bit */
343 }
344 } else {
345#endif /* VMS */
346 as_fatal( "Symbol \"%s\" is already defined as \"%s\"/%d.%d.%d.",
347 sym_name,
348 seg_name [(int) N_TYPE_seg [symbolP -> sy_type & N_TYPE]],
349 symbolP -> sy_other, symbolP -> sy_desc,
350 symbolP -> sy_value);
351#ifdef VMS
352 }
353#endif /* VMS */
354 }
355 }
356 else
357 {
358 as_fatal("Symbol %s already defined.",sym_name);
359 }
360 }
361 else
362 {
363 symbolP = symbol_new (sym_name,
364 (unsigned char)(seg_N_TYPE [(int) now_seg]),
365#ifdef VMS
366 const_flag,
367#else
368 0,
369#endif
370 0,
371 (valueT)(obstack_next_free(&frags)-frag_now->fr_literal),
372 frag_now);
373 symbol_table_insert (symbolP);
374 }
375}
376
377\f
378/*
379 * symbol_table_insert()
380 *
381 * Die if we can't insert the symbol.
382 *
383 */
384
385void
386symbol_table_insert (symbolP)
387 struct symbol * symbolP;
388{
389 register char * error_string;
390
391 know( symbolP );
392 know( symbolP -> sy_name );
393 if ( * (error_string = hash_jam (sy_hash, symbolP -> sy_name, (char *)symbolP)))
394 {
395 as_fatal( "Inserting \"%s\" into symbol table failed: %s",
396 symbolP -> sy_name, error_string);
397 }
398}
399\f
400/*
401 * symbol_find_or_make()
402 *
403 * If a symbol name does not exist, create it as undefined, and insert
404 * it into the symbol table. Return a pointer to it.
405 */
406symbolS *
407symbol_find_or_make (name)
408 char * name;
409{
410 register symbolS * symbolP;
411
412 symbolP = symbol_table_lookup (name);
413 if (symbolP == NULL)
414 {
415 symbolP = symbol_new (name, N_UNDF, 0, 0, 0, & zero_address_frag);
416 symbol_table_insert (symbolP);
417 }
418 return (symbolP);
419}
420
421/*
422 * symbol_find()
423 *
424 * Implement symbol table lookup.
425 * In: A symbol's name as a string: '\0' can't be part of a symbol name.
426 * Out: NULL if the name was not in the symbol table, else the address
427 * of a struct symbol associated with that name.
428 */
429
430symbolS *
431symbol_find (name)
432 char * name;
433{
434 return ( (symbolS *) hash_find( sy_hash, name ));
435}
436
437
438/* end: symbols.c */