blob: 9152552e46260f408777107c8035f425ad990ed3 [file] [log] [blame]
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07001/* ----------------------------------------------------------------------- *
2 *
3 * Copyright 1996-2009 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00006 *
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07007 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
10 *
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.
17 *
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.
31 *
32 * ----------------------------------------------------------------------- */
33
34/*
35 * labels.c label handling for the Netwide Assembler
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000036 */
37
H. Peter Anvinfe501952007-10-02 21:53:51 -070038#include "compiler.h"
39
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000040#include <stdio.h>
41#include <string.h>
42#include <stdlib.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +000043#include <inttypes.h>
44
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000045#include "nasm.h"
46#include "nasmlib.h"
H. Peter Anvin6244f4b2007-09-14 18:03:29 -070047#include "hashtbl.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000048
49/*
50 * A local label is one that begins with exactly one period. Things
51 * that begin with _two_ periods are NASM-specific things.
H. Peter Anvin1cd0e2d2002-04-30 21:00:33 +000052 *
53 * If TASM compatibility is enabled, a local label can also begin with
54 * @@, so @@local is a TASM compatible local label. Note that we only
55 * check for the first @ symbol, although TASM requires both.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000056 */
H. Peter Anvin1cd0e2d2002-04-30 21:00:33 +000057#define islocal(l) \
58 (tasm_compatible_mode ? \
59 (((l)[0] == '.' || (l)[0] == '@') && (l)[1] != '.') : \
60 ((l)[0] == '.' && (l)[1] != '.'))
61#define islocalchar(c) \
62 (tasm_compatible_mode ? \
63 ((c) == '.' || (c) == '@') : \
64 ((c) == '.'))
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000065
H. Peter Anvin6244f4b2007-09-14 18:03:29 -070066#define LABEL_BLOCK 128 /* no. of labels/block */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000067#define LBLK_SIZE (LABEL_BLOCK*sizeof(union label))
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000068
H. Peter Anvine2c80182005-01-15 22:15:51 +000069#define END_LIST -3 /* don't clash with NO_SEG! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000070#define END_BLOCK -2
71#define BOGUS_VALUE -4
72
H. Peter Anvin565be912009-07-05 22:15:57 -070073#define PERMTS_SIZE 16384 /* size of text blocks */
74#if (PERMTS_SIZE < IDLEN_MAX)
75#error "IPERMTS_SIZE must be greater than or equal to IDLEN_MAX"
Ed Berosetc06f6df2003-09-08 00:30:40 +000076#endif
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000077
78/* values for label.defn.is_global */
H. Peter Anvinaeb0e0e2009-06-27 16:30:00 -070079#define DEFINED_BIT 1
80#define GLOBAL_BIT 2
81#define EXTERN_BIT 4
82#define COMMON_BIT 8
H. Peter Anvin76690a12002-04-30 20:52:49 +000083
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000084#define NOT_DEFINED_YET 0
H. Peter Anvin76690a12002-04-30 20:52:49 +000085#define TYPE_MASK 3
86#define LOCAL_SYMBOL (DEFINED_BIT)
87#define GLOBAL_PLACEHOLDER (GLOBAL_BIT)
88#define GLOBAL_SYMBOL (DEFINED_BIT|GLOBAL_BIT)
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000089
H. Peter Anvine2c80182005-01-15 22:15:51 +000090union label { /* actual label structures */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000091 struct {
Charles Crayne4e8563d2007-11-05 17:19:32 -080092 int32_t segment;
93 int64_t offset;
Keith Kaniosa6dfa782007-04-13 16:47:53 +000094 char *label, *special;
H. Peter Anvinaf535c12002-04-30 20:59:21 +000095 int is_global, is_norm;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000096 } defn;
97 struct {
Charles Crayne4e8563d2007-11-05 17:19:32 -080098 int32_t movingon;
99 int64_t dummy;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000100 union label *next;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000101 } admin;
102};
103
H. Peter Anvine2c80182005-01-15 22:15:51 +0000104struct permts { /* permanent text storage */
105 struct permts *next; /* for the linked list */
106 int size, usage; /* size and used space in ... */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000107 char data[PERMTS_SIZE]; /* ... the data block itself */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000108};
109
Charles Craynec1905c22008-09-11 18:54:06 -0700110extern int64_t global_offset_changed; /* defined in nasm.c */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000111
H. Peter Anvin166c2472008-05-28 12:28:58 -0700112static struct hash_table ltab; /* labels hash table */
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700113static union label *ldata; /* all label data blocks */
114static union label *lfree; /* labels free block */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000115static struct permts *perm_head; /* start of perm. text storage */
116static struct permts *perm_tail; /* end of perm. text storage */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000117
H. Peter Anvine2c80182005-01-15 22:15:51 +0000118static void init_block(union label *blk);
H. Peter Anvind2fb7a62007-09-16 17:53:17 -0700119static char *perm_copy(const char *string);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000120
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000121static char *prevlabel;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000122
H. Peter Anvin70055962007-10-11 00:05:31 -0700123static bool initialized = false;
H. Peter Anvin76690a12002-04-30 20:52:49 +0000124
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000125char lprefix[PREFIX_MAX] = { 0 };
126char lpostfix[PREFIX_MAX] = { 0 };
H. Peter Anvin1cd0e2d2002-04-30 21:00:33 +0000127
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000128/*
129 * Internal routine: finds the `union label' corresponding to the
130 * given label name. Creates a new one, if it isn't found, and if
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700131 * `create' is true.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000132 */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000133static union label *find_label(char *label, int create)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000134{
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700135 char *prev;
136 int prevlen, len;
H. Peter Anvin97a23472007-09-16 17:57:25 -0700137 union label *lptr, **lpp;
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700138 char label_str[IDLEN_MAX];
139 struct hash_insert ip;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000140
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700141 if (islocal(label)) {
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000142 prev = prevlabel;
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700143 prevlen = strlen(prev);
144 len = strlen(label);
145 if (prevlen+len >= IDLEN_MAX)
146 return NULL; /* Error... */
147 memcpy(label_str, prev, prevlen);
H. Peter Anvind2fb7a62007-09-16 17:53:17 -0700148 memcpy(label_str+prevlen, label, len+1);
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700149 label = label_str;
150 } else {
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000151 prev = "";
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700152 prevlen = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000153 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000154
H. Peter Anvin166c2472008-05-28 12:28:58 -0700155 lpp = (union label **) hash_find(&ltab, label, &ip);
H. Peter Anvin97a23472007-09-16 17:57:25 -0700156 lptr = lpp ? *lpp : NULL;
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700157
158 if (lptr || !create)
159 return lptr;
160
161 /* Create a new label... */
162 if (lfree->admin.movingon == END_BLOCK) {
163 /*
164 * must allocate a new block
165 */
166 lfree->admin.next =
167 (union label *)nasm_malloc(LBLK_SIZE);
168 lfree = lfree->admin.next;
169 init_block(lfree);
170 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700171
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700172 lfree->admin.movingon = BOGUS_VALUE;
H. Peter Anvind2fb7a62007-09-16 17:53:17 -0700173 lfree->defn.label = perm_copy(label);
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700174 lfree->defn.special = NULL;
175 lfree->defn.is_global = NOT_DEFINED_YET;
H. Peter Anvin70653092007-10-19 14:42:29 -0700176
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700177 hash_add(&ip, lfree->defn.label, lfree);
178 return lfree++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000179}
180
Charles Crayne4e8563d2007-11-05 17:19:32 -0800181bool lookup_label(char *label, int32_t *segment, int64_t *offset)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000182{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000183 union label *lptr;
184
Keith Kaniosb7a89542007-04-12 02:40:54 +0000185 if (!initialized)
H. Peter Anvin70055962007-10-11 00:05:31 -0700186 return false;
H. Peter Anvin76690a12002-04-30 20:52:49 +0000187
H. Peter Anvine2c80182005-01-15 22:15:51 +0000188 lptr = find_label(label, 0);
H. Peter Anvin76690a12002-04-30 20:52:49 +0000189 if (lptr && (lptr->defn.is_global & DEFINED_BIT)) {
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000190 *segment = lptr->defn.segment;
191 *offset = lptr->defn.offset;
H. Peter Anvin70055962007-10-11 00:05:31 -0700192 return true;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000193 } else
H. Peter Anvin70055962007-10-11 00:05:31 -0700194 return false;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000195}
196
H. Peter Anvin70055962007-10-11 00:05:31 -0700197bool is_extern(char *label)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000198{
H. Peter Anvin76690a12002-04-30 20:52:49 +0000199 union label *lptr;
200
Keith Kaniosb7a89542007-04-12 02:40:54 +0000201 if (!initialized)
H. Peter Anvin70055962007-10-11 00:05:31 -0700202 return false;
H. Peter Anvin76690a12002-04-30 20:52:49 +0000203
H. Peter Anvine2c80182005-01-15 22:15:51 +0000204 lptr = find_label(label, 0);
H. Peter Anvin70055962007-10-11 00:05:31 -0700205 return (lptr && (lptr->defn.is_global & EXTERN_BIT));
H. Peter Anvin76690a12002-04-30 20:52:49 +0000206}
207
Charles Crayne4e8563d2007-11-05 17:19:32 -0800208void redefine_label(char *label, int32_t segment, int64_t offset, char *special,
H. Peter Anvin605f5152009-07-18 18:31:41 -0700209 bool is_norm, bool isextrn)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000210{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000211 union label *lptr;
H. Peter Anvin1cd0e2d2002-04-30 21:00:33 +0000212 int exi;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000213
H. Peter Anvineba20a72002-04-30 20:53:55 +0000214 /* This routine possibly ought to check for phase errors. Most assemblers
215 * check for phase errors at this point. I don't know whether phase errors
216 * are even possible, nor whether they are checked somewhere else
217 */
218
H. Peter Anvine2c80182005-01-15 22:15:51 +0000219 (void)special; /* Don't warn that this parameter is unused */
220 (void)is_norm; /* Don't warn that this parameter is unused */
221 (void)isextrn; /* Don't warn that this parameter is unused */
H. Peter Anvineba20a72002-04-30 20:53:55 +0000222
223#ifdef DEBUG
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000224#if DEBUG<3
H. Peter Anvineba20a72002-04-30 20:53:55 +0000225 if (!strncmp(label, "debugdump", 9))
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000226#endif
Victor van den Elzen15bb2332009-08-11 02:10:16 +0200227 nasm_error(ERR_DEBUG, "redefine_label (%s, %"PRIx32", %"PRIx64", %s, %d, %d)",
H. Peter Anvine2c80182005-01-15 22:15:51 +0000228 label, segment, offset, special, is_norm, isextrn);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000229#endif
230
H. Peter Anvine2c80182005-01-15 22:15:51 +0000231 lptr = find_label(label, 1);
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000232 if (!lptr)
H. Peter Anvin605f5152009-07-18 18:31:41 -0700233 nasm_error(ERR_PANIC, "can't find label `%s' on pass two", label);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000234
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000235 if (!islocal(label)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000236 if (!islocalchar(*label) && lptr->defn.is_norm)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000237 prevlabel = lptr->defn.label;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000238 }
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000239
H. Peter Anvinaeb0e0e2009-06-27 16:30:00 -0700240 if (lptr->defn.offset != offset)
241 global_offset_changed++;
242
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000243 lptr->defn.offset = offset;
Charles Craynecd341802008-06-04 15:53:21 -0700244 lptr->defn.segment = segment;
H. Peter Anvin1cd0e2d2002-04-30 21:00:33 +0000245
H. Peter Anvine2c80182005-01-15 22:15:51 +0000246 if (pass0 == 1) {
247 exi = !!(lptr->defn.is_global & GLOBAL_BIT);
248 if (exi) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000249 char *xsymbol;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000250 int slen;
251 slen = strlen(lprefix);
252 slen += strlen(lptr->defn.label);
253 slen += strlen(lpostfix);
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000254 slen++; /* room for that null char */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000255 xsymbol = nasm_malloc(slen);
256 snprintf(xsymbol, slen, "%s%s%s", lprefix, lptr->defn.label,
257 lpostfix);
258
259 ofmt->symdef(xsymbol, segment, offset, exi,
260 special ? special : lptr->defn.special);
261 ofmt->current_dfmt->debug_deflabel(xsymbol, segment, offset,
262 exi,
263 special ? special : lptr->
264 defn.special);
H. Peter Anvin1cd0e2d2002-04-30 21:00:33 +0000265/** nasm_free(xsymbol); ! outobj.c stores the pointer; ouch!!! **/
H. Peter Anvine2c80182005-01-15 22:15:51 +0000266 } else {
267 if ((lptr->defn.is_global & (GLOBAL_BIT | EXTERN_BIT)) !=
268 EXTERN_BIT) {
269 ofmt->symdef(lptr->defn.label, segment, offset, exi,
270 special ? special : lptr->defn.special);
271 ofmt->current_dfmt->debug_deflabel(label, segment, offset,
272 exi,
273 special ? special :
274 lptr->defn.special);
275 }
276 }
H. Peter Anvin1cd0e2d2002-04-30 21:00:33 +0000277 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000278 /* if (pass0 == 1) */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000279}
280
Charles Crayne4e8563d2007-11-05 17:19:32 -0800281void define_label(char *label, int32_t segment, int64_t offset, char *special,
H. Peter Anvin605f5152009-07-18 18:31:41 -0700282 bool is_norm, bool isextrn)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000283{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000284 union label *lptr;
H. Peter Anvin1cd0e2d2002-04-30 21:00:33 +0000285 int exi;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000286
H. Peter Anvineba20a72002-04-30 20:53:55 +0000287#ifdef DEBUG
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000288#if DEBUG<3
H. Peter Anvineba20a72002-04-30 20:53:55 +0000289 if (!strncmp(label, "debugdump", 9))
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000290#endif
Victor van den Elzen15bb2332009-08-11 02:10:16 +0200291 nasm_error(ERR_DEBUG, "define_label (%s, %"PRIx32", %"PRIx64", %s, %d, %d)",
H. Peter Anvine2c80182005-01-15 22:15:51 +0000292 label, segment, offset, special, is_norm, isextrn);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000293#endif
H. Peter Anvine2c80182005-01-15 22:15:51 +0000294 lptr = find_label(label, 1);
H. Peter Anvin76690a12002-04-30 20:52:49 +0000295 if (lptr->defn.is_global & DEFINED_BIT) {
H. Peter Anvin605f5152009-07-18 18:31:41 -0700296 nasm_error(ERR_NONFATAL, "symbol `%s' redefined", label);
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000297 return;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000298 }
H. Peter Anvin76690a12002-04-30 20:52:49 +0000299 lptr->defn.is_global |= DEFINED_BIT;
300 if (isextrn)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000301 lptr->defn.is_global |= EXTERN_BIT;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000302
H. Peter Anvinaeb0e0e2009-06-27 16:30:00 -0700303 if (!islocalchar(label[0]) && is_norm) {
304 /* not local, but not special either */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000305 prevlabel = lptr->defn.label;
H. Peter Anvinaeb0e0e2009-06-27 16:30:00 -0700306 } else if (islocal(label) && !*prevlabel) {
H. Peter Anvin605f5152009-07-18 18:31:41 -0700307 nasm_error(ERR_NONFATAL, "attempt to define a local label before any"
H. Peter Anvine2c80182005-01-15 22:15:51 +0000308 " non-local labels");
309 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000310
311 lptr->defn.segment = segment;
312 lptr->defn.offset = offset;
H. Peter Anvin1cd0e2d2002-04-30 21:00:33 +0000313 lptr->defn.is_norm = (!islocalchar(label[0]) && is_norm);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000314
Charles Crayne82e94992008-03-03 14:43:55 -0800315 if (pass0 == 1 || (!is_norm && !isextrn && (segment > 0) && (segment & 1))) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000316 exi = !!(lptr->defn.is_global & GLOBAL_BIT);
317 if (exi) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000318 char *xsymbol;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000319 int slen;
320 slen = strlen(lprefix);
321 slen += strlen(lptr->defn.label);
322 slen += strlen(lpostfix);
323 slen++; /* room for that null char */
324 xsymbol = nasm_malloc(slen);
325 snprintf(xsymbol, slen, "%s%s%s", lprefix, lptr->defn.label,
326 lpostfix);
H. Peter Anvin1cd0e2d2002-04-30 21:00:33 +0000327
H. Peter Anvine2c80182005-01-15 22:15:51 +0000328 ofmt->symdef(xsymbol, segment, offset, exi,
329 special ? special : lptr->defn.special);
330 ofmt->current_dfmt->debug_deflabel(xsymbol, segment, offset,
331 exi,
332 special ? special : lptr->
333 defn.special);
H. Peter Anvin1cd0e2d2002-04-30 21:00:33 +0000334/** nasm_free(xsymbol); ! outobj.c stores the pointer; ouch!!! **/
H. Peter Anvine2c80182005-01-15 22:15:51 +0000335 } else {
336 if ((lptr->defn.is_global & (GLOBAL_BIT | EXTERN_BIT)) !=
337 EXTERN_BIT) {
338 ofmt->symdef(lptr->defn.label, segment, offset, exi,
339 special ? special : lptr->defn.special);
340 ofmt->current_dfmt->debug_deflabel(label, segment, offset,
341 exi,
342 special ? special :
343 lptr->defn.special);
344 }
345 }
346 } /* if (pass0 == 1) */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000347}
348
H. Peter Anvin605f5152009-07-18 18:31:41 -0700349void define_common(char *label, int32_t segment, int32_t size, char *special)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000350{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000351 union label *lptr;
352
H. Peter Anvine2c80182005-01-15 22:15:51 +0000353 lptr = find_label(label, 1);
H. Peter Anvinaeb0e0e2009-06-27 16:30:00 -0700354 if ((lptr->defn.is_global & DEFINED_BIT) &&
355 (passn == 1 || !(lptr->defn.is_global & COMMON_BIT))) {
H. Peter Anvin605f5152009-07-18 18:31:41 -0700356 nasm_error(ERR_NONFATAL, "symbol `%s' redefined", label);
H. Peter Anvinaeb0e0e2009-06-27 16:30:00 -0700357 return;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000358 }
H. Peter Anvinaeb0e0e2009-06-27 16:30:00 -0700359 lptr->defn.is_global |= DEFINED_BIT|COMMON_BIT;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000360
H. Peter Anvinaeb0e0e2009-06-27 16:30:00 -0700361 if (!islocalchar(label[0])) {
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000362 prevlabel = lptr->defn.label;
H. Peter Anvinaeb0e0e2009-06-27 16:30:00 -0700363 } else {
H. Peter Anvin605f5152009-07-18 18:31:41 -0700364 nasm_error(ERR_NONFATAL, "attempt to define a local label as a "
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000365 "common variable");
H. Peter Anvinaeb0e0e2009-06-27 16:30:00 -0700366 return;
367 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000368
369 lptr->defn.segment = segment;
370 lptr->defn.offset = 0;
371
H. Peter Anvinaeb0e0e2009-06-27 16:30:00 -0700372 if (pass0 == 0)
373 return;
374
H. Peter Anvine2c80182005-01-15 22:15:51 +0000375 ofmt->symdef(lptr->defn.label, segment, size, 2,
H. Peter Anvinaeb0e0e2009-06-27 16:30:00 -0700376 special ? special : lptr->defn.special);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000377 ofmt->current_dfmt->debug_deflabel(lptr->defn.label, segment, size, 2,
H. Peter Anvinaeb0e0e2009-06-27 16:30:00 -0700378 special ? special : lptr->defn.
379 special);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000380}
381
H. Peter Anvin605f5152009-07-18 18:31:41 -0700382void declare_as_global(char *label, char *special)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000383{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000384 union label *lptr;
385
386 if (islocal(label)) {
H. Peter Anvin605f5152009-07-18 18:31:41 -0700387 nasm_error(ERR_NONFATAL, "attempt to declare local symbol `%s' as"
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000388 " global", label);
389 return;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000390 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000391 lptr = find_label(label, 1);
H. Peter Anvin76690a12002-04-30 20:52:49 +0000392 switch (lptr->defn.is_global & TYPE_MASK) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000393 case NOT_DEFINED_YET:
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000394 lptr->defn.is_global = GLOBAL_PLACEHOLDER;
H. Peter Anvind2fb7a62007-09-16 17:53:17 -0700395 lptr->defn.special = special ? perm_copy(special) : NULL;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000396 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000397 case GLOBAL_PLACEHOLDER: /* already done: silently ignore */
398 case GLOBAL_SYMBOL:
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000399 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000400 case LOCAL_SYMBOL:
Charles Crayne18152f02009-01-28 19:07:18 -0800401 if (!(lptr->defn.is_global & EXTERN_BIT)) {
H. Peter Anvin605f5152009-07-18 18:31:41 -0700402 nasm_error(ERR_WARNING, "symbol `%s': GLOBAL directive "
Charles Crayne18152f02009-01-28 19:07:18 -0800403 "after symbol definition is an experimental feature", label);
404 lptr->defn.is_global = GLOBAL_SYMBOL;
405 }
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000406 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000407 }
408}
409
H. Peter Anvine2c80182005-01-15 22:15:51 +0000410int init_labels(void)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000411{
H. Peter Anvin166c2472008-05-28 12:28:58 -0700412 hash_init(&ltab, HASH_LARGE);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000413
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700414 ldata = lfree = (union label *)nasm_malloc(LBLK_SIZE);
415 init_block(lfree);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000416
H. Peter Anvine2c80182005-01-15 22:15:51 +0000417 perm_head =
418 perm_tail = (struct permts *)nasm_malloc(sizeof(struct permts));
H. Peter Anvineba20a72002-04-30 20:53:55 +0000419
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000420 perm_head->next = NULL;
421 perm_head->size = PERMTS_SIZE;
422 perm_head->usage = 0;
423
424 prevlabel = "";
425
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700426 initialized = true;
H. Peter Anvin76690a12002-04-30 20:52:49 +0000427
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000428 return 0;
429}
430
H. Peter Anvine2c80182005-01-15 22:15:51 +0000431void cleanup_labels(void)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000432{
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700433 union label *lptr, *lhold;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000434
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700435 initialized = false;
H. Peter Anvin76690a12002-04-30 20:52:49 +0000436
H. Peter Anvin166c2472008-05-28 12:28:58 -0700437 hash_free(&ltab);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000438
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700439 lptr = lhold = ldata;
440 while (lptr) {
441 lptr = &lptr[LABEL_BLOCK-1];
442 lptr = lptr->admin.next;
443 nasm_free(lhold);
444 lhold = lptr;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000445 }
446
447 while (perm_head) {
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000448 perm_tail = perm_head;
449 perm_head = perm_head->next;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000450 nasm_free(perm_tail);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000451 }
452}
453
H. Peter Anvine2c80182005-01-15 22:15:51 +0000454static void init_block(union label *blk)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000455{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000456 int j;
457
H. Peter Anvine2c80182005-01-15 22:15:51 +0000458 for (j = 0; j < LABEL_BLOCK - 1; j++)
459 blk[j].admin.movingon = END_LIST;
460 blk[LABEL_BLOCK - 1].admin.movingon = END_BLOCK;
461 blk[LABEL_BLOCK - 1].admin.next = NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000462}
463
H. Peter Anvind2fb7a62007-09-16 17:53:17 -0700464static char *perm_copy(const char *string)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000465{
H. Peter Anvind2fb7a62007-09-16 17:53:17 -0700466 char *p;
467 int len = strlen(string)+1;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000468
H. Peter Anvin565be912009-07-05 22:15:57 -0700469 nasm_assert(len <= PERMTS_SIZE);
470
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000471 if (perm_tail->size - perm_tail->usage < len) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000472 perm_tail->next =
473 (struct permts *)nasm_malloc(sizeof(struct permts));
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000474 perm_tail = perm_tail->next;
475 perm_tail->next = NULL;
476 perm_tail->size = PERMTS_SIZE;
477 perm_tail->usage = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000478 }
H. Peter Anvind2fb7a62007-09-16 17:53:17 -0700479 p = perm_tail->data + perm_tail->usage;
480 memcpy(p, string, len);
481 perm_tail->usage += len;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000482
483 return p;
484}
H. Peter Anvineba20a72002-04-30 20:53:55 +0000485
Charles Crayned60059e2008-03-12 22:39:03 -0700486char *local_scope(char *label)
487{
488 return islocal(label) ? prevlabel : "";
489}
490
H. Peter Anvineba20a72002-04-30 20:53:55 +0000491/*
492 * Notes regarding bug involving redefinition of external segments.
493 *
494 * Up to and including v0.97, the following code didn't work. From 0.97
495 * developers release 2 onwards, it will generate an error.
496 *
497 * EXTERN extlabel
498 * newlabel EQU extlabel + 1
499 *
500 * The results of allowing this code through are that two import records
501 * are generated, one for 'extlabel' and one for 'newlabel'.
502 *
503 * The reason for this is an inadequacy in the defined interface between
504 * the label manager and the output formats. The problem lies in how the
505 * output format driver tells that a label is an external label for which
506 * a label import record must be produced. Most (all except bin?) produce
507 * the record if the segment number of the label is not one of the internal
508 * segments that the output driver is producing.
509 *
510 * A simple fix to this would be to make the output formats keep track of
511 * which symbols they've produced import records for, and make them not
512 * produce import records for segments that are already defined.
513 *
514 * The best way, which is slightly harder but reduces duplication of code
515 * and should therefore make the entire system smaller and more stable is
516 * to change the interface between assembler, define_label(), and
517 * the output module. The changes that are needed are:
518 *
519 * The semantics of the 'isextern' flag passed to define_label() need
520 * examining. This information may or may not tell us what we need to
521 * know (ie should we be generating an import record at this point for this
522 * label). If these aren't the semantics, the semantics should be changed
523 * to this.
524 *
525 * The output module interface needs changing, so that the `isextern' flag
526 * is passed to the module, so that it can be easily tested for.
527 */