Merge branch 'new-preproc'
[platform/upstream/nasm.git] / labels.c
1 /* ----------------------------------------------------------------------- *
2  *   
3  *   Copyright 1996-2009 The NASM Authors - All Rights Reserved
4  *   See the file AUTHORS included with the NASM distribution for
5  *   the specific copyright holders.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following
9  *   conditions are met:
10  *
11  *   * Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer.
13  *   * Redistributions in binary form must reproduce the above
14  *     copyright notice, this list of conditions and the following
15  *     disclaimer in the documentation and/or other materials provided
16  *     with the distribution.
17  *     
18  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * ----------------------------------------------------------------------- */
33
34 /*
35  * labels.c  label handling for the Netwide Assembler
36  */
37
38 #include "compiler.h"
39
40 #include <stdio.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <inttypes.h>
44
45 #include "nasm.h"
46 #include "nasmlib.h"
47 #include "hashtbl.h"
48
49 /*
50  * A local label is one that begins with exactly one period. Things
51  * that begin with _two_ periods are NASM-specific things.
52  *
53  * If TASM compatibility is enabled, a local label can also begin with
54  * @@, so @@local is a TASM compatible local label. Note that we only
55  * check for the first @ symbol, although TASM requires both.
56  */
57 #define islocal(l)                                              \
58         (tasm_compatible_mode ?                                 \
59         (((l)[0] == '.' || (l)[0] == '@') && (l)[1] != '.') :   \
60         ((l)[0] == '.' && (l)[1] != '.'))
61 #define islocalchar(c)                                          \
62         (tasm_compatible_mode ?                                  \
63         ((c) == '.' || (c) == '@') :                            \
64         ((c) == '.'))
65
66 #define LABEL_BLOCK  128        /* no. of labels/block */
67 #define LBLK_SIZE    (LABEL_BLOCK*sizeof(union label))
68
69 #define END_LIST -3             /* don't clash with NO_SEG! */
70 #define END_BLOCK -2
71 #define BOGUS_VALUE -4
72
73 #define PERMTS_SIZE  16384      /* size of text blocks */
74 #if (PERMTS_SIZE < IDLEN_MAX)
75 #error "IPERMTS_SIZE must be greater than or equal to IDLEN_MAX"
76 #endif
77
78 /* values for label.defn.is_global */
79 #define DEFINED_BIT     1
80 #define GLOBAL_BIT      2
81 #define EXTERN_BIT      4
82 #define COMMON_BIT      8
83
84 #define NOT_DEFINED_YET 0
85 #define TYPE_MASK 3
86 #define LOCAL_SYMBOL (DEFINED_BIT)
87 #define GLOBAL_PLACEHOLDER (GLOBAL_BIT)
88 #define GLOBAL_SYMBOL (DEFINED_BIT|GLOBAL_BIT)
89
90 union label {                   /* actual label structures */
91     struct {
92         int32_t segment;
93         int64_t offset;
94         char *label, *special;
95         int is_global, is_norm;
96     } defn;
97     struct {
98         int32_t movingon;
99         int64_t dummy;
100         union label *next;
101     } admin;
102 };
103
104 struct permts {                 /* permanent text storage */
105     struct permts *next;        /* for the linked list */
106     int size, usage;            /* size and used space in ... */
107     char data[PERMTS_SIZE];     /* ... the data block itself */
108 };
109
110 extern int64_t global_offset_changed;       /* defined in nasm.c */
111
112 static struct hash_table ltab;          /* labels hash table */
113 static union label *ldata;              /* all label data blocks */
114 static union label *lfree;              /* labels free block */
115 static struct permts *perm_head;        /* start of perm. text storage */
116 static struct permts *perm_tail;        /* end of perm. text storage */
117
118 static void init_block(union label *blk);
119 static char *perm_copy(const char *string);
120
121 static char *prevlabel;
122
123 static bool initialized = false;
124
125 char lprefix[PREFIX_MAX] = { 0 };
126 char lpostfix[PREFIX_MAX] = { 0 };
127
128 /*
129  * Internal routine: finds the `union label' corresponding to the
130  * given label name. Creates a new one, if it isn't found, and if
131  * `create' is true.
132  */
133 static union label *find_label(char *label, int create)
134 {
135     char *prev;
136     int prevlen, len;
137     union label *lptr, **lpp;
138     char label_str[IDLEN_MAX];
139     struct hash_insert ip;
140
141     if (islocal(label)) {
142         prev = prevlabel;
143         prevlen = strlen(prev);
144         len = strlen(label);
145         if (prevlen+len >= IDLEN_MAX)
146             return NULL;        /* Error... */
147         memcpy(label_str, prev, prevlen);
148         memcpy(label_str+prevlen, label, len+1);
149         label = label_str;
150     } else {
151         prev = "";
152         prevlen = 0;
153     }
154
155     lpp = (union label **) hash_find(&ltab, label, &ip);
156     lptr = lpp ? *lpp : NULL;
157
158     if (lptr || !create)
159         return lptr;
160
161     /* Create a new label... */
162     if (lfree->admin.movingon == END_BLOCK) {
163         /*
164          * must allocate a new block
165          */
166         lfree->admin.next =
167             (union label *)nasm_malloc(LBLK_SIZE);
168         lfree = lfree->admin.next;
169         init_block(lfree);
170     }
171
172     lfree->admin.movingon = BOGUS_VALUE;
173     lfree->defn.label = perm_copy(label);
174     lfree->defn.special = NULL;
175     lfree->defn.is_global = NOT_DEFINED_YET;
176
177     hash_add(&ip, lfree->defn.label, lfree);
178     return lfree++;
179 }
180
181 bool lookup_label(char *label, int32_t *segment, int64_t *offset)
182 {
183     union label *lptr;
184
185     if (!initialized)
186         return false;
187
188     lptr = find_label(label, 0);
189     if (lptr && (lptr->defn.is_global & DEFINED_BIT)) {
190         *segment = lptr->defn.segment;
191         *offset = lptr->defn.offset;
192         return true;
193     } else
194         return false;
195 }
196
197 bool is_extern(char *label)
198 {
199     union label *lptr;
200
201     if (!initialized)
202         return false;
203
204     lptr = find_label(label, 0);
205     return (lptr && (lptr->defn.is_global & EXTERN_BIT));
206 }
207
208 void redefine_label(char *label, int32_t segment, int64_t offset, char *special,
209                     bool is_norm, bool isextrn)
210 {
211     union label *lptr;
212     int exi;
213
214     /* This routine possibly ought to check for phase errors.  Most assemblers
215      * check for phase errors at this point.  I don't know whether phase errors
216      * are even possible, nor whether they are checked somewhere else
217      */
218
219     (void)special;              /* Don't warn that this parameter is unused */
220     (void)is_norm;              /* Don't warn that this parameter is unused */
221     (void)isextrn;              /* Don't warn that this parameter is unused */
222
223 #ifdef DEBUG
224 #if DEBUG<3
225     if (!strncmp(label, "debugdump", 9))
226 #endif
227         nasm_error(ERR_DEBUG, "redefine_label (%s, %ld, %08lx, %s, %d, %d)",
228               label, segment, offset, special, is_norm, isextrn);
229 #endif
230
231     lptr = find_label(label, 1);
232     if (!lptr)
233         nasm_error(ERR_PANIC, "can't find label `%s' on pass two", label);
234
235     if (!islocal(label)) {
236         if (!islocalchar(*label) && lptr->defn.is_norm)
237             prevlabel = lptr->defn.label;
238     }
239
240     if (lptr->defn.offset != offset)
241         global_offset_changed++;
242
243     lptr->defn.offset = offset;
244     lptr->defn.segment = segment;
245
246     if (pass0 == 1) {
247         exi = !!(lptr->defn.is_global & GLOBAL_BIT);
248         if (exi) {
249             char *xsymbol;
250             int slen;
251             slen = strlen(lprefix);
252             slen += strlen(lptr->defn.label);
253             slen += strlen(lpostfix);
254             slen++;             /* room for that null char */
255             xsymbol = nasm_malloc(slen);
256             snprintf(xsymbol, slen, "%s%s%s", lprefix, lptr->defn.label,
257                      lpostfix);
258
259             ofmt->symdef(xsymbol, segment, offset, exi,
260                          special ? special : lptr->defn.special);
261             ofmt->current_dfmt->debug_deflabel(xsymbol, segment, offset,
262                                                exi,
263                                                special ? special : lptr->
264                                                defn.special);
265 /**     nasm_free(xsymbol);  ! outobj.c stores the pointer; ouch!!! **/
266         } else {
267             if ((lptr->defn.is_global & (GLOBAL_BIT | EXTERN_BIT)) !=
268                 EXTERN_BIT) {
269                 ofmt->symdef(lptr->defn.label, segment, offset, exi,
270                              special ? special : lptr->defn.special);
271                 ofmt->current_dfmt->debug_deflabel(label, segment, offset,
272                                                    exi,
273                                                    special ? special :
274                                                    lptr->defn.special);
275             }
276         }
277     }
278     /* if (pass0 == 1) */
279 }
280
281 void define_label(char *label, int32_t segment, int64_t offset, char *special,
282                   bool is_norm, bool isextrn)
283 {
284     union label *lptr;
285     int exi;
286
287 #ifdef DEBUG
288 #if DEBUG<3
289     if (!strncmp(label, "debugdump", 9))
290 #endif
291         nasm_error(ERR_DEBUG, "define_label (%s, %ld, %08lx, %s, %d, %d)",
292               label, segment, offset, special, is_norm, isextrn);
293 #endif
294     lptr = find_label(label, 1);
295     if (lptr->defn.is_global & DEFINED_BIT) {
296         nasm_error(ERR_NONFATAL, "symbol `%s' redefined", label);
297         return;
298     }
299     lptr->defn.is_global |= DEFINED_BIT;
300     if (isextrn)
301         lptr->defn.is_global |= EXTERN_BIT;
302
303     if (!islocalchar(label[0]) && is_norm) {
304         /* not local, but not special either */
305         prevlabel = lptr->defn.label;
306     } else if (islocal(label) && !*prevlabel) {
307         nasm_error(ERR_NONFATAL, "attempt to define a local label before any"
308               " non-local labels");
309     }
310
311     lptr->defn.segment = segment;
312     lptr->defn.offset = offset;
313     lptr->defn.is_norm = (!islocalchar(label[0]) && is_norm);
314
315     if (pass0 == 1 || (!is_norm && !isextrn && (segment > 0) && (segment & 1))) {
316         exi = !!(lptr->defn.is_global & GLOBAL_BIT);
317         if (exi) {
318             char *xsymbol;
319             int slen;
320             slen = strlen(lprefix);
321             slen += strlen(lptr->defn.label);
322             slen += strlen(lpostfix);
323             slen++;             /* room for that null char */
324             xsymbol = nasm_malloc(slen);
325             snprintf(xsymbol, slen, "%s%s%s", lprefix, lptr->defn.label,
326                      lpostfix);
327
328             ofmt->symdef(xsymbol, segment, offset, exi,
329                          special ? special : lptr->defn.special);
330             ofmt->current_dfmt->debug_deflabel(xsymbol, segment, offset,
331                                                exi,
332                                                special ? special : lptr->
333                                                defn.special);
334 /**     nasm_free(xsymbol);  ! outobj.c stores the pointer; ouch!!! **/
335         } else {
336             if ((lptr->defn.is_global & (GLOBAL_BIT | EXTERN_BIT)) !=
337                 EXTERN_BIT) {
338                 ofmt->symdef(lptr->defn.label, segment, offset, exi,
339                              special ? special : lptr->defn.special);
340                 ofmt->current_dfmt->debug_deflabel(label, segment, offset,
341                                                    exi,
342                                                    special ? special :
343                                                    lptr->defn.special);
344             }
345         }
346     }                           /* if (pass0 == 1) */
347 }
348
349 void define_common(char *label, int32_t segment, int32_t size, char *special)
350 {
351     union label *lptr;
352
353     lptr = find_label(label, 1);
354     if ((lptr->defn.is_global & DEFINED_BIT) &&
355         (passn == 1 || !(lptr->defn.is_global & COMMON_BIT))) {
356             nasm_error(ERR_NONFATAL, "symbol `%s' redefined", label);
357             return;
358     }
359     lptr->defn.is_global |= DEFINED_BIT|COMMON_BIT;
360
361     if (!islocalchar(label[0])) {
362         prevlabel = lptr->defn.label;
363     } else {
364         nasm_error(ERR_NONFATAL, "attempt to define a local label as a "
365               "common variable");
366         return;
367     }
368
369     lptr->defn.segment = segment;
370     lptr->defn.offset = 0;
371
372     if (pass0 == 0)
373         return;
374
375     ofmt->symdef(lptr->defn.label, segment, size, 2,
376                  special ? special : lptr->defn.special);
377     ofmt->current_dfmt->debug_deflabel(lptr->defn.label, segment, size, 2,
378                                        special ? special : lptr->defn.
379                                        special);
380 }
381
382 void declare_as_global(char *label, char *special)
383 {
384     union label *lptr;
385
386     if (islocal(label)) {
387         nasm_error(ERR_NONFATAL, "attempt to declare local symbol `%s' as"
388               " global", label);
389         return;
390     }
391     lptr = find_label(label, 1);
392     switch (lptr->defn.is_global & TYPE_MASK) {
393     case NOT_DEFINED_YET:
394         lptr->defn.is_global = GLOBAL_PLACEHOLDER;
395         lptr->defn.special = special ? perm_copy(special) : NULL;
396         break;
397     case GLOBAL_PLACEHOLDER:   /* already done: silently ignore */
398     case GLOBAL_SYMBOL:
399         break;
400     case LOCAL_SYMBOL:
401         if (!(lptr->defn.is_global & EXTERN_BIT)) {
402             nasm_error(ERR_WARNING, "symbol `%s': GLOBAL directive "
403                   "after symbol definition is an experimental feature", label);
404             lptr->defn.is_global = GLOBAL_SYMBOL;
405         }
406         break;
407     }
408 }
409
410 int init_labels(void)
411 {
412     hash_init(&ltab, HASH_LARGE);
413
414     ldata = lfree = (union label *)nasm_malloc(LBLK_SIZE);
415     init_block(lfree);
416
417     perm_head =
418         perm_tail = (struct permts *)nasm_malloc(sizeof(struct permts));
419
420     perm_head->next = NULL;
421     perm_head->size = PERMTS_SIZE;
422     perm_head->usage = 0;
423
424     prevlabel = "";
425
426     initialized = true;
427
428     return 0;
429 }
430
431 void cleanup_labels(void)
432 {
433     union label *lptr, *lhold;
434
435     initialized = false;
436
437     hash_free(&ltab);
438
439     lptr = lhold = ldata;
440     while (lptr) {
441         lptr = &lptr[LABEL_BLOCK-1];
442         lptr = lptr->admin.next;
443         nasm_free(lhold);
444         lhold = lptr;
445     }
446
447     while (perm_head) {
448         perm_tail = perm_head;
449         perm_head = perm_head->next;
450         nasm_free(perm_tail);
451     }
452 }
453
454 static void init_block(union label *blk)
455 {
456     int j;
457
458     for (j = 0; j < LABEL_BLOCK - 1; j++)
459         blk[j].admin.movingon = END_LIST;
460     blk[LABEL_BLOCK - 1].admin.movingon = END_BLOCK;
461     blk[LABEL_BLOCK - 1].admin.next = NULL;
462 }
463
464 static char *perm_copy(const char *string)
465 {
466     char *p;
467     int len = strlen(string)+1;
468
469     nasm_assert(len <= PERMTS_SIZE);
470
471     if (perm_tail->size - perm_tail->usage < len) {
472         perm_tail->next =
473             (struct permts *)nasm_malloc(sizeof(struct permts));
474         perm_tail = perm_tail->next;
475         perm_tail->next = NULL;
476         perm_tail->size = PERMTS_SIZE;
477         perm_tail->usage = 0;
478     }
479     p = perm_tail->data + perm_tail->usage;
480     memcpy(p, string, len);
481     perm_tail->usage += len;
482
483     return p;
484 }
485
486 char *local_scope(char *label)
487 {
488    return islocal(label) ? prevlabel : "";
489 }
490
491 /*
492  * Notes regarding bug involving redefinition of external segments.
493  *
494  * Up to and including v0.97, the following code didn't work. From 0.97
495  * developers release 2 onwards, it will generate an error.
496  *
497  * EXTERN extlabel
498  * newlabel EQU extlabel + 1
499  *
500  * The results of allowing this code through are that two import records
501  * are generated, one for 'extlabel' and one for 'newlabel'.
502  *
503  * The reason for this is an inadequacy in the defined interface between
504  * the label manager and the output formats. The problem lies in how the
505  * output format driver tells that a label is an external label for which
506  * a label import record must be produced. Most (all except bin?) produce
507  * the record if the segment number of the label is not one of the internal
508  * segments that the output driver is producing.
509  *
510  * A simple fix to this would be to make the output formats keep track of
511  * which symbols they've produced import records for, and make them not
512  * produce import records for segments that are already defined.
513  *
514  * The best way, which is slightly harder but reduces duplication of code
515  * and should therefore make the entire system smaller and more stable is
516  * to change the interface between assembler, define_label(), and
517  * the output module. The changes that are needed are:
518  *
519  * The semantics of the 'isextern' flag passed to define_label() need
520  * examining. This information may or may not tell us what we need to
521  * know (ie should we be generating an import record at this point for this
522  * label). If these aren't the semantics, the semantics should be changed
523  * to this.
524  *
525  * The output module interface needs changing, so that the `isextern' flag
526  * is passed to the module, so that it can be easily tested for.
527  */