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