preproc: Fix nil dereference on error paths
[nasm.git] / asm / labels.c
blob7527156d660659cab88da87830b8425c13dcf1ad
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", "global", "static", "extern", "common", "special",
101 "output format special"};
103 union label { /* actual label structures */
104 struct {
105 int32_t segment;
106 int32_t subsection; /* Available for ofmt->herelabel() */
107 int64_t offset;
108 int64_t size;
109 int64_t defined; /* 0 if undefined, passn+1 for when defn seen */
110 char *label, *mangled, *special;
111 const char *def_file; /* Where defined */
112 int32_t def_line;
113 enum label_type type, mangled_type;
114 } defn;
115 struct {
116 int32_t movingon;
117 int64_t dummy;
118 union label *next;
119 } admin;
122 struct permts { /* permanent text storage */
123 struct permts *next; /* for the linked list */
124 unsigned int size, usage; /* size and used space in ... */
125 char data[PERMTS_SIZE]; /* ... the data block itself */
127 #define PERMTS_HEADER offsetof(struct permts, data)
129 uint64_t global_offset_changed; /* counter for global offset changes */
131 static struct hash_table ltab; /* labels hash table */
132 static union label *ldata; /* all label data blocks */
133 static union label *lfree; /* labels free block */
134 static struct permts *perm_head; /* start of perm. text storage */
135 static struct permts *perm_tail; /* end of perm. text storage */
137 static void init_block(union label *blk);
138 static char *perm_alloc(size_t len);
139 static char *perm_copy(const char *string);
140 static char *perm_copy3(const char *s1, const char *s2, const char *s3);
141 static const char *mangle_label_name(union label *lptr);
143 static const char *prevlabel;
145 static bool initialized = false;
148 * Emit a symdef to the output and the debug format backends.
150 static void out_symdef(union label *lptr)
152 int backend_type;
153 int64_t backend_offset;
155 /* Backend-defined special segments are passed to symdef immediately */
156 if (pass_final()) {
157 /* Emit special fixups for globals and commons */
158 switch (lptr->defn.type) {
159 case LBL_GLOBAL:
160 case LBL_EXTERN:
161 case LBL_COMMON:
162 if (lptr->defn.special)
163 ofmt->symdef(lptr->defn.mangled, 0, 0, 3, lptr->defn.special);
164 break;
165 default:
166 break;
168 return;
171 if (pass_type() != PASS_STAB && lptr->defn.type != LBL_BACKEND)
172 return;
174 /* Clean up this hack... */
175 switch(lptr->defn.type) {
176 case LBL_GLOBAL:
177 case LBL_EXTERN:
178 backend_type = 1;
179 backend_offset = lptr->defn.offset;
180 break;
181 case LBL_COMMON:
182 backend_type = 2;
183 backend_offset = lptr->defn.size;
184 break;
185 default:
186 backend_type = 0;
187 backend_offset = lptr->defn.offset;
188 break;
191 /* Might be necessary for a backend symbol */
192 mangle_label_name(lptr);
194 ofmt->symdef(lptr->defn.mangled, lptr->defn.segment,
195 backend_offset, backend_type,
196 lptr->defn.special);
199 * NASM special symbols are not passed to the debug format; none
200 * of the current backends want to see them.
202 if (lptr->defn.type == LBL_SPECIAL || lptr->defn.type == LBL_BACKEND)
203 return;
205 dfmt->debug_deflabel(lptr->defn.mangled, lptr->defn.segment,
206 lptr->defn.offset, backend_type,
207 lptr->defn.special);
211 * Internal routine: finds the `union label' corresponding to the
212 * given label name. Creates a new one, if it isn't found, and if
213 * `create' is true.
215 static union label *find_label(const char *label, bool create, bool *created)
217 union label *lptr, **lpp;
218 char *label_str = NULL;
219 struct hash_insert ip;
221 nasm_assert(label != NULL);
223 if (islocal(label))
224 label = label_str = nasm_strcat(prevlabel, label);
226 lpp = (union label **) hash_find(&ltab, label, &ip);
227 lptr = lpp ? *lpp : NULL;
229 if (lptr || !create) {
230 if (created)
231 *created = false;
232 return lptr;
235 /* Create a new label... */
236 if (lfree->admin.movingon == END_BLOCK) {
238 * must allocate a new block
240 lfree->admin.next = nasm_malloc(LBLK_SIZE);
241 lfree = lfree->admin.next;
242 init_block(lfree);
245 if (created)
246 *created = true;
248 nasm_zero(*lfree);
249 lfree->defn.label = perm_copy(label);
250 lfree->defn.subsection = NO_SEG;
251 if (label_str)
252 nasm_free(label_str);
254 hash_add(&ip, lfree->defn.label, lfree);
255 return lfree++;
258 bool lookup_label(const char *label, int32_t *segment, int64_t *offset)
260 union label *lptr;
262 if (!initialized)
263 return false;
265 lptr = find_label(label, false, NULL);
266 if (lptr && lptr->defn.defined) {
267 *segment = lptr->defn.segment;
268 *offset = lptr->defn.offset;
269 return true;
272 return false;
275 bool is_extern(const char *label)
277 union label *lptr;
279 if (!initialized)
280 return false;
282 lptr = find_label(label, false, NULL);
283 return lptr && lptr->defn.type == LBL_EXTERN;
286 static const char *mangle_strings[] = {"", "", "", ""};
287 static bool mangle_string_set[ARRAY_SIZE(mangle_strings)];
290 * Set a prefix or suffix
292 void set_label_mangle(enum mangle_index which, const char *what)
294 if (mangle_string_set[which])
295 return; /* Once set, do not change */
297 mangle_strings[which] = perm_copy(what);
298 mangle_string_set[which] = true;
302 * Format a label name with appropriate prefixes and suffixes
304 static const char *mangle_label_name(union label *lptr)
306 const char *prefix;
307 const char *suffix;
309 if (likely(lptr->defn.mangled &&
310 lptr->defn.mangled_type == lptr->defn.type))
311 return lptr->defn.mangled; /* Already mangled */
313 switch (lptr->defn.type) {
314 case LBL_GLOBAL:
315 case LBL_STATIC:
316 case LBL_EXTERN:
317 prefix = mangle_strings[LM_GPREFIX];
318 suffix = mangle_strings[LM_GSUFFIX];
319 break;
320 case LBL_BACKEND:
321 case LBL_SPECIAL:
322 prefix = suffix = "";
323 break;
324 default:
325 prefix = mangle_strings[LM_LPREFIX];
326 suffix = mangle_strings[LM_LSUFFIX];
327 break;
330 lptr->defn.mangled_type = lptr->defn.type;
332 if (!(*prefix) && !(*suffix))
333 lptr->defn.mangled = lptr->defn.label;
334 else
335 lptr->defn.mangled = perm_copy3(prefix, lptr->defn.label, suffix);
337 return lptr->defn.mangled;
340 static void
341 handle_herelabel(union label *lptr, int32_t *segment, int64_t *offset)
343 int32_t oldseg;
345 if (likely(!ofmt->herelabel))
346 return;
348 if (unlikely(location.segment == NO_SEG))
349 return;
351 oldseg = *segment;
353 if (oldseg == location.segment && *offset == location.offset) {
354 /* This label is defined at this location */
355 int32_t newseg;
356 bool copyoffset = false;
358 nasm_assert(lptr->defn.mangled);
359 newseg = ofmt->herelabel(lptr->defn.mangled, lptr->defn.type,
360 oldseg, &lptr->defn.subsection, &copyoffset);
361 if (likely(newseg == oldseg))
362 return;
364 *segment = newseg;
365 if (copyoffset) {
366 /* Maintain the offset from the old to the new segment */
367 switch_segment(newseg);
368 location.offset = *offset;
369 } else {
370 /* Keep a separate offset for the new segment */
371 *offset = switch_segment(newseg);
376 static bool declare_label_lptr(union label *lptr,
377 enum label_type type, const char *special)
379 if (special && !special[0])
380 special = NULL;
382 if (lptr->defn.type == type ||
383 (!pass_stable() && lptr->defn.type == LBL_LOCAL)) {
384 lptr->defn.type = type;
385 if (special) {
386 if (!lptr->defn.special)
387 lptr->defn.special = perm_copy(special);
388 else if (nasm_stricmp(lptr->defn.special, special))
389 nasm_nonfatal("symbol `%s' has inconsistent attributes `%s' and `%s'",
390 lptr->defn.label, lptr->defn.special, special);
392 return true;
395 /* EXTERN can be replaced with GLOBAL or COMMON */
396 if (lptr->defn.type == LBL_EXTERN &&
397 (type == LBL_GLOBAL || type == LBL_COMMON)) {
398 lptr->defn.type = type;
399 /* Override special unconditionally */
400 if (special)
401 lptr->defn.special = perm_copy(special);
402 return true;
405 /* GLOBAL or COMMON ignore subsequent EXTERN */
406 if ((lptr->defn.type == LBL_GLOBAL || lptr->defn.type == LBL_COMMON) &&
407 type == LBL_EXTERN) {
408 if (!lptr->defn.special)
409 lptr->defn.special = perm_copy(special);
410 return false; /* Don't call define_label() after this! */
413 nasm_nonfatal("symbol `%s' declared both as %s and %s",
414 lptr->defn.label, types[lptr->defn.type], types[type]);
416 return false;
419 bool declare_label(const char *label, enum label_type type, const char *special)
421 union label *lptr = find_label(label, true, NULL);
422 return declare_label_lptr(lptr, type, special);
426 * The "normal" argument decides if we should update the local segment
427 * base name or not.
429 void define_label(const char *label, int32_t segment,
430 int64_t offset, bool normal)
432 union label *lptr;
433 bool created, changed;
434 int64_t size;
435 int64_t lpass, lastdef;
438 * The backend may invoke this during initialization, at which
439 * pass_count() is zero, so add one so we never have a zero value
440 * for a defined variable.
442 lpass = pass_count() + 1;
445 * Phase errors here can be one of two types: a new label appears,
446 * or the offset changes. Increment global_offset_changed when that
447 * happens, to tell the assembler core to make another pass.
449 lptr = find_label(label, true, &created);
451 lastdef = lptr->defn.defined;
453 if (segment) {
454 /* We are actually defining this label */
455 if (lptr->defn.type == LBL_EXTERN) {
456 /* auto-promote EXTERN to GLOBAL */
457 lptr->defn.type = LBL_GLOBAL;
458 lastdef = 0; /* We are "re-creating" this label */
460 } else {
461 /* It's a pseudo-segment (extern, common) */
462 segment = lptr->defn.segment ? lptr->defn.segment : seg_alloc();
465 if (lastdef || lptr->defn.type == LBL_BACKEND) {
467 * We have seen this on at least one previous pass, or
468 * potentially earlier in this same pass (in which case we
469 * will probably error out further down.)
471 mangle_label_name(lptr);
472 handle_herelabel(lptr, &segment, &offset);
475 if (ismagic(label) && lptr->defn.type == LBL_LOCAL)
476 lptr->defn.type = LBL_SPECIAL;
478 if (set_prevlabel(label) && normal)
479 prevlabel = lptr->defn.label;
481 if (lptr->defn.type == LBL_COMMON) {
482 size = offset;
483 offset = 0;
484 } else {
485 size = 0; /* This is a hack... */
488 changed = created || !lastdef ||
489 lptr->defn.segment != segment ||
490 lptr->defn.offset != offset ||
491 lptr->defn.size != size;
492 global_offset_changed += changed;
494 if (lastdef == lpass) {
495 int32_t saved_line = 0;
496 const char *saved_fname = NULL;
497 int noteflags;
500 * Defined elsewhere in the program, seen in this pass.
502 if (changed) {
503 nasm_nonfatal("label `%s' inconsistently redefined", lptr->defn.label);
504 noteflags = ERR_NOTE|ERR_HERE;
505 } else {
507 *!label-redef [off] label redefined to an identical value
508 *! warns if a label is defined more than once, but the
509 *! value is identical. It is an unconditional error to
510 *! define the same label more than once to \e{different} values.
512 nasm_warn(WARN_LABEL_REDEF,
513 "label `%s' redefined to an identical value", lptr->defn.label);
514 noteflags = ERR_NOTE|ERR_HERE|WARN_LABEL_REDEF;
517 src_get(&saved_line, &saved_fname);
518 src_set(lptr->defn.def_line, lptr->defn.def_file);
519 nasm_error(noteflags, "label `%s' originally defined",
520 lptr->defn.label);
521 src_set(saved_line, saved_fname);
522 } else if (changed && pass_final() && lptr->defn.type != LBL_SPECIAL) {
524 *!label-redef-late [err] label (re)defined during code generation
525 *! the value of a label changed during the final, code-generation
526 *! pass. This may be the result of strange use of the
527 *! preprocessor. This is very likely to produce incorrect code and
528 *! may end up being an unconditional error in a future
529 *! version of NASM.
531 * WARN_LABEL_LATE defaults to an error, as this should never
532 * actually happen. Just in case this is a backwards
533 * compatibility problem, still make it a warning so that the
534 * user can suppress or demote it.
536 * Note: As a special case, LBL_SPECIAL symbols are allowed
537 * to be changed even during the last pass.
539 nasm_warn(WARN_LABEL_REDEF_LATE|ERR_UNDEAD,
540 "label `%s' %s during code generation",
541 lptr->defn.label, created ? "defined" : "changed");
543 lptr->defn.segment = segment;
544 lptr->defn.offset = offset;
545 lptr->defn.size = size;
546 lptr->defn.defined = lpass;
548 if (changed || lastdef != lpass)
549 src_get(&lptr->defn.def_line, &lptr->defn.def_file);
551 if (lastdef != lpass)
552 out_symdef(lptr);
556 * Define a special backend label
558 void backend_label(const char *label, int32_t segment, int64_t offset)
560 if (!declare_label(label, LBL_BACKEND, NULL))
561 return;
563 define_label(label, segment, offset, false);
566 int init_labels(void)
568 ldata = lfree = nasm_malloc(LBLK_SIZE);
569 init_block(lfree);
571 perm_head = perm_tail =
572 nasm_malloc(sizeof(struct permts));
574 perm_head->next = NULL;
575 perm_head->size = PERMTS_SIZE;
576 perm_head->usage = 0;
578 prevlabel = "";
580 initialized = true;
582 return 0;
585 void cleanup_labels(void)
587 union label *lptr, *lhold;
589 initialized = false;
591 hash_free(&ltab);
593 lptr = lhold = ldata;
594 while (lptr) {
595 lptr = &lptr[LABEL_BLOCK-1];
596 lptr = lptr->admin.next;
597 nasm_free(lhold);
598 lhold = lptr;
601 while (perm_head) {
602 perm_tail = perm_head;
603 perm_head = perm_head->next;
604 nasm_free(perm_tail);
608 static void init_block(union label *blk)
610 int j;
612 for (j = 0; j < LABEL_BLOCK - 1; j++)
613 blk[j].admin.movingon = END_LIST;
614 blk[LABEL_BLOCK - 1].admin.movingon = END_BLOCK;
615 blk[LABEL_BLOCK - 1].admin.next = NULL;
618 static char * safe_alloc perm_alloc(size_t len)
620 char *p;
622 if (perm_tail->size - perm_tail->usage < len) {
623 size_t alloc_len = (len > PERMTS_SIZE) ? len : PERMTS_SIZE;
624 perm_tail->next = nasm_malloc(PERMTS_HEADER + alloc_len);
625 perm_tail = perm_tail->next;
626 perm_tail->next = NULL;
627 perm_tail->size = alloc_len;
628 perm_tail->usage = 0;
630 p = perm_tail->data + perm_tail->usage;
631 perm_tail->usage += len;
632 return p;
635 static char *perm_copy(const char *string)
637 char *p;
638 size_t len;
640 if (!string)
641 return NULL;
643 len = strlen(string)+1; /* Include final NUL */
645 p = perm_alloc(len);
646 memcpy(p, string, len);
648 return p;
651 static char *
652 perm_copy3(const char *s1, const char *s2, const char *s3)
654 char *p;
655 size_t l1 = strlen(s1);
656 size_t l2 = strlen(s2);
657 size_t l3 = strlen(s3)+1; /* Include final NUL */
659 p = perm_alloc(l1+l2+l3);
660 memcpy(p, s1, l1);
661 memcpy(p+l1, s2, l2);
662 memcpy(p+l1+l2, s3, l3);
664 return p;
667 const char *local_scope(const char *label)
669 return islocal(label) ? prevlabel : "";
673 * Notes regarding bug involving redefinition of external segments.
675 * Up to and including v0.97, the following code didn't work. From 0.97
676 * developers release 2 onwards, it will generate an error.
678 * EXTERN extlabel
679 * newlabel EQU extlabel + 1
681 * The results of allowing this code through are that two import records
682 * are generated, one for 'extlabel' and one for 'newlabel'.
684 * The reason for this is an inadequacy in the defined interface between
685 * the label manager and the output formats. The problem lies in how the
686 * output format driver tells that a label is an external label for which
687 * a label import record must be produced. Most (all except bin?) produce
688 * the record if the segment number of the label is not one of the internal
689 * segments that the output driver is producing.
691 * A simple fix to this would be to make the output formats keep track of
692 * which symbols they've produced import records for, and make them not
693 * produce import records for segments that are already defined.
695 * The best way, which is slightly harder but reduces duplication of code
696 * and should therefore make the entire system smaller and more stable is
697 * to change the interface between assembler, define_label(), and
698 * the output module. The changes that are needed are:
700 * The semantics of the 'isextern' flag passed to define_label() need
701 * examining. This information may or may not tell us what we need to
702 * know (ie should we be generating an import record at this point for this
703 * label). If these aren't the semantics, the semantics should be changed
704 * to this.
706 * The output module interface needs changing, so that the `isextern' flag
707 * is passed to the module, so that it can be easily tested for.