blob: 6259986ac5e7d01a7a7b654b77abd9c58f5904ea [file] [log] [blame]
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001/* labels.c label handling for the Netwide Assembler
2 *
3 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4 * Julian Hall. All rights reserved. The software is
5 * redistributable under the licence given in the file "Licence"
6 * distributed in the NASM archive.
7 */
8
9#include <stdio.h>
10#include <string.h>
11#include <stdlib.h>
12#include "nasm.h"
13#include "nasmlib.h"
14
15/*
16 * A local label is one that begins with exactly one period. Things
17 * that begin with _two_ periods are NASM-specific things.
18 */
19#define islocal(l) ((l)[0] == '.' && (l)[1] != '.')
20
21#define LABEL_BLOCK 320 /* no. of labels/block */
22#define LBLK_SIZE (LABEL_BLOCK*sizeof(union label))
23#define LABEL_HASHES 32 /* no. of hash table entries */
24
25#define END_LIST -3 /* don't clash with NO_SEG! */
26#define END_BLOCK -2
27#define BOGUS_VALUE -4
28
29#define PERMTS_SIZE 4096 /* size of text blocks */
30
31/* values for label.defn.is_global */
H. Peter Anvin76690a12002-04-30 20:52:49 +000032#define DEFINED_BIT 1
33#define GLOBAL_BIT 2
34#define EXTERN_BIT 4
35
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000036#define NOT_DEFINED_YET 0
H. Peter Anvin76690a12002-04-30 20:52:49 +000037#define TYPE_MASK 3
38#define LOCAL_SYMBOL (DEFINED_BIT)
39#define GLOBAL_PLACEHOLDER (GLOBAL_BIT)
40#define GLOBAL_SYMBOL (DEFINED_BIT|GLOBAL_BIT)
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000041
42union label { /* actual label structures */
43 struct {
44 long segment, offset;
H. Peter Anvin76690a12002-04-30 20:52:49 +000045 char *label, *special;
H. Peter Anvineba20a72002-04-30 20:53:55 +000046 int is_global, is_norm;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000047 } defn;
48 struct {
49 long movingon, dummy;
50 union label *next;
51 } admin;
52};
53
54struct permts { /* permanent text storage */
55 struct permts *next; /* for the linked list */
56 int size, usage; /* size and used space in ... */
57 char data[PERMTS_SIZE]; /* ... the data block itself */
58};
59
60static union label *ltab[LABEL_HASHES];/* using a hash table */
61static union label *lfree[LABEL_HASHES];/* pointer into the above */
62static struct permts *perm_head; /* start of perm. text storage */
63static struct permts *perm_tail; /* end of perm. text storage */
64
65static void init_block (union label *blk);
66static char *perm_copy (char *string1, char *string2);
67
68static char *prevlabel;
69
H. Peter Anvin76690a12002-04-30 20:52:49 +000070static int initialised = FALSE;
71
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000072/*
73 * Internal routine: finds the `union label' corresponding to the
74 * given label name. Creates a new one, if it isn't found, and if
75 * `create' is TRUE.
76 */
H. Peter Anvineba20a72002-04-30 20:53:55 +000077static union label *find_label (char *label, int create)
78{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000079 int hash = 0;
80 char *p, *prev;
81 int prevlen;
82 union label *lptr;
83
84 if (islocal(label))
85 prev = prevlabel;
86 else
87 prev = "";
88 prevlen = strlen(prev);
89 p = prev;
90 while (*p) hash += *p++;
91 p = label;
92 while (*p) hash += *p++;
93 hash %= LABEL_HASHES;
94 lptr = ltab[hash];
95 while (lptr->admin.movingon != END_LIST) {
96 if (lptr->admin.movingon == END_BLOCK) {
97 lptr = lptr->admin.next;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +000098 if (!lptr)
99 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000100 }
101 if (!strncmp(lptr->defn.label, prev, prevlen) &&
102 !strcmp(lptr->defn.label+prevlen, label))
103 return lptr;
104 lptr++;
105 }
106 if (create) {
107 if (lfree[hash]->admin.movingon == END_BLOCK) {
108 /*
109 * must allocate a new block
110 */
111 lfree[hash]->admin.next = (union label *) nasm_malloc (LBLK_SIZE);
112 lfree[hash] = lfree[hash]->admin.next;
113 init_block(lfree[hash]);
114 }
115
116 lfree[hash]->admin.movingon = BOGUS_VALUE;
117 lfree[hash]->defn.label = perm_copy (prev, label);
H. Peter Anvin76690a12002-04-30 20:52:49 +0000118 lfree[hash]->defn.special = NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000119 lfree[hash]->defn.is_global = NOT_DEFINED_YET;
120 return lfree[hash]++;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000121 }
122 else
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000123 return NULL;
124}
125
H. Peter Anvineba20a72002-04-30 20:53:55 +0000126int lookup_label (char *label, long *segment, long *offset)
127{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000128 union label *lptr;
129
H. Peter Anvin76690a12002-04-30 20:52:49 +0000130 if (!initialised)
131 return 0;
132
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000133 lptr = find_label (label, 0);
H. Peter Anvin76690a12002-04-30 20:52:49 +0000134 if (lptr && (lptr->defn.is_global & DEFINED_BIT)) {
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000135 *segment = lptr->defn.segment;
136 *offset = lptr->defn.offset;
137 return 1;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000138 }
139 else
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000140 return 0;
141}
142
H. Peter Anvineba20a72002-04-30 20:53:55 +0000143int is_extern (char *label)
144{
H. Peter Anvin76690a12002-04-30 20:52:49 +0000145 union label *lptr;
146
147 if (!initialised)
148 return 0;
149
150 lptr = find_label (label, 0);
151 if (lptr && (lptr->defn.is_global & EXTERN_BIT))
152 return 1;
153 else
154 return 0;
155}
156
H. Peter Anvineba20a72002-04-30 20:53:55 +0000157void redefine_label (char *label, long segment, long offset, char *special,
158 int is_norm, int isextrn, struct ofmt *ofmt, efunc error)
159{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000160 union label *lptr;
161
H. Peter Anvineba20a72002-04-30 20:53:55 +0000162 /* This routine possibly ought to check for phase errors. Most assemblers
163 * check for phase errors at this point. I don't know whether phase errors
164 * are even possible, nor whether they are checked somewhere else
165 */
166
167 (void) segment; /* Don't warn that this parameter is unused */
168 (void) offset; /* Don't warn that this parameter is unused */
169 (void) special; /* Don't warn that this parameter is unused */
170 (void) is_norm; /* Don't warn that this parameter is unused */
171 (void) isextrn; /* Don't warn that this parameter is unused */
172 (void) ofmt; /* Don't warn that this parameter is unused */
173
174#ifdef DEBUG
175 if (!strncmp(label, "debugdump", 9))
176 fprintf(stderr, "debug: redefine_label (%s, %ld, %08lx, %s, %d, %d)\n",
177 label, segment, offset, special, is_norm, isextrn);
178#endif
179
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000180 if (!islocal(label)) {
181 lptr = find_label (label, 1);
182 if (!lptr)
183 error (ERR_PANIC, "can't find label `%s' on pass two", label);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000184 if (*label != '.' && lptr->defn.is_norm)
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000185 prevlabel = lptr->defn.label;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000186 }
187}
188
H. Peter Anvin76690a12002-04-30 20:52:49 +0000189void define_label (char *label, long segment, long offset, char *special,
H. Peter Anvineba20a72002-04-30 20:53:55 +0000190 int is_norm, int isextrn, struct ofmt *ofmt, efunc error)
191{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000192 union label *lptr;
193
H. Peter Anvineba20a72002-04-30 20:53:55 +0000194#ifdef DEBUG
195 if (!strncmp(label, "debugdump", 9))
196 fprintf(stderr, "debug: define_label (%s, %ld, %08lx, %s, %d, %d)\n",
197 label, segment, offset, special, is_norm, isextrn);
198#endif
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000199 lptr = find_label (label, 1);
H. Peter Anvin76690a12002-04-30 20:52:49 +0000200 if (lptr->defn.is_global & DEFINED_BIT) {
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000201 error(ERR_NONFATAL, "symbol `%s' redefined", label);
202 return;
203 }
H. Peter Anvin76690a12002-04-30 20:52:49 +0000204 lptr->defn.is_global |= DEFINED_BIT;
205 if (isextrn)
206 lptr->defn.is_global |= EXTERN_BIT;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000207
H. Peter Anvin76690a12002-04-30 20:52:49 +0000208 if (label[0] != '.' && is_norm) /* not local, but not special either */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000209 prevlabel = lptr->defn.label;
H. Peter Anvin76690a12002-04-30 20:52:49 +0000210 else if (label[0] == '.' && label[1] != '.' && !*prevlabel)
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000211 error(ERR_NONFATAL, "attempt to define a local label before any"
212 " non-local labels");
213
214 lptr->defn.segment = segment;
215 lptr->defn.offset = offset;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000216 lptr->defn.is_norm = (label[0] != '.' && is_norm);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000217
H. Peter Anvin41bf8002002-04-30 20:58:18 +0000218 if ( (lptr->defn.is_global & (GLOBAL_BIT|EXTERN_BIT)) != EXTERN_BIT ) {
219 ofmt->symdef (lptr->defn.label, segment, offset,
220 !!(lptr->defn.is_global & GLOBAL_BIT),
221 special ? special : lptr->defn.special);
222 ofmt->current_dfmt->debug_deflabel (label, segment, offset,
223 !!(lptr->defn.is_global & GLOBAL_BIT),
224 special ? special : lptr->defn.special);
225 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000226}
227
H. Peter Anvin76690a12002-04-30 20:52:49 +0000228void define_common (char *label, long segment, long size, char *special,
H. Peter Anvineba20a72002-04-30 20:53:55 +0000229 struct ofmt *ofmt, efunc error)
230{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000231 union label *lptr;
232
233 lptr = find_label (label, 1);
H. Peter Anvin76690a12002-04-30 20:52:49 +0000234 if (lptr->defn.is_global & DEFINED_BIT) {
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000235 error(ERR_NONFATAL, "symbol `%s' redefined", label);
236 return;
237 }
H. Peter Anvin76690a12002-04-30 20:52:49 +0000238 lptr->defn.is_global |= DEFINED_BIT;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000239
240 if (label[0] != '.') /* not local, but not special either */
241 prevlabel = lptr->defn.label;
242 else
243 error(ERR_NONFATAL, "attempt to define a local label as a "
244 "common variable");
245
246 lptr->defn.segment = segment;
247 lptr->defn.offset = 0;
248
H. Peter Anvin76690a12002-04-30 20:52:49 +0000249 ofmt->symdef (lptr->defn.label, segment, size, 2,
250 special ? special : lptr->defn.special);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000251 ofmt->current_dfmt->debug_deflabel(lptr->defn.label, segment, size, 2,
252 special ? special : lptr->defn.special);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000253}
254
H. Peter Anvineba20a72002-04-30 20:53:55 +0000255void declare_as_global (char *label, char *special, efunc error)
256{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000257 union label *lptr;
258
259 if (islocal(label)) {
260 error(ERR_NONFATAL, "attempt to declare local symbol `%s' as"
261 " global", label);
262 return;
263 }
264 lptr = find_label (label, 1);
H. Peter Anvin76690a12002-04-30 20:52:49 +0000265 switch (lptr->defn.is_global & TYPE_MASK) {
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000266 case NOT_DEFINED_YET:
267 lptr->defn.is_global = GLOBAL_PLACEHOLDER;
H. Peter Anvin76690a12002-04-30 20:52:49 +0000268 lptr->defn.special = special ? perm_copy(special, "") : NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000269 break;
270 case GLOBAL_PLACEHOLDER: /* already done: silently ignore */
271 case GLOBAL_SYMBOL:
272 break;
273 case LOCAL_SYMBOL:
H. Peter Anvin76690a12002-04-30 20:52:49 +0000274 if (!lptr->defn.is_global & EXTERN_BIT)
275 error(ERR_NONFATAL, "symbol `%s': GLOBAL directive must"
276 " appear before symbol definition", label);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000277 break;
278 }
279}
280
H. Peter Anvineba20a72002-04-30 20:53:55 +0000281int init_labels (void)
282{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000283 int i;
284
285 for (i=0; i<LABEL_HASHES; i++) {
286 ltab[i] = (union label *) nasm_malloc (LBLK_SIZE);
287 if (!ltab[i])
288 return -1; /* can't initialise, panic */
289 init_block (ltab[i]);
290 lfree[i] = ltab[i];
291 }
292
H. Peter Anvineba20a72002-04-30 20:53:55 +0000293 perm_head =
294 perm_tail = (struct permts *) nasm_malloc (sizeof(struct permts));
295
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000296 if (!perm_head)
297 return -1;
298
299 perm_head->next = NULL;
300 perm_head->size = PERMTS_SIZE;
301 perm_head->usage = 0;
302
303 prevlabel = "";
304
H. Peter Anvin76690a12002-04-30 20:52:49 +0000305 initialised = TRUE;
306
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000307 return 0;
308}
309
H. Peter Anvineba20a72002-04-30 20:53:55 +0000310void cleanup_labels (void)
311{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000312 int i;
313
H. Peter Anvin76690a12002-04-30 20:52:49 +0000314 initialised = FALSE;
315
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000316 for (i=0; i<LABEL_HASHES; i++) {
317 union label *lptr, *lhold;
318
319 lptr = lhold = ltab[i];
320
321 while (lptr) {
322 while (lptr->admin.movingon != END_BLOCK) lptr++;
323 lptr = lptr->admin.next;
324 nasm_free (lhold);
325 lhold = lptr;
326 }
327 }
328
329 while (perm_head) {
330 perm_tail = perm_head;
331 perm_head = perm_head->next;
332 nasm_free (perm_tail);
333 }
334}
335
H. Peter Anvineba20a72002-04-30 20:53:55 +0000336static void init_block (union label *blk)
337{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000338 int j;
339
340 for (j=0; j<LABEL_BLOCK-1; j++)
341 blk[j].admin.movingon = END_LIST;
342 blk[LABEL_BLOCK-1].admin.movingon = END_BLOCK;
343 blk[LABEL_BLOCK-1].admin.next = NULL;
344}
345
H. Peter Anvineba20a72002-04-30 20:53:55 +0000346static char *perm_copy (char *string1, char *string2)
347{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000348 char *p, *q;
349 int len = strlen(string1)+strlen(string2)+1;
350
351 if (perm_tail->size - perm_tail->usage < len) {
352 perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts));
353 perm_tail = perm_tail->next;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000354 perm_tail->next = NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000355 perm_tail->size = PERMTS_SIZE;
356 perm_tail->usage = 0;
357 }
358 p = q = perm_tail->data + perm_tail->usage;
359 while ( (*q = *string1++) ) q++;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000360 while ( (*q++ = *string2++) ) ;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000361 perm_tail->usage = q - perm_tail->data;
362
363 return p;
364}
H. Peter Anvineba20a72002-04-30 20:53:55 +0000365
366/*
367 * Notes regarding bug involving redefinition of external segments.
368 *
369 * Up to and including v0.97, the following code didn't work. From 0.97
370 * developers release 2 onwards, it will generate an error.
371 *
372 * EXTERN extlabel
373 * newlabel EQU extlabel + 1
374 *
375 * The results of allowing this code through are that two import records
376 * are generated, one for 'extlabel' and one for 'newlabel'.
377 *
378 * The reason for this is an inadequacy in the defined interface between
379 * the label manager and the output formats. The problem lies in how the
380 * output format driver tells that a label is an external label for which
381 * a label import record must be produced. Most (all except bin?) produce
382 * the record if the segment number of the label is not one of the internal
383 * segments that the output driver is producing.
384 *
385 * A simple fix to this would be to make the output formats keep track of
386 * which symbols they've produced import records for, and make them not
387 * produce import records for segments that are already defined.
388 *
389 * The best way, which is slightly harder but reduces duplication of code
390 * and should therefore make the entire system smaller and more stable is
391 * to change the interface between assembler, define_label(), and
392 * the output module. The changes that are needed are:
393 *
394 * The semantics of the 'isextern' flag passed to define_label() need
395 * examining. This information may or may not tell us what we need to
396 * know (ie should we be generating an import record at this point for this
397 * label). If these aren't the semantics, the semantics should be changed
398 * to this.
399 *
400 * The output module interface needs changing, so that the `isextern' flag
401 * is passed to the module, so that it can be easily tested for.
402 */