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
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
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
54 static bool islocal(const char *l
)
56 if (tasm_compatible_mode
) {
57 if (l
[0] == '@' && l
[1] == '@')
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] == '@')
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! */
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"
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 */
107 int32_t subsection
; /* Available for ofmt->herelabel() */
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 */
115 enum label_type type
, mangled_type
;
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
)
155 int64_t backend_offset
;
157 /* Backend-defined special segments are passed to symdef immediately */
159 /* Emit special fixups for globals and commons */
160 switch (lptr
->defn
.type
) {
164 if (lptr
->defn
.special
)
165 ofmt
->symdef(lptr
->defn
.mangled
, 0, 0, 3, lptr
->defn
.special
);
173 if (pass_type() != PASS_STAB
&& lptr
->defn
.type
!= LBL_BACKEND
)
176 /* Clean up this hack... */
177 switch(lptr
->defn
.type
) {
179 /* If not seen in the previous or this pass, drop it */
180 if (lptr
->defn
.lastref
< pass_count())
183 /* Otherwise, promote to LBL_REQUIRED at this time */
184 lptr
->defn
.type
= LBL_REQUIRED
;
190 backend_offset
= lptr
->defn
.offset
;
194 backend_offset
= lptr
->defn
.size
;
198 backend_offset
= lptr
->defn
.offset
;
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
,
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
)
216 dfmt
->debug_deflabel(lptr
->defn
.mangled
, lptr
->defn
.segment
,
217 lptr
->defn
.offset
, backend_type
,
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
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
);
235 label
= label_str
= nasm_strcat(prevlabel
, label
);
237 lpp
= (union label
**) hash_find(<ab
, label
, &ip
);
238 lptr
= lpp
? *lpp
: NULL
;
240 if (lptr
|| !create
) {
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
;
260 lfree
->defn
.label
= perm_copy(label
);
261 lfree
->defn
.subsection
= NO_SEG
;
263 nasm_free(label_str
);
265 hash_add(&ip
, lfree
->defn
.label
, lfree
);
269 enum label_type
lookup_label(const char *label
,
270 int32_t *segment
, int64_t *offset
)
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
;
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
)
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
) {
327 prefix
= mangle_strings
[LM_GPREFIX
];
328 suffix
= mangle_strings
[LM_GSUFFIX
];
332 prefix
= suffix
= "";
335 prefix
= mangle_strings
[LM_LPREFIX
];
336 suffix
= mangle_strings
[LM_LSUFFIX
];
340 lptr
->defn
.mangled_type
= lptr
->defn
.type
;
342 if (!(*prefix
) && !(*suffix
))
343 lptr
->defn
.mangled
= lptr
->defn
.label
;
345 lptr
->defn
.mangled
= perm_copy3(prefix
, lptr
->defn
.label
, suffix
);
347 return lptr
->defn
.mangled
;
351 handle_herelabel(union label
*lptr
, int32_t *segment
, int64_t *offset
)
355 if (likely(!ofmt
->herelabel
))
358 if (unlikely(location
.segment
== NO_SEG
))
363 if (oldseg
== location
.segment
&& *offset
== location
.offset
) {
364 /* This label is defined at this location */
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
, ©offset
);
371 if (likely(newseg
== oldseg
))
376 /* Maintain the offset from the old to the new segment */
377 switch_segment(newseg
);
378 location
.offset
= *offset
;
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])
394 if (oldtype
== type
|| (!pass_stable() && oldtype
== LBL_LOCAL
) ||
395 (oldtype
== LBL_EXTERN
&& type
== LBL_REQUIRED
)) {
396 lptr
->defn
.type
= type
;
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
);
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 */
412 lptr
->defn
.special
= perm_copy(special
);
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
]);
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
442 void define_label(const char *label
, int32_t segment
,
443 int64_t offset
, bool normal
)
446 bool created
, changed
;
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
;
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 */
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
) {
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
;
513 * Defined elsewhere in the program, seen in this pass.
516 nasm_nonfatal("label `%s' inconsistently redefined", lptr
->defn
.label
);
517 noteflags
= ERR_NONFATAL
|ERR_HERE
|ERR_NO_SEVERITY
;
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
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
)
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
))
575 define_label(label
, segment
, offset
, false);
578 int init_labels(void)
580 ldata
= lfree
= nasm_malloc(LBLK_SIZE
);
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;
597 void cleanup_labels(void)
599 union label
*lptr
, *lhold
;
605 lptr
= lhold
= ldata
;
607 lptr
= &lptr
[LABEL_BLOCK
-1];
608 lptr
= lptr
->admin
.next
;
614 perm_tail
= perm_head
;
615 perm_head
= perm_head
->next
;
616 nasm_free(perm_tail
);
620 static void init_block(union label
*blk
)
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
)
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
;
647 static char *perm_copy(const char *string
)
655 len
= strlen(string
)+1; /* Include final NUL */
658 memcpy(p
, string
, len
);
664 perm_copy3(const char *s1
, const char *s2
, const char *s3
)
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
);
673 memcpy(p
+l1
, s2
, l2
);
674 memcpy(p
+l1
+l2
, s3
, l3
);
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.
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
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.