]>
Commit | Line | Data |
---|---|---|
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 | ||
65 | union 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 | ||
77 | struct 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 | ||
83 | static union label *ltab[LABEL_HASHES];/* using a hash table */ | |
84 | static union label *lfree[LABEL_HASHES];/* pointer into the above */ | |
85 | static struct permts *perm_head; /* start of perm. text storage */ | |
86 | static struct permts *perm_tail; /* end of perm. text storage */ | |
87 | ||
88 | static void init_block (union label *blk); | |
89 | static char *perm_copy (char *string1, char *string2); | |
90 | ||
91 | static char *prevlabel; | |
92 | ||
93 | static 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 | */ | |
100 | static 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 | ||
147 | int 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 | ||
162 | int 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 | ||
175 | void 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 | ||
187 | void 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 | ||
214 | void 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 | ||
238 | void 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 | ||
263 | int 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 | ||
289 | void 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 | ||
314 | static 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 | ||
323 | static 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 | } |