blob: 2c17c7c820b6328357fabb94c7b706677aae8cd7 [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 Anvinea6e34d2002-04-30 20:51:32 +000046 int is_global;
47 } 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 */
77static union label *find_label (char *label, int create) {
78 int hash = 0;
79 char *p, *prev;
80 int prevlen;
81 union label *lptr;
82
83 if (islocal(label))
84 prev = prevlabel;
85 else
86 prev = "";
87 prevlen = strlen(prev);
88 p = prev;
89 while (*p) hash += *p++;
90 p = label;
91 while (*p) hash += *p++;
92 hash %= LABEL_HASHES;
93 lptr = ltab[hash];
94 while (lptr->admin.movingon != END_LIST) {
95 if (lptr->admin.movingon == END_BLOCK) {
96 lptr = lptr->admin.next;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +000097 if (!lptr)
98 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000099 }
100 if (!strncmp(lptr->defn.label, prev, prevlen) &&
101 !strcmp(lptr->defn.label+prevlen, label))
102 return lptr;
103 lptr++;
104 }
105 if (create) {
106 if (lfree[hash]->admin.movingon == END_BLOCK) {
107 /*
108 * must allocate a new block
109 */
110 lfree[hash]->admin.next = (union label *) nasm_malloc (LBLK_SIZE);
111 lfree[hash] = lfree[hash]->admin.next;
112 init_block(lfree[hash]);
113 }
114
115 lfree[hash]->admin.movingon = BOGUS_VALUE;
116 lfree[hash]->defn.label = perm_copy (prev, label);
H. Peter Anvin76690a12002-04-30 20:52:49 +0000117 lfree[hash]->defn.special = NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000118 lfree[hash]->defn.is_global = NOT_DEFINED_YET;
119 return lfree[hash]++;
120 } else
121 return NULL;
122}
123
124int lookup_label (char *label, long *segment, long *offset) {
125 union label *lptr;
126
H. Peter Anvin76690a12002-04-30 20:52:49 +0000127 if (!initialised)
128 return 0;
129
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000130 lptr = find_label (label, 0);
H. Peter Anvin76690a12002-04-30 20:52:49 +0000131 if (lptr && (lptr->defn.is_global & DEFINED_BIT)) {
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000132 *segment = lptr->defn.segment;
133 *offset = lptr->defn.offset;
134 return 1;
135 } else
136 return 0;
137}
138
H. Peter Anvin76690a12002-04-30 20:52:49 +0000139int is_extern (char *label) {
140 union label *lptr;
141
142 if (!initialised)
143 return 0;
144
145 lptr = find_label (label, 0);
146 if (lptr && (lptr->defn.is_global & EXTERN_BIT))
147 return 1;
148 else
149 return 0;
150}
151
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000152void define_label_stub (char *label, efunc error) {
153 union label *lptr;
154
155 if (!islocal(label)) {
156 lptr = find_label (label, 1);
157 if (!lptr)
158 error (ERR_PANIC, "can't find label `%s' on pass two", label);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000159 if (*label != '.')
160 prevlabel = lptr->defn.label;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000161 }
162}
163
H. Peter Anvin76690a12002-04-30 20:52:49 +0000164void define_label (char *label, long segment, long offset, char *special,
165 int is_norm, int isextrn, struct ofmt *ofmt, efunc error) {
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000166 union label *lptr;
167
168 lptr = find_label (label, 1);
H. Peter Anvin76690a12002-04-30 20:52:49 +0000169 if (lptr->defn.is_global & DEFINED_BIT) {
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000170 error(ERR_NONFATAL, "symbol `%s' redefined", label);
171 return;
172 }
H. Peter Anvin76690a12002-04-30 20:52:49 +0000173 lptr->defn.is_global |= DEFINED_BIT;
174 if (isextrn)
175 lptr->defn.is_global |= EXTERN_BIT;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000176
H. Peter Anvin76690a12002-04-30 20:52:49 +0000177 if (label[0] != '.' && is_norm) /* not local, but not special either */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000178 prevlabel = lptr->defn.label;
H. Peter Anvin76690a12002-04-30 20:52:49 +0000179 else if (label[0] == '.' && label[1] != '.' && !*prevlabel)
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000180 error(ERR_NONFATAL, "attempt to define a local label before any"
181 " non-local labels");
182
183 lptr->defn.segment = segment;
184 lptr->defn.offset = offset;
185
186 ofmt->symdef (lptr->defn.label, segment, offset,
H. Peter Anvin76690a12002-04-30 20:52:49 +0000187 !!(lptr->defn.is_global & GLOBAL_BIT),
188 special ? special : lptr->defn.special);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000189}
190
H. Peter Anvin76690a12002-04-30 20:52:49 +0000191void define_common (char *label, long segment, long size, char *special,
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000192 struct ofmt *ofmt, efunc error) {
193 union label *lptr;
194
195 lptr = find_label (label, 1);
H. Peter Anvin76690a12002-04-30 20:52:49 +0000196 if (lptr->defn.is_global & DEFINED_BIT) {
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000197 error(ERR_NONFATAL, "symbol `%s' redefined", label);
198 return;
199 }
H. Peter Anvin76690a12002-04-30 20:52:49 +0000200 lptr->defn.is_global |= DEFINED_BIT;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000201
202 if (label[0] != '.') /* not local, but not special either */
203 prevlabel = lptr->defn.label;
204 else
205 error(ERR_NONFATAL, "attempt to define a local label as a "
206 "common variable");
207
208 lptr->defn.segment = segment;
209 lptr->defn.offset = 0;
210
H. Peter Anvin76690a12002-04-30 20:52:49 +0000211 ofmt->symdef (lptr->defn.label, segment, size, 2,
212 special ? special : lptr->defn.special);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000213}
214
H. Peter Anvin76690a12002-04-30 20:52:49 +0000215void declare_as_global (char *label, char *special, efunc error) {
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000216 union label *lptr;
217
218 if (islocal(label)) {
219 error(ERR_NONFATAL, "attempt to declare local symbol `%s' as"
220 " global", label);
221 return;
222 }
223 lptr = find_label (label, 1);
H. Peter Anvin76690a12002-04-30 20:52:49 +0000224 switch (lptr->defn.is_global & TYPE_MASK) {
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000225 case NOT_DEFINED_YET:
226 lptr->defn.is_global = GLOBAL_PLACEHOLDER;
H. Peter Anvin76690a12002-04-30 20:52:49 +0000227 lptr->defn.special = special ? perm_copy(special, "") : NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000228 break;
229 case GLOBAL_PLACEHOLDER: /* already done: silently ignore */
230 case GLOBAL_SYMBOL:
231 break;
232 case LOCAL_SYMBOL:
H. Peter Anvin76690a12002-04-30 20:52:49 +0000233 if (!lptr->defn.is_global & EXTERN_BIT)
234 error(ERR_NONFATAL, "symbol `%s': GLOBAL directive must"
235 " appear before symbol definition", label);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000236 break;
237 }
238}
239
240int init_labels (void) {
241 int i;
242
243 for (i=0; i<LABEL_HASHES; i++) {
244 ltab[i] = (union label *) nasm_malloc (LBLK_SIZE);
245 if (!ltab[i])
246 return -1; /* can't initialise, panic */
247 init_block (ltab[i]);
248 lfree[i] = ltab[i];
249 }
250
251 perm_head = perm_tail = (struct permts *) nasm_malloc (sizeof(struct permts));
252 if (!perm_head)
253 return -1;
254
255 perm_head->next = NULL;
256 perm_head->size = PERMTS_SIZE;
257 perm_head->usage = 0;
258
259 prevlabel = "";
260
H. Peter Anvin76690a12002-04-30 20:52:49 +0000261 initialised = TRUE;
262
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000263 return 0;
264}
265
266void cleanup_labels (void) {
267 int i;
268
H. Peter Anvin76690a12002-04-30 20:52:49 +0000269 initialised = FALSE;
270
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000271 for (i=0; i<LABEL_HASHES; i++) {
272 union label *lptr, *lhold;
273
274 lptr = lhold = ltab[i];
275
276 while (lptr) {
277 while (lptr->admin.movingon != END_BLOCK) lptr++;
278 lptr = lptr->admin.next;
279 nasm_free (lhold);
280 lhold = lptr;
281 }
282 }
283
284 while (perm_head) {
285 perm_tail = perm_head;
286 perm_head = perm_head->next;
287 nasm_free (perm_tail);
288 }
289}
290
291static void init_block (union label *blk) {
292 int j;
293
294 for (j=0; j<LABEL_BLOCK-1; j++)
295 blk[j].admin.movingon = END_LIST;
296 blk[LABEL_BLOCK-1].admin.movingon = END_BLOCK;
297 blk[LABEL_BLOCK-1].admin.next = NULL;
298}
299
300static char *perm_copy (char *string1, char *string2) {
301 char *p, *q;
302 int len = strlen(string1)+strlen(string2)+1;
303
304 if (perm_tail->size - perm_tail->usage < len) {
305 perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts));
306 perm_tail = perm_tail->next;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000307 perm_tail->next = NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000308 perm_tail->size = PERMTS_SIZE;
309 perm_tail->usage = 0;
310 }
311 p = q = perm_tail->data + perm_tail->usage;
312 while ( (*q = *string1++) ) q++;
313 while ( (*q++ = *string2++) );
314 perm_tail->usage = q - perm_tail->data;
315
316 return p;
317}