preproc_init: Just clean include path
[nasm.git] / asm / labels.c
blobc00d6e5b5572ba076f129f88c1031403e2f250f8
1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2018 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
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.
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.
32 * ----------------------------------------------------------------------- */
35 * labels.c label handling for the Netwide Assembler
38 #include "compiler.h"
40 #include <stdio.h>
41 #include <string.h>
42 #include <stdlib.h>
44 #include "nasm.h"
45 #include "nasmlib.h"
46 #include "error.h"
47 #include "hashtbl.h"
48 #include "labels.h"
51 * A dot-local label is one that begins with exactly one period. Things
52 * that begin with _two_ periods are NASM-specific things.
54 * If TASM compatibility is enabled, a local label can also begin with
55 * @@.
57 static bool islocal(const char *l)
59 if (tasm_compatible_mode) {
60 if (l[0] == '@' && l[1] == '@')
61 return true;
64 return (l[0] == '.' && l[1] != '.');
68 * Return true if this falls into NASM's '..' namespace
70 static bool ismagic(const char *l)
72 return l[0] == '.' && l[1] == '.' && l[2] != '@';
76 * Return true if we should update the local label base
77 * as a result of this symbol. We must exclude local labels
78 * as well as any kind of special labels, including ..@ ones.
80 static bool set_prevlabel(const char *l)
82 if (tasm_compatible_mode) {
83 if (l[0] == '@' && l[1] == '@')
84 return false;
87 return l[0] != '.';
90 #define LABEL_BLOCK 128 /* no. of labels/block */
91 #define LBLK_SIZE (LABEL_BLOCK * sizeof(union label))
93 #define END_LIST -3 /* don't clash with NO_SEG! */
94 #define END_BLOCK -2
96 #define PERMTS_SIZE 16384 /* size of text blocks */
97 #if (PERMTS_SIZE < IDLEN_MAX)
98 #error "IPERMTS_SIZE must be greater than or equal to IDLEN_MAX"
99 #endif
101 /* string values for enum label_type */
102 static const char * const types[] =
103 {"local", "global", "static", "extern", "common", "special",
104 "output format special"};
106 union label { /* actual label structures */
107 struct {
108 int32_t segment;
109 int32_t subsection; /* Available for ofmt->herelabel() */
110 int64_t offset;
111 int64_t size;
112 char *label, *mangled, *special;
113 enum label_type type, mangled_type;
114 bool defined;
115 } defn;
116 struct {
117 int32_t movingon;
118 int64_t dummy;
119 union label *next;
120 } admin;
123 struct permts { /* permanent text storage */
124 struct permts *next; /* for the linked list */
125 unsigned int size, usage; /* size and used space in ... */
126 char data[PERMTS_SIZE]; /* ... the data block itself */
128 #define PERMTS_HEADER offsetof(struct permts, data)
130 uint64_t global_offset_changed; /* counter for global offset changes */
132 static struct hash_table ltab; /* labels hash table */
133 static union label *ldata; /* all label data blocks */
134 static union label *lfree; /* labels free block */
135 static struct permts *perm_head; /* start of perm. text storage */
136 static struct permts *perm_tail; /* end of perm. text storage */
138 static void init_block(union label *blk);
139 static char *perm_alloc(size_t len);
140 static char *perm_copy(const char *string);
141 static char *perm_copy3(const char *s1, const char *s2, const char *s3);
142 static const char *mangle_label_name(union label *lptr);
144 static const char *prevlabel;
146 static bool initialized = false;
149 * Emit a symdef to the output and the debug format backends.
151 static void out_symdef(union label *lptr)
153 int backend_type;
154 int64_t backend_offset;
156 /* Backend-defined special segments are passed to symdef immediately */
157 if (pass0 == 2) {
158 /* Emit special fixups for globals and commons */
159 switch (lptr->defn.type) {
160 case LBL_GLOBAL:
161 case LBL_EXTERN:
162 case LBL_COMMON:
163 if (lptr->defn.special)
164 ofmt->symdef(lptr->defn.mangled, 0, 0, 3, lptr->defn.special);
165 break;
166 default:
167 break;
169 return;
172 if (pass0 != 1 && lptr->defn.type != LBL_BACKEND)
173 return;
175 /* Clean up this hack... */
176 switch(lptr->defn.type) {
177 case LBL_GLOBAL:
178 case LBL_EXTERN:
179 backend_type = 1;
180 backend_offset = lptr->defn.offset;
181 break;
182 case LBL_COMMON:
183 backend_type = 2;
184 backend_offset = lptr->defn.size;
185 break;
186 default:
187 backend_type = 0;
188 backend_offset = lptr->defn.offset;
189 break;
192 /* Might be necessary for a backend symbol */
193 mangle_label_name(lptr);
195 ofmt->symdef(lptr->defn.mangled, lptr->defn.segment,
196 backend_offset, backend_type,
197 lptr->defn.special);
200 * NASM special symbols are not passed to the debug format; none
201 * of the current backends want to see them.
203 if (lptr->defn.type == LBL_SPECIAL || lptr->defn.type == LBL_BACKEND)
204 return;
206 dfmt->debug_deflabel(lptr->defn.mangled, lptr->defn.segment,
207 lptr->defn.offset, backend_type,
208 lptr->defn.special);
212 * Internal routine: finds the `union label' corresponding to the
213 * given label name. Creates a new one, if it isn't found, and if
214 * `create' is true.
216 static union label *find_label(const char *label, bool create, bool *created)
218 union label *lptr, **lpp;
219 char *label_str = NULL;
220 struct hash_insert ip;
222 nasm_assert(label != NULL);
224 if (islocal(label))
225 label = label_str = nasm_strcat(prevlabel, label);
227 lpp = (union label **) hash_find(&ltab, label, &ip);
228 lptr = lpp ? *lpp : NULL;
230 if (lptr || !create) {
231 if (created)
232 *created = false;
233 return lptr;
236 /* Create a new label... */
237 if (lfree->admin.movingon == END_BLOCK) {
239 * must allocate a new block
241 lfree->admin.next = nasm_malloc(LBLK_SIZE);
242 lfree = lfree->admin.next;
243 init_block(lfree);
246 if (created)
247 *created = true;
249 nasm_zero(*lfree);
250 lfree->defn.label = perm_copy(label);
251 lfree->defn.subsection = NO_SEG;
252 if (label_str)
253 nasm_free(label_str);
255 hash_add(&ip, lfree->defn.label, lfree);
256 return lfree++;
259 bool lookup_label(const char *label, int32_t *segment, int64_t *offset)
261 union label *lptr;
263 if (!initialized)
264 return false;
266 lptr = find_label(label, false, NULL);
267 if (lptr && lptr->defn.defined) {
268 *segment = lptr->defn.segment;
269 *offset = lptr->defn.offset;
270 return true;
273 return false;
276 bool is_extern(const char *label)
278 union label *lptr;
280 if (!initialized)
281 return false;
283 lptr = find_label(label, false, NULL);
284 return lptr && lptr->defn.type == LBL_EXTERN;
287 static const char *mangle_strings[] = {"", "", "", ""};
288 static bool mangle_string_set[ARRAY_SIZE(mangle_strings)];
291 * Set a prefix or suffix
293 void set_label_mangle(enum mangle_index which, const char *what)
295 if (mangle_string_set[which])
296 return; /* Once set, do not change */
298 mangle_strings[which] = perm_copy(what);
299 mangle_string_set[which] = true;
303 * Format a label name with appropriate prefixes and suffixes
305 static const char *mangle_label_name(union label *lptr)
307 const char *prefix;
308 const char *suffix;
310 if (likely(lptr->defn.mangled &&
311 lptr->defn.mangled_type == lptr->defn.type))
312 return lptr->defn.mangled; /* Already mangled */
314 switch (lptr->defn.type) {
315 case LBL_GLOBAL:
316 case LBL_STATIC:
317 case LBL_EXTERN:
318 prefix = mangle_strings[LM_GPREFIX];
319 suffix = mangle_strings[LM_GSUFFIX];
320 break;
321 case LBL_BACKEND:
322 case LBL_SPECIAL:
323 prefix = suffix = "";
324 break;
325 default:
326 prefix = mangle_strings[LM_LPREFIX];
327 suffix = mangle_strings[LM_LSUFFIX];
328 break;
331 lptr->defn.mangled_type = lptr->defn.type;
333 if (!(*prefix) && !(*suffix))
334 lptr->defn.mangled = lptr->defn.label;
335 else
336 lptr->defn.mangled = perm_copy3(prefix, lptr->defn.label, suffix);
338 return lptr->defn.mangled;
341 static void
342 handle_herelabel(union label *lptr, int32_t *segment, int64_t *offset)
344 int32_t oldseg;
346 if (likely(!ofmt->herelabel))
347 return;
349 if (unlikely(location.segment == NO_SEG))
350 return;
352 oldseg = *segment;
354 if (oldseg == location.segment && *offset == location.offset) {
355 /* This label is defined at this location */
356 int32_t newseg;
357 bool copyoffset = false;
359 nasm_assert(lptr->defn.mangled);
360 newseg = ofmt->herelabel(lptr->defn.mangled, lptr->defn.type,
361 oldseg, &lptr->defn.subsection, &copyoffset);
362 if (likely(newseg == oldseg))
363 return;
365 *segment = newseg;
366 if (copyoffset) {
367 /* Maintain the offset from the old to the new segment */
368 switch_segment(newseg);
369 location.offset = *offset;
370 } else {
371 /* Keep a separate offset for the new segment */
372 *offset = switch_segment(newseg);
377 static bool declare_label_lptr(union label *lptr,
378 enum label_type type, const char *special)
380 if (special && !special[0])
381 special = NULL;
383 if (lptr->defn.type == type ||
384 (pass0 == 0 && lptr->defn.type == LBL_LOCAL)) {
385 lptr->defn.type = type;
386 if (special) {
387 if (!lptr->defn.special)
388 lptr->defn.special = perm_copy(special);
389 else if (nasm_stricmp(lptr->defn.special, special))
390 nasm_error(ERR_NONFATAL,
391 "symbol `%s' has inconsistent attributes `%s' and `%s'",
392 lptr->defn.label, lptr->defn.special, special);
394 return true;
397 /* EXTERN can be replaced with GLOBAL or COMMON */
398 if (lptr->defn.type == LBL_EXTERN &&
399 (type == LBL_GLOBAL || type == LBL_COMMON)) {
400 lptr->defn.type = type;
401 /* Override special unconditionally */
402 if (special)
403 lptr->defn.special = perm_copy(special);
404 return true;
407 /* GLOBAL or COMMON ignore subsequent EXTERN */
408 if ((lptr->defn.type == LBL_GLOBAL || lptr->defn.type == LBL_COMMON) &&
409 type == LBL_EXTERN) {
410 if (!lptr->defn.special)
411 lptr->defn.special = perm_copy(special);
412 return false; /* Don't call define_label() after this! */
415 nasm_error(ERR_NONFATAL, "symbol `%s' declared both as %s and %s",
416 lptr->defn.label, types[lptr->defn.type], types[type]);
418 return false;
421 bool declare_label(const char *label, enum label_type type, const char *special)
423 union label *lptr = find_label(label, true, NULL);
424 return declare_label_lptr(lptr, type, special);
428 * The "normal" argument decides if we should update the local segment
429 * base name or not.
431 void define_label(const char *label, int32_t segment,
432 int64_t offset, bool normal)
434 union label *lptr;
435 bool created, changed;
436 int64_t size;
439 * Phase errors here can be one of two types: a new label appears,
440 * or the offset changes. Increment global_offset_changed when that
441 * happens, to tell the assembler core to make another pass.
443 lptr = find_label(label, true, &created);
445 if (segment) {
446 /* We are actually defining this label */
447 if (lptr->defn.type == LBL_EXTERN) /* auto-promote EXTERN to GLOBAL */
448 lptr->defn.type = LBL_GLOBAL;
449 } else {
450 /* It's a pseudo-segment (extern, common) */
451 segment = lptr->defn.segment ? lptr->defn.segment : seg_alloc();
454 if (lptr->defn.defined || lptr->defn.type == LBL_BACKEND) {
455 /* We have seen this on at least one previous pass */
456 mangle_label_name(lptr);
457 handle_herelabel(lptr, &segment, &offset);
460 if (ismagic(label) && lptr->defn.type == LBL_LOCAL)
461 lptr->defn.type = LBL_SPECIAL;
463 if (set_prevlabel(label) && normal)
464 prevlabel = lptr->defn.label;
466 if (lptr->defn.type == LBL_COMMON) {
467 size = offset;
468 offset = 0;
469 } else {
470 size = 0; /* This is a hack... */
473 changed = created || !lptr->defn.defined ||
474 lptr->defn.segment != segment ||
475 lptr->defn.offset != offset || lptr->defn.size != size;
476 global_offset_changed += changed;
479 * This probably should be ERR_NONFATAL, but not quite yet. As a
480 * special case, LBL_SPECIAL symbols are allowed to be changed
481 * even during the last pass.
483 if (changed && pass0 > 1 && lptr->defn.type != LBL_SPECIAL) {
484 nasm_error(ERR_WARNING, "label `%s' %s during code generation",
485 lptr->defn.label,
486 created ? "defined" : "changed");
489 lptr->defn.segment = segment;
490 lptr->defn.offset = offset;
491 lptr->defn.size = size;
492 lptr->defn.defined = true;
494 out_symdef(lptr);
498 * Define a special backend label
500 void backend_label(const char *label, int32_t segment, int64_t offset)
502 if (!declare_label(label, LBL_BACKEND, NULL))
503 return;
505 define_label(label, segment, offset, false);
508 int init_labels(void)
510 hash_init(&ltab, HASH_LARGE);
512 ldata = lfree = nasm_malloc(LBLK_SIZE);
513 init_block(lfree);
515 perm_head = perm_tail =
516 nasm_malloc(sizeof(struct permts));
518 perm_head->next = NULL;
519 perm_head->size = PERMTS_SIZE;
520 perm_head->usage = 0;
522 prevlabel = "";
524 initialized = true;
526 return 0;
529 void cleanup_labels(void)
531 union label *lptr, *lhold;
533 initialized = false;
535 hash_free(&ltab);
537 lptr = lhold = ldata;
538 while (lptr) {
539 lptr = &lptr[LABEL_BLOCK-1];
540 lptr = lptr->admin.next;
541 nasm_free(lhold);
542 lhold = lptr;
545 while (perm_head) {
546 perm_tail = perm_head;
547 perm_head = perm_head->next;
548 nasm_free(perm_tail);
552 static void init_block(union label *blk)
554 int j;
556 for (j = 0; j < LABEL_BLOCK - 1; j++)
557 blk[j].admin.movingon = END_LIST;
558 blk[LABEL_BLOCK - 1].admin.movingon = END_BLOCK;
559 blk[LABEL_BLOCK - 1].admin.next = NULL;
562 static char * safe_alloc perm_alloc(size_t len)
564 char *p;
566 if (perm_tail->size - perm_tail->usage < len) {
567 size_t alloc_len = (len > PERMTS_SIZE) ? len : PERMTS_SIZE;
568 perm_tail->next = nasm_malloc(PERMTS_HEADER + alloc_len);
569 perm_tail = perm_tail->next;
570 perm_tail->next = NULL;
571 perm_tail->size = alloc_len;
572 perm_tail->usage = 0;
574 p = perm_tail->data + perm_tail->usage;
575 perm_tail->usage += len;
576 return p;
579 static char *perm_copy(const char *string)
581 char *p;
582 size_t len;
584 if (!string)
585 return NULL;
587 len = strlen(string)+1; /* Include final NUL */
589 p = perm_alloc(len);
590 memcpy(p, string, len);
592 return p;
595 static char *
596 perm_copy3(const char *s1, const char *s2, const char *s3)
598 char *p;
599 size_t l1 = strlen(s1);
600 size_t l2 = strlen(s2);
601 size_t l3 = strlen(s3)+1; /* Include final NUL */
603 p = perm_alloc(l1+l2+l3);
604 memcpy(p, s1, l1);
605 memcpy(p+l1, s2, l2);
606 memcpy(p+l1+l2, s3, l3);
608 return p;
611 const char *local_scope(const char *label)
613 return islocal(label) ? prevlabel : "";
617 * Notes regarding bug involving redefinition of external segments.
619 * Up to and including v0.97, the following code didn't work. From 0.97
620 * developers release 2 onwards, it will generate an error.
622 * EXTERN extlabel
623 * newlabel EQU extlabel + 1
625 * The results of allowing this code through are that two import records
626 * are generated, one for 'extlabel' and one for 'newlabel'.
628 * The reason for this is an inadequacy in the defined interface between
629 * the label manager and the output formats. The problem lies in how the
630 * output format driver tells that a label is an external label for which
631 * a label import record must be produced. Most (all except bin?) produce
632 * the record if the segment number of the label is not one of the internal
633 * segments that the output driver is producing.
635 * A simple fix to this would be to make the output formats keep track of
636 * which symbols they've produced import records for, and make them not
637 * produce import records for segments that are already defined.
639 * The best way, which is slightly harder but reduces duplication of code
640 * and should therefore make the entire system smaller and more stable is
641 * to change the interface between assembler, define_label(), and
642 * the output module. The changes that are needed are:
644 * The semantics of the 'isextern' flag passed to define_label() need
645 * examining. This information may or may not tell us what we need to
646 * know (ie should we be generating an import record at this point for this
647 * label). If these aren't the semantics, the semantics should be changed
648 * to this.
650 * The output module interface needs changing, so that the `isextern' flag
651 * is passed to the module, so that it can be easily tested for.