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", "global", "static", "extern", "common", "special",
101 "output format special"};
103 union label
{ /* actual label structures */
106 int32_t subsection
; /* Available for ofmt->herelabel() */
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 */
113 enum label_type type
, mangled_type
;
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
)
153 int64_t backend_offset
;
155 /* Backend-defined special segments are passed to symdef immediately */
157 /* Emit special fixups for globals and commons */
158 switch (lptr
->defn
.type
) {
162 if (lptr
->defn
.special
)
163 ofmt
->symdef(lptr
->defn
.mangled
, 0, 0, 3, lptr
->defn
.special
);
171 if (pass_type() != PASS_STAB
&& lptr
->defn
.type
!= LBL_BACKEND
)
174 /* Clean up this hack... */
175 switch(lptr
->defn
.type
) {
179 backend_offset
= lptr
->defn
.offset
;
183 backend_offset
= lptr
->defn
.size
;
187 backend_offset
= lptr
->defn
.offset
;
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
,
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
)
205 dfmt
->debug_deflabel(lptr
->defn
.mangled
, lptr
->defn
.segment
,
206 lptr
->defn
.offset
, backend_type
,
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
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
);
224 label
= label_str
= nasm_strcat(prevlabel
, label
);
226 lpp
= (union label
**) hash_find(<ab
, label
, &ip
);
227 lptr
= lpp
? *lpp
: NULL
;
229 if (lptr
|| !create
) {
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
;
249 lfree
->defn
.label
= perm_copy(label
);
250 lfree
->defn
.subsection
= NO_SEG
;
252 nasm_free(label_str
);
254 hash_add(&ip
, lfree
->defn
.label
, lfree
);
258 bool lookup_label(const char *label
, int32_t *segment
, int64_t *offset
)
265 lptr
= find_label(label
, false, NULL
);
266 if (lptr
&& lptr
->defn
.defined
) {
267 *segment
= lptr
->defn
.segment
;
268 *offset
= lptr
->defn
.offset
;
275 bool is_extern(const char *label
)
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
)
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
) {
317 prefix
= mangle_strings
[LM_GPREFIX
];
318 suffix
= mangle_strings
[LM_GSUFFIX
];
322 prefix
= suffix
= "";
325 prefix
= mangle_strings
[LM_LPREFIX
];
326 suffix
= mangle_strings
[LM_LSUFFIX
];
330 lptr
->defn
.mangled_type
= lptr
->defn
.type
;
332 if (!(*prefix
) && !(*suffix
))
333 lptr
->defn
.mangled
= lptr
->defn
.label
;
335 lptr
->defn
.mangled
= perm_copy3(prefix
, lptr
->defn
.label
, suffix
);
337 return lptr
->defn
.mangled
;
341 handle_herelabel(union label
*lptr
, int32_t *segment
, int64_t *offset
)
345 if (likely(!ofmt
->herelabel
))
348 if (unlikely(location
.segment
== NO_SEG
))
353 if (oldseg
== location
.segment
&& *offset
== location
.offset
) {
354 /* This label is defined at this location */
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
, ©offset
);
361 if (likely(newseg
== oldseg
))
366 /* Maintain the offset from the old to the new segment */
367 switch_segment(newseg
);
368 location
.offset
= *offset
;
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])
382 if (lptr
->defn
.type
== type
||
383 (!pass_stable() && lptr
->defn
.type
== LBL_LOCAL
)) {
384 lptr
->defn
.type
= type
;
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
);
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 */
401 lptr
->defn
.special
= perm_copy(special
);
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
]);
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
429 void define_label(const char *label
, int32_t segment
,
430 int64_t offset
, bool normal
)
433 bool created
, changed
;
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
;
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 */
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
) {
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
;
500 * Defined elsewhere in the program, seen in this pass.
503 nasm_nonfatal("label `%s' inconsistently redefined", lptr
->defn
.label
);
504 noteflags
= ERR_NOTE
|ERR_HERE
;
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",
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
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
)
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
))
563 define_label(label
, segment
, offset
, false);
566 int init_labels(void)
568 ldata
= lfree
= nasm_malloc(LBLK_SIZE
);
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;
585 void cleanup_labels(void)
587 union label
*lptr
, *lhold
;
593 lptr
= lhold
= ldata
;
595 lptr
= &lptr
[LABEL_BLOCK
-1];
596 lptr
= lptr
->admin
.next
;
602 perm_tail
= perm_head
;
603 perm_head
= perm_head
->next
;
604 nasm_free(perm_tail
);
608 static void init_block(union label
*blk
)
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
)
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
;
635 static char *perm_copy(const char *string
)
643 len
= strlen(string
)+1; /* Include final NUL */
646 memcpy(p
, string
, len
);
652 perm_copy3(const char *s1
, const char *s2
, const char *s3
)
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
);
661 memcpy(p
+l1
, s2
, l2
);
662 memcpy(p
+l1
+l2
, s3
, l3
);
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.
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
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.