/* ----------------------------------------------------------------------- * * * Copyright 1996-2018 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * ----------------------------------------------------------------------- */ /* * labels.c label handling for the Netwide Assembler */ #include "compiler.h" #include "nasm.h" #include "nasmlib.h" #include "error.h" #include "hashtbl.h" #include "labels.h" /* * A dot-local label is one that begins with exactly one period. Things * that begin with _two_ periods are NASM-specific things. * * If TASM compatibility is enabled, a local label can also begin with * @@. */ static bool islocal(const char *l) { … } /* * Return true if this falls into NASM's '..' namespace */ static bool ismagic(const char *l) { … } /* * Return true if we should update the local label base * as a result of this symbol. We must exclude local labels * as well as any kind of special labels, including ..@ ones. */ static bool set_prevlabel(const char *l) { … } #define LABEL_BLOCK … #define LBLK_SIZE … #define END_LIST … #define END_BLOCK … #define PERMTS_SIZE … #if (PERMTS_SIZE < IDLEN_MAX) #error "IPERMTS_SIZE must be greater than or equal to IDLEN_MAX" #endif /* string values for enum label_type */ static const char * const types[] = …; label; struct permts { … }; #define PERMTS_HEADER … uint64_t global_offset_changed; /* counter for global offset changes */ static struct hash_table ltab; /* labels hash table */ static union label *ldata; /* all label data blocks */ static union label *lfree; /* labels free block */ static struct permts *perm_head; /* start of perm. text storage */ static struct permts *perm_tail; /* end of perm. text storage */ static void init_block(union label *blk); static char *perm_alloc(size_t len); static char *perm_copy(const char *string); static char *perm_copy3(const char *s1, const char *s2, const char *s3); static const char *mangle_label_name(union label *lptr); static const char *prevlabel; static bool initialized = …; /* * Emit a symdef to the output and the debug format backends. */ static void out_symdef(union label *lptr) { … } /* * Internal routine: finds the `union label' corresponding to the * given label name. Creates a new one, if it isn't found, and if * `create' is true. */ static union label *find_label(const char *label, bool create, bool *created) { … } enum label_type lookup_label(const char *label, int32_t *segment, int64_t *offset) { … } static inline bool is_global(enum label_type type) { … } static const char *mangle_strings[] = …; static bool mangle_string_set[ARRAY_SIZE(mangle_strings)]; /* * Set a prefix or suffix */ void set_label_mangle(enum mangle_index which, const char *what) { … } /* * Format a label name with appropriate prefixes and suffixes */ static const char *mangle_label_name(union label *lptr) { … } static void handle_herelabel(union label *lptr, int32_t *segment, int64_t *offset) { … } static bool declare_label_lptr(union label *lptr, enum label_type type, const char *special) { … } bool declare_label(const char *label, enum label_type type, const char *special) { … } /* * The "normal" argument decides if we should update the local segment * base name or not. */ void define_label(const char *label, int32_t segment, int64_t offset, bool normal) { … } /* * Define a special backend label */ void backend_label(const char *label, int32_t segment, int64_t offset) { … } int init_labels(void) { … } void cleanup_labels(void) { … } static void init_block(union label *blk) { … } static char * safe_alloc perm_alloc(size_t len) { … } static char *perm_copy(const char *string) { … } static char * perm_copy3(const char *s1, const char *s2, const char *s3) { … } const char *local_scope(const char *label) { … } /* * Notes regarding bug involving redefinition of external segments. * * Up to and including v0.97, the following code didn't work. From 0.97 * developers release 2 onwards, it will generate an error. * * EXTERN extlabel * newlabel EQU extlabel + 1 * * The results of allowing this code through are that two import records * are generated, one for 'extlabel' and one for 'newlabel'. * * The reason for this is an inadequacy in the defined interface between * the label manager and the output formats. The problem lies in how the * output format driver tells that a label is an external label for which * a label import record must be produced. Most (all except bin?) produce * the record if the segment number of the label is not one of the internal * segments that the output driver is producing. * * A simple fix to this would be to make the output formats keep track of * which symbols they've produced import records for, and make them not * produce import records for segments that are already defined. * * The best way, which is slightly harder but reduces duplication of code * and should therefore make the entire system smaller and more stable is * to change the interface between assembler, define_label(), and * the output module. The changes that are needed are: * * The semantics of the 'isextern' flag passed to define_label() need * examining. This information may or may not tell us what we need to * know (ie should we be generating an import record at this point for this * label). If these aren't the semantics, the semantics should be changed * to this. * * The output module interface needs changing, so that the `isextern' flag * is passed to the module, so that it can be easily tested for. */