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