MPX: Adapt GAS's mib syntax with an index reg only
[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             nasm_error(ERR_NONFATAL, "identifier length exceed %i bytes",
147                        IDLEN_MAX);
148             return NULL;
149         }
150         memcpy(label_str, prev, prevlen);
151         memcpy(label_str+prevlen, label, len+1);
152         label = label_str;
153     } else {
154         prev = "";
155         prevlen = 0;
156     }
157
158     lpp = (union label **) hash_find(&ltab, label, &ip);
159     lptr = lpp ? *lpp : NULL;
160
161     if (lptr || !create)
162         return lptr;
163
164     /* Create a new label... */
165     if (lfree->admin.movingon == END_BLOCK) {
166         /*
167          * must allocate a new block
168          */
169         lfree->admin.next = (union label *)nasm_malloc(LBLK_SIZE);
170         lfree = lfree->admin.next;
171         init_block(lfree);
172     }
173
174     lfree->admin.movingon = BOGUS_VALUE;
175     lfree->defn.label = perm_copy(label);
176     lfree->defn.special = NULL;
177     lfree->defn.is_global = NOT_DEFINED_YET;
178
179     hash_add(&ip, lfree->defn.label, lfree);
180     return lfree++;
181 }
182
183 bool lookup_label(char *label, int32_t *segment, int64_t *offset)
184 {
185     union label *lptr;
186
187     if (!initialized)
188         return false;
189
190     lptr = find_label(label, 0);
191     if (lptr && (lptr->defn.is_global & DEFINED_BIT)) {
192         *segment = lptr->defn.segment;
193         *offset = lptr->defn.offset;
194         return true;
195     }
196
197     return false;
198 }
199
200 bool is_extern(char *label)
201 {
202     union label *lptr;
203
204     if (!initialized)
205         return false;
206
207     lptr = find_label(label, 0);
208     return (lptr && (lptr->defn.is_global & EXTERN_BIT));
209 }
210
211 void redefine_label(char *label, int32_t segment, int64_t offset, char *special,
212                     bool is_norm, bool isextrn)
213 {
214     union label *lptr;
215     int exi;
216
217     /* This routine possibly ought to check for phase errors.  Most assemblers
218      * check for phase errors at this point.  I don't know whether phase errors
219      * are even possible, nor whether they are checked somewhere else
220      */
221
222     (void)special;              /* Don't warn that this parameter is unused */
223     (void)is_norm;              /* Don't warn that this parameter is unused */
224     (void)isextrn;              /* Don't warn that this parameter is unused */
225
226 #ifdef DEBUG
227 #if DEBUG < 3
228     if (!strncmp(label, "debugdump", 9))
229 #endif
230         nasm_error(ERR_DEBUG, "redefine_label (%s, %"PRIx32", %"PRIx64", %s, %d, %d)",
231               label, segment, offset, special, is_norm, isextrn);
232 #endif
233
234     lptr = find_label(label, 1);
235     if (!lptr)
236         nasm_error(ERR_PANIC, "can't find label `%s' on pass two", label);
237
238     if (!islocal(label)) {
239         if (!islocalchar(*label) && lptr->defn.is_norm)
240             prevlabel = lptr->defn.label;
241     }
242
243     if (lptr->defn.offset != offset)
244         global_offset_changed++;
245
246     lptr->defn.offset = offset;
247     lptr->defn.segment = segment;
248
249     if (pass0 == 1) {
250         exi = !!(lptr->defn.is_global & GLOBAL_BIT);
251         if (exi) {
252             char *xsymbol;
253             int slen;
254             slen = strlen(lprefix);
255             slen += strlen(lptr->defn.label);
256             slen += strlen(lpostfix);
257             slen++;             /* room for that null char */
258             xsymbol = nasm_malloc(slen);
259             snprintf(xsymbol, slen, "%s%s%s", lprefix, lptr->defn.label,
260                      lpostfix);
261
262             ofmt->symdef(xsymbol, segment, offset, exi,
263                          special ? special : lptr->defn.special);
264             ofmt->current_dfmt->debug_deflabel(xsymbol, segment, offset, exi,
265                                                special ? special : lptr->defn.special);
266 /**     nasm_free(xsymbol);  ! outobj.c stores the pointer; ouch!!! **/
267         } else {
268             if ((lptr->defn.is_global & (GLOBAL_BIT | EXTERN_BIT)) != 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, exi,
272                                                    special ? special : lptr->defn.special);
273             }
274         }
275     }   /* if (pass0 == 1) */
276 }
277
278 void define_label(char *label, int32_t segment, int64_t offset, char *special,
279                   bool is_norm, bool isextrn)
280 {
281     union label *lptr;
282     int exi;
283
284 #ifdef DEBUG
285 #if DEBUG<3
286     if (!strncmp(label, "debugdump", 9))
287 #endif
288         nasm_error(ERR_DEBUG, "define_label (%s, %"PRIx32", %"PRIx64", %s, %d, %d)",
289               label, segment, offset, special, is_norm, isextrn);
290 #endif
291     lptr = find_label(label, 1);
292     if (!lptr)
293         return;
294     if (lptr->defn.is_global & DEFINED_BIT) {
295         nasm_error(ERR_NONFATAL, "symbol `%s' redefined", label);
296         return;
297     }
298     lptr->defn.is_global |= DEFINED_BIT;
299     if (isextrn)
300         lptr->defn.is_global |= EXTERN_BIT;
301
302     if (!islocalchar(label[0]) && is_norm) {
303         /* not local, but not special either */
304         prevlabel = lptr->defn.label;
305     } else if (islocal(label) && !*prevlabel) {
306         nasm_error(ERR_NONFATAL, "attempt to define a local label before any"
307               " non-local labels");
308     }
309
310     lptr->defn.segment = segment;
311     lptr->defn.offset = offset;
312     lptr->defn.is_norm = (!islocalchar(label[0]) && is_norm);
313
314     if (pass0 == 1 || (!is_norm && !isextrn && (segment > 0) && (segment & 1))) {
315         exi = !!(lptr->defn.is_global & GLOBAL_BIT);
316         if (exi) {
317             char *xsymbol;
318             int slen;
319             slen = strlen(lprefix);
320             slen += strlen(lptr->defn.label);
321             slen += strlen(lpostfix);
322             slen++;             /* room for that null char */
323             xsymbol = nasm_malloc(slen);
324             snprintf(xsymbol, slen, "%s%s%s", lprefix, lptr->defn.label,
325                      lpostfix);
326
327             ofmt->symdef(xsymbol, segment, offset, exi,
328                          special ? special : lptr->defn.special);
329             ofmt->current_dfmt->debug_deflabel(xsymbol, segment, offset, exi,
330                                                special ? special : lptr->defn.special);
331 /**     nasm_free(xsymbol);  ! outobj.c stores the pointer; ouch!!! **/
332         } else {
333             if ((lptr->defn.is_global & (GLOBAL_BIT | EXTERN_BIT)) != EXTERN_BIT) {
334                 ofmt->symdef(lptr->defn.label, segment, offset, exi,
335                              special ? special : lptr->defn.special);
336                 ofmt->current_dfmt->debug_deflabel(label, segment, offset, exi,
337                                                    special ? special : lptr->defn.special);
338             }
339         }
340     }   /* if (pass0 == 1) */
341 }
342
343 void define_common(char *label, int32_t segment, int32_t size, char *special)
344 {
345     union label *lptr;
346
347     lptr = find_label(label, 1);
348     if (!lptr)
349         return;
350     if ((lptr->defn.is_global & DEFINED_BIT) &&
351         (passn == 1 || !(lptr->defn.is_global & COMMON_BIT))) {
352             nasm_error(ERR_NONFATAL, "symbol `%s' redefined", label);
353             return;
354     }
355     lptr->defn.is_global |= DEFINED_BIT|COMMON_BIT;
356
357     if (!islocalchar(label[0])) {
358         prevlabel = lptr->defn.label;
359     } else {
360         nasm_error(ERR_NONFATAL, "attempt to define a local label as a "
361               "common variable");
362         return;
363     }
364
365     lptr->defn.segment = segment;
366     lptr->defn.offset = 0;
367
368     if (pass0 == 0)
369         return;
370
371     ofmt->symdef(lptr->defn.label, segment, size, 2,
372                  special ? special : lptr->defn.special);
373     ofmt->current_dfmt->debug_deflabel(lptr->defn.label, segment, size, 2,
374                                        special ? special : lptr->defn.special);
375 }
376
377 void declare_as_global(char *label, char *special)
378 {
379     union label *lptr;
380
381     if (islocal(label)) {
382         nasm_error(ERR_NONFATAL, "attempt to declare local symbol `%s' as"
383               " global", label);
384         return;
385     }
386     lptr = find_label(label, 1);
387     if (!lptr)
388         return;
389     switch (lptr->defn.is_global & TYPE_MASK) {
390     case NOT_DEFINED_YET:
391         lptr->defn.is_global = GLOBAL_PLACEHOLDER;
392         lptr->defn.special = special ? perm_copy(special) : NULL;
393         break;
394     case GLOBAL_PLACEHOLDER:   /* already done: silently ignore */
395     case GLOBAL_SYMBOL:
396         break;
397     case LOCAL_SYMBOL:
398         if (!(lptr->defn.is_global & EXTERN_BIT)) {
399             nasm_error(ERR_WARNING, "symbol `%s': GLOBAL directive "
400                   "after symbol definition is an experimental feature", label);
401             lptr->defn.is_global = GLOBAL_SYMBOL;
402         }
403         break;
404     }
405 }
406
407 int init_labels(void)
408 {
409     hash_init(&ltab, HASH_LARGE);
410
411     ldata = lfree = (union label *)nasm_malloc(LBLK_SIZE);
412     init_block(lfree);
413
414     perm_head = perm_tail =
415         (struct permts *)nasm_malloc(sizeof(struct permts));
416
417     perm_head->next = NULL;
418     perm_head->size = PERMTS_SIZE;
419     perm_head->usage = 0;
420
421     prevlabel = "";
422
423     initialized = true;
424
425     return 0;
426 }
427
428 void cleanup_labels(void)
429 {
430     union label *lptr, *lhold;
431
432     initialized = false;
433
434     hash_free(&ltab);
435
436     lptr = lhold = ldata;
437     while (lptr) {
438         lptr = &lptr[LABEL_BLOCK-1];
439         lptr = lptr->admin.next;
440         nasm_free(lhold);
441         lhold = lptr;
442     }
443
444     while (perm_head) {
445         perm_tail = perm_head;
446         perm_head = perm_head->next;
447         nasm_free(perm_tail);
448     }
449 }
450
451 static void init_block(union label *blk)
452 {
453     int j;
454
455     for (j = 0; j < LABEL_BLOCK - 1; j++)
456         blk[j].admin.movingon = END_LIST;
457     blk[LABEL_BLOCK - 1].admin.movingon = END_BLOCK;
458     blk[LABEL_BLOCK - 1].admin.next = NULL;
459 }
460
461 static char *perm_copy(const char *string)
462 {
463     char *p;
464     int len = strlen(string)+1;
465
466     nasm_assert(len <= PERMTS_SIZE);
467
468     if (perm_tail->size - perm_tail->usage < len) {
469         perm_tail->next =
470             (struct permts *)nasm_malloc(sizeof(struct permts));
471         perm_tail = perm_tail->next;
472         perm_tail->next = NULL;
473         perm_tail->size = PERMTS_SIZE;
474         perm_tail->usage = 0;
475     }
476     p = perm_tail->data + perm_tail->usage;
477     memcpy(p, string, len);
478     perm_tail->usage += len;
479
480     return p;
481 }
482
483 char *local_scope(char *label)
484 {
485    return islocal(label) ? prevlabel : "";
486 }
487
488 /*
489  * Notes regarding bug involving redefinition of external segments.
490  *
491  * Up to and including v0.97, the following code didn't work. From 0.97
492  * developers release 2 onwards, it will generate an error.
493  *
494  * EXTERN extlabel
495  * newlabel EQU extlabel + 1
496  *
497  * The results of allowing this code through are that two import records
498  * are generated, one for 'extlabel' and one for 'newlabel'.
499  *
500  * The reason for this is an inadequacy in the defined interface between
501  * the label manager and the output formats. The problem lies in how the
502  * output format driver tells that a label is an external label for which
503  * a label import record must be produced. Most (all except bin?) produce
504  * the record if the segment number of the label is not one of the internal
505  * segments that the output driver is producing.
506  *
507  * A simple fix to this would be to make the output formats keep track of
508  * which symbols they've produced import records for, and make them not
509  * produce import records for segments that are already defined.
510  *
511  * The best way, which is slightly harder but reduces duplication of code
512  * and should therefore make the entire system smaller and more stable is
513  * to change the interface between assembler, define_label(), and
514  * the output module. The changes that are needed are:
515  *
516  * The semantics of the 'isextern' flag passed to define_label() need
517  * examining. This information may or may not tell us what we need to
518  * know (ie should we be generating an import record at this point for this
519  * label). If these aren't the semantics, the semantics should be changed
520  * to this.
521  *
522  * The output module interface needs changing, so that the `isextern' flag
523  * is passed to the module, so that it can be easily tested for.
524  */