Commit | Line | Data |
---|---|---|
fecd2382 | 1 | /* symbols.c -symbol table- |
6efd877d KR |
2 | |
3 | Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. | |
4 | ||
a39116f1 | 5 | This file is part of GAS, the GNU Assembler. |
6efd877d | 6 | |
a39116f1 RP |
7 | GAS is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
6efd877d | 11 | |
a39116f1 RP |
12 | GAS is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
6efd877d | 16 | |
a39116f1 RP |
17 | You should have received a copy of the GNU General Public License |
18 | along with GAS; see the file COPYING. If not, write to | |
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
fecd2382 | 20 | |
6efd877d KR |
21 | #include <ctype.h> |
22 | ||
fecd2382 RP |
23 | #include "as.h" |
24 | ||
25 | #include "obstack.h" /* For "symbols.h" */ | |
26 | #include "subsegs.h" | |
27 | ||
28 | #ifndef WORKING_DOT_WORD | |
29 | extern int new_broken_words; | |
30 | #endif | |
31 | #ifdef VMS | |
32 | extern char const_flag; | |
33 | #endif | |
34 | ||
35 | static | |
6efd877d KR |
36 | struct hash_control * |
37 | sy_hash; /* symbol-name => struct symbol pointer */ | |
fecd2382 | 38 | |
a39116f1 | 39 | /* Below are commented in "symbols.h". */ |
fecd2382 | 40 | unsigned int local_bss_counter; |
6efd877d KR |
41 | symbolS *symbol_rootP; |
42 | symbolS *symbol_lastP; | |
43 | symbolS abs_symbol; | |
fecd2382 | 44 | |
6efd877d KR |
45 | symbolS *dot_text_symbol; |
46 | symbolS *dot_data_symbol; | |
47 | symbolS *dot_bss_symbol; | |
fecd2382 | 48 | |
6efd877d | 49 | struct obstack notes; |
fecd2382 | 50 | |
6efd877d KR |
51 | #if __STDC__ == 1 |
52 | static void fb_label_init (void); | |
53 | #else /* not __STDC__ */ | |
54 | static void fb_label_init (); | |
55 | #endif /* not __STDC__ */ | |
fecd2382 | 56 | |
fecd2382 | 57 | void |
6efd877d | 58 | symbol_begin () |
fecd2382 | 59 | { |
6efd877d KR |
60 | symbol_lastP = NULL; |
61 | symbol_rootP = NULL; /* In case we have 0 symbols (!!) */ | |
62 | sy_hash = hash_new (); | |
63 | memset ((char *) (&abs_symbol), '\0', sizeof (abs_symbol)); | |
64 | S_SET_SEGMENT (&abs_symbol, SEG_ABSOLUTE); /* Can't initialise a union. Sigh. */ | |
65 | local_bss_counter = 0; | |
66 | #ifdef LOCAL_LABELS_FB | |
67 | fb_label_init (); | |
68 | #endif /* LOCAL_LABELS_FB */ | |
fecd2382 | 69 | } |
fecd2382 | 70 | |
fecd2382 RP |
71 | /* |
72 | * symbol_new() | |
73 | * | |
74 | * Return a pointer to a new symbol. | |
75 | * Die if we can't make a new symbol. | |
76 | * Fill in the symbol's values. | |
77 | * Add symbol to end of symbol chain. | |
78 | * | |
79 | * | |
80 | * Please always call this to create a new symbol. | |
81 | * | |
82 | * Changes since 1985: Symbol names may not contain '\0'. Sigh. | |
83 | * 2nd argument is now a SEG rather than a TYPE. The mapping between | |
84 | * segments and types is mostly encapsulated herein (actually, we inherit it | |
85 | * from macros in struc-symbol.h). | |
86 | */ | |
87 | ||
6efd877d KR |
88 | symbolS * |
89 | symbol_new (name, segment, value, frag) | |
90 | char *name; /* It is copied, the caller can destroy/modify */ | |
91 | segT segment; /* Segment identifier (SEG_<something>) */ | |
92 | long value; /* Symbol value */ | |
93 | fragS *frag; /* Associated fragment */ | |
fecd2382 | 94 | { |
6efd877d KR |
95 | unsigned int name_length; |
96 | char *preserved_copy_of_name; | |
97 | symbolS *symbolP; | |
98 | ||
99 | name_length = strlen (name) + 1; /* +1 for \0 */ | |
100 | obstack_grow (¬es, name, name_length); | |
101 | preserved_copy_of_name = obstack_finish (¬es); | |
102 | symbolP = (symbolS *) obstack_alloc (¬es, sizeof (symbolS)); | |
103 | ||
104 | /* symbol must be born in some fixed state. This seems as good as any. */ | |
105 | memset (symbolP, 0, sizeof (symbolS)); | |
106 | ||
a6c6eaf8 | 107 | #ifdef STRIP_UNDERSCORE |
6efd877d KR |
108 | S_SET_NAME (symbolP, (*preserved_copy_of_name == '_' |
109 | ? preserved_copy_of_name + 1 | |
110 | : preserved_copy_of_name)); | |
fecd2382 | 111 | #else /* STRIP_UNDERSCORE */ |
6efd877d | 112 | S_SET_NAME (symbolP, preserved_copy_of_name); |
fecd2382 | 113 | #endif /* STRIP_UNDERSCORE */ |
6efd877d KR |
114 | |
115 | S_SET_SEGMENT (symbolP, segment); | |
116 | S_SET_VALUE (symbolP, value); | |
117 | /* symbol_clear_list_pointers(symbolP); uneeded if symbol is born zeroed. */ | |
118 | ||
119 | symbolP->sy_frag = frag; | |
120 | /* krm: uneeded if symbol is born zeroed. | |
121 | symbolP->sy_forward = NULL; *//* JF */ | |
122 | symbolP->sy_number = ~0; | |
123 | symbolP->sy_name_offset = ~0; | |
124 | ||
125 | /* | |
fecd2382 RP |
126 | * Link to end of symbol chain. |
127 | */ | |
6efd877d KR |
128 | symbol_append (symbolP, symbol_lastP, &symbol_rootP, &symbol_lastP); |
129 | ||
130 | obj_symbol_new_hook (symbolP); | |
131 | ||
fecd2382 | 132 | #ifdef DEBUG |
6efd877d | 133 | /* verify_symbol_chain(symbol_rootP, symbol_lastP); */ |
fecd2382 | 134 | #endif /* DEBUG */ |
fecd2382 | 135 | |
6efd877d KR |
136 | return (symbolP); |
137 | } /* symbol_new() */ | |
fecd2382 | 138 | \f |
6efd877d | 139 | |
fecd2382 RP |
140 | /* |
141 | * colon() | |
142 | * | |
143 | * We have just seen "<name>:". | |
144 | * Creates a struct symbol unless it already exists. | |
145 | * | |
146 | * Gripes if we are redefining a symbol incompatibly (and ignores it). | |
147 | * | |
148 | */ | |
6efd877d KR |
149 | void |
150 | colon (sym_name) /* just seen "x:" - rattle symbols & frags */ | |
151 | register char *sym_name; /* symbol name, as a cannonical string */ | |
152 | /* We copy this string: OK to alter later. */ | |
fecd2382 | 153 | { |
6efd877d KR |
154 | register symbolS *symbolP; /* symbol we are working with */ |
155 | ||
fecd2382 | 156 | #ifdef LOCAL_LABELS_DOLLAR |
6efd877d KR |
157 | /* Sun local labels go out of scope whenever a non-local symbol is defined. */ |
158 | ||
159 | if (*sym_name != 'L') | |
160 | dollar_label_clear (); | |
161 | #endif /* LOCAL_LABELS_DOLLAR */ | |
162 | ||
fecd2382 | 163 | #ifndef WORKING_DOT_WORD |
6efd877d KR |
164 | if (new_broken_words) |
165 | { | |
166 | struct broken_word *a; | |
167 | int possible_bytes; | |
168 | fragS *frag_tmp; | |
169 | char *frag_opcode; | |
170 | ||
171 | extern md_short_jump_size; | |
172 | extern md_long_jump_size; | |
173 | possible_bytes = md_short_jump_size + new_broken_words * md_long_jump_size; | |
174 | ||
175 | frag_tmp = frag_now; | |
176 | frag_opcode = frag_var (rs_broken_word, | |
177 | possible_bytes, | |
178 | possible_bytes, | |
179 | (relax_substateT) 0, | |
180 | (symbolS *) broken_words, | |
181 | 0L, | |
182 | NULL); | |
183 | ||
184 | /* We want to store the pointer to where to insert the jump table in the | |
a39116f1 | 185 | fr_opcode of the rs_broken_word frag. This requires a little hackery */ |
6efd877d KR |
186 | while (frag_tmp && (frag_tmp->fr_type != rs_broken_word || frag_tmp->fr_opcode)) |
187 | frag_tmp = frag_tmp->fr_next; | |
188 | know (frag_tmp); | |
189 | frag_tmp->fr_opcode = frag_opcode; | |
190 | new_broken_words = 0; | |
191 | ||
192 | for (a = broken_words; a && a->dispfrag == 0; a = a->next_broken_word) | |
193 | a->dispfrag = frag_tmp; | |
194 | } | |
195 | #endif /* WORKING_DOT_WORD */ | |
196 | ||
197 | if ((symbolP = symbol_find (sym_name)) != 0) | |
198 | { | |
fecd2382 | 199 | #ifdef VMS |
6efd877d | 200 | /* |
a39116f1 RP |
201 | * If the new symbol is .comm AND it has a size of zero, |
202 | * we ignore it (i.e. the old symbol overrides it) | |
203 | */ | |
6efd877d KR |
204 | if ((SEGMENT_TO_SYMBOL_TYPE ((int) now_seg) == (N_UNDF | N_EXT)) && |
205 | ((obstack_next_free (&frags) - frag_now->fr_literal) == 0)) | |
206 | return; | |
207 | /* | |
a39116f1 RP |
208 | * If the old symbol is .comm and it has a size of zero, |
209 | * we override it with the new symbol value. | |
210 | */ | |
6efd877d KR |
211 | if ((symbolP->sy_type == (N_UNDF | N_EXT)) |
212 | && (S_GET_VALUE (symbolP) == 0)) | |
213 | { | |
214 | symbolP->sy_frag = frag_now; | |
215 | symbolP->sy_other = const_flag; | |
216 | S_SET_VALUE (symbolP, obstack_next_free (&frags) - frag_now->fr_literal); | |
217 | symbolP->sy_type |= SEGMENT_TO_SYMBOL_TYPE ((int) now_seg); /* keep N_EXT bit */ | |
218 | return; | |
219 | } | |
220 | #endif /* VMS */ | |
221 | /* | |
a39116f1 RP |
222 | * Now check for undefined symbols |
223 | */ | |
6efd877d KR |
224 | if (!S_IS_DEFINED (symbolP)) |
225 | { | |
226 | if (S_GET_VALUE (symbolP) == 0) | |
227 | { | |
228 | symbolP->sy_frag = frag_now; | |
fecd2382 | 229 | #ifdef VMS |
6efd877d | 230 | symbolP->sy_other = const_flag; |
fecd2382 | 231 | #endif |
6efd877d KR |
232 | S_SET_VALUE (symbolP, obstack_next_free (&frags) - frag_now->fr_literal); |
233 | S_SET_SEGMENT (symbolP, now_seg); | |
fecd2382 | 234 | #ifdef N_UNDF |
6efd877d | 235 | know (N_UNDF == 0); |
fecd2382 | 236 | #endif /* if we have one, it better be zero. */ |
6efd877d KR |
237 | |
238 | } | |
239 | else | |
240 | { | |
241 | /* | |
a39116f1 RP |
242 | * There are still several cases to check: |
243 | * A .comm/.lcomm symbol being redefined as | |
244 | * initialized data is OK | |
245 | * A .comm/.lcomm symbol being redefined with | |
246 | * a larger size is also OK | |
247 | * | |
248 | * This only used to be allowed on VMS gas, but Sun cc | |
249 | * on the sparc also depends on it. | |
250 | */ | |
6efd877d | 251 | /* char New_Type = SEGMENT_TO_SYMBOL_TYPE((int) now_seg); */ |
a6c6eaf8 RP |
252 | #ifdef MANY_SEGMENTS |
253 | #define SEG_BSS SEG_E2 | |
254 | #define SEG_DATA SEG_E1 | |
255 | #endif | |
6efd877d KR |
256 | |
257 | if (((!S_IS_DEBUG (symbolP) && !S_IS_DEFINED (symbolP) && S_IS_EXTERNAL (symbolP)) | |
258 | || (S_GET_SEGMENT (symbolP) == SEG_BSS)) | |
259 | && ((now_seg == SEG_DATA) | |
260 | || (now_seg == S_GET_SEGMENT (symbolP)))) | |
261 | { | |
262 | /* | |
a39116f1 RP |
263 | * Select which of the 2 cases this is |
264 | */ | |
6efd877d KR |
265 | if (now_seg != SEG_DATA) |
266 | { | |
267 | /* | |
a39116f1 RP |
268 | * New .comm for prev .comm symbol. |
269 | * If the new size is larger we just | |
270 | * change its value. If the new size | |
271 | * is smaller, we ignore this symbol | |
272 | */ | |
6efd877d KR |
273 | if (S_GET_VALUE (symbolP) |
274 | < ((unsigned) (obstack_next_free (&frags) - frag_now->fr_literal))) | |
275 | { | |
276 | S_SET_VALUE (symbolP, | |
277 | obstack_next_free (&frags) - | |
278 | frag_now->fr_literal); | |
279 | } | |
280 | } | |
281 | else | |
282 | { | |
283 | /* | |
a39116f1 RP |
284 | * It is a .comm/.lcomm being converted |
285 | * to initialized data. | |
286 | */ | |
6efd877d | 287 | symbolP->sy_frag = frag_now; |
fecd2382 | 288 | #ifdef VMS |
6efd877d | 289 | symbolP->sy_other = const_flag; |
fecd2382 | 290 | #endif /* VMS */ |
6efd877d KR |
291 | S_SET_VALUE (symbolP, obstack_next_free (&frags) - frag_now->fr_literal); |
292 | S_SET_SEGMENT (symbolP, now_seg); /* keep N_EXT bit */ | |
293 | } | |
294 | } | |
295 | else | |
296 | { | |
fecd2382 | 297 | #ifdef OBJ_COFF |
6efd877d KR |
298 | as_fatal ("Symbol \"%s\" is already defined as \"%s\"/%d.", |
299 | sym_name, | |
300 | segment_name (S_GET_SEGMENT (symbolP)), | |
301 | S_GET_VALUE (symbolP)); | |
fecd2382 | 302 | #else /* OBJ_COFF */ |
6efd877d KR |
303 | as_fatal ("Symbol \"%s\" is already defined as \"%s\"/%d.%d.%d.", |
304 | sym_name, | |
305 | segment_name (S_GET_SEGMENT (symbolP)), | |
306 | S_GET_OTHER (symbolP), S_GET_DESC (symbolP), | |
307 | S_GET_VALUE (symbolP)); | |
fecd2382 | 308 | #endif /* OBJ_COFF */ |
6efd877d KR |
309 | } |
310 | } /* if the undefined symbol has no value */ | |
311 | } | |
312 | else | |
313 | { | |
314 | /* Don't blow up if the definition is the same */ | |
315 | if (!(frag_now == symbolP->sy_frag | |
316 | && S_GET_VALUE (symbolP) == obstack_next_free (&frags) - frag_now->fr_literal | |
317 | && S_GET_SEGMENT (symbolP) == now_seg)) | |
318 | as_fatal ("Symbol %s already defined.", sym_name); | |
319 | } /* if this symbol is not yet defined */ | |
320 | ||
321 | } | |
322 | else | |
323 | { | |
324 | symbolP = symbol_new (sym_name, | |
325 | now_seg, | |
326 | (valueT) (obstack_next_free (&frags) - frag_now->fr_literal), | |
327 | frag_now); | |
fecd2382 | 328 | #ifdef VMS |
6efd877d | 329 | S_SET_OTHER (symbolP, const_flag); |
fecd2382 | 330 | #endif /* VMS */ |
fecd2382 | 331 | |
6efd877d KR |
332 | symbol_table_insert (symbolP); |
333 | } /* if we have seen this symbol before */ | |
334 | ||
335 | return; | |
336 | } /* colon() */ | |
fecd2382 | 337 | \f |
6efd877d | 338 | |
fecd2382 RP |
339 | /* |
340 | * symbol_table_insert() | |
341 | * | |
342 | * Die if we can't insert the symbol. | |
343 | * | |
344 | */ | |
345 | ||
6efd877d KR |
346 | void |
347 | symbol_table_insert (symbolP) | |
348 | symbolS *symbolP; | |
fecd2382 | 349 | { |
6efd877d KR |
350 | register char *error_string; |
351 | ||
352 | know (symbolP); | |
353 | know (S_GET_NAME (symbolP)); | |
354 | ||
355 | if (*(error_string = hash_jam (sy_hash, S_GET_NAME (symbolP), (char *) symbolP))) | |
356 | { | |
357 | as_fatal ("Inserting \"%s\" into symbol table failed: %s", | |
358 | S_GET_NAME (symbolP), error_string); | |
359 | } /* on error */ | |
360 | } /* symbol_table_insert() */ | |
fecd2382 RP |
361 | \f |
362 | /* | |
363 | * symbol_find_or_make() | |
364 | * | |
365 | * If a symbol name does not exist, create it as undefined, and insert | |
366 | * it into the symbol table. Return a pointer to it. | |
367 | */ | |
6efd877d KR |
368 | symbolS * |
369 | symbol_find_or_make (name) | |
370 | char *name; | |
fecd2382 | 371 | { |
6efd877d KR |
372 | register symbolS *symbolP; |
373 | ||
374 | symbolP = symbol_find (name); | |
375 | ||
376 | if (symbolP == NULL) | |
377 | { | |
378 | symbolP = symbol_make (name); | |
379 | ||
380 | symbol_table_insert (symbolP); | |
381 | } /* if symbol wasn't found */ | |
382 | ||
383 | return (symbolP); | |
384 | } /* symbol_find_or_make() */ | |
385 | ||
386 | symbolS * | |
387 | symbol_make (name) | |
388 | char *name; | |
fecd2382 | 389 | { |
6efd877d KR |
390 | symbolS *symbolP; |
391 | ||
392 | /* Let the machine description default it, e.g. for register names. */ | |
393 | symbolP = md_undefined_symbol (name); | |
394 | ||
395 | if (!symbolP) | |
396 | { | |
397 | symbolP = symbol_new (name, | |
398 | SEG_UNKNOWN, | |
399 | 0, | |
400 | &zero_address_frag); | |
401 | } /* if md didn't build us a symbol */ | |
402 | ||
403 | return (symbolP); | |
404 | } /* symbol_make() */ | |
fecd2382 RP |
405 | |
406 | /* | |
407 | * symbol_find() | |
6efd877d | 408 | * |
fecd2382 RP |
409 | * Implement symbol table lookup. |
410 | * In: A symbol's name as a string: '\0' can't be part of a symbol name. | |
411 | * Out: NULL if the name was not in the symbol table, else the address | |
412 | * of a struct symbol associated with that name. | |
413 | */ | |
414 | ||
6efd877d KR |
415 | symbolS * |
416 | symbol_find (name) | |
417 | char *name; | |
fecd2382 | 418 | { |
a6c6eaf8 | 419 | #ifdef STRIP_UNDERSCORE |
6efd877d | 420 | return (symbol_find_base (name, 1)); |
a6c6eaf8 | 421 | #else /* STRIP_UNDERSCORE */ |
6efd877d | 422 | return (symbol_find_base (name, 0)); |
fecd2382 | 423 | #endif /* STRIP_UNDERSCORE */ |
6efd877d | 424 | } /* symbol_find() */ |
fecd2382 | 425 | |
6efd877d KR |
426 | symbolS * |
427 | symbol_find_base (name, strip_underscore) | |
428 | char *name; | |
429 | int strip_underscore; | |
fecd2382 | 430 | { |
6efd877d KR |
431 | if (strip_underscore && *name == '_') |
432 | name++; | |
433 | return ((symbolS *) hash_find (sy_hash, name)); | |
fecd2382 RP |
434 | } |
435 | ||
436 | /* | |
437 | * Once upon a time, symbols were kept in a singly linked list. At | |
438 | * least coff needs to be able to rearrange them from time to time, for | |
439 | * which a doubly linked list is much more convenient. Loic did these | |
440 | * as macros which seemed dangerous to me so they're now functions. | |
441 | * xoxorich. | |
442 | */ | |
443 | ||
444 | /* Link symbol ADDME after symbol TARGET in the chain. */ | |
6efd877d KR |
445 | void |
446 | symbol_append (addme, target, rootPP, lastPP) | |
447 | symbolS *addme; | |
448 | symbolS *target; | |
449 | symbolS **rootPP; | |
450 | symbolS **lastPP; | |
fecd2382 | 451 | { |
6efd877d KR |
452 | if (target == NULL) |
453 | { | |
454 | know (*rootPP == NULL); | |
455 | know (*lastPP == NULL); | |
456 | *rootPP = addme; | |
457 | *lastPP = addme; | |
458 | return; | |
459 | } /* if the list is empty */ | |
460 | ||
461 | if (target->sy_next != NULL) | |
462 | { | |
fecd2382 | 463 | #ifdef SYMBOLS_NEED_BACKPOINTERS |
6efd877d | 464 | target->sy_next->sy_previous = addme; |
fecd2382 | 465 | #endif /* SYMBOLS_NEED_BACKPOINTERS */ |
6efd877d KR |
466 | } |
467 | else | |
468 | { | |
469 | know (*lastPP == target); | |
470 | *lastPP = addme; | |
471 | } /* if we have a next */ | |
472 | ||
473 | addme->sy_next = target->sy_next; | |
474 | target->sy_next = addme; | |
475 | ||
fecd2382 | 476 | #ifdef SYMBOLS_NEED_BACKPOINTERS |
6efd877d | 477 | addme->sy_previous = target; |
fecd2382 | 478 | #endif /* SYMBOLS_NEED_BACKPOINTERS */ |
6efd877d | 479 | |
fecd2382 | 480 | #ifdef DEBUG |
6efd877d | 481 | /* verify_symbol_chain(*rootPP, *lastPP); */ |
fecd2382 | 482 | #endif /* DEBUG */ |
6efd877d KR |
483 | |
484 | return; | |
485 | } /* symbol_append() */ | |
fecd2382 RP |
486 | |
487 | #ifdef SYMBOLS_NEED_BACKPOINTERS | |
488 | /* Remove SYMBOLP from the list. */ | |
6efd877d KR |
489 | void |
490 | symbol_remove (symbolP, rootPP, lastPP) | |
491 | symbolS *symbolP; | |
492 | symbolS **rootPP; | |
493 | symbolS **lastPP; | |
fecd2382 | 494 | { |
6efd877d KR |
495 | if (symbolP == *rootPP) |
496 | { | |
497 | *rootPP = symbolP->sy_next; | |
498 | } /* if it was the root */ | |
499 | ||
500 | if (symbolP == *lastPP) | |
501 | { | |
502 | *lastPP = symbolP->sy_previous; | |
503 | } /* if it was the tail */ | |
504 | ||
505 | if (symbolP->sy_next != NULL) | |
506 | { | |
507 | symbolP->sy_next->sy_previous = symbolP->sy_previous; | |
508 | } /* if not last */ | |
509 | ||
510 | if (symbolP->sy_previous != NULL) | |
511 | { | |
512 | symbolP->sy_previous->sy_next = symbolP->sy_next; | |
513 | } /* if not first */ | |
514 | ||
fecd2382 | 515 | #ifdef DEBUG |
6efd877d | 516 | verify_symbol_chain (*rootPP, *lastPP); |
fecd2382 | 517 | #endif /* DEBUG */ |
6efd877d KR |
518 | |
519 | return; | |
520 | } /* symbol_remove() */ | |
fecd2382 RP |
521 | |
522 | /* Set the chain pointers of SYMBOL to null. */ | |
6efd877d KR |
523 | void |
524 | symbol_clear_list_pointers (symbolP) | |
525 | symbolS *symbolP; | |
fecd2382 | 526 | { |
6efd877d KR |
527 | symbolP->sy_next = NULL; |
528 | symbolP->sy_previous = NULL; | |
529 | } /* symbol_clear_list_pointers() */ | |
fecd2382 RP |
530 | |
531 | /* Link symbol ADDME before symbol TARGET in the chain. */ | |
6efd877d KR |
532 | void |
533 | symbol_insert (addme, target, rootPP, lastPP) | |
534 | symbolS *addme; | |
535 | symbolS *target; | |
536 | symbolS **rootPP; | |
537 | symbolS **lastPP; | |
fecd2382 | 538 | { |
6efd877d KR |
539 | if (target->sy_previous != NULL) |
540 | { | |
541 | target->sy_previous->sy_next = addme; | |
542 | } | |
543 | else | |
544 | { | |
545 | know (*rootPP == target); | |
546 | *rootPP = addme; | |
547 | } /* if not first */ | |
548 | ||
549 | addme->sy_previous = target->sy_previous; | |
550 | target->sy_previous = addme; | |
551 | addme->sy_next = target; | |
552 | ||
fecd2382 | 553 | #ifdef DEBUG |
6efd877d | 554 | verify_symbol_chain (*rootPP, *lastPP); |
fecd2382 | 555 | #endif /* DEBUG */ |
6efd877d KR |
556 | |
557 | return; | |
558 | } /* symbol_insert() */ | |
559 | ||
fecd2382 RP |
560 | #endif /* SYMBOLS_NEED_BACKPOINTERS */ |
561 | ||
6efd877d KR |
562 | void |
563 | verify_symbol_chain (rootP, lastP) | |
564 | symbolS *rootP; | |
565 | symbolS *lastP; | |
fecd2382 | 566 | { |
6efd877d KR |
567 | symbolS *symbolP = rootP; |
568 | ||
569 | if (symbolP == NULL) | |
570 | { | |
571 | return; | |
572 | } /* empty chain */ | |
573 | ||
574 | for (; symbol_next (symbolP) != NULL; symbolP = symbol_next (symbolP)) | |
575 | { | |
fecd2382 | 576 | #ifdef SYMBOLS_NEED_BACKPOINTERS |
6efd877d | 577 | /*$if (symbolP->sy_previous) { |
a39116f1 RP |
578 | know(symbolP->sy_previous->sy_next == symbolP); |
579 | } else { | |
580 | know(symbolP == rootP); | |
6efd877d KR |
581 | }$*//* both directions */ |
582 | know (symbolP->sy_next->sy_previous == symbolP); | |
fecd2382 | 583 | #else /* SYMBOLS_NEED_BACKPOINTERS */ |
6efd877d | 584 | ; |
fecd2382 | 585 | #endif /* SYMBOLS_NEED_BACKPOINTERS */ |
6efd877d KR |
586 | } /* verify pointers */ |
587 | ||
588 | know (lastP == symbolP); | |
589 | ||
590 | return; | |
591 | } /* verify_symbol_chain() */ | |
592 | ||
593 | ||
594 | #ifdef LOCAL_LABELS_DOLLAR | |
595 | ||
596 | /* Dollar labels look like a number followed by a dollar sign. Eg, "42$". | |
597 | They are *really* local. That is, they go out of scope whenever we see a | |
598 | label that isn't local. Also, like fb labels, there can be multiple | |
599 | instances of a dollar label. Therefor, we name encode each instance with | |
600 | the instance number, keep a list of defined symbols separate from the real | |
601 | symbol table, and we treat these buggers as a sparse array. */ | |
602 | ||
603 | static long *dollar_labels = NULL; | |
604 | static long *dollar_label_instances = NULL; | |
605 | static char *dollar_label_defines = NULL; | |
606 | static long dollar_label_count = 0; | |
607 | static long dollar_label_max = 0; | |
608 | ||
609 | int | |
610 | dollar_label_defined (label) | |
611 | long label; | |
612 | { | |
613 | long *i; | |
614 | ||
615 | know ((dollar_labels != NULL) || (dollar_label_count == 0)); | |
616 | ||
617 | for (i = dollar_labels; i < dollar_labels + dollar_label_count; ++i) | |
618 | { | |
619 | if (*i == label) | |
620 | { | |
621 | return (dollar_label_defines[i - dollar_labels]); | |
622 | } /* found it */ | |
623 | } /* look for label */ | |
624 | ||
625 | /* if we get here, label isn't defined */ | |
626 | return (0); | |
627 | } /* dollar_label_defined() */ | |
628 | ||
629 | static int | |
630 | dollar_label_instance (label) | |
631 | long label; | |
632 | { | |
633 | long *i; | |
634 | ||
635 | know ((dollar_labels != NULL) || (dollar_label_count == 0)); | |
636 | ||
637 | for (i = dollar_labels; i < dollar_labels + dollar_label_count; ++i) | |
638 | { | |
639 | if (*i == label) | |
640 | { | |
641 | return (dollar_label_instances[i - dollar_labels]); | |
642 | } /* found it */ | |
643 | } /* look for (the union :-) label */ | |
644 | ||
645 | /* if we get here, we haven't seen the label before, therefor it's instance | |
646 | count is zero. */ | |
647 | return (0); | |
648 | } /* dollar_label_instance() */ | |
649 | ||
650 | void | |
651 | dollar_label_clear () | |
652 | { | |
653 | memset (dollar_label_defines, '\0', dollar_label_count); | |
654 | return; | |
655 | } /* clear_dollar_labels() */ | |
656 | ||
657 | #define DOLLAR_LABEL_BUMP_BY 10 | |
658 | ||
659 | void | |
660 | define_dollar_label (label) | |
661 | long label; | |
662 | { | |
663 | long *i; | |
664 | ||
665 | for (i = dollar_labels; i < dollar_labels + dollar_label_count; ++i) | |
666 | { | |
667 | if (*i == label) | |
668 | { | |
669 | ++dollar_label_instances[i - dollar_labels]; | |
670 | dollar_label_defines[i - dollar_labels] = 1; | |
671 | return; | |
672 | } /* if we find it */ | |
673 | } /* for each existing label */ | |
674 | ||
675 | /* if we get to here, we don't have label listed yet. */ | |
676 | ||
677 | if (dollar_labels == NULL) | |
678 | { | |
679 | dollar_labels = (long *) xmalloc (DOLLAR_LABEL_BUMP_BY * sizeof (long)); | |
680 | dollar_label_instances = (long *) xmalloc (DOLLAR_LABEL_BUMP_BY * sizeof (long)); | |
681 | dollar_label_defines = xmalloc (DOLLAR_LABEL_BUMP_BY); | |
682 | dollar_label_max = DOLLAR_LABEL_BUMP_BY; | |
683 | dollar_label_count = 0; | |
684 | ||
685 | } | |
686 | else if (dollar_label_count == dollar_label_max) | |
687 | { | |
688 | dollar_label_max += DOLLAR_LABEL_BUMP_BY; | |
689 | dollar_labels = (long *) xrealloc ((char *) dollar_labels, | |
690 | dollar_label_max * sizeof (long)); | |
691 | dollar_label_instances = (long *) xrealloc ((char *) dollar_label_instances, | |
692 | dollar_label_max * sizeof (long)); | |
693 | dollar_label_defines = xrealloc (dollar_label_defines, dollar_label_max); | |
694 | } /* if we needed to grow */ | |
695 | ||
696 | dollar_labels[dollar_label_count] = label; | |
697 | dollar_label_instances[dollar_label_count] = 1; | |
698 | dollar_label_defines[dollar_label_count] = 1; | |
699 | ++dollar_label_count; | |
700 | return; | |
701 | } /* define_dollar_label() */ | |
702 | ||
703 | /* | |
704 | * dollar_label_name() | |
705 | * | |
706 | * Caller must copy returned name: we re-use the area for the next name. | |
707 | * | |
708 | * The mth occurence of label n: is turned into the symbol "Ln^Am" where | |
709 | * n is the label number and m is the instance number. "L" makes it a label discarded | |
710 | * unless debugging and "^A"('\1') ensures no ordinary symbol SHOULD get the | |
711 | * same name as a local label symbol. The first "4:" is "L4^A1" - the m | |
712 | * numbers begin at 1. | |
713 | * | |
714 | * fb labels get the same treatment, except that ^B is used in place of ^A. | |
715 | */ | |
716 | ||
717 | char * /* Return local label name. */ | |
718 | dollar_label_name (n, augend) | |
719 | register long n; /* we just saw "n$:" : n a number */ | |
720 | register int augend; /* 0 for current instance, 1 for new instance */ | |
721 | { | |
722 | long i; | |
723 | /* Returned to caller, then copied. used for created names ("4f") */ | |
724 | static char symbol_name_build[24]; | |
725 | register char *p; | |
726 | register char *q; | |
727 | char symbol_name_temporary[20]; /* build up a number, BACKWARDS */ | |
728 | ||
729 | know (n >= 0); | |
730 | know (augend == 0 || augend == 1); | |
731 | p = symbol_name_build; | |
732 | *p++ = 'L'; | |
733 | ||
734 | /* Next code just does sprintf( {}, "%d", n); */ | |
735 | /* label number */ | |
736 | q = symbol_name_temporary; | |
737 | for (*q++ = 0, i = n; i; ++q) | |
738 | { | |
739 | *q = i % 10 + '0'; | |
740 | i /= 10; | |
741 | } | |
742 | while ((*p = *--q) != '\0') | |
743 | ++p; | |
744 | ||
745 | *p++ = 1; /* ^A */ | |
746 | ||
747 | /* instance number */ | |
748 | q = symbol_name_temporary; | |
749 | for (*q++ = 0, i = dollar_label_instance (n) + augend; i; ++q) | |
750 | { | |
751 | *q = i % 10 + '0'; | |
752 | i /= 10; | |
753 | } | |
754 | while ((*p++ = *--q) != '\0');; | |
755 | ||
756 | /* The label, as a '\0' ended string, starts at symbol_name_build. */ | |
757 | return (symbol_name_build); | |
758 | } /* dollar_label_name() */ | |
759 | ||
760 | #endif /* LOCAL_LABELS_DOLLAR */ | |
761 | ||
762 | #ifdef LOCAL_LABELS_FB | |
763 | ||
764 | /* | |
765 | * Sombody else's idea of local labels. They are made by "n:" where n | |
766 | * is any decimal digit. Refer to them with | |
767 | * "nb" for previous (backward) n: | |
768 | * or "nf" for next (forward) n:. | |
769 | * | |
770 | * We do a little better and let n be any number, not just a single digit, but | |
771 | * since the other guy's assembler only does ten, we treat the first ten | |
772 | * specially. | |
773 | * | |
774 | * Like someone else's assembler, we have one set of local label counters for | |
775 | * entire assembly, not one set per (sub)segment like in most assemblers. This | |
776 | * implies that one can refer to a label in another segment, and indeed some | |
777 | * crufty compilers have done just that. | |
778 | * | |
779 | * Since there could be a LOT of these things, treat them as a sparse array. | |
780 | */ | |
781 | ||
782 | #define FB_LABEL_SPECIAL (10) | |
783 | ||
784 | static long fb_low_counter[FB_LABEL_SPECIAL]; | |
785 | static long *fb_labels; | |
786 | static long *fb_label_instances; | |
787 | static long fb_label_count = 0; | |
788 | static long fb_label_max = 0; | |
789 | ||
790 | /* this must be more than FB_LABEL_SPECIAL */ | |
791 | #define FB_LABEL_BUMP_BY (FB_LABEL_SPECIAL + 6) | |
792 | ||
793 | static void | |
794 | fb_label_init () | |
795 | { | |
796 | memset ((void *) fb_low_counter, '\0', sizeof (fb_low_counter)); | |
797 | return; | |
798 | } /* fb_label_init() */ | |
799 | ||
800 | /* add one to the instance number of this fb label */ | |
801 | void | |
802 | fb_label_instance_inc (label) | |
803 | long label; | |
804 | { | |
805 | long *i; | |
806 | ||
807 | if (label < FB_LABEL_SPECIAL) | |
808 | { | |
809 | ++fb_low_counter[label]; | |
810 | return; | |
811 | } | |
812 | ||
813 | for (i = fb_labels + FB_LABEL_SPECIAL; i < fb_labels + fb_label_count; ++i) | |
814 | { | |
815 | if (*i == label) | |
816 | { | |
817 | ++fb_label_instances[i - fb_labels]; | |
818 | return; | |
819 | } /* if we find it */ | |
820 | } /* for each existing label */ | |
821 | ||
822 | /* if we get to here, we don't have label listed yet. */ | |
823 | ||
824 | if (fb_labels == NULL) | |
825 | { | |
826 | fb_labels = (long *) xmalloc (FB_LABEL_BUMP_BY * sizeof (long)); | |
827 | fb_label_instances = (long *) xmalloc (FB_LABEL_BUMP_BY * sizeof (long)); | |
828 | fb_label_max = FB_LABEL_BUMP_BY; | |
829 | fb_label_count = FB_LABEL_SPECIAL; | |
830 | ||
831 | } | |
832 | else if (fb_label_count == fb_label_max) | |
833 | { | |
834 | fb_label_max += FB_LABEL_BUMP_BY; | |
835 | fb_labels = (long *) xrealloc ((char *) fb_labels, | |
836 | fb_label_max * sizeof (long)); | |
837 | fb_label_instances = (long *) xrealloc ((char *) fb_label_instances, | |
838 | fb_label_max * sizeof (long)); | |
839 | } /* if we needed to grow */ | |
840 | ||
841 | fb_labels[fb_label_count] = label; | |
842 | fb_label_instances[fb_label_count] = 1; | |
843 | ++fb_label_count; | |
844 | return; | |
845 | } /* fb_label_instance_inc() */ | |
846 | ||
847 | static long | |
848 | fb_label_instance (label) | |
849 | long label; | |
850 | { | |
851 | long *i; | |
852 | ||
853 | if (label < FB_LABEL_SPECIAL) | |
854 | { | |
855 | return (fb_low_counter[label]); | |
856 | } | |
857 | ||
858 | for (i = fb_labels + FB_LABEL_SPECIAL; i < fb_labels + fb_label_count; ++i) | |
859 | { | |
860 | if (*i == label) | |
861 | { | |
862 | return (fb_label_instances[i - fb_labels]); | |
863 | } /* if we find it */ | |
864 | } /* for each existing label */ | |
865 | ||
866 | /* NOTREACHED */ | |
867 | know (0); | |
868 | } /* fb_label_instance() */ | |
869 | ||
870 | /* | |
871 | * fb_label_name() | |
872 | * | |
873 | * Caller must copy returned name: we re-use the area for the next name. | |
874 | * | |
875 | * The mth occurence of label n: is turned into the symbol "Ln^Bm" where | |
876 | * n is the label number and m is the instance number. "L" makes it a label discarded | |
877 | * unless debugging and "^B"('\2') ensures no ordinary symbol SHOULD get the | |
878 | * same name as a local label symbol. The first "4:" is "L4^B1" - the m | |
879 | * numbers begin at 1. | |
880 | * | |
881 | * dollar labels get the same treatment, except that ^A is used in place of ^B. | |
882 | */ | |
883 | ||
884 | char * /* Return local label name. */ | |
885 | fb_label_name (n, augend) | |
886 | long n; /* we just saw "n:", "nf" or "nb" : n a number */ | |
887 | long augend; /* 0 for nb, 1 for n:, nf */ | |
888 | { | |
889 | long i; | |
890 | /* Returned to caller, then copied. used for created names ("4f") */ | |
891 | static char symbol_name_build[24]; | |
892 | register char *p; | |
893 | register char *q; | |
894 | char symbol_name_temporary[20]; /* build up a number, BACKWARDS */ | |
895 | ||
896 | know (n >= 0); | |
897 | know (augend == 0 || augend == 1); | |
898 | p = symbol_name_build; | |
899 | *p++ = 'L'; | |
900 | ||
901 | /* Next code just does sprintf( {}, "%d", n); */ | |
902 | /* label number */ | |
903 | q = symbol_name_temporary; | |
904 | for (*q++ = 0, i = n; i; ++q) | |
905 | { | |
906 | *q = i % 10 + '0'; | |
907 | i /= 10; | |
908 | } | |
909 | while ((*p = *--q) != '\0') | |
910 | ++p; | |
911 | ||
912 | *p++ = 2; /* ^B */ | |
913 | ||
914 | /* instance number */ | |
915 | q = symbol_name_temporary; | |
916 | for (*q++ = 0, i = fb_label_instance (n) + augend; i; ++q) | |
917 | { | |
918 | *q = i % 10 + '0'; | |
919 | i /= 10; | |
920 | } | |
921 | while ((*p++ = *--q) != '\0');; | |
922 | ||
923 | /* The label, as a '\0' ended string, starts at symbol_name_build. */ | |
924 | return (symbol_name_build); | |
925 | } /* fb_label_name() */ | |
926 | ||
927 | #endif /* LOCAL_LABELS_FB */ | |
fecd2382 RP |
928 | |
929 | ||
a6c6eaf8 | 930 | /* |
6efd877d KR |
931 | * decode name that may have been generated by foo_label_name() above. If |
932 | * the name wasn't generated by foo_label_name(), then return it unaltered. | |
a6c6eaf8 RP |
933 | * This is used for error messages. |
934 | */ | |
a39116f1 | 935 | |
6efd877d KR |
936 | char * |
937 | decode_local_label_name (s) | |
938 | char *s; | |
a6c6eaf8 | 939 | { |
6efd877d KR |
940 | char *p; |
941 | char *symbol_decode; | |
942 | int label_number; | |
943 | int instance_number; | |
944 | char *type; | |
945 | const char *message_format = "\"%d\" (instance number %d of a %s label)"; | |
946 | ||
947 | if (s[0] != 'L') | |
948 | return (s); | |
949 | ||
950 | for (label_number = 0, p = s + 1; isdigit (*p); ++p) | |
951 | { | |
952 | label_number = (10 * label_number) + *p - '0'; | |
953 | } | |
954 | ||
955 | if (*p == 1) | |
956 | { | |
957 | type = "dollar"; | |
958 | } | |
959 | else if (*p == 2) | |
960 | { | |
961 | type = "fb"; | |
962 | } | |
963 | else | |
964 | { | |
965 | return (s); | |
966 | } | |
967 | ||
968 | for (instance_number = 0, p = s + 1; isdigit (*p); ++p) | |
969 | { | |
970 | instance_number = (10 * instance_number) + *p - '0'; | |
971 | } | |
972 | ||
973 | symbol_decode = obstack_alloc (¬es, strlen (message_format) + 30); | |
974 | (void) sprintf (symbol_decode, message_format, label_number, | |
975 | instance_number, type); | |
976 | ||
977 | return (symbol_decode); | |
978 | } /* decode_local_label_name() */ | |
a6c6eaf8 RP |
979 | |
980 | ||
fecd2382 RP |
981 | /* |
982 | * Local Variables: | |
983 | * comment-column: 0 | |
984 | * fill-column: 131 | |
985 | * End: | |
986 | */ | |
987 | ||
8b228fe9 | 988 | /* end of symbols.c */ |