travis: weirdpaste.i now has better line directives
[nasm.git] / asm / labels.c
blobf6b940fcaaa70bb502c9f91e17c0668ecd43eebf
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"
41 #include "nasm.h"
42 #include "nasmlib.h"
43 #include "error.h"
44 #include "hashtbl.h"
45 #include "labels.h"
48 * A dot-local label is one that begins with exactly one period. Things
49 * that begin with _two_ periods are NASM-specific things.
51 * If TASM compatibility is enabled, a local label can also begin with
52 * @@.
54 static bool islocal(const char *l)
56 if (tasm_compatible_mode) {
57 if (l[0] == '@' && l[1] == '@')
58 return true;
61 return (l[0] == '.' && l[1] != '.');
65 * Return true if this falls into NASM's '..' namespace
67 static bool ismagic(const char *l)
69 return l[0] == '.' && l[1] == '.' && l[2] != '@';
73 * Return true if we should update the local label base
74 * as a result of this symbol. We must exclude local labels
75 * as well as any kind of special labels, including ..@ ones.
77 static bool set_prevlabel(const char *l)
79 if (tasm_compatible_mode) {
80 if (l[0] == '@' && l[1] == '@')
81 return false;
84 return l[0] != '.';
87 #define LABEL_BLOCK 128 /* no. of labels/block */
88 #define LBLK_SIZE (LABEL_BLOCK * sizeof(union label))
90 #define END_LIST -3 /* don't clash with NO_SEG! */
91 #define END_BLOCK -2
93 #define PERMTS_SIZE 16384 /* size of text blocks */
94 #if (PERMTS_SIZE < IDLEN_MAX)
95 #error "IPERMTS_SIZE must be greater than or equal to IDLEN_MAX"
96 #endif
98 /* string values for enum label_type */
99 static const char * const types[] = {
100 "local", "static", "global", "extern", "required", "common",
101 "special", "output format special"
104 union label { /* actual label structures */
105 struct {
106 int32_t segment;
107 int32_t subsection; /* Available for ofmt->herelabel() */
108 int64_t offset;
109 int64_t size;
110 int64_t defined; /* 0 if undefined, passn+1 for when defn seen */
111 int64_t lastref; /* Last pass where we saw a reference */
112 char *label, *mangled, *special;
113 const char *def_file; /* Where defined */
114 int32_t def_line;
115 enum label_type type, mangled_type;
116 } defn;
117 struct {
118 int32_t movingon;
119 int64_t dummy;
120 union label *next;
121 } admin;
124 struct permts { /* permanent text storage */
125 struct permts *next; /* for the linked list */
126 unsigned int size, usage; /* size and used space in ... */
127 char data[PERMTS_SIZE]; /* ... the data block itself */
129 #define PERMTS_HEADER offsetof(struct permts, data)
131 uint64_t global_offset_changed; /* counter for global offset changes */
133 static struct hash_table ltab; /* labels hash table */
134 static union label *ldata; /* all label data blocks */
135 static union label *lfree; /* labels free block */
136 static struct permts *perm_head; /* start of perm. text storage */
137 static struct permts *perm_tail; /* end of perm. text storage */
139 static void init_block(union label *blk);
140 static char *perm_alloc(size_t len);
141 static char *perm_copy(const char *string);
142 static char *perm_copy3(const char *s1, const char *s2, const char *s3);
143 static const char *mangle_label_name(union label *lptr);
145 static const char *prevlabel;
147 static bool initialized = false;
150 * Emit a symdef to the output and the debug format backends.
152 static void out_symdef(union label *lptr)
154 int backend_type;
155 int64_t backend_offset;
157 /* Backend-defined special segments are passed to symdef immediately */
158 if (pass_final()) {
159 /* Emit special fixups for globals and commons */
160 switch (lptr->defn.type) {
161 case LBL_GLOBAL:
162 case LBL_REQUIRED:
163 case LBL_COMMON:
164 if (lptr->defn.special)
165 ofmt->symdef(lptr->defn.mangled, 0, 0, 3, lptr->defn.special);
166 break;
167 default:
168 break;
170 return;
173 if (pass_type() != PASS_STAB && lptr->defn.type != LBL_BACKEND)
174 return;
176 /* Clean up this hack... */
177 switch(lptr->defn.type) {
178 case LBL_EXTERN:
179 /* If not seen in the previous or this pass, drop it */
180 if (lptr->defn.lastref < pass_count())
181 return;
183 /* Otherwise, promote to LBL_REQUIRED at this time */
184 lptr->defn.type = LBL_REQUIRED;
186 /* fall through */
187 case LBL_GLOBAL:
188 case LBL_REQUIRED:
189 backend_type = 1;
190 backend_offset = lptr->defn.offset;
191 break;
192 case LBL_COMMON:
193 backend_type = 2;
194 backend_offset = lptr->defn.size;
195 break;
196 default:
197 backend_type = 0;
198 backend_offset = lptr->defn.offset;
199 break;
202 /* Might be necessary for a backend symbol */
203 mangle_label_name(lptr);
205 ofmt->symdef(lptr->defn.mangled, lptr->defn.segment,
206 backend_offset, backend_type,
207 lptr->defn.special);
210 * NASM special symbols are not passed to the debug format; none
211 * of the current backends want to see them.
213 if (lptr->defn.type == LBL_SPECIAL || lptr->defn.type == LBL_BACKEND)
214 return;
216 dfmt->debug_deflabel(lptr->defn.mangled, lptr->defn.segment,
217 lptr->defn.offset, backend_type,
218 lptr->defn.special);
222 * Internal routine: finds the `union label' corresponding to the
223 * given label name. Creates a new one, if it isn't found, and if
224 * `create' is true.
226 static union label *find_label(const char *label, bool create, bool *created)
228 union label *lptr, **lpp;
229 char *label_str = NULL;
230 struct hash_insert ip;
232 nasm_assert(label != NULL);
234 if (islocal(label))
235 label = label_str = nasm_strcat(prevlabel, label);
237 lpp = (union label **) hash_find(&ltab, label, &ip);
238 lptr = lpp ? *lpp : NULL;
240 if (lptr || !create) {
241 if (created)
242 *created = false;
243 return lptr;
246 /* Create a new label... */
247 if (lfree->admin.movingon == END_BLOCK) {
249 * must allocate a new block
251 lfree->admin.next = nasm_malloc(LBLK_SIZE);
252 lfree = lfree->admin.next;
253 init_block(lfree);
256 if (created)
257 *created = true;
259 nasm_zero(*lfree);
260 lfree->defn.label = perm_copy(label);
261 lfree->defn.subsection = NO_SEG;
262 if (label_str)
263 nasm_free(label_str);
265 hash_add(&ip, lfree->defn.label, lfree);
266 return lfree++;
269 enum label_type lookup_label(const char *label,
270 int32_t *segment, int64_t *offset)
272 union label *lptr;
274 if (!initialized)
275 return LBL_none;
277 lptr = find_label(label, false, NULL);
278 if (lptr && lptr->defn.defined) {
279 int64_t lpass = pass_count() + 1;
281 lptr->defn.lastref = lpass;
282 *segment = lptr->defn.segment;
283 *offset = lptr->defn.offset;
284 return lptr->defn.type;
287 return LBL_none;
290 static inline bool is_global(enum label_type type)
292 return type == LBL_GLOBAL || type == LBL_COMMON;
295 static const char *mangle_strings[] = {"", "", "", ""};
296 static bool mangle_string_set[ARRAY_SIZE(mangle_strings)];
299 * Set a prefix or suffix
301 void set_label_mangle(enum mangle_index which, const char *what)
303 if (mangle_string_set[which])
304 return; /* Once set, do not change */
306 mangle_strings[which] = perm_copy(what);
307 mangle_string_set[which] = true;
311 * Format a label name with appropriate prefixes and suffixes
313 static const char *mangle_label_name(union label *lptr)
315 const char *prefix;
316 const char *suffix;
318 if (likely(lptr->defn.mangled &&
319 lptr->defn.mangled_type == lptr->defn.type))
320 return lptr->defn.mangled; /* Already mangled */
322 switch (lptr->defn.type) {
323 case LBL_GLOBAL:
324 case LBL_STATIC:
325 case LBL_EXTERN:
326 case LBL_REQUIRED:
327 prefix = mangle_strings[LM_GPREFIX];
328 suffix = mangle_strings[LM_GSUFFIX];
329 break;
330 case LBL_BACKEND:
331 case LBL_SPECIAL:
332 prefix = suffix = "";
333 break;
334 default:
335 prefix = mangle_strings[LM_LPREFIX];
336 suffix = mangle_strings[LM_LSUFFIX];
337 break;
340 lptr->defn.mangled_type = lptr->defn.type;
342 if (!(*prefix) && !(*suffix))
343 lptr->defn.mangled = lptr->defn.label;
344 else
345 lptr->defn.mangled = perm_copy3(prefix, lptr->defn.label, suffix);
347 return lptr->defn.mangled;
350 static void
351 handle_herelabel(union label *lptr, int32_t *segment, int64_t *offset)
353 int32_t oldseg;
355 if (likely(!ofmt->herelabel))
356 return;
358 if (unlikely(location.segment == NO_SEG))
359 return;
361 oldseg = *segment;
363 if (oldseg == location.segment && *offset == location.offset) {
364 /* This label is defined at this location */
365 int32_t newseg;
366 bool copyoffset = false;
368 nasm_assert(lptr->defn.mangled);
369 newseg = ofmt->herelabel(lptr->defn.mangled, lptr->defn.type,
370 oldseg, &lptr->defn.subsection, &copyoffset);
371 if (likely(newseg == oldseg))
372 return;
374 *segment = newseg;
375 if (copyoffset) {
376 /* Maintain the offset from the old to the new segment */
377 switch_segment(newseg);
378 location.offset = *offset;
379 } else {
380 /* Keep a separate offset for the new segment */
381 *offset = switch_segment(newseg);
386 static bool declare_label_lptr(union label *lptr,
387 enum label_type type, const char *special)
389 enum label_type oldtype = lptr->defn.type;
391 if (special && !special[0])
392 special = NULL;
394 if (oldtype == type || (!pass_stable() && oldtype == LBL_LOCAL) ||
395 (oldtype == LBL_EXTERN && type == LBL_REQUIRED)) {
396 lptr->defn.type = type;
398 if (special) {
399 if (!lptr->defn.special)
400 lptr->defn.special = perm_copy(special);
401 else if (nasm_stricmp(lptr->defn.special, special))
402 nasm_nonfatal("symbol `%s' has inconsistent attributes `%s' and `%s'",
403 lptr->defn.label, lptr->defn.special, special);
405 return true;
406 } else if (is_extern(oldtype) && is_global(type)) {
407 /* EXTERN or REQUIRED can be replaced with GLOBAL or COMMON */
408 lptr->defn.type = type;
410 /* Override special unconditionally */
411 if (special)
412 lptr->defn.special = perm_copy(special);
413 return true;
414 } else if (is_extern(type) && (is_global(oldtype) || is_extern(oldtype))) {
416 * GLOBAL or COMMON ignore subsequent EXTERN or REQUIRED;
417 * REQUIRED ignores subsequent EXTERN.
420 /* Ignore special unless we don't already have one */
421 if (!lptr->defn.special)
422 lptr->defn.special = perm_copy(special);
424 return false; /* Don't call define_label() after this! */
427 nasm_nonfatal("symbol `%s' declared both as %s and %s",
428 lptr->defn.label, types[lptr->defn.type], types[type]);
429 return false;
432 bool declare_label(const char *label, enum label_type type, const char *special)
434 union label *lptr = find_label(label, true, NULL);
435 return declare_label_lptr(lptr, type, special);
439 * The "normal" argument decides if we should update the local segment
440 * base name or not.
442 void define_label(const char *label, int32_t segment,
443 int64_t offset, bool normal)
445 union label *lptr;
446 bool created, changed;
447 int64_t size;
448 int64_t lpass, lastdef;
451 * The backend may invoke this during initialization, at which
452 * pass_count() is zero, so add one so we never have a zero value
453 * for a defined variable.
455 lpass = pass_count() + 1;
458 * Phase errors here can be one of two types: a new label appears,
459 * or the offset changes. Increment global_offset_changed when that
460 * happens, to tell the assembler core to make another pass.
462 lptr = find_label(label, true, &created);
464 lastdef = lptr->defn.defined;
466 if (segment) {
467 /* We are actually defining this label */
468 if (is_extern(lptr->defn.type)) {
469 /* auto-promote EXTERN/REQUIRED to GLOBAL */
470 lptr->defn.type = LBL_GLOBAL;
471 lastdef = 0; /* We are "re-creating" this label */
473 } else {
474 /* It's a pseudo-segment (extern, required, common) */
475 segment = lptr->defn.segment ? lptr->defn.segment : seg_alloc();
478 if (lastdef || lptr->defn.type == LBL_BACKEND) {
480 * We have seen this on at least one previous pass, or
481 * potentially earlier in this same pass (in which case we
482 * will probably error out further down.)
484 mangle_label_name(lptr);
485 handle_herelabel(lptr, &segment, &offset);
488 if (ismagic(label) && lptr->defn.type == LBL_LOCAL)
489 lptr->defn.type = LBL_SPECIAL;
491 if (set_prevlabel(label) && normal)
492 prevlabel = lptr->defn.label;
494 if (lptr->defn.type == LBL_COMMON) {
495 size = offset;
496 offset = 0;
497 } else {
498 size = 0; /* This is a hack... */
501 changed = created || !lastdef ||
502 lptr->defn.segment != segment ||
503 lptr->defn.offset != offset ||
504 lptr->defn.size != size;
505 global_offset_changed += changed;
507 if (lastdef == lpass) {
508 int32_t saved_line = 0;
509 const char *saved_fname = NULL;
510 int noteflags;
513 * Defined elsewhere in the program, seen in this pass.
515 if (changed) {
516 nasm_nonfatal("label `%s' inconsistently redefined", lptr->defn.label);
517 noteflags = ERR_NONFATAL|ERR_HERE|ERR_NO_SEVERITY;
518 } else {
520 *!label-redef [off] label redefined to an identical value
521 *! warns if a label is defined more than once, but the
522 *! value is identical. It is an unconditional error to
523 *! define the same label more than once to \e{different} values.
525 nasm_warn(WARN_LABEL_REDEF,
526 "info: label `%s' redefined to an identical value", lptr->defn.label);
527 noteflags = ERR_WARNING|ERR_HERE|ERR_NO_SEVERITY|WARN_LABEL_REDEF;
530 src_get(&saved_line, &saved_fname);
531 src_set(lptr->defn.def_line, lptr->defn.def_file);
532 nasm_error(noteflags, "info: label `%s' originally defined", lptr->defn.label);
533 src_set(saved_line, saved_fname);
534 } else if (changed && pass_final() && lptr->defn.type != LBL_SPECIAL) {
536 *!label-redef-late [err] label (re)defined during code generation
537 *! the value of a label changed during the final, code-generation
538 *! pass. This may be the result of strange use of the
539 *! preprocessor. This is very likely to produce incorrect code and
540 *! may end up being an unconditional error in a future
541 *! version of NASM.
543 * WARN_LABEL_LATE defaults to an error, as this should never
544 * actually happen. Just in case this is a backwards
545 * compatibility problem, still make it a warning so that the
546 * user can suppress or demote it.
548 * Note: As a special case, LBL_SPECIAL symbols are allowed
549 * to be changed even during the last pass.
551 nasm_warn(WARN_LABEL_REDEF_LATE|ERR_UNDEAD,
552 "label `%s' %s during code generation",
553 lptr->defn.label, created ? "defined" : "changed");
555 lptr->defn.segment = segment;
556 lptr->defn.offset = offset;
557 lptr->defn.size = size;
558 lptr->defn.defined = lpass;
560 if (changed || lastdef != lpass)
561 src_get(&lptr->defn.def_line, &lptr->defn.def_file);
563 if (lastdef != lpass)
564 out_symdef(lptr);
568 * Define a special backend label
570 void backend_label(const char *label, int32_t segment, int64_t offset)
572 if (!declare_label(label, LBL_BACKEND, NULL))
573 return;
575 define_label(label, segment, offset, false);
578 int init_labels(void)
580 ldata = lfree = nasm_malloc(LBLK_SIZE);
581 init_block(lfree);
583 perm_head = perm_tail =
584 nasm_malloc(sizeof(struct permts));
586 perm_head->next = NULL;
587 perm_head->size = PERMTS_SIZE;
588 perm_head->usage = 0;
590 prevlabel = "";
592 initialized = true;
594 return 0;
597 void cleanup_labels(void)
599 union label *lptr, *lhold;
601 initialized = false;
603 hash_free(&ltab);
605 lptr = lhold = ldata;
606 while (lptr) {
607 lptr = &lptr[LABEL_BLOCK-1];
608 lptr = lptr->admin.next;
609 nasm_free(lhold);
610 lhold = lptr;
613 while (perm_head) {
614 perm_tail = perm_head;
615 perm_head = perm_head->next;
616 nasm_free(perm_tail);
620 static void init_block(union label *blk)
622 int j;
624 for (j = 0; j < LABEL_BLOCK - 1; j++)
625 blk[j].admin.movingon = END_LIST;
626 blk[LABEL_BLOCK - 1].admin.movingon = END_BLOCK;
627 blk[LABEL_BLOCK - 1].admin.next = NULL;
630 static char * safe_alloc perm_alloc(size_t len)
632 char *p;
634 if (perm_tail->size - perm_tail->usage < len) {
635 size_t alloc_len = (len > PERMTS_SIZE) ? len : PERMTS_SIZE;
636 perm_tail->next = nasm_malloc(PERMTS_HEADER + alloc_len);
637 perm_tail = perm_tail->next;
638 perm_tail->next = NULL;
639 perm_tail->size = alloc_len;
640 perm_tail->usage = 0;
642 p = perm_tail->data + perm_tail->usage;
643 perm_tail->usage += len;
644 return p;
647 static char *perm_copy(const char *string)
649 char *p;
650 size_t len;
652 if (!string)
653 return NULL;
655 len = strlen(string)+1; /* Include final NUL */
657 p = perm_alloc(len);
658 memcpy(p, string, len);
660 return p;
663 static char *
664 perm_copy3(const char *s1, const char *s2, const char *s3)
666 char *p;
667 size_t l1 = strlen(s1);
668 size_t l2 = strlen(s2);
669 size_t l3 = strlen(s3)+1; /* Include final NUL */
671 p = perm_alloc(l1+l2+l3);
672 memcpy(p, s1, l1);
673 memcpy(p+l1, s2, l2);
674 memcpy(p+l1+l2, s3, l3);
676 return p;
679 const char *local_scope(const char *label)
681 return islocal(label) ? prevlabel : "";
685 * Notes regarding bug involving redefinition of external segments.
687 * Up to and including v0.97, the following code didn't work. From 0.97
688 * developers release 2 onwards, it will generate an error.
690 * EXTERN extlabel
691 * newlabel EQU extlabel + 1
693 * The results of allowing this code through are that two import records
694 * are generated, one for 'extlabel' and one for 'newlabel'.
696 * The reason for this is an inadequacy in the defined interface between
697 * the label manager and the output formats. The problem lies in how the
698 * output format driver tells that a label is an external label for which
699 * a label import record must be produced. Most (all except bin?) produce
700 * the record if the segment number of the label is not one of the internal
701 * segments that the output driver is producing.
703 * A simple fix to this would be to make the output formats keep track of
704 * which symbols they've produced import records for, and make them not
705 * produce import records for segments that are already defined.
707 * The best way, which is slightly harder but reduces duplication of code
708 * and should therefore make the entire system smaller and more stable is
709 * to change the interface between assembler, define_label(), and
710 * the output module. The changes that are needed are:
712 * The semantics of the 'isextern' flag passed to define_label() need
713 * examining. This information may or may not tell us what we need to
714 * know (ie should we be generating an import record at this point for this
715 * label). If these aren't the semantics, the semantics should be changed
716 * to this.
718 * The output module interface needs changing, so that the `isextern' flag
719 * is passed to the module, so that it can be easily tested for.