NASM 0.95
[nasm/avx512.git] / labels.c
blob7793a0a9663168b71a902c6e6a898c9f040eb49e
1 /* labels.c label handling for the Netwide Assembler
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 */
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include "nasm.h"
13 #include "nasmlib.h"
16 * A local label is one that begins with exactly one period. Things
17 * that begin with _two_ periods are NASM-specific things.
19 #define islocal(l) ((l)[0] == '.' && (l)[1] != '.')
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 */
25 #define END_LIST -3 /* don't clash with NO_SEG! */
26 #define END_BLOCK -2
27 #define BOGUS_VALUE -4
29 #define PERMTS_SIZE 4096 /* size of text blocks */
31 /* values for label.defn.is_global */
32 #define NOT_DEFINED_YET 0
33 #define LOCAL_SYMBOL 1
34 #define GLOBAL_SYMBOL 2
35 #define GLOBAL_PLACEHOLDER 3
37 union label { /* actual label structures */
38 struct {
39 long segment, offset;
40 char *label;
41 int is_global;
42 } defn;
43 struct {
44 long movingon, dummy;
45 union label *next;
46 } admin;
49 struct permts { /* permanent text storage */
50 struct permts *next; /* for the linked list */
51 int size, usage; /* size and used space in ... */
52 char data[PERMTS_SIZE]; /* ... the data block itself */
55 static union label *ltab[LABEL_HASHES];/* using a hash table */
56 static union label *lfree[LABEL_HASHES];/* pointer into the above */
57 static struct permts *perm_head; /* start of perm. text storage */
58 static struct permts *perm_tail; /* end of perm. text storage */
60 static void init_block (union label *blk);
61 static char *perm_copy (char *string1, char *string2);
63 static char *prevlabel;
66 * Internal routine: finds the `union label' corresponding to the
67 * given label name. Creates a new one, if it isn't found, and if
68 * `create' is TRUE.
70 static union label *find_label (char *label, int create) {
71 int hash = 0;
72 char *p, *prev;
73 int prevlen;
74 union label *lptr;
76 if (islocal(label))
77 prev = prevlabel;
78 else
79 prev = "";
80 prevlen = strlen(prev);
81 p = prev;
82 while (*p) hash += *p++;
83 p = label;
84 while (*p) hash += *p++;
85 hash %= LABEL_HASHES;
86 lptr = ltab[hash];
87 while (lptr->admin.movingon != END_LIST) {
88 if (lptr->admin.movingon == END_BLOCK) {
89 lptr = lptr->admin.next;
90 if (!lptr)
91 break;
93 if (!strncmp(lptr->defn.label, prev, prevlen) &&
94 !strcmp(lptr->defn.label+prevlen, label))
95 return lptr;
96 lptr++;
98 if (create) {
99 if (lfree[hash]->admin.movingon == END_BLOCK) {
101 * must allocate a new block
103 lfree[hash]->admin.next = (union label *) nasm_malloc (LBLK_SIZE);
104 lfree[hash] = lfree[hash]->admin.next;
105 init_block(lfree[hash]);
108 lfree[hash]->admin.movingon = BOGUS_VALUE;
109 lfree[hash]->defn.label = perm_copy (prev, label);
110 lfree[hash]->defn.is_global = NOT_DEFINED_YET;
111 return lfree[hash]++;
112 } else
113 return NULL;
116 int lookup_label (char *label, long *segment, long *offset) {
117 union label *lptr;
119 lptr = find_label (label, 0);
120 if (lptr && (lptr->defn.is_global == LOCAL_SYMBOL ||
121 lptr->defn.is_global == GLOBAL_SYMBOL)) {
122 *segment = lptr->defn.segment;
123 *offset = lptr->defn.offset;
124 return 1;
125 } else
126 return 0;
129 void define_label_stub (char *label, efunc error) {
130 union label *lptr;
132 if (!islocal(label)) {
133 lptr = find_label (label, 1);
134 if (!lptr)
135 error (ERR_PANIC, "can't find label `%s' on pass two", label);
136 if (*label != '.')
137 prevlabel = lptr->defn.label;
141 void define_label (char *label, long segment, long offset,
142 struct ofmt *ofmt, efunc error) {
143 union label *lptr;
145 lptr = find_label (label, 1);
146 switch (lptr->defn.is_global) {
147 case NOT_DEFINED_YET:
148 lptr->defn.is_global = LOCAL_SYMBOL;
149 break;
150 case GLOBAL_PLACEHOLDER:
151 lptr->defn.is_global = GLOBAL_SYMBOL;
152 break;
153 default:
154 error(ERR_NONFATAL, "symbol `%s' redefined", label);
155 return;
158 if (label[0] != '.') /* not local, but not special either */
159 prevlabel = lptr->defn.label;
160 else if (label[1] != '.' && !*prevlabel)
161 error(ERR_NONFATAL, "attempt to define a local label before any"
162 " non-local labels");
164 lptr->defn.segment = segment;
165 lptr->defn.offset = offset;
167 ofmt->symdef (lptr->defn.label, segment, offset,
168 lptr->defn.is_global == GLOBAL_SYMBOL);
171 void define_common (char *label, long segment, long size,
172 struct ofmt *ofmt, efunc error) {
173 union label *lptr;
175 lptr = find_label (label, 1);
176 switch (lptr->defn.is_global) {
177 case NOT_DEFINED_YET:
178 lptr->defn.is_global = LOCAL_SYMBOL;
179 break;
180 case GLOBAL_PLACEHOLDER:
181 lptr->defn.is_global = GLOBAL_SYMBOL;
182 break;
183 default:
184 error(ERR_NONFATAL, "symbol `%s' redefined", label);
185 return;
188 if (label[0] != '.') /* not local, but not special either */
189 prevlabel = lptr->defn.label;
190 else
191 error(ERR_NONFATAL, "attempt to define a local label as a "
192 "common variable");
194 lptr->defn.segment = segment;
195 lptr->defn.offset = 0;
197 ofmt->symdef (lptr->defn.label, segment, size, 2);
200 void declare_as_global (char *label, efunc error) {
201 union label *lptr;
203 if (islocal(label)) {
204 error(ERR_NONFATAL, "attempt to declare local symbol `%s' as"
205 " global", label);
206 return;
208 lptr = find_label (label, 1);
209 switch (lptr->defn.is_global) {
210 case NOT_DEFINED_YET:
211 lptr->defn.is_global = GLOBAL_PLACEHOLDER;
212 break;
213 case GLOBAL_PLACEHOLDER: /* already done: silently ignore */
214 case GLOBAL_SYMBOL:
215 break;
216 case LOCAL_SYMBOL:
217 error(ERR_NONFATAL, "symbol `%s': [GLOBAL] directive must"
218 " appear before symbol definition", label);
219 break;
223 int init_labels (void) {
224 int i;
226 for (i=0; i<LABEL_HASHES; i++) {
227 ltab[i] = (union label *) nasm_malloc (LBLK_SIZE);
228 if (!ltab[i])
229 return -1; /* can't initialise, panic */
230 init_block (ltab[i]);
231 lfree[i] = ltab[i];
234 perm_head = perm_tail = (struct permts *) nasm_malloc (sizeof(struct permts));
235 if (!perm_head)
236 return -1;
238 perm_head->next = NULL;
239 perm_head->size = PERMTS_SIZE;
240 perm_head->usage = 0;
242 prevlabel = "";
244 return 0;
247 void cleanup_labels (void) {
248 int i;
250 for (i=0; i<LABEL_HASHES; i++) {
251 union label *lptr, *lhold;
253 lptr = lhold = ltab[i];
255 while (lptr) {
256 while (lptr->admin.movingon != END_BLOCK) lptr++;
257 lptr = lptr->admin.next;
258 nasm_free (lhold);
259 lhold = lptr;
263 while (perm_head) {
264 perm_tail = perm_head;
265 perm_head = perm_head->next;
266 nasm_free (perm_tail);
270 static void init_block (union label *blk) {
271 int j;
273 for (j=0; j<LABEL_BLOCK-1; j++)
274 blk[j].admin.movingon = END_LIST;
275 blk[LABEL_BLOCK-1].admin.movingon = END_BLOCK;
276 blk[LABEL_BLOCK-1].admin.next = NULL;
279 static char *perm_copy (char *string1, char *string2) {
280 char *p, *q;
281 int len = strlen(string1)+strlen(string2)+1;
283 if (perm_tail->size - perm_tail->usage < len) {
284 perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts));
285 perm_tail = perm_tail->next;
286 perm_tail->next = NULL;
287 perm_tail->size = PERMTS_SIZE;
288 perm_tail->usage = 0;
290 p = q = perm_tail->data + perm_tail->usage;
291 while ( (*q = *string1++) ) q++;
292 while ( (*q++ = *string2++) );
293 perm_tail->usage = q - perm_tail->data;
295 return p;