]> git.saurik.com Git - apple/boot.git/blob - i386/nasm/labels.c
boot-111.tar.gz
[apple/boot.git] / i386 / nasm / labels.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /* labels.c label handling for the Netwide Assembler
26 *
27 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
28 * Julian Hall. All rights reserved. The software is
29 * redistributable under the licence given in the file "Licence"
30 * distributed in the NASM archive.
31 */
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include "nasm.h"
37 #include "nasmlib.h"
38
39 /*
40 * A local label is one that begins with exactly one period. Things
41 * that begin with _two_ periods are NASM-specific things.
42 */
43 #define islocal(l) ((l)[0] == '.' && (l)[1] != '.')
44
45 #define LABEL_BLOCK 320 /* no. of labels/block */
46 #define LBLK_SIZE (LABEL_BLOCK*sizeof(union label))
47 #define LABEL_HASHES 32 /* no. of hash table entries */
48
49 #define END_LIST -3 /* don't clash with NO_SEG! */
50 #define END_BLOCK -2
51 #define BOGUS_VALUE -4
52
53 #define PERMTS_SIZE 4096 /* size of text blocks */
54
55 /* values for label.defn.is_global */
56 #define DEFINED_BIT 1
57 #define GLOBAL_BIT 2
58 #define EXTERN_BIT 4
59
60 #define NOT_DEFINED_YET 0
61 #define TYPE_MASK 3
62 #define LOCAL_SYMBOL (DEFINED_BIT)
63 #define GLOBAL_PLACEHOLDER (GLOBAL_BIT)
64 #define GLOBAL_SYMBOL (DEFINED_BIT|GLOBAL_BIT)
65
66 union label { /* actual label structures */
67 struct {
68 long segment, offset;
69 char *label, *special;
70 int is_global;
71 } defn;
72 struct {
73 long movingon, dummy;
74 union label *next;
75 } admin;
76 };
77
78 struct permts { /* permanent text storage */
79 struct permts *next; /* for the linked list */
80 int size, usage; /* size and used space in ... */
81 char data[PERMTS_SIZE]; /* ... the data block itself */
82 };
83
84 static union label *ltab[LABEL_HASHES];/* using a hash table */
85 static union label *lfree[LABEL_HASHES];/* pointer into the above */
86 static struct permts *perm_head; /* start of perm. text storage */
87 static struct permts *perm_tail; /* end of perm. text storage */
88
89 static void init_block (union label *blk);
90 static char *perm_copy (char *string1, char *string2);
91
92 static char *prevlabel;
93
94 static int initialised = FALSE;
95
96 /*
97 * Internal routine: finds the `union label' corresponding to the
98 * given label name. Creates a new one, if it isn't found, and if
99 * `create' is TRUE.
100 */
101 static union label *find_label (char *label, int create) {
102 int hash = 0;
103 char *p, *prev;
104 int prevlen;
105 union label *lptr;
106
107 if (islocal(label))
108 prev = prevlabel;
109 else
110 prev = "";
111 prevlen = strlen(prev);
112 p = prev;
113 while (*p) hash += *p++;
114 p = label;
115 while (*p) hash += *p++;
116 hash %= LABEL_HASHES;
117 lptr = ltab[hash];
118 while (lptr->admin.movingon != END_LIST) {
119 if (lptr->admin.movingon == END_BLOCK) {
120 lptr = lptr->admin.next;
121 if (!lptr)
122 break;
123 }
124 if (!strncmp(lptr->defn.label, prev, prevlen) &&
125 !strcmp(lptr->defn.label+prevlen, label))
126 return lptr;
127 lptr++;
128 }
129 if (create) {
130 if (lfree[hash]->admin.movingon == END_BLOCK) {
131 /*
132 * must allocate a new block
133 */
134 lfree[hash]->admin.next = (union label *) nasm_malloc (LBLK_SIZE);
135 lfree[hash] = lfree[hash]->admin.next;
136 init_block(lfree[hash]);
137 }
138
139 lfree[hash]->admin.movingon = BOGUS_VALUE;
140 lfree[hash]->defn.label = perm_copy (prev, label);
141 lfree[hash]->defn.special = NULL;
142 lfree[hash]->defn.is_global = NOT_DEFINED_YET;
143 return lfree[hash]++;
144 } else
145 return NULL;
146 }
147
148 int lookup_label (char *label, long *segment, long *offset) {
149 union label *lptr;
150
151 if (!initialised)
152 return 0;
153
154 lptr = find_label (label, 0);
155 if (lptr && (lptr->defn.is_global & DEFINED_BIT)) {
156 *segment = lptr->defn.segment;
157 *offset = lptr->defn.offset;
158 return 1;
159 } else
160 return 0;
161 }
162
163 int is_extern (char *label) {
164 union label *lptr;
165
166 if (!initialised)
167 return 0;
168
169 lptr = find_label (label, 0);
170 if (lptr && (lptr->defn.is_global & EXTERN_BIT))
171 return 1;
172 else
173 return 0;
174 }
175
176 void define_label_stub (char *label, efunc error) {
177 union label *lptr;
178
179 if (!islocal(label)) {
180 lptr = find_label (label, 1);
181 if (!lptr)
182 error (ERR_PANIC, "can't find label `%s' on pass two", label);
183 if (*label != '.')
184 prevlabel = lptr->defn.label;
185 }
186 }
187
188 void define_label (char *label, long segment, long offset, char *special,
189 int is_norm, int isextrn, struct ofmt *ofmt, efunc error) {
190 union label *lptr;
191
192 lptr = find_label (label, 1);
193 if (lptr->defn.is_global & DEFINED_BIT) {
194 error(ERR_NONFATAL, "symbol `%s' redefined", label);
195 return;
196 }
197 lptr->defn.is_global |= DEFINED_BIT;
198 if (isextrn)
199 lptr->defn.is_global |= EXTERN_BIT;
200
201 if (label[0] != '.' && is_norm) /* not local, but not special either */
202 prevlabel = lptr->defn.label;
203 else if (label[0] == '.' && label[1] != '.' && !*prevlabel)
204 error(ERR_NONFATAL, "attempt to define a local label before any"
205 " non-local labels");
206
207 lptr->defn.segment = segment;
208 lptr->defn.offset = offset;
209
210 ofmt->symdef (lptr->defn.label, segment, offset,
211 !!(lptr->defn.is_global & GLOBAL_BIT),
212 special ? special : lptr->defn.special);
213 }
214
215 void define_common (char *label, long segment, long size, char *special,
216 struct ofmt *ofmt, efunc error) {
217 union label *lptr;
218
219 lptr = find_label (label, 1);
220 if (lptr->defn.is_global & DEFINED_BIT) {
221 error(ERR_NONFATAL, "symbol `%s' redefined", label);
222 return;
223 }
224 lptr->defn.is_global |= DEFINED_BIT;
225
226 if (label[0] != '.') /* not local, but not special either */
227 prevlabel = lptr->defn.label;
228 else
229 error(ERR_NONFATAL, "attempt to define a local label as a "
230 "common variable");
231
232 lptr->defn.segment = segment;
233 lptr->defn.offset = 0;
234
235 ofmt->symdef (lptr->defn.label, segment, size, 2,
236 special ? special : lptr->defn.special);
237 }
238
239 void declare_as_global (char *label, char *special, efunc error) {
240 union label *lptr;
241
242 if (islocal(label)) {
243 error(ERR_NONFATAL, "attempt to declare local symbol `%s' as"
244 " global", label);
245 return;
246 }
247 lptr = find_label (label, 1);
248 switch (lptr->defn.is_global & TYPE_MASK) {
249 case NOT_DEFINED_YET:
250 lptr->defn.is_global = GLOBAL_PLACEHOLDER;
251 lptr->defn.special = special ? perm_copy(special, "") : NULL;
252 break;
253 case GLOBAL_PLACEHOLDER: /* already done: silently ignore */
254 case GLOBAL_SYMBOL:
255 break;
256 case LOCAL_SYMBOL:
257 if (!lptr->defn.is_global & EXTERN_BIT)
258 error(ERR_NONFATAL, "symbol `%s': GLOBAL directive must"
259 " appear before symbol definition", label);
260 break;
261 }
262 }
263
264 int init_labels (void) {
265 int i;
266
267 for (i=0; i<LABEL_HASHES; i++) {
268 ltab[i] = (union label *) nasm_malloc (LBLK_SIZE);
269 if (!ltab[i])
270 return -1; /* can't initialise, panic */
271 init_block (ltab[i]);
272 lfree[i] = ltab[i];
273 }
274
275 perm_head = perm_tail = (struct permts *) nasm_malloc (sizeof(struct permts));
276 if (!perm_head)
277 return -1;
278
279 perm_head->next = NULL;
280 perm_head->size = PERMTS_SIZE;
281 perm_head->usage = 0;
282
283 prevlabel = "";
284
285 initialised = TRUE;
286
287 return 0;
288 }
289
290 void cleanup_labels (void) {
291 int i;
292
293 initialised = FALSE;
294
295 for (i=0; i<LABEL_HASHES; i++) {
296 union label *lptr, *lhold;
297
298 lptr = lhold = ltab[i];
299
300 while (lptr) {
301 while (lptr->admin.movingon != END_BLOCK) lptr++;
302 lptr = lptr->admin.next;
303 nasm_free (lhold);
304 lhold = lptr;
305 }
306 }
307
308 while (perm_head) {
309 perm_tail = perm_head;
310 perm_head = perm_head->next;
311 nasm_free (perm_tail);
312 }
313 }
314
315 static void init_block (union label *blk) {
316 int j;
317
318 for (j=0; j<LABEL_BLOCK-1; j++)
319 blk[j].admin.movingon = END_LIST;
320 blk[LABEL_BLOCK-1].admin.movingon = END_BLOCK;
321 blk[LABEL_BLOCK-1].admin.next = NULL;
322 }
323
324 static char *perm_copy (char *string1, char *string2) {
325 char *p, *q;
326 int len = strlen(string1)+strlen(string2)+1;
327
328 if (perm_tail->size - perm_tail->usage < len) {
329 perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts));
330 perm_tail = perm_tail->next;
331 perm_tail->next = NULL;
332 perm_tail->size = PERMTS_SIZE;
333 perm_tail->usage = 0;
334 }
335 p = q = perm_tail->data + perm_tail->usage;
336 while ( (*q = *string1++) ) q++;
337 while ( (*q++ = *string2++) );
338 perm_tail->usage = q - perm_tail->data;
339
340 return p;
341 }